From: Sebastian Dröge Date: Tue, 10 Jan 2012 14:17:11 +0000 (+0100) Subject: Merge branch 'master' into 0.11 X-Git-Tag: RELEASE-0.11.1~36 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=31063f009861415c45bbaf16c5970a45cedde81b;p=platform%2Fupstream%2Fgst-plugins-ugly.git Merge branch 'master' into 0.11 Conflicts: ext/a52dec/gsta52dec.c ext/a52dec/gsta52dec.h ext/lame/gstlame.c ext/lame/gstlame.h ext/lame/gstlamemp3enc.c ext/mad/gstmad.c ext/mad/gstmad.h gst/mpegaudioparse/gstmpegaudioparse.c gst/mpegstream/gstdvddemux.c gst/realmedia/rdtdepay.c po/es.po po/lv.po po/sr.po --- 31063f009861415c45bbaf16c5970a45cedde81b diff --cc ext/a52dec/gsta52dec.c index 558eb9b,5827f57..eef9088 --- a/ext/a52dec/gsta52dec.c +++ b/ext/a52dec/gsta52dec.c @@@ -87,18 -86,21 +87,21 @@@ static GstStaticPadTemplate src_factor "rate = (int) [ 4000, 96000 ], " "channels = (int) [ 1, 6 ]") ); -GST_BOILERPLATE (GstA52Dec, gst_a52dec, GstAudioDecoder, - GST_TYPE_AUDIO_DECODER); +#define gst_a52dec_parent_class parent_class - G_DEFINE_TYPE (GstA52Dec, gst_a52dec, GST_TYPE_ELEMENT); ++G_DEFINE_TYPE (GstA52Dec, gst_a52dec, 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 (GstPad * pad, GstObject * parent, + GstBuffer * buffer); - static GstFlowReturn gst_a52dec_chain_raw (GstPad * pad, GstObject * parent, - GstBuffer * buf); - static gboolean gst_a52dec_sink_event (GstPad * pad, GstObject * parent, - 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); static void gst_a52dec_get_property (GObject * object, guint prop_id, @@@ -131,11 -133,27 +134,13 @@@ static voi 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; @@@ -211,23 -222,115 +221,116 @@@ } static void -gst_a52dec_init (GstA52Dec * a52dec, GstA52DecClass * g_class) +gst_a52dec_init (GstA52Dec * a52dec) { - /* create the sink and src pads */ - a52dec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_pad_set_chain_function (a52dec->sinkpad, + a52dec->request_channels = A52_CHANNEL; + a52dec->dynamic_range_compression = FALSE; + + a52dec->state = NULL; + a52dec->samples = NULL; + + /* 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)); - 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_element_add_pad (GST_ELEMENT (a52dec), a52dec->srcpad); + static gboolean + gst_a52dec_start (GstAudioDecoder * dec) + { + GstA52Dec *a52dec = GST_A52DEC (dec); + GstA52DecClass *klass; - a52dec->request_channels = A52_CHANNEL; - a52dec->dynamic_range_compression = FALSE; + GST_DEBUG_OBJECT (dec, "start"); + + 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), LIBRARY, INIT, (NULL), + ("failed to initialize a52 state")); + return FALSE; + } + + 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; - gst_segment_init (&a52dec->segment, GST_FORMAT_UNDEFINED); + /* 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; ++ const guint8 *data; + gint av, size; + gint length = 0, flags, sample_rate, bit_rate; - GstFlowReturn result = GST_FLOW_UNEXPECTED; ++ GstFlowReturn result = GST_FLOW_EOS; + + a52dec = GST_A52DEC (bdec); + + size = av = gst_adapter_available (adapter); - data = (guint8 *) gst_adapter_peek (adapter, av); ++ data = (const guint8 *) gst_adapter_map (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); ++ length = a52_syncinfo ((guint8 *) 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; + } + } ++ gst_adapter_unmap (adapter); + + *_offset = av - size; + *len = length; + + return result; } static gint @@@ -310,119 -421,13 +413,15 @@@ gst_a52dec_channels (int flags, GstAudi 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; - sample_t *data; - - flags &= (A52_CHANNEL_MASK | A52_LFE); - if (!(chans = gst_a52dec_channels (flags, NULL))) - goto no_channels; - - buf = gst_buffer_new_allocate (NULL, 256 * chans * (SAMPLE_WIDTH / 8), 0); - - data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE); - for (n = 0; n < 256; n++) { - for (c = 0; c < chans; c++) { - data[n * chans + c] = samples[c * 256 + n]; - } - } - gst_audio_reorder_channels (data, 256 * chans * (SAMPLE_WIDTH / 8), - (SAMPLE_WIDTH == 64) ? GST_AUDIO_FORMAT_F64 : GST_AUDIO_FORMAT_F32, chans, - a52dec->from, a52dec->to); - gst_buffer_unmap (buf, data, -1); - - 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; - - /* ERRORS */ - no_channels: - { - GST_ELEMENT_ERROR (GST_ELEMENT (a52dec), STREAM, DECODE, (NULL), - ("invalid channel flags: %d", flags)); - return GST_FLOW_ERROR; - } - } - static gboolean --gst_a52dec_reneg (GstA52Dec * a52dec, GstPad * pad) ++gst_a52dec_reneg (GstA52Dec * a52dec) { - GstAudioChannelPosition *pos; - gint channels = gst_a52dec_channels (a52dec->using_channels, &pos); + gint channels; GstCaps *caps = NULL; gboolean result = FALSE; ++ GstAudioChannelPosition from[6], to[6]; + - channels = gst_a52dec_channels (a52dec->using_channels, a52dec->from); ++ channels = gst_a52dec_channels (a52dec->using_channels, from); if (!channels) goto done; @@@ -430,26 -435,15 +429,26 @@@ GST_INFO_OBJECT (a52dec, "reneg channels:%d rate:%d", channels, a52dec->sample_rate); - memcpy (a52dec->to, a52dec->from, sizeof (a52dec->from)); - gst_audio_channel_positions_to_valid_order (a52dec->to, channels); - caps = gst_caps_new_simple ("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, SAMPLE_WIDTH, ++ memcpy (to, from, sizeof (GstAudioChannelPosition) * channels); ++ gst_audio_channel_positions_to_valid_order (to, channels); ++ gst_audio_get_channel_reorder_map (channels, from, to, ++ a52dec->channel_reorder_map); + + caps = gst_caps_new_simple ("audio/x-raw", + "format", G_TYPE_STRING, SAMPLE_FORMAT, + "layout", G_TYPE_STRING, "interleaved", "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, a52dec->sample_rate, NULL); - gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos); - g_free (pos); - if (!gst_pad_set_caps (pad, caps)) + if (channels > 1) { + guint64 channel_mask = 0; - gint i; + - for (i = 0; i < channels; i++) - channel_mask |= G_GUINT64_CONSTANT (1) << a52dec->to[i]; ++ gst_audio_channel_positions_to_mask (to, channels, &channel_mask); + gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask, + NULL); + } + - if (!gst_pad_set_caps (pad, caps)) ++ if (!gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (a52dec), caps)) goto done; result = TRUE; @@@ -460,113 -454,69 +459,69 @@@ done return result; } - static gboolean - gst_a52dec_sink_setcaps (GstA52Dec * a52dec, GstCaps * caps) - { - GstStructure *structure; - - structure = gst_caps_get_structure (caps, 0); - - if (structure && gst_structure_has_name (structure, "audio/x-private1-ac3")) - a52dec->dvdmode = TRUE; - else - a52dec->dvdmode = FALSE; - - return TRUE; - } - - static gboolean - gst_a52dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) + static void + gst_a52dec_update_streaminfo (GstA52Dec * a52dec) { - GstA52Dec *a52dec = GST_A52DEC (parent); - gboolean ret = FALSE; - - GST_LOG ("Handling %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS: - { - GstCaps *caps; - - gst_event_parse_caps (event, &caps); + GstTagList *taglist; - ret = gst_a52dec_sink_setcaps (a52dec, caps); - gst_event_unref (event); - break; - } - case GST_EVENT_SEGMENT: - { - GstSegment seg; - - gst_event_copy_segment (event, &seg); - - /* drain queued buffers before activating the segment so that we can clip - * against the old segment first */ - gst_a52dec_drain (a52dec); - - if (seg.format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (seg.start)) { - GST_WARNING ("No time in newsegment event %p (format is %s)", - event, gst_format_get_name (seg.format)); - gst_event_unref (event); - a52dec->sent_segment = FALSE; - /* set some dummy values, FIXME: do proper conversion */ - a52dec->time = seg.start = seg.position = 0; - seg.format = GST_FORMAT_TIME; - seg.stop = -1; - } else { - a52dec->time = seg.start; - a52dec->sent_segment = TRUE; - GST_DEBUG_OBJECT (a52dec, "Pushing segment %" GST_SEGMENT_FORMAT, &seg); - taglist = gst_tag_list_new (); ++ taglist = gst_tag_list_new_empty (); + gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_BITRATE, + (guint) a52dec->bit_rate, NULL); - ret = gst_pad_push_event (a52dec->srcpad, event); - } - a52dec->segment = seg; - 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; + if (a52dec->pending_tags) { + gst_tag_list_free (a52dec->pending_tags); + a52dec->pending_tags = NULL; } - 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_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); ++ gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (a52dec), ++ gst_event_new_tag (a52dec->pending_tags)); + a52dec->pending_tags = NULL; + } - gst_pad_push_event (GST_PAD (a52dec->srcpad), gst_event_new_tag (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 chans; + gint length = 0, flags, sample_rate, bit_rate; + guint8 *data; ++ gsize size; + 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); ++ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); + 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; @@@ -636,10 -587,11 +592,13 @@@ 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_buffer_unmap (buffer, data, size); + GST_AUDIO_DECODER_ERROR (a52dec, 1, STREAM, DECODE, (NULL), + ("a52_frame error"), result); + goto exit; } ++ gst_buffer_unmap (buffer, data, size); + channels = flags & (A52_CHANNEL_MASK | A52_LFE); if (a52dec->using_channels != channels) { need_reneg = TRUE; @@@ -648,60 -600,96 +607,100 @@@ /* 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))) ++ if (!gst_a52dec_reneg (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++) { - if (a52_block (a52dec->state)) { - /* ignore errors but mark a discont */ - GST_WARNING ("a52_block error %d", i); - a52dec->discont = TRUE; - } else { - GstFlowReturn ret; + flags &= (A52_CHANNEL_MASK | A52_LFE); + chans = gst_a52dec_channels (flags, NULL); + if (!chans) + goto invalid_flags; - /* push on */ - ret = gst_a52dec_push (a52dec, a52dec->srcpad, a52dec->using_channels, - a52dec->samples, a52dec->time); - if (ret != GST_FLOW_OK) - return ret; + /* 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)) { - /* 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 { - gint n, c; ++ outbuf = ++ gst_buffer_new_and_alloc (256 * chans * (SAMPLE_WIDTH / 8) * num_blocks); + - for (n = 0; n < 256; n++) { - for (c = 0; c < chans; c++) { - ((sample_t *) data)[n * chans + c] = a52dec->samples[c * 256 + n]; ++ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_WRITE); ++ { ++ guint8 *ptr = data; ++ for (i = 0; i < num_blocks; i++) { ++ if (a52_block (a52dec->state)) { ++ /* also marks discont */ ++ GST_AUDIO_DECODER_ERROR (a52dec, 1, STREAM, DECODE, (NULL), ++ ("error decoding block %d", i), result); ++ if (result != GST_FLOW_OK) { ++ gst_buffer_unmap (outbuf, data, size); ++ goto exit; ++ } ++ } else { ++ gint n, c; ++ gint *reorder_map = a52dec->channel_reorder_map; ++ ++ for (n = 0; n < 256; n++) { ++ for (c = 0; c < chans; c++) { ++ ((sample_t *) ptr)[reorder_map[n] * chans + c] = ++ a52dec->samples[c * 256 + n]; ++ } + } + } ++ ptr += 256 * chans * (SAMPLE_WIDTH / 8); } - a52dec->time += 256 * GST_SECOND / a52dec->sample_rate; - data += 256 * chans * (SAMPLE_WIDTH / 8); } ++ gst_buffer_unmap (outbuf, data, size); - 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_set_format (GstAudioDecoder * bdec, GstCaps * caps) + { + GstA52Dec *a52dec = GST_A52DEC (bdec); + GstStructure *structure; + + structure = gst_caps_get_structure (caps, 0); + + if (structure && gst_structure_has_name (structure, "audio/x-private1-ac3")) + a52dec->dvdmode = TRUE; + else + a52dec->dvdmode = FALSE; + + return TRUE; } static GstFlowReturn -gst_a52dec_chain (GstPad * pad, GstBuffer * buf) +gst_a52dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { - GstA52Dec *a52dec = GST_A52DEC (GST_PAD_PARENT (pad)); + GstA52Dec *a52dec = GST_A52DEC (parent); - 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); + gsize size; + guint8 data[2]; gint offset; gint len; GstBuffer *subbuf; @@@ -722,32 -709,34 +721,35 @@@ if (len <= 0 || offset + len > size) goto bad_first_access_parameter; - subbuf = gst_buffer_create_sub (buf, offset, len); - gst_buffer_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); + subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len); GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE; - ret = gst_a52dec_chain_raw (pad, parent, subbuf); - if (ret != GST_FLOW_OK) - ret = a52dec->base_chain (pad, subbuf); ++ ret = a52dec->base_chain (pad, parent, 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); + subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len); GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - ret = gst_a52dec_chain_raw (pad, parent, subbuf); - ret = a52dec->base_chain (pad, subbuf); ++ ret = a52dec->base_chain (pad, parent, 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_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); - ret = a52dec->base_chain (pad, subbuf); + subbuf = + gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, + size - offset); + GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - ret = gst_a52dec_chain_raw (pad, parent, subbuf); ++ ret = a52dec->base_chain (pad, parent, subbuf); } } else { - ret = a52dec->base_chain (pad, buf); + gst_buffer_ref (buf); - ret = gst_a52dec_chain_raw (pad, parent, buf); ++ ret = a52dec->base_chain (pad, parent, buf); } done: diff --cc ext/a52dec/gsta52dec.h index 4508a82,44fab5d..dd272c1 --- a/ext/a52dec/gsta52dec.h +++ b/ext/a52dec/gsta52dec.h @@@ -22,7 -22,7 +22,8 @@@ #define __GST_A52DEC_H__ #include +#include + #include G_BEGIN_DECLS @@@ -61,8 -56,7 +57,8 @@@ struct _GstA52Dec int request_channels; int using_channels; - GstAudioChannelPosition from[6], to[6]; - /* decoding properties */ ++ gint channel_reorder_map[6]; + sample_t level; sample_t bias; gboolean dynamic_range_compression; diff --cc ext/dvdread/dvdreadsrc.c index 71497a7,1ed59e5..6522854 --- a/ext/dvdread/dvdreadsrc.c +++ b/ext/dvdread/dvdreadsrc.c @@@ -529,9 -529,18 +531,18 @@@ gst_dvd_read_src_goto_title (GstDvdRead continue; u = &src->vts_file->vtsi_mat->vts_subp_attr[i]; + v = &src->vts_file->vtsi_mat->vts_video_attr; + + sid = i; + if (pgc0 != NULL) { - if (v->display_aspect_ratio == 0) /* 4:3 */ ++ if (v->display_aspect_ratio == 0) /* 4:3 */ + sid = (pgc0->subp_control[i] >> 24) & 0x1f; + else if (v->display_aspect_ratio == 3) /* 16:9 */ + sid = (pgc0->subp_control[i] >> 8) & 0x1f; + } if (u->type) { - t = g_strdup_printf ("subtitle-%d-language", i); + t = g_strdup_printf ("subtitle-%d-language", sid); lang_code[0] = (u->lang_code >> 8) & 0xff; lang_code[1] = u->lang_code & 0xff; gst_structure_set (s, t, G_TYPE_STRING, lang_code, NULL); diff --cc ext/lame/Makefile.am index 103e68e,41457e3..03a1dc4 --- a/ext/lame/Makefile.am +++ b/ext/lame/Makefile.am @@@ -1,10 -1,10 +1,10 @@@ plugin_LTLIBRARIES = libgstlame.la -libgstlame_la_SOURCES = gstlame.c gstlamemp3enc.c plugin.c +libgstlame_la_SOURCES = gstlamemp3enc.c plugin.c libgstlame_la_CFLAGS = -DGST_USE_UNSTABLE_API \ - $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS) - libgstlame_la_LIBADD = $(LAME_LIBS) $(GST_PLUGINS_BASE_LIBS) \ - -lgstaudio-$(GST_MAJORMINOR) $(GST_LIBS) + $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LAME_CFLAGS) + libgstlame_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) $(GST_LIBS) $(LAME_LIBS) libgstlame_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstlame_la_LIBTOOLFLAGS = --tag=disable-static diff --cc ext/lame/gstlamemp3enc.c index 0998873,c8cd3e6..d0a1813 --- a/ext/lame/gstlamemp3enc.c +++ b/ext/lame/gstlamemp3enc.c @@@ -486,30 -499,221 +499,226 @@@ gst_lamemp3enc_get_property (GObject * } } + /* **** credits go to mpegaudioparse **** */ + + static const guint mp3types_bitrates[2][3][16] = { + { + {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,} + }, + { + {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,} + }, + }; + + static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000}, + {22050, 24000, 16000}, + {11025, 12000, 8000} + }; + + static inline guint + mp3_type_frame_length_from_header (GstLameMP3Enc * lame, guint32 header, + guint * put_version, guint * put_layer, guint * put_channels, + guint * put_bitrate, guint * put_samplerate, guint * put_mode, + guint * put_crc) + { + guint length; + gulong mode, samplerate, bitrate, layer, channels, padding, crc; + gulong version; + gint lsf, mpg25; + + if (header & (1 << 20)) { + lsf = (header & (1 << 19)) ? 0 : 1; + mpg25 = 0; + } else { + lsf = 1; + mpg25 = 1; + } + + version = 1 + lsf + mpg25; + + layer = 4 - ((header >> 17) & 0x3); + + crc = (header >> 16) & 0x1; + + bitrate = (header >> 12) & 0xF; + bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000; + /* The caller has ensured we have a valid header, so bitrate can't be + zero here. */ + g_assert (bitrate != 0); + + samplerate = (header >> 10) & 0x3; + samplerate = mp3types_freqs[lsf + mpg25][samplerate]; + + padding = (header >> 9) & 0x1; + + mode = (header >> 6) & 0x3; + channels = (mode == 3) ? 1 : 2; + + switch (layer) { + case 1: + length = 4 * ((bitrate * 12) / samplerate + padding); + break; + case 2: + length = (bitrate * 144) / samplerate + padding; + break; + default: + case 3: + length = (bitrate * 144) / (samplerate << lsf) + padding; + break; + } + + GST_DEBUG_OBJECT (lame, "Calculated mp3 frame length of %u bytes", length); + GST_DEBUG_OBJECT (lame, "samplerate = %lu, bitrate = %lu, version = %lu, " + "layer = %lu, channels = %lu", samplerate, bitrate, version, + layer, channels); + + if (put_version) + *put_version = version; + if (put_layer) + *put_layer = layer; + if (put_channels) + *put_channels = channels; + if (put_bitrate) + *put_bitrate = bitrate; + if (put_samplerate) + *put_samplerate = samplerate; + if (put_mode) + *put_mode = mode; + if (put_crc) + *put_crc = crc; + + return length; + } + + static gboolean + mp3_sync_check (GstLameMP3Enc * lame, unsigned long head) + { + GST_DEBUG_OBJECT (lame, "checking mp3 header 0x%08lx", head); + /* if it's not a valid sync */ + if ((head & 0xffe00000) != 0xffe00000) { + GST_WARNING_OBJECT (lame, "invalid sync"); + return FALSE; + } + /* if it's an invalid MPEG version */ + if (((head >> 19) & 3) == 0x1) { + GST_WARNING_OBJECT (lame, "invalid MPEG version: 0x%lx", (head >> 19) & 3); + return FALSE; + } + /* if it's an invalid layer */ + if (!((head >> 17) & 3)) { + GST_WARNING_OBJECT (lame, "invalid layer: 0x%lx", (head >> 17) & 3); + return FALSE; + } + /* if it's an invalid bitrate */ + if (((head >> 12) & 0xf) == 0x0) { + GST_WARNING_OBJECT (lame, "invalid bitrate: 0x%lx." + "Free format files are not supported yet", (head >> 12) & 0xf); + return FALSE; + } + if (((head >> 12) & 0xf) == 0xf) { + GST_WARNING_OBJECT (lame, "invalid bitrate: 0x%lx", (head >> 12) & 0xf); + return FALSE; + } + /* if it's an invalid samplerate */ + if (((head >> 10) & 0x3) == 0x3) { + GST_WARNING_OBJECT (lame, "invalid samplerate: 0x%lx", (head >> 10) & 0x3); + return FALSE; + } + + if ((head & 0x3) == 0x2) { + /* Ignore this as there are some files with emphasis 0x2 that can + * be played fine. See BGO #537235 */ + GST_WARNING_OBJECT (lame, "invalid emphasis: 0x%lx", head & 0x3); + } + + return TRUE; + } + + /* **** end mpegaudioparse **** */ + + static GstFlowReturn + gst_lamemp3enc_finish_frames (GstLameMP3Enc * lame) + { + gint av; + guint header; + GstFlowReturn result = GST_FLOW_OK; + + /* limited parsing, we don't expect to lose sync here */ + while ((result == GST_FLOW_OK) && + ((av = gst_adapter_available (lame->adapter)) > 4)) { + guint rate, version, layer, size; + GstBuffer *mp3_buf; + const guint8 *data; + - data = gst_adapter_peek (lame->adapter, 4); ++ data = gst_adapter_map (lame->adapter, 4); + header = GST_READ_UINT32_BE (data); ++ gst_adapter_unmap (lame->adapter); ++ + if (!mp3_sync_check (lame, header)) + goto invalid_header; + + size = mp3_type_frame_length_from_header (lame, header, &version, &layer, + NULL, NULL, &rate, NULL, NULL); + + if (G_UNLIKELY (layer != 3 || rate != lame->out_samplerate)) { + GST_DEBUG_OBJECT (lame, + "unexpected mp3 header with rate %u, version %u, layer %u", + rate, version, layer); + goto invalid_header; + } + + if (size > av) { + /* pretty likely to occur when lame is holding back on us */ + GST_LOG_OBJECT (lame, "frame size %u (> %d)", size, av); + break; + } + + /* should be ok now */ + mp3_buf = gst_adapter_take_buffer (lame->adapter, size); + /* number of samples for MPEG-1, layer 3 */ + result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), + mp3_buf, version == 1 ? 1152 : 576); + } + + exit: + return result; + + /* ERRORS */ + invalid_header: + { + GST_ELEMENT_ERROR (lame, STREAM, ENCODE, + ("invalid lame mp3 sync header %08X", header), (NULL)); + result = GST_FLOW_ERROR; + goto exit; + } + } + static GstFlowReturn gst_lamemp3enc_flush_full (GstLameMP3Enc * lame, gboolean push) { GstBuffer *buf; gint size; + guint8 *data; GstFlowReturn result = GST_FLOW_OK; + gint av; if (!lame->lgf) return GST_FLOW_OK; buf = gst_buffer_new_and_alloc (7200); - size = lame_encode_flush (lame->lgf, GST_BUFFER_DATA (buf), 7200); + data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE); + size = lame_encode_flush (lame->lgf, data, 7200); if (size > 0) { - GST_BUFFER_SIZE (buf) = size; + gst_buffer_unmap (buf, data, size); - if (push) { - GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size); - result = - gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1); - } + GST_DEBUG_OBJECT (lame, "collecting final %d bytes", size); + gst_adapter_push (lame->adapter, buf); } else { + gst_buffer_unmap (buf, data, 0); GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push); gst_buffer_unref (buf); result = GST_FLOW_OK; @@@ -560,16 -781,17 +785,19 @@@ gst_lamemp3enc_handle_frame (GstAudioEn (short int *) data, num_samples / lame->num_channels, mp3_data, mp3_buffer_size); } + gst_buffer_unmap (in_buf, data, size); - GST_LOG_OBJECT (lame, "encoded %d bytes of audio to %d bytes of mp3", - size, mp3_size); + GST_LOG_OBJECT (lame, "encoded %" G_GSIZE_FORMAT " bytes of audio " + "to %d bytes of mp3", size, mp3_size); if (G_LIKELY (mp3_size > 0)) { - GST_BUFFER_SIZE (mp3_buf) = mp3_size; + /* unfortunately lame does not provide frame delineated output, + * so collect output and parse into frames ... */ + gst_buffer_unmap (mp3_buf, mp3_data, mp3_size); - result = gst_audio_encoder_finish_frame (enc, mp3_buf, -1); + gst_adapter_push (lame->adapter, mp3_buf); + result = gst_lamemp3enc_finish_frames (lame); } else { + gst_buffer_unmap (mp3_buf, mp3_data, 0); if (mp3_size < 0) { /* eat error ? */ g_warning ("error %d", mp3_size); diff --cc ext/mad/gstmad.c index db3cc20,bff7634..a896650 --- a/ext/mad/gstmad.c +++ b/ext/mad/gstmad.c @@@ -93,15 -111,17 +94,22 @@@ static voi gst_mad_class_init (GstMadClass * klass) { GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *element_class = (GstElementClass *) klass; GstAudioDecoderClass *base_class = (GstAudioDecoderClass *) klass; - parent_class = g_type_class_peek_parent (klass); + base_class->start = GST_DEBUG_FUNCPTR (gst_mad_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_mad_stop); + base_class->parse = GST_DEBUG_FUNCPTR (gst_mad_parse); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mad_handle_frame); + base_class->flush = GST_DEBUG_FUNCPTR (gst_mad_flush); + base_class->start = GST_DEBUG_FUNCPTR (gst_mad_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_mad_stop); + base_class->parse = GST_DEBUG_FUNCPTR (gst_mad_parse); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mad_handle_frame); + base_class->flush = GST_DEBUG_FUNCPTR (gst_mad_flush); + base_class->event = GST_DEBUG_FUNCPTR (gst_mad_event); + gobject_class->set_property = gst_mad_set_property; gobject_class->get_property = gst_mad_get_property; @@@ -281,6 -285,20 +289,20 @@@ gst_mad_parse (GstAudioDecoder * dec, G mad = GST_MAD (dec); + if (mad->eos) { + /* This is one steaming hack right there. + * mad will not decode the last frame if it is not followed by + * a number of 0 bytes, due to some buffer overflow, which can + * not be fixed for reasons I did not inquire into, see + * http://www.mars.org/mailman/public/mad-dev/2001-May/000262.html + */ + GstBuffer *guard = gst_buffer_new_and_alloc (MAD_BUFFER_GUARD); - memset (GST_BUFFER_DATA (guard), 0, GST_BUFFER_SIZE (guard)); ++ gst_buffer_memset (guard, 0, 0, MAD_BUFFER_GUARD); + GST_DEBUG_OBJECT (mad, "Discreetly stuffing %u zero bytes in the adapter", - GST_BUFFER_SIZE (guard)); ++ MAD_BUFFER_GUARD); + gst_adapter_push (adapter, guard); + } + /* we basically let mad library do parsing, * and translate that back to baseclass. * if a frame is found (and also decoded), subsequent handle_frame