From fa2d16b905447906d55290a312e3472b4138df9f Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 3 Oct 2011 17:19:02 +0200 Subject: [PATCH] amrnbdec: port to audiodecoder --- ext/amrnb/amrnbdec.c | 315 +++++++++++++------------------------------ ext/amrnb/amrnbdec.h | 16 +-- 2 files changed, 93 insertions(+), 238 deletions(-) diff --git a/ext/amrnb/amrnbdec.c b/ext/amrnb/amrnbdec.c index b6b4169a1f..a6f83ecdac 100644 --- a/ext/amrnb/amrnbdec.c +++ b/ext/amrnb/amrnbdec.c @@ -96,19 +96,19 @@ static void gst_amrnbdec_set_property (GObject * object, guint prop_id, static void gst_amrnbdec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_amrnbdec_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps); -static GstStateChangeReturn gst_amrnbdec_state_change (GstElement * element, - GstStateChange transition); - -static void gst_amrnbdec_finalize (GObject * object); +static gboolean gst_amrnbdec_start (GstAudioDecoder * dec); +static gboolean gst_amrnbdec_stop (GstAudioDecoder * dec); +static gboolean gst_amrnbdec_set_format (GstAudioDecoder * dec, GstCaps * caps); +static gboolean gst_amrnbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length); +static GstFlowReturn gst_amrnbdec_handle_frame (GstAudioDecoder * dec, + GstBuffer * buffer); #define _do_init(bla) \ GST_DEBUG_CATEGORY_INIT (gst_amrnbdec_debug, "amrnbdec", 0, "AMR-NB audio decoder"); -GST_BOILERPLATE_FULL (GstAmrnbDec, gst_amrnbdec, GstElement, GST_TYPE_ELEMENT, - _do_init); +GST_BOILERPLATE_FULL (GstAmrnbDec, gst_amrnbdec, GstAudioDecoder, + GST_TYPE_AUDIO_DECODER, _do_init); static void gst_amrnbdec_base_init (gpointer klass) @@ -130,53 +130,53 @@ static void gst_amrnbdec_class_init (GstAmrnbDecClass * 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->set_property = gst_amrnbdec_set_property; object_class->get_property = gst_amrnbdec_get_property; - object_class->finalize = gst_amrnbdec_finalize; + + base_class->start = GST_DEBUG_FUNCPTR (gst_amrnbdec_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_amrnbdec_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_amrnbdec_set_format); + base_class->parse = GST_DEBUG_FUNCPTR (gst_amrnbdec_parse); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_amrnbdec_handle_frame); g_object_class_install_property (object_class, PROP_VARIANT, g_param_spec_enum ("variant", "Variant", "The decoder variant", GST_AMRNB_VARIANT_TYPE, VARIANT_DEFAULT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_amrnbdec_state_change); } static void gst_amrnbdec_init (GstAmrnbDec * amrnbdec, GstAmrnbDecClass * klass) { - /* create the sink pad */ - amrnbdec->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_pad_set_setcaps_function (amrnbdec->sinkpad, gst_amrnbdec_setcaps); - gst_pad_set_event_function (amrnbdec->sinkpad, gst_amrnbdec_event); - gst_pad_set_chain_function (amrnbdec->sinkpad, gst_amrnbdec_chain); - gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->sinkpad); - - /* create the src pad */ - amrnbdec->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_pad_use_fixed_caps (amrnbdec->srcpad); - gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->srcpad); - - amrnbdec->adapter = gst_adapter_new (); - - /* init rest */ - amrnbdec->handle = NULL; } -static void -gst_amrnbdec_finalize (GObject * object) +static gboolean +gst_amrnbdec_start (GstAudioDecoder * dec) { - GstAmrnbDec *amrnbdec; + GstAmrnbDec *amrnbdec = GST_AMRNBDEC (dec); - amrnbdec = GST_AMRNBDEC (object); + GST_DEBUG_OBJECT (dec, "start"); + if (!(amrnbdec->handle = Decoder_Interface_init ())) + return FALSE; - gst_adapter_clear (amrnbdec->adapter); - g_object_unref (amrnbdec->adapter); + amrnbdec->rate = 0; + amrnbdec->channels = 0; - G_OBJECT_CLASS (parent_class)->finalize (object); + return TRUE; +} + +static gboolean +gst_amrnbdec_stop (GstAudioDecoder * dec) +{ + GstAmrnbDec *amrnbdec = GST_AMRNBDEC (dec); + + GST_DEBUG_OBJECT (dec, "stop"); + Decoder_Interface_exit (amrnbdec->handle); + + return TRUE; } static void @@ -214,13 +214,13 @@ gst_amrnbdec_get_property (GObject * object, guint prop_id, } static gboolean -gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps) +gst_amrnbdec_set_format (GstAudioDecoder * dec, GstCaps * caps) { GstStructure *structure; GstAmrnbDec *amrnbdec; GstCaps *copy; - amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad)); + amrnbdec = GST_AMRNBDEC (dec); structure = gst_caps_get_structure (caps, 0); @@ -236,168 +236,86 @@ gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps) "endianness", G_TYPE_INT, G_BYTE_ORDER, "rate", G_TYPE_INT, amrnbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL); - amrnbdec->duration = gst_util_uint64_scale_int (GST_SECOND, 160, - amrnbdec->rate * amrnbdec->channels); - - gst_pad_set_caps (amrnbdec->srcpad, copy); + gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), copy); gst_caps_unref (copy); - gst_object_unref (amrnbdec); - return TRUE; } -static gboolean -gst_amrnbdec_event (GstPad * pad, GstEvent * event) +static GstFlowReturn +gst_amrnbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length) { - GstAmrnbDec *amrnbdec; - gboolean ret = TRUE; + GstAmrnbDec *amrnbdec = GST_AMRNBDEC (dec); + const guint8 *data; + guint size; + gboolean sync, eos; + gint block, mode; - amrnbdec = GST_AMRNBDEC (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 (amrnbdec->srcpad, event); + gst_audio_decoder_get_parse_state (dec, &sync, &eos); + + /* need to peek data to get the size */ + if (gst_adapter_available (adapter) < 1) + return GST_FLOW_ERROR; + + data = gst_adapter_peek (adapter, 1); + + /* get size */ + switch (amrnbdec->variant) { + case GST_AMRNB_VARIANT_IF1: + mode = (data[0] >> 3) & 0x0F; + block = block_size_if1[mode] + 1; break; - case GST_EVENT_FLUSH_STOP: - ret = gst_pad_push_event (amrnbdec->srcpad, event); - gst_adapter_clear (amrnbdec->adapter); - amrnbdec->ts = -1; - break; - case GST_EVENT_EOS: - gst_adapter_clear (amrnbdec->adapter); - ret = gst_pad_push_event (amrnbdec->srcpad, event); - break; - case GST_EVENT_NEWSEGMENT: - { - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - gboolean update; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - /* we need time for now */ - if (format != GST_FORMAT_TIME) - goto newseg_wrong_format; - - GST_DEBUG_OBJECT (amrnbdec, - "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)); - - /* now configure the values */ - gst_segment_set_newsegment_full (&amrnbdec->segment, update, - rate, arate, format, start, stop, time); - ret = gst_pad_push_event (amrnbdec->srcpad, event); - } + case GST_AMRNB_VARIANT_IF2: + mode = data[0] & 0x0F; + block = block_size_if2[mode] + 1; break; default: - ret = gst_pad_push_event (amrnbdec->srcpad, event); + g_assert_not_reached (); + return GST_FLOW_ERROR; break; } -done: - gst_object_unref (amrnbdec); - return ret; + GST_DEBUG_OBJECT (amrnbdec, "mode %d, block %d", mode, block); - /* ERRORS */ -newseg_wrong_format: - { - GST_DEBUG_OBJECT (amrnbdec, "received non TIME newsegment"); - goto done; - } + *offset = 0; + *length = block; + + return GST_FLOW_OK; } static GstFlowReturn -gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer) +gst_amrnbdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer) { GstAmrnbDec *amrnbdec; - GstFlowReturn ret; + guint8 *data; + GstBuffer *out; - amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad)); + amrnbdec = GST_AMRNBDEC (dec); + + /* no fancy flushing */ + if (!buffer || !GST_BUFFER_SIZE (buffer)) + return GST_FLOW_OK; if (amrnbdec->rate == 0 || amrnbdec->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 (amrnbdec->adapter); - amrnbdec->ts = -1; - amrnbdec->discont = TRUE; - } + /* the library seems to write into the source data, hence + * the copy. */ + /* should not be a problem though */ + 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)) - amrnbdec->ts = GST_BUFFER_TIMESTAMP (buffer); + /* get output */ + out = gst_buffer_new_and_alloc (160 * 2); - gst_adapter_push (amrnbdec->adapter, buffer); + /* decode */ + Decoder_Interface_Decode (amrnbdec->handle, data, + (short *) GST_BUFFER_DATA (out), 0); - ret = GST_FLOW_OK; - - while (TRUE) { - GstBuffer *out; - guint8 *data; - gint block, mode; - - /* need to peek data to get the size */ - if (gst_adapter_available (amrnbdec->adapter) < 1) - break; - data = (guint8 *) gst_adapter_peek (amrnbdec->adapter, 1); - - /* get size */ - switch (amrnbdec->variant) { - case GST_AMRNB_VARIANT_IF1: - mode = (data[0] >> 3) & 0x0F; - block = block_size_if1[mode] + 1; - break; - case GST_AMRNB_VARIANT_IF2: - mode = data[0] & 0x0F; - block = block_size_if2[mode] + 1; - break; - default: - goto invalid_variant; - } - - GST_DEBUG_OBJECT (amrnbdec, "mode %d, block %d", mode, block); - - if (!block || gst_adapter_available (amrnbdec->adapter) < block) - break; - - /* the library seems to write into the source data, hence - * the copy. */ - data = gst_adapter_take (amrnbdec->adapter, block); - - /* get output */ - out = gst_buffer_new_and_alloc (160 * 2); - GST_BUFFER_DURATION (out) = amrnbdec->duration; - GST_BUFFER_TIMESTAMP (out) = amrnbdec->ts; - - if (amrnbdec->ts != -1) - amrnbdec->ts += amrnbdec->duration; - if (amrnbdec->discont) { - GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT); - amrnbdec->discont = FALSE; - } - - gst_buffer_set_caps (out, GST_PAD_CAPS (amrnbdec->srcpad)); - - /* decode */ - Decoder_Interface_Decode (amrnbdec->handle, data, - (short *) GST_BUFFER_DATA (out), 0); - g_free (data); - - /* send out */ - ret = gst_pad_push (amrnbdec->srcpad, out); - } - - gst_object_unref (amrnbdec); - - return ret; + return gst_audio_decoder_finish_frame (dec, out, 1); /* ERRORS */ not_negotiated: @@ -407,57 +325,4 @@ not_negotiated: gst_object_unref (amrnbdec); return GST_FLOW_NOT_NEGOTIATED; } -invalid_variant: - { - GST_ELEMENT_ERROR (amrnbdec, STREAM, TYPE_NOT_FOUND, (NULL), - ("Invalid variant")); - gst_object_unref (amrnbdec); - return GST_FLOW_ERROR; - } -} - -static GstStateChangeReturn -gst_amrnbdec_state_change (GstElement * element, GstStateChange transition) -{ - GstAmrnbDec *amrnbdec; - GstStateChangeReturn ret; - - amrnbdec = GST_AMRNBDEC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!(amrnbdec->handle = Decoder_Interface_init ())) - goto init_failed; - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_adapter_clear (amrnbdec->adapter); - amrnbdec->rate = 0; - amrnbdec->channels = 0; - amrnbdec->ts = -1; - amrnbdec->discont = TRUE; - gst_segment_init (&amrnbdec->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: - Decoder_Interface_exit (amrnbdec->handle); - break; - default: - break; - } - - return ret; - - /* ERRORS */ -init_failed: - { - GST_ELEMENT_ERROR (amrnbdec, LIBRARY, INIT, (NULL), - ("Failed to open AMR Decoder")); - return GST_STATE_CHANGE_FAILURE; - } } diff --git a/ext/amrnb/amrnbdec.h b/ext/amrnb/amrnbdec.h index 6caaf2e8ba..1e818395b9 100644 --- a/ext/amrnb/amrnbdec.h +++ b/ext/amrnb/amrnbdec.h @@ -21,7 +21,7 @@ #define __GST_AMRNBDEC_H__ #include -#include +#include #include G_BEGIN_DECLS @@ -47,29 +47,19 @@ typedef enum } GstAmrnbVariant; struct _GstAmrnbDec { - GstElement element; - - /* pads */ - GstPad *sinkpad, *srcpad; - guint64 ts; + GstAudioDecoder element; GstAmrnbVariant variant; - GstAdapter *adapter; - /* library handle */ void *handle; /* output settings */ gint channels, rate; - gint duration; - - GstSegment segment; - gboolean discont; }; struct _GstAmrnbDecClass { - GstElementClass parent_class; + GstAudioDecoderClass parent_class; }; GType gst_amrnbdec_get_type (void);