diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/gsm/gstgsmdec.c | 124 | ||||
-rw-r--r-- | ext/gsm/gstgsmdec.h | 5 | ||||
-rw-r--r-- | ext/gsm/gstgsmenc.c | 40 |
3 files changed, 143 insertions, 26 deletions
diff --git a/ext/gsm/gstgsmdec.c b/ext/gsm/gstgsmdec.c index 6475a779..a3ec28ed 100644 --- a/ext/gsm/gstgsmdec.c +++ b/ext/gsm/gstgsmdec.c @@ -54,7 +54,9 @@ enum static void gst_gsmdec_base_init (gpointer g_class); static void gst_gsmdec_class_init (GstGSMDec * klass); static void gst_gsmdec_init (GstGSMDec * gsmdec); +static void gst_gsmdec_finalize (GObject * object); +static gboolean gst_gsmdec_sink_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_gsmdec_chain (GstPad * pad, GstBuffer * buf); static GstElementClass *parent_class = NULL; @@ -118,11 +120,15 @@ gst_gsmdec_base_init (gpointer g_class) static void gst_gsmdec_class_init (GstGSMDec * klass) { + GObjectClass *gobject_class; GstElementClass *gstelement_class; + gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = gst_gsmdec_finalize; GST_DEBUG_CATEGORY_INIT (gsmdec_debug, "gsmdec", 0, "GSM Decoder"); } @@ -130,10 +136,13 @@ gst_gsmdec_class_init (GstGSMDec * klass) static void gst_gsmdec_init (GstGSMDec * gsmdec) { + gint use_wav49; + /* create the sink and src pads */ gsmdec->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&gsmdec_sink_template), "sink"); + gst_pad_set_event_function (gsmdec->sinkpad, gst_gsmdec_sink_event); gst_pad_set_chain_function (gsmdec->sinkpad, gst_gsmdec_chain); gst_element_add_pad (GST_ELEMENT (gsmdec), gsmdec->sinkpad); @@ -143,59 +152,138 @@ gst_gsmdec_init (GstGSMDec * gsmdec) gst_element_add_pad (GST_ELEMENT (gsmdec), gsmdec->srcpad); gsmdec->state = gsm_create (); - // turn on WAN49 handling - gint use_wav49 = 0; + /* turn on WAV49 handling */ + use_wav49 = 0; gsm_option (gsmdec->state, GSM_OPT_WAV49, &use_wav49); + gsmdec->adapter = gst_adapter_new (); gsmdec->next_of = 0; gsmdec->next_ts = 0; } +static void +gst_gsmdec_finalize (GObject * object) +{ + GstGSMDec *gsmdec; + + gsmdec = GST_GSMDEC (object); + + g_object_unref (gsmdec->adapter); + gsm_destroy (gsmdec->state); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_gsmdec_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstGSMDec *gsmdec; + + gsmdec = GST_GSMDEC (gst_pad_get_parent (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + res = gst_pad_push_event (gsmdec->srcpad, event); + break; + case GST_EVENT_FLUSH_STOP: + gst_segment_init (&gsmdec->segment, GST_FORMAT_UNDEFINED); + res = gst_pad_push_event (gsmdec->srcpad, event); + break; + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + GstFormat format; + gdouble rate; + gint64 start, stop, time; + + gst_event_parse_new_segment (event, &update, &rate, &format, &start, + &stop, &time); + + /* now configure the values */ + gst_segment_set_newsegment (&gsmdec->segment, update, + rate, format, start, stop, time); + + /* and forward */ + res = gst_pad_push_event (gsmdec->srcpad, event); + break; + } + case GST_EVENT_EOS: + default: + res = gst_pad_push_event (gsmdec->srcpad, event); + break; + } + + gst_object_unref (gsmdec); + + return res; +} + static GstFlowReturn gst_gsmdec_chain (GstPad * pad, GstBuffer * buf) { GstGSMDec *gsmdec; gsm_byte *data; GstFlowReturn ret = GST_FLOW_OK; + GstClockTime timestamp; gsmdec = GST_GSMDEC (gst_pad_get_parent (pad)); - // do we have enough bytes to read a header - if (GST_BUFFER_SIZE (buf) >= 33) { + timestamp = GST_BUFFER_TIMESTAMP (buf); + + if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { + gst_adapter_clear (gsmdec->adapter); + } + gst_adapter_push (gsmdec->adapter, buf); + + /* do we have enough bytes to read a header */ + while (gst_adapter_available (gsmdec->adapter) >= 33) { GstBuffer *outbuf; outbuf = gst_buffer_new_and_alloc (160 * sizeof (gsm_signal)); - // TODO take new segment in consideration, if not given restart - // timestamps at 0 - if (GST_BUFFER_TIMESTAMP (buf) == GST_CLOCK_TIME_NONE) { + + /* TODO take new segment in consideration, if not given restart + * timestamps at 0 */ + if (timestamp == GST_CLOCK_TIME_NONE) { /* If we are not given any timestamp */ GST_BUFFER_TIMESTAMP (outbuf) = gsmdec->next_ts; - gsmdec->next_ts += 20 * GST_MSECOND; + if (gsmdec->next_ts != GST_CLOCK_TIME_NONE) + gsmdec->next_ts += 20 * GST_MSECOND; } else { - /* But if you insist on giving us a timestamp, you are welcome. */ - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); + /* upstream gave a timestamp, use it. */ + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + gsmdec->next_ts = timestamp + 20 * GST_MSECOND; + /* and make sure we interpollate in the next run */ + timestamp = GST_CLOCK_TIME_NONE; } GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND; GST_BUFFER_OFFSET (outbuf) = gsmdec->next_of; - GST_BUFFER_OFFSET_END (outbuf) = gsmdec->next_of + 160 - 1; - gst_buffer_set_caps (outbuf, gst_pad_get_caps (gsmdec->srcpad)); gsmdec->next_of += 160; + GST_BUFFER_OFFSET_END (outbuf) = gsmdec->next_of; - data = (gsm_byte *) GST_BUFFER_DATA (buf); - gsm_decode (gsmdec->state, data, (gsm_signal *) GST_BUFFER_DATA (outbuf)); + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (gsmdec->srcpad)); - GST_DEBUG ("Pushing buffer of size %d ts %" GST_TIME_FORMAT, + /* now encode frame into the output buffer */ + data = (gsm_byte *) gst_adapter_peek (gsmdec->adapter, 33); + if (gsm_decode (gsmdec->state, data, + (gsm_signal *) GST_BUFFER_DATA (outbuf)) < 0) { + /* invalid frame */ + GST_WARNING_OBJECT (gsmdec, "tried to decode an invalid frame, skipping"); + } + gst_adapter_flush (gsmdec->adapter, 33); + + GST_DEBUG_OBJECT (gsmdec, "Pushing buffer of size %d ts %" GST_TIME_FORMAT, GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); - //gst_util_dump_mem (GST_BUFFER_DATA(outbuf), GST_BUFFER_SIZE (outbuf)); + + /* push */ ret = gst_pad_push (gsmdec->srcpad, outbuf); } - gst_buffer_unref (buf); gst_object_unref (gsmdec); return ret; diff --git a/ext/gsm/gstgsmdec.h b/ext/gsm/gstgsmdec.h index 1718e74b..7e73cccf 100644 --- a/ext/gsm/gstgsmdec.h +++ b/ext/gsm/gstgsmdec.h @@ -21,6 +21,7 @@ #define __GST_GSMDEC_H__ #include <gst/gst.h> +#include <gst/base/gstadapter.h> #ifdef GSM_HEADER_IN_SUBDIR #include <gsm/gsm.h> @@ -54,6 +55,10 @@ struct _GstGSMDec gsm state; gint64 next_of; GstClockTime next_ts; + + GstAdapter *adapter; + + GstSegment segment; }; struct _GstGSMDecClass diff --git a/ext/gsm/gstgsmenc.c b/ext/gsm/gstgsmenc.c index 2ecbefc7..4c69d1e6 100644 --- a/ext/gsm/gstgsmenc.c +++ b/ext/gsm/gstgsmenc.c @@ -54,6 +54,7 @@ enum static void gst_gsmenc_base_init (gpointer g_class); static void gst_gsmenc_class_init (GstGSMEnc * klass); static void gst_gsmenc_init (GstGSMEnc * gsmenc); +static void gst_gsmenc_finalize (GObject * object); static GstFlowReturn gst_gsmenc_chain (GstPad * pad, GstBuffer * buf); @@ -122,7 +123,9 @@ gst_gsmenc_class_init (GstGSMEnc * klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = gst_gsmenc_finalize; GST_DEBUG_CATEGORY_INIT (gsmenc_debug, "gsmenc", 0, "GSM Encoder"); } @@ -130,6 +133,8 @@ gst_gsmenc_class_init (GstGSMEnc * klass) static void gst_gsmenc_init (GstGSMEnc * gsmenc) { + gint use_wav49; + /* create the sink and src pads */ gsmenc->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get @@ -143,16 +148,28 @@ gst_gsmenc_init (GstGSMEnc * gsmenc) gst_element_add_pad (GST_ELEMENT (gsmenc), gsmenc->srcpad); gsmenc->state = gsm_create (); - // turn on WAN49 handling - gint use_wav49 = 0; + /* turn on WAV49 handling */ + use_wav49 = 0; gsm_option (gsmenc->state, GSM_OPT_WAV49, &use_wav49); gsmenc->adapter = gst_adapter_new (); - gsmenc->next_ts = 0; } +static void +gst_gsmenc_finalize (GObject * object) +{ + GstGSMEnc *gsmenc; + + gsmenc = GST_GSMENC (object); + + g_object_unref (gsmenc->adapter); + gsm_destroy (gsmenc->state); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + static GstFlowReturn gst_gsmenc_chain (GstPad * pad, GstBuffer * buf) { @@ -161,24 +178,31 @@ gst_gsmenc_chain (GstPad * pad, GstBuffer * buf) GstFlowReturn ret = GST_FLOW_OK; gsmenc = GST_GSMENC (gst_pad_get_parent (pad)); + + if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { + gst_adapter_clear (gsmenc->adapter); + } gst_adapter_push (gsmenc->adapter, buf); while (gst_adapter_available (gsmenc->adapter) >= 320) { GstBuffer *outbuf; outbuf = gst_buffer_new_and_alloc (33 * sizeof (gsm_byte)); + GST_BUFFER_TIMESTAMP (outbuf) = gsmenc->next_ts; GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND; gsmenc->next_ts += 20 * GST_MSECOND; - // encode 160 16-bit samples into 33 bytes + /* encode 160 16-bit samples into 33 bytes */ data = (gsm_signal *) gst_adapter_peek (gsmenc->adapter, 320); gsm_encode (gsmenc->state, data, (gsm_byte *) GST_BUFFER_DATA (outbuf)); gst_adapter_flush (gsmenc->adapter, 320); - gst_buffer_set_caps (outbuf, gst_pad_get_caps (gsmenc->srcpad)); - GST_DEBUG ("Pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); - //gst_util_dump_mem (GST_BUFFER_DATA(outbuf), GST_BUFFER_SIZE (outbuf)); + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (gsmenc->srcpad)); + + GST_DEBUG_OBJECT (gsmenc, "Pushing buffer of size %d", + GST_BUFFER_SIZE (outbuf)); + ret = gst_pad_push (gsmenc->srcpad, outbuf); } |