diff --git a/ext/amrwbdec/Makefile.am b/ext/amrwbdec/Makefile.am index 08eda533e3..2f822f0735 100644 --- a/ext/amrwbdec/Makefile.am +++ b/ext/amrwbdec/Makefile.am @@ -4,8 +4,11 @@ libgstamrwbdec_la_SOURCES = \ amrwb.c \ amrwbdec.c -libgstamrwbdec_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AMRWB_CFLAGS) -libgstamrwbdec_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(AMRWB_LIBS) +libgstamrwbdec_la_CFLAGS = -DGST_USE_UNSTABLE_API $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AMRWB_CFLAGS) +libgstamrwbdec_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) $(GST_LIBS) $(AMRWB_LIBS) libgstamrwbdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstamrwbdec_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/ext/amrwbdec/amrwbdec.c b/ext/amrwbdec/amrwbdec.c index 51f759d855..e00dd99d12 100644 --- a/ext/amrwbdec/amrwbdec.c +++ b/ext/amrwbdec/amrwbdec.c @@ -66,19 +66,19 @@ static const unsigned char block_size[16] = 6, 0, 0, 0, 0, 1, 1 }; -static gboolean gst_amrwbdec_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_amrwbdec_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_amrwbdec_setcaps (GstPad * pad, GstCaps * caps); -static GstStateChangeReturn gst_amrwbdec_state_change (GstElement * element, - GstStateChange transition); - -static void gst_amrwbdec_finalize (GObject * object); +static gboolean gst_amrwbdec_start (GstAudioDecoder * dec); +static gboolean gst_amrwbdec_stop (GstAudioDecoder * dec); +static gboolean gst_amrwbdec_set_format (GstAudioDecoder * dec, GstCaps * caps); +static gboolean gst_amrwbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length); +static GstFlowReturn gst_amrwbdec_handle_frame (GstAudioDecoder * dec, + GstBuffer * buffer); #define _do_init(bla) \ GST_DEBUG_CATEGORY_INIT (gst_amrwbdec_debug, "amrwbdec", 0, "AMR-WB audio decoder"); -GST_BOILERPLATE_FULL (GstAmrwbDec, gst_amrwbdec, GstElement, GST_TYPE_ELEMENT, - _do_init); +GST_BOILERPLATE_FULL (GstAmrwbDec, gst_amrwbdec, GstAudioDecoder, + GST_TYPE_AUDIO_DECODER, _do_init); static void gst_amrwbdec_base_init (gpointer klass) @@ -99,60 +99,54 @@ gst_amrwbdec_base_init (gpointer klass) static void gst_amrwbdec_class_init (GstAmrwbDecClass * klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass); - object_class->finalize = gst_amrwbdec_finalize; - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_amrwbdec_state_change); + base_class->start = GST_DEBUG_FUNCPTR (gst_amrwbdec_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_amrwbdec_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_amrwbdec_set_format); + base_class->parse = GST_DEBUG_FUNCPTR (gst_amrwbdec_parse); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_amrwbdec_handle_frame); } static void gst_amrwbdec_init (GstAmrwbDec * amrwbdec, GstAmrwbDecClass * klass) { - /* create the sink pad */ - amrwbdec->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_pad_set_setcaps_function (amrwbdec->sinkpad, gst_amrwbdec_setcaps); - gst_pad_set_event_function (amrwbdec->sinkpad, gst_amrwbdec_event); - gst_pad_set_chain_function (amrwbdec->sinkpad, gst_amrwbdec_chain); - gst_element_add_pad (GST_ELEMENT (amrwbdec), amrwbdec->sinkpad); - - /* create the src pad */ - amrwbdec->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_pad_use_fixed_caps (amrwbdec->srcpad); - gst_element_add_pad (GST_ELEMENT (amrwbdec), amrwbdec->srcpad); - - amrwbdec->adapter = gst_adapter_new (); - - /* init rest */ - amrwbdec->handle = NULL; - amrwbdec->channels = 0; - amrwbdec->rate = 0; - amrwbdec->duration = 0; - amrwbdec->ts = -1; -} - -static void -gst_amrwbdec_finalize (GObject * object) -{ - GstAmrwbDec *amrwbdec; - - amrwbdec = GST_AMRWBDEC (object); - - gst_adapter_clear (amrwbdec->adapter); - g_object_unref (amrwbdec->adapter); - - G_OBJECT_CLASS (parent_class)->finalize (object); } static gboolean -gst_amrwbdec_setcaps (GstPad * pad, GstCaps * caps) +gst_amrwbdec_start (GstAudioDecoder * dec) +{ + GstAmrwbDec *amrwbdec = GST_AMRWBDEC (dec); + + GST_DEBUG_OBJECT (dec, "start"); + if (!(amrwbdec->handle = D_IF_init ())) + return FALSE; + + amrwbdec->rate = 0; + amrwbdec->channels = 0; + + return TRUE; +} + +static gboolean +gst_amrwbdec_stop (GstAudioDecoder * dec) +{ + GstAmrwbDec *amrwbdec = GST_AMRWBDEC (dec); + + GST_DEBUG_OBJECT (dec, "stop"); + D_IF_exit (amrwbdec->handle); + + return TRUE; +} + +static gboolean +gst_amrwbdec_set_format (GstAudioDecoder * dec, GstCaps * caps) { GstStructure *structure; GstAmrwbDec *amrwbdec; GstCaps *copy; - amrwbdec = GST_AMRWBDEC (gst_pad_get_parent (pad)); + amrwbdec = GST_AMRWBDEC (dec); structure = gst_caps_get_structure (caps, 0); @@ -168,215 +162,85 @@ gst_amrwbdec_setcaps (GstPad * pad, GstCaps * caps) "endianness", G_TYPE_INT, G_BYTE_ORDER, "rate", G_TYPE_INT, amrwbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL); - amrwbdec->duration = gst_util_uint64_scale_int (GST_SECOND, L_FRAME16k, - amrwbdec->rate * amrwbdec->channels); - - gst_pad_set_caps (amrwbdec->srcpad, copy); + gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (amrwbdec), copy); gst_caps_unref (copy); - gst_object_unref (amrwbdec); - return TRUE; } -static gboolean -gst_amrwbdec_event (GstPad * pad, GstEvent * event) +static GstFlowReturn +gst_amrwbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length) { - GstAmrwbDec *amrwbdec; - gboolean ret = TRUE; + GstAmrwbDec *amrwbdec = GST_AMRWBDEC (dec); + const guint8 *data; + guint size; + gboolean sync, eos; + gint block, mode; - amrwbdec = GST_AMRWBDEC (gst_pad_get_parent (pad)); + size = gst_adapter_available (adapter); + g_return_val_if_fail (size > 0, GST_FLOW_ERROR); - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - ret = gst_pad_push_event (amrwbdec->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - ret = gst_pad_push_event (amrwbdec->srcpad, event); - gst_adapter_clear (amrwbdec->adapter); - amrwbdec->ts = -1; - break; - case GST_EVENT_EOS: - gst_adapter_clear (amrwbdec->adapter); - ret = gst_pad_push_event (amrwbdec->srcpad, event); - break; - case GST_EVENT_NEWSEGMENT: - { - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - gboolean update; + gst_audio_decoder_get_parse_state (dec, &sync, &eos); - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); + /* need to peek data to get the size */ + if (gst_adapter_available (adapter) < 1) + return GST_FLOW_ERROR; - /* we need time for now */ - if (format != GST_FORMAT_TIME) - goto newseg_wrong_format; + data = gst_adapter_peek (adapter, 1); + mode = (data[0] >> 3) & 0x0F; + block = block_size[mode]; - GST_DEBUG_OBJECT (amrwbdec, - "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT - ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, - update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), - GST_TIME_ARGS (time)); + GST_DEBUG_OBJECT (amrwbdec, "mode %d, block %d", mode, block); - /* now configure the values */ - gst_segment_set_newsegment_full (&amrwbdec->segment, update, - rate, arate, format, start, stop, time); - ret = gst_pad_push_event (amrwbdec->srcpad, event); - } - break; - default: - ret = gst_pad_push_event (amrwbdec->srcpad, event); - break; + if (block) { + *offset = 0; + *length = block; + } else { + /* no frame yet, skip one byte */ + GST_LOG_OBJECT (amrwbdec, "skipping byte"); + *offset = 1; + return GST_FLOW_UNEXPECTED; } -done: - gst_object_unref (amrwbdec); - return ret; - - /* ERRORS */ -newseg_wrong_format: - { - GST_DEBUG_OBJECT (amrwbdec, "received non TIME newsegment"); - goto done; - } + return GST_FLOW_OK; } static GstFlowReturn -gst_amrwbdec_chain (GstPad * pad, GstBuffer * buffer) +gst_amrwbdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer) { GstAmrwbDec *amrwbdec; - GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *out; + const guint8 *data; - amrwbdec = GST_AMRWBDEC (gst_pad_get_parent (pad)); + amrwbdec = GST_AMRWBDEC (dec); + + /* no fancy flushing */ + if (!buffer || !GST_BUFFER_SIZE (buffer)) + return GST_FLOW_OK; if (amrwbdec->rate == 0 || amrwbdec->channels == 0) goto not_negotiated; - /* discontinuity, don't combine samples before and after the - * DISCONT */ - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { - gst_adapter_clear (amrwbdec->adapter); - amrwbdec->ts = -1; - amrwbdec->discont = TRUE; - } + /* the library seems to write into the source data, hence the copy. */ + /* should be no problem */ + data = GST_BUFFER_DATA (buffer); - /* take latest timestamp, FIXME timestamp is the one of the - * first buffer in the adapter. */ - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) - amrwbdec->ts = GST_BUFFER_TIMESTAMP (buffer); + /* get output */ + out = gst_buffer_new_and_alloc (sizeof (gint16) * L_FRAME16k); - gst_adapter_push (amrwbdec->adapter, buffer); + /* decode */ + D_IF_decode (amrwbdec->handle, (unsigned char *) data, + (Word16 *) GST_BUFFER_DATA (out), _good_frame); - while (TRUE) { - GstBuffer *out; - const guint8 *data; - gint block, mode; - - /* need to peek data to get the size */ - if (gst_adapter_available (amrwbdec->adapter) < 1) - break; - data = gst_adapter_peek (amrwbdec->adapter, 1); - - /* get size */ - mode = (data[0] >> 3) & 0x0F; - block = block_size[mode]; - - GST_DEBUG_OBJECT (amrwbdec, "mode %d, block %d", mode, block); - - if (!block) { - GST_LOG_OBJECT (amrwbdec, "skipping byte"); - gst_adapter_flush (amrwbdec->adapter, 1); - continue; - } - - if (gst_adapter_available (amrwbdec->adapter) < block) - break; - - /* the library seems to write into the source data, hence the copy. */ - data = gst_adapter_take (amrwbdec->adapter, block); - - /* get output */ - out = gst_buffer_new_and_alloc (sizeof (gint16) * L_FRAME16k); - - GST_BUFFER_DURATION (out) = amrwbdec->duration; - GST_BUFFER_TIMESTAMP (out) = amrwbdec->ts; - - if (amrwbdec->ts != -1) - amrwbdec->ts += amrwbdec->duration; - if (amrwbdec->discont) { - GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT); - amrwbdec->discont = FALSE; - } - - gst_buffer_set_caps (out, GST_PAD_CAPS (amrwbdec->srcpad)); - - /* decode */ - D_IF_decode (amrwbdec->handle, (unsigned char *) data, - (Word16 *) GST_BUFFER_DATA (out), _good_frame); - - g_free ((gpointer) data); - - /* send out */ - ret = gst_pad_push (amrwbdec->srcpad, out); - } - - gst_object_unref (amrwbdec); - return ret; + /* send out */ + return gst_audio_decoder_finish_frame (dec, out, 1); /* ERRORS */ not_negotiated: { GST_ELEMENT_ERROR (amrwbdec, STREAM, TYPE_NOT_FOUND, (NULL), ("Decoder is not initialized")); - gst_object_unref (amrwbdec); return GST_FLOW_NOT_NEGOTIATED; } } - -static GstStateChangeReturn -gst_amrwbdec_state_change (GstElement * element, GstStateChange transition) -{ - GstAmrwbDec *amrwbdec; - GstStateChangeReturn ret; - - amrwbdec = GST_AMRWBDEC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!(amrwbdec->handle = D_IF_init ())) - goto init_failed; - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_adapter_clear (amrwbdec->adapter); - amrwbdec->rate = 0; - amrwbdec->channels = 0; - amrwbdec->ts = -1; - amrwbdec->discont = TRUE; - gst_segment_init (&amrwbdec->segment, GST_FORMAT_TIME); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - D_IF_exit (amrwbdec->handle); - break; - default: - break; - } - - return ret; - - /* ERRORS */ -init_failed: - { - GST_ELEMENT_ERROR (amrwbdec, LIBRARY, INIT, (NULL), - ("Failed to open AMR Decoder")); - return GST_STATE_CHANGE_FAILURE; - } -} diff --git a/ext/amrwbdec/amrwbdec.h b/ext/amrwbdec/amrwbdec.h index e41157ab93..c3528fca00 100644 --- a/ext/amrwbdec/amrwbdec.h +++ b/ext/amrwbdec/amrwbdec.h @@ -21,7 +21,7 @@ #define __GST_AMRWBDEC_H__ #include -#include +#include #include #include @@ -47,27 +47,17 @@ typedef struct _GstAmrwbDecClass GstAmrwbDecClass; * Opaque data structure. */ struct _GstAmrwbDec { - GstElement element; - - /* pads */ - GstPad *sinkpad, *srcpad; - guint64 ts; - - GstAdapter *adapter; + GstAudioDecoder element; /* library handle */ void *handle; /* output settings */ gint channels, rate; - gint duration; - - GstSegment segment; - gboolean discont; }; struct _GstAmrwbDecClass { - GstElementClass parent_class; + GstAudioDecoderClass parent_class; }; GType gst_amrwbdec_get_type (void);