From d55d4054bd43045c4a3d9ae672c34d0285afe003 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 14 Dec 2011 17:33:52 +0100 Subject: [PATCH] a52dec: port to audiodecoder --- ext/a52dec/Makefile.am | 7 +- ext/a52dec/gsta52dec.c | 638 ++++++++++++++++++------------------------------- ext/a52dec/gsta52dec.h | 21 +- 3 files changed, 243 insertions(+), 423 deletions(-) diff --git a/ext/a52dec/Makefile.am b/ext/a52dec/Makefile.am index d572236..bf56cc9 100644 --- a/ext/a52dec/Makefile.am +++ b/ext/a52dec/Makefile.am @@ -3,12 +3,15 @@ plugin_LTLIBRARIES = libgsta52dec.la libgsta52dec_la_SOURCES = gsta52dec.c libgsta52dec_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ $(ORC_CFLAGS) \ $(A52DEC_CFLAGS) libgsta52dec_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) \ - -lgstaudio-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + -lgstaudio-$(GST_MAJORMINOR) \ $(ORC_LIBS) \ $(A52DEC_LIBS) libgsta52dec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/ext/a52dec/gsta52dec.c b/ext/a52dec/gsta52dec.c index 3840c44..ac1462e 100644 --- a/ext/a52dec/gsta52dec.c +++ b/ext/a52dec/gsta52dec.c @@ -86,14 +86,20 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", "rate = (int) [ 4000, 96000 ], " "channels = (int) [ 1, 6 ]") ); -GST_BOILERPLATE (GstA52Dec, gst_a52dec, GstElement, GST_TYPE_ELEMENT); +GST_BOILERPLATE (GstA52Dec, gst_a52dec, GstAudioDecoder, + GST_TYPE_AUDIO_DECODER); + +static gboolean gst_a52dec_start (GstAudioDecoder * dec); +static gboolean gst_a52dec_stop (GstAudioDecoder * dec); +static gboolean gst_a52dec_set_format (GstAudioDecoder * bdec, GstCaps * caps); +static gboolean gst_a52dec_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length); +static GstFlowReturn gst_a52dec_handle_frame (GstAudioDecoder * dec, + GstBuffer * buffer); +static GstFlowReturn gst_a52dec_pre_push (GstAudioDecoder * bdec, + GstBuffer ** buffer); static GstFlowReturn gst_a52dec_chain (GstPad * pad, GstBuffer * buffer); -static GstFlowReturn gst_a52dec_chain_raw (GstPad * pad, GstBuffer * buf); -static gboolean gst_a52dec_sink_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_a52dec_sink_event (GstPad * pad, GstEvent * event); -static GstStateChangeReturn gst_a52dec_change_state (GstElement * element, - GstStateChange transition); static void gst_a52dec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -143,16 +149,21 @@ static void gst_a52dec_class_init (GstA52DecClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; + GstAudioDecoderClass *gstbase_class; guint cpuflags; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; + gstbase_class = (GstAudioDecoderClass *) klass; gobject_class->set_property = gst_a52dec_set_property; gobject_class->get_property = gst_a52dec_get_property; - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_a52dec_change_state); + gstbase_class->start = GST_DEBUG_FUNCPTR (gst_a52dec_start); + gstbase_class->stop = GST_DEBUG_FUNCPTR (gst_a52dec_stop); + gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_a52dec_set_format); + gstbase_class->parse = GST_DEBUG_FUNCPTR (gst_a52dec_parse); + gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_a52dec_handle_frame); + gstbase_class->pre_push = GST_DEBUG_FUNCPTR (gst_a52dec_pre_push); /** * GstA52Dec::drc @@ -213,27 +224,106 @@ gst_a52dec_class_init (GstA52DecClass * klass) static void gst_a52dec_init (GstA52Dec * a52dec, GstA52DecClass * g_class) { - /* create the sink and src pads */ - a52dec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_pad_set_setcaps_function (a52dec->sinkpad, - GST_DEBUG_FUNCPTR (gst_a52dec_sink_setcaps)); - gst_pad_set_chain_function (a52dec->sinkpad, - GST_DEBUG_FUNCPTR (gst_a52dec_chain)); - gst_pad_set_event_function (a52dec->sinkpad, - GST_DEBUG_FUNCPTR (gst_a52dec_sink_event)); - gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->sinkpad); - - a52dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_pad_use_fixed_caps (a52dec->srcpad); - gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->srcpad); - a52dec->request_channels = A52_CHANNEL; a52dec->dynamic_range_compression = FALSE; a52dec->state = NULL; a52dec->samples = NULL; - gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED); + /* retrieve and intercept base class chain. + * Quite HACKish, but that's dvd specs/caps for you, + * since one buffer needs to be split into 2 frames */ + a52dec->base_chain = GST_PAD_CHAINFUNC (GST_AUDIO_DECODER_SINK_PAD (a52dec)); + gst_pad_set_chain_function (GST_AUDIO_DECODER_SINK_PAD (a52dec), + GST_DEBUG_FUNCPTR (gst_a52dec_chain)); +} + +static gboolean +gst_a52dec_start (GstAudioDecoder * dec) +{ + GstA52Dec *a52dec = GST_A52DEC (dec); + GstA52DecClass *klass; + + GST_DEBUG_OBJECT (dec, "start"); + + klass = GST_A52DEC_CLASS (G_OBJECT_GET_CLASS (a52dec)); + a52dec->state = a52_init (klass->a52_cpuflags); + a52dec->samples = a52_samples (a52dec->state); + a52dec->bit_rate = -1; + a52dec->sample_rate = -1; + a52dec->stream_channels = A52_CHANNEL; + a52dec->using_channels = A52_CHANNEL; + a52dec->level = 1; + a52dec->bias = 0; + a52dec->flag_update = TRUE; + + /* call upon legacy upstream byte support (e.g. seeking) */ + gst_audio_decoder_set_byte_time (dec, TRUE); + + return TRUE; +} + +static gboolean +gst_a52dec_stop (GstAudioDecoder * dec) +{ + GstA52Dec *a52dec = GST_A52DEC (dec); + + GST_DEBUG_OBJECT (dec, "stop"); + + a52dec->samples = NULL; + if (a52dec->state) { + a52_free (a52dec->state); + a52dec->state = NULL; + } + if (a52dec->pending_tags) { + gst_tag_list_free (a52dec->pending_tags); + a52dec->pending_tags = NULL; + } + + return TRUE; +} + +static GstFlowReturn +gst_a52dec_parse (GstAudioDecoder * bdec, GstAdapter * adapter, + gint * _offset, gint * len) +{ + GstA52Dec *a52dec; + guint8 *data; + gint av, size; + gint length = 0, flags, sample_rate, bit_rate; + GstFlowReturn result = GST_FLOW_UNEXPECTED; + + a52dec = GST_A52DEC (bdec); + + size = av = gst_adapter_available (adapter); + data = (guint8 *) gst_adapter_peek (adapter, av); + + /* find and read header */ + bit_rate = a52dec->bit_rate; + sample_rate = a52dec->sample_rate; + flags = 0; + while (av >= 7) { + length = a52_syncinfo (data, &flags, &sample_rate, &bit_rate); + + if (length == 0) { + /* shift window to re-find sync */ + data++; + size--; + } else if (length <= size) { + GST_LOG_OBJECT (a52dec, "Sync: frame size %d", length); + result = GST_FLOW_OK; + break; + } else { + GST_LOG_OBJECT (a52dec, "Not enough data available (needed %d had %d)", + length, size); + break; + } + } + + *_offset = av - size; + *len = length; + + return result; } static gint @@ -324,106 +414,6 @@ gst_a52dec_channels (int flags, GstAudioChannelPosition ** _pos) return chans; } -static void -clear_queued (GstA52Dec * dec) -{ - g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->queued); - dec->queued = NULL; -} - -static GstFlowReturn -flush_queued (GstA52Dec * dec) -{ - GstFlowReturn ret = GST_FLOW_OK; - - while (dec->queued) { - GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data); - - GST_LOG_OBJECT (dec, "pushing buffer %p, timestamp %" - GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - /* iterate ouput queue an push downstream */ - ret = gst_pad_push (dec->srcpad, buf); - - dec->queued = g_list_delete_link (dec->queued, dec->queued); - } - return ret; -} - -static GstFlowReturn -gst_a52dec_drain (GstA52Dec * dec) -{ - GstFlowReturn ret = GST_FLOW_OK; - - if (dec->segment.rate < 0.0) { - /* if we have some queued frames for reverse playback, flush - * them now */ - ret = flush_queued (dec); - } - return ret; -} - -static GstFlowReturn -gst_a52dec_push (GstA52Dec * a52dec, - GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp) -{ - GstBuffer *buf; - int chans, n, c; - GstFlowReturn result; - - flags &= (A52_CHANNEL_MASK | A52_LFE); - chans = gst_a52dec_channels (flags, NULL); - if (!chans) { - GST_ELEMENT_ERROR (GST_ELEMENT (a52dec), STREAM, DECODE, (NULL), - ("invalid channel flags: %d", flags)); - return GST_FLOW_ERROR; - } - - result = - gst_pad_alloc_buffer_and_set_caps (srcpad, 0, - 256 * chans * (SAMPLE_WIDTH / 8), GST_PAD_CAPS (srcpad), &buf); - if (result != GST_FLOW_OK) - return result; - - for (n = 0; n < 256; n++) { - for (c = 0; c < chans; c++) { - ((sample_t *) GST_BUFFER_DATA (buf))[n * chans + c] = - samples[c * 256 + n]; - } - } - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / a52dec->sample_rate; - - result = GST_FLOW_OK; - if ((buf = gst_audio_buffer_clip (buf, &a52dec->segment, - a52dec->sample_rate, (SAMPLE_WIDTH / 8) * chans))) { - /* set discont when needed */ - if (a52dec->discont) { - GST_LOG_OBJECT (a52dec, "marking DISCONT"); - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - a52dec->discont = FALSE; - } - - if (a52dec->segment.rate > 0.0) { - GST_DEBUG_OBJECT (a52dec, - "Pushing buffer with ts %" GST_TIME_FORMAT " duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - result = gst_pad_push (srcpad, buf); - } else { - /* reverse playback, queue frame till later when we get a discont. */ - GST_DEBUG_OBJECT (a52dec, "queued frame"); - a52dec->queued = g_list_prepend (a52dec->queued, buf); - } - } - return result; -} - static gboolean gst_a52dec_reneg (GstA52Dec * a52dec, GstPad * pad) { @@ -457,102 +447,69 @@ done: return result; } -static gboolean -gst_a52dec_sink_event (GstPad * pad, GstEvent * event) +static void +gst_a52dec_update_streaminfo (GstA52Dec * a52dec) { - GstA52Dec *a52dec = GST_A52DEC (gst_pad_get_parent (pad)); - gboolean ret = FALSE; - - GST_LOG ("Handling %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - GstFormat fmt; - gboolean update; - gint64 start, end, pos; - gdouble rate, arate; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt, - &start, &end, &pos); - - /* drain queued buffers before activating the segment so that we can clip - * against the old segment first */ - gst_a52dec_drain (a52dec); - - if (fmt != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (start)) { - GST_WARNING ("No time in newsegment event %p (format is %s)", - event, gst_format_get_name (fmt)); - gst_event_unref (event); - a52dec->sent_segment = FALSE; - /* set some dummy values, FIXME: do proper conversion */ - a52dec->time = start = pos = 0; - fmt = GST_FORMAT_TIME; - end = -1; - } else { - a52dec->time = start; - a52dec->sent_segment = TRUE; - GST_DEBUG_OBJECT (a52dec, - "Pushing newseg rate %g, applied rate %g, format %d, start %" - G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", pos %" - G_GINT64_FORMAT, rate, arate, fmt, start, end, pos); - - ret = gst_pad_push_event (a52dec->srcpad, event); - } + GstTagList *taglist; - gst_segment_set_newsegment (&a52dec->segment, update, rate, fmt, start, - end, pos); - break; - } - case GST_EVENT_TAG: - ret = gst_pad_push_event (a52dec->srcpad, event); - break; - case GST_EVENT_EOS: - gst_a52dec_drain (a52dec); - ret = gst_pad_push_event (a52dec->srcpad, event); - break; - case GST_EVENT_FLUSH_START: - ret = gst_pad_push_event (a52dec->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - if (a52dec->cache) { - gst_buffer_unref (a52dec->cache); - a52dec->cache = NULL; - } - clear_queued (a52dec); - gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED); - ret = gst_pad_push_event (a52dec->srcpad, event); - break; - default: - ret = gst_pad_push_event (a52dec->srcpad, event); - break; + taglist = gst_tag_list_new (); + gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_BITRATE, + (guint) a52dec->bit_rate, NULL); + + if (a52dec->pending_tags) { + gst_tag_list_free (a52dec->pending_tags); + a52dec->pending_tags = NULL; } - gst_object_unref (a52dec); - return ret; + a52dec->pending_tags = taglist; } -static void -gst_a52dec_update_streaminfo (GstA52Dec * a52dec) +static GstFlowReturn +gst_a52dec_pre_push (GstAudioDecoder * bdec, GstBuffer ** buffer) { - GstTagList *taglist; + GstA52Dec *a52dec = GST_A52DEC (bdec); - taglist = gst_tag_list_new (); - - gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, - GST_TAG_AUDIO_CODEC, "Dolby Digital (AC-3)", - GST_TAG_BITRATE, (guint) a52dec->bit_rate, NULL); + if (G_UNLIKELY (a52dec->pending_tags)) { + gst_element_found_tags_for_pad (GST_ELEMENT (a52dec), + GST_AUDIO_DECODER_SRC_PAD (a52dec), a52dec->pending_tags); + a52dec->pending_tags = NULL; + } - gst_element_found_tags_for_pad (GST_ELEMENT (a52dec), - GST_PAD (a52dec->srcpad), taglist); + return GST_FLOW_OK; } static GstFlowReturn -gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data, - guint length, gint flags, gint sample_rate, gint bit_rate) +gst_a52dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buffer) { + GstA52Dec *a52dec; gint channels, i; gboolean need_reneg = FALSE; + gint size, chans; + gint length = 0, flags, sample_rate, bit_rate; + guint8 *data; + GstFlowReturn result = GST_FLOW_OK; + GstBuffer *outbuf; + const gint num_blocks = 6; + + a52dec = GST_A52DEC (bdec); + + /* no fancy draining */ + if (G_UNLIKELY (!buffer)) + return GST_FLOW_OK; + + /* parsed stuff already, so this should work out fine */ + data = GST_BUFFER_DATA (buffer); + size = GST_BUFFER_SIZE (buffer); + g_assert (size >= 7); + + /* re-obtain some sync header info, + * should be same as during _parse and could also be cached there, + * but anyway ... */ + bit_rate = a52dec->bit_rate; + sample_rate = a52dec->sample_rate; + flags = 0; + length = a52_syncinfo (data, &flags, &sample_rate, &bit_rate); + g_assert (length == size); /* update stream information, renegotiate or re-streaminfo if needed */ need_reneg = FALSE; @@ -582,7 +539,7 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data, a52dec->flag_update = FALSE; - caps = gst_pad_get_allowed_caps (a52dec->srcpad); + caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (a52dec)); if (caps && gst_caps_get_size (caps) > 0) { GstCaps *copy = gst_caps_copy_nth (caps, 0); GstStructure *structure = gst_caps_get_structure (copy, 0); @@ -618,14 +575,16 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data, } else { flags = a52dec->using_channels; } + /* process */ flags |= A52_ADJUST_LEVEL; a52dec->level = 1; if (a52_frame (a52dec->state, data, &flags, &a52dec->level, a52dec->bias)) { - GST_WARNING ("a52_frame error"); - a52dec->discont = TRUE; - return GST_FLOW_OK; + GST_AUDIO_DECODER_ERROR (a52dec, 1, STREAM, DECODE, (NULL), + ("a52_frame error"), result); + goto exit; } + channels = flags & (A52_CHANNEL_MASK | A52_LFE); if (a52dec->using_channels != channels) { need_reneg = TRUE; @@ -634,43 +593,74 @@ gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data, /* negotiate if required */ if (need_reneg) { - GST_DEBUG ("a52dec reneg: sample_rate:%d stream_chans:%d using_chans:%d", + GST_DEBUG_OBJECT (a52dec, + "a52dec reneg: sample_rate:%d stream_chans:%d using_chans:%d", a52dec->sample_rate, a52dec->stream_channels, a52dec->using_channels); - if (!gst_a52dec_reneg (a52dec, a52dec->srcpad)) { - GST_ELEMENT_ERROR (a52dec, CORE, NEGOTIATION, (NULL), (NULL)); - return GST_FLOW_ERROR; - } + if (!gst_a52dec_reneg (a52dec, GST_AUDIO_DECODER_SRC_PAD (a52dec))) + goto failed_negotiation; } if (a52dec->dynamic_range_compression == FALSE) { a52_dynrng (a52dec->state, NULL, NULL); } - /* each frame consists of 6 blocks */ - for (i = 0; i < 6; i++) { + flags &= (A52_CHANNEL_MASK | A52_LFE); + chans = gst_a52dec_channels (flags, NULL); + if (!chans) + goto invalid_flags; + + /* handle decoded data; + * each frame has 6 blocks, one block is 256 samples, ea */ + result = + gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (a52dec), 0, + 256 * chans * (SAMPLE_WIDTH / 8) * num_blocks, + GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (a52dec)), &outbuf); + if (result != GST_FLOW_OK) + goto exit; + + data = GST_BUFFER_DATA (outbuf); + for (i = 0; i < num_blocks; i++) { if (a52_block (a52dec->state)) { - /* ignore errors but mark a discont */ - GST_WARNING ("a52_block error %d", i); - a52dec->discont = TRUE; + /* also marks discont */ + GST_AUDIO_DECODER_ERROR (a52dec, 1, STREAM, DECODE, (NULL), + ("error decoding block %d", i), result); + if (result != GST_FLOW_OK) + goto exit; } else { - GstFlowReturn ret; + gint n, c; - /* push on */ - ret = gst_a52dec_push (a52dec, a52dec->srcpad, a52dec->using_channels, - a52dec->samples, a52dec->time); - if (ret != GST_FLOW_OK) - return ret; + for (n = 0; n < 256; n++) { + for (c = 0; c < chans; c++) { + ((sample_t *) data)[n * chans + c] = a52dec->samples[c * 256 + n]; + } + } } - a52dec->time += 256 * GST_SECOND / a52dec->sample_rate; + data += 256 * chans * (SAMPLE_WIDTH / 8); } - return GST_FLOW_OK; + result = gst_audio_decoder_finish_frame (bdec, outbuf, 1); + +exit: + return result; + + /* ERRORS */ +failed_negotiation: + { + GST_ELEMENT_ERROR (a52dec, CORE, NEGOTIATION, (NULL), (NULL)); + return GST_FLOW_ERROR; + } +invalid_flags: + { + GST_ELEMENT_ERROR (GST_ELEMENT (a52dec), STREAM, DECODE, (NULL), + ("Invalid channel flags: %d", flags)); + return GST_FLOW_ERROR; + } } static gboolean -gst_a52dec_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_a52dec_set_format (GstAudioDecoder * bdec, GstCaps * caps) { - GstA52Dec *a52dec = GST_A52DEC (gst_pad_get_parent (pad)); + GstA52Dec *a52dec = GST_A52DEC (bdec); GstStructure *structure; structure = gst_caps_get_structure (caps, 0); @@ -680,8 +670,6 @@ gst_a52dec_sink_setcaps (GstPad * pad, GstCaps * caps) else a52dec->dvdmode = FALSE; - gst_object_unref (a52dec); - return TRUE; } @@ -689,20 +677,9 @@ static GstFlowReturn gst_a52dec_chain (GstPad * pad, GstBuffer * buf) { GstA52Dec *a52dec = GST_A52DEC (GST_PAD_PARENT (pad)); - GstFlowReturn ret; + GstFlowReturn ret = GST_FLOW_OK; gint first_access; - if (GST_BUFFER_IS_DISCONT (buf)) { - GST_LOG_OBJECT (a52dec, "received DISCONT"); - gst_a52dec_drain (a52dec); - /* clear cache on discont and mark a discont in the element */ - if (a52dec->cache) { - gst_buffer_unref (a52dec->cache); - a52dec->cache = NULL; - } - a52dec->discont = TRUE; - } - if (a52dec->dvdmode) { gint size = GST_BUFFER_SIZE (buf); guchar *data = GST_BUFFER_DATA (buf); @@ -726,33 +703,36 @@ gst_a52dec_chain (GstPad * pad, GstBuffer * buf) goto bad_first_access_parameter; subbuf = gst_buffer_create_sub (buf, offset, len); + gst_buffer_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE; - ret = gst_a52dec_chain_raw (pad, subbuf); - if (ret != GST_FLOW_OK) + ret = a52dec->base_chain (pad, subbuf); + if (ret != GST_FLOW_OK) { + gst_buffer_unref (buf); goto done; + } offset += len; len = size - offset; if (len > 0) { subbuf = gst_buffer_create_sub (buf, offset, len); + gst_buffer_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - ret = gst_a52dec_chain_raw (pad, subbuf); + ret = a52dec->base_chain (pad, subbuf); } + gst_buffer_unref (buf); } else { /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */ subbuf = gst_buffer_create_sub (buf, offset, size - offset); - GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - ret = gst_a52dec_chain_raw (pad, subbuf); + gst_buffer_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); + ret = a52dec->base_chain (pad, subbuf); } } else { - gst_buffer_ref (buf); - ret = gst_a52dec_chain_raw (pad, buf); + ret = a52dec->base_chain (pad, buf); } done: - gst_buffer_unref (buf); return ret; /* ERRORS */ @@ -772,162 +752,6 @@ bad_first_access_parameter: } } -static GstFlowReturn -gst_a52dec_chain_raw (GstPad * pad, GstBuffer * buf) -{ - GstA52Dec *a52dec; - guint8 *data; - guint size; - gint length = 0, flags, sample_rate, bit_rate; - GstFlowReturn result = GST_FLOW_OK; - - a52dec = GST_A52DEC (GST_PAD_PARENT (pad)); - - if (!a52dec->sent_segment) { - GstSegment segment; - - /* Create a basic segment. Usually, we'll get a new-segment sent by - * another element that will know more information (a demuxer). If we're - * just looking at a raw AC3 stream, we won't - so we need to send one - * here, but we don't know much info, so just send a minimal TIME - * new-segment event - */ - gst_segment_init (&segment, GST_FORMAT_TIME); - gst_pad_push_event (a52dec->srcpad, gst_event_new_new_segment (FALSE, - segment.rate, segment.format, segment.start, - segment.duration, segment.start)); - a52dec->sent_segment = TRUE; - } - - /* merge with cache, if any. Also make sure timestamps match */ - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - a52dec->time = GST_BUFFER_TIMESTAMP (buf); - GST_DEBUG_OBJECT (a52dec, - "Received buffer with ts %" GST_TIME_FORMAT " duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - } - - if (a52dec->cache) { - buf = gst_buffer_join (a52dec->cache, buf); - a52dec->cache = NULL; - } - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - /* find and read header */ - bit_rate = a52dec->bit_rate; - sample_rate = a52dec->sample_rate; - flags = 0; - while (size >= 7) { - length = a52_syncinfo (data, &flags, &sample_rate, &bit_rate); - - if (length == 0) { - /* no sync */ - data++; - size--; - } else if (length <= size) { - GST_DEBUG ("Sync: %d", length); - - if (flags != a52dec->prev_flags) - a52dec->flag_update = TRUE; - a52dec->prev_flags = flags; - - result = gst_a52dec_handle_frame (a52dec, data, - length, flags, sample_rate, bit_rate); - if (result != GST_FLOW_OK) { - size = 0; - break; - } - size -= length; - data += length; - } else { - /* not enough data */ - GST_LOG ("Not enough data available"); - break; - } - } - - /* keep cache */ - if (length == 0) { - GST_LOG ("No sync found"); - } - - if (size > 0) { - a52dec->cache = gst_buffer_create_sub (buf, - GST_BUFFER_SIZE (buf) - size, size); - } - - gst_buffer_unref (buf); - - return result; -} - -static GstStateChangeReturn -gst_a52dec_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstA52Dec *a52dec = GST_A52DEC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY:{ - GstA52DecClass *klass; - - klass = GST_A52DEC_CLASS (G_OBJECT_GET_CLASS (a52dec)); - a52dec->state = a52_init (klass->a52_cpuflags); - - if (!a52dec->state) { - GST_ELEMENT_ERROR (GST_ELEMENT (a52dec), STREAM, DECODE, (NULL), - ("Failed to initialize a52 state")); - ret = GST_STATE_CHANGE_FAILURE; - } - break; - } - case GST_STATE_CHANGE_READY_TO_PAUSED: - a52dec->samples = a52_samples (a52dec->state); - a52dec->bit_rate = -1; - a52dec->sample_rate = -1; - a52dec->stream_channels = A52_CHANNEL; - a52dec->using_channels = A52_CHANNEL; - a52dec->level = 1; - a52dec->bias = 0; - a52dec->time = 0; - a52dec->sent_segment = FALSE; - a52dec->flag_update = TRUE; - gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - a52dec->samples = NULL; - if (a52dec->cache) { - gst_buffer_unref (a52dec->cache); - a52dec->cache = NULL; - } - clear_queued (a52dec); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - if (a52dec->state) { - a52_free (a52dec->state); - a52dec->state = NULL; - } - break; - default: - break; - } - - return ret; -} - static void gst_a52dec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) diff --git a/ext/a52dec/gsta52dec.h b/ext/a52dec/gsta52dec.h index e575b81..44fab5d 100644 --- a/ext/a52dec/gsta52dec.h +++ b/ext/a52dec/gsta52dec.h @@ -22,6 +22,7 @@ #define __GST_A52DEC_H__ #include +#include G_BEGIN_DECLS @@ -40,41 +41,33 @@ typedef struct _GstA52Dec GstA52Dec; typedef struct _GstA52DecClass GstA52DecClass; struct _GstA52Dec { - GstElement element; + GstAudioDecoder element; - /* pads */ - GstPad *sinkpad, - *srcpad; - GstSegment segment; + GstPadChainFunction base_chain; gboolean dvdmode; - gboolean sent_segment; - gboolean discont; - gboolean flag_update; int prev_flags; + /* stream properties */ int bit_rate; int sample_rate; int stream_channels; int request_channels; int using_channels; + /* decoding properties */ sample_t level; sample_t bias; gboolean dynamic_range_compression; sample_t *samples; a52_state_t *state; - GstBuffer *cache; - GstClockTime time; - - /* reverse */ - GList *queued; + GstTagList *pending_tags; }; struct _GstA52DecClass { - GstElementClass parent_class; + GstAudioDecoderClass parent_class; guint32 a52_cpuflags; }; -- 2.7.4