Merge branch 'master' into 0.11
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 10 Jan 2012 14:17:11 +0000 (15:17 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 10 Jan 2012 14:17:11 +0000 (15:17 +0100)
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

1  2 
ext/a52dec/gsta52dec.c
ext/a52dec/gsta52dec.h
ext/dvdread/dvdreadsrc.c
ext/lame/Makefile.am
ext/lame/gstlamemp3enc.c
ext/mad/gstmad.c
gst/asfdemux/gstasfdemux.c
gst/realmedia/rademux.c
gst/realmedia/rdtmanager.c
gst/realmedia/rmdemux.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;
  }
  
  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;
-   channels = gst_a52dec_channels (a52dec->using_channels, a52dec->from);
++  GstAudioChannelPosition from[6], to[6];
 +
++  channels = gst_a52dec_channels (a52dec->using_channels, from);
  
    if (!channels)
      goto done;
    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;
    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;
  
    /* 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;
        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:
@@@ -22,7 -22,7 +22,8 @@@
  #define __GST_A52DEC_H__
  
  #include <gst/gst.h>
 +#include <gst/audio/audio.h>
+ #include <gst/audio/gstaudiodecoder.h>
  
  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;
@@@ -529,9 -529,18 +531,18 @@@ gst_dvd_read_src_goto_title (GstDvdRead
        continue;
  
      u = &src->vts_file->vtsi_mat->vts_subp_attr[i];
 -      if (v->display_aspect_ratio == 0)         /* 4:3 */
+     v = &src->vts_file->vtsi_mat->vts_video_attr;
+     sid = i;
+     if (pgc0 != NULL) {
++      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);
@@@ -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
  
@@@ -486,30 -499,221 +499,226 @@@ gst_lamemp3enc_get_property (GObject * 
    }
  }
  
 -    data = gst_adapter_peek (lame->adapter, 4);
+ /* **** 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_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);
@@@ -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);
  
 -    memset (GST_BUFFER_DATA (guard), 0, GST_BUFFER_SIZE (guard));
+   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);
 -        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",
++        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
Simple merge
Simple merge
Simple merge
Simple merge