Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Sat, 8 Oct 2011 08:19:06 +0000 (10:19 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Sat, 8 Oct 2011 08:19:06 +0000 (10:19 +0200)
Conflicts:
ext/vorbis/gstvorbisdec.c
ext/vorbis/gstvorbisenc.c
ext/vorbis/gstvorbisenc.h
gst/audiotestsrc/gstaudiotestsrc.c

12 files changed:
1  2 
ext/vorbis/gstvorbisdec.c
ext/vorbis/gstvorbisdec.h
ext/vorbis/gstvorbisenc.c
gst-libs/gst/audio/gstaudiodecoder.c
gst-libs/gst/audio/gstaudioencoder.c
gst/audiotestsrc/gstaudiotestsrc.c
gst/encoding/gstencodebin.c
gst/playback/gstplaybin2.c
gst/playback/gstplaysink.c
gst/playback/gstplaysinkaudioconvert.c
gst/playback/gstplaysinkvideoconvert.c
tests/check/elements/audiotestsrc.c

@@@ -64,91 -64,52 +64,46 @@@ GST_STATIC_PAD_TEMPLATE ("sink"
      GST_STATIC_CAPS ("audio/x-vorbis")
      );
  
 -GST_BOILERPLATE (GstVorbisDec, gst_vorbis_dec, GstAudioDecoder,
 +#define gst_vorbis_dec_parent_class parent_class
- G_DEFINE_TYPE (GST_VORBIS_DEC_GLIB_TYPE_NAME, gst_vorbis_dec, GST_TYPE_ELEMENT);
++G_DEFINE_TYPE (GST_VORBIS_DEC_GLIB_TYPE_NAME, gst_vorbis_dec,
+     GST_TYPE_AUDIO_DECODER);
  
  static void vorbis_dec_finalize (GObject * object);
- static gboolean vorbis_dec_sink_event (GstPad * pad, GstEvent * event);
- static GstFlowReturn vorbis_dec_chain (GstPad * pad, GstBuffer * buffer);
- static GstFlowReturn vorbis_dec_chain_forward (GstVorbisDec * vd,
-     gboolean discont, GstBuffer * buffer);
- static GstFlowReturn vorbis_dec_chain_reverse (GstVorbisDec * vd,
-     gboolean discont, GstBuffer * buf);
- static GstStateChangeReturn vorbis_dec_change_state (GstElement * element,
-     GstStateChange transition);
- static gboolean vorbis_dec_src_event (GstPad * pad, GstEvent * event);
- static gboolean vorbis_dec_src_query (GstPad * pad, GstQuery * query);
- static gboolean vorbis_dec_convert (GstPad * pad,
-     GstFormat src_format, gint64 src_value,
-     GstFormat dest_format, gint64 * dest_value);
- static gboolean vorbis_dec_sink_query (GstPad * pad, GstQuery * query);
+ static gboolean vorbis_dec_start (GstAudioDecoder * dec);
+ static gboolean vorbis_dec_stop (GstAudioDecoder * dec);
+ static GstFlowReturn vorbis_dec_handle_frame (GstAudioDecoder * dec,
+     GstBuffer * buffer);
+ static void vorbis_dec_flush (GstAudioDecoder * dec, gboolean hard);
  
  static void
 -gst_vorbis_dec_base_init (gpointer g_class)
 +gst_vorbis_dec_class_init (GstVorbisDecClass * klass)
  {
 -  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 -  GstPadTemplate *src_template, *sink_template;
 +  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 +  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
++  GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass);
  
 -  src_template = gst_static_pad_template_get (&vorbis_dec_src_factory);
 -  gst_element_class_add_pad_template (element_class, src_template);
 +  gobject_class->finalize = vorbis_dec_finalize;
  
 -  sink_template = gst_static_pad_template_get (&vorbis_dec_sink_factory);
 -  gst_element_class_add_pad_template (element_class, sink_template);
 +  gst_element_class_add_pad_template (gstelement_class,
 +      gst_static_pad_template_get (&vorbis_dec_src_factory));
 +  gst_element_class_add_pad_template (gstelement_class,
 +      gst_static_pad_template_get (&vorbis_dec_sink_factory));
  
 -  gst_element_class_set_details_simple (element_class,
 +  gst_element_class_set_details_simple (gstelement_class,
        "Vorbis audio decoder", "Codec/Decoder/Audio",
        GST_VORBIS_DEC_DESCRIPTION,
        "Benjamin Otte <otte@gnome.org>, Chris Lord <chris@openedhand.com>");
 -}
 -
 -static void
 -gst_vorbis_dec_class_init (GstVorbisDecClass * klass)
 -{
 -  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 -  GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass);
 -
 -  gobject_class->finalize = vorbis_dec_finalize;
  
-   gstelement_class->change_state = GST_DEBUG_FUNCPTR (vorbis_dec_change_state);
- }
- static const GstQueryType *
- vorbis_get_query_types (GstPad * pad)
- {
-   static const GstQueryType vorbis_dec_src_query_types[] = {
-     GST_QUERY_POSITION,
-     GST_QUERY_DURATION,
-     GST_QUERY_CONVERT,
-     0
-   };
-   return vorbis_dec_src_query_types;
+   base_class->start = GST_DEBUG_FUNCPTR (vorbis_dec_start);
+   base_class->stop = GST_DEBUG_FUNCPTR (vorbis_dec_stop);
+   base_class->handle_frame = GST_DEBUG_FUNCPTR (vorbis_dec_handle_frame);
+   base_class->flush = GST_DEBUG_FUNCPTR (vorbis_dec_flush);
  }
  
  static void
 -gst_vorbis_dec_init (GstVorbisDec * dec, GstVorbisDecClass * g_class)
 +gst_vorbis_dec_init (GstVorbisDec * dec)
  {
-   dec->sinkpad = gst_pad_new_from_static_template (&vorbis_dec_sink_factory,
-       "sink");
-   gst_pad_set_event_function (dec->sinkpad,
-       GST_DEBUG_FUNCPTR (vorbis_dec_sink_event));
-   gst_pad_set_chain_function (dec->sinkpad,
-       GST_DEBUG_FUNCPTR (vorbis_dec_chain));
-   gst_pad_set_query_function (dec->sinkpad,
-       GST_DEBUG_FUNCPTR (vorbis_dec_sink_query));
-   gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
-   dec->srcpad = gst_pad_new_from_static_template (&vorbis_dec_src_factory,
-       "src");
-   gst_pad_set_event_function (dec->srcpad,
-       GST_DEBUG_FUNCPTR (vorbis_dec_src_event));
-   gst_pad_set_query_type_function (dec->srcpad,
-       GST_DEBUG_FUNCPTR (vorbis_get_query_types));
-   gst_pad_set_query_function (dec->srcpad,
-       GST_DEBUG_FUNCPTR (vorbis_dec_src_query));
-   gst_pad_use_fixed_caps (dec->srcpad);
-   gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
-   dec->queued = NULL;
-   dec->pendingevents = NULL;
-   dec->taglist = NULL;
  }
  
  static void
@@@ -539,14 -264,43 +262,14 @@@ vorbis_handle_identification_packet (Gs
      }
    }
  
 -  /* negotiate width with downstream */
 -  caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (vd));
 -  if (caps) {
 -    if (!gst_caps_is_empty (caps)) {
 -      GstStructure *s;
 -
 -      s = gst_caps_get_structure (caps, 0);
 -      /* template ensures 16 or 32 */
 -      gst_structure_get_int (s, "width", &width);
 -
 -      GST_INFO_OBJECT (vd, "using %s with %d channels and %d bit audio depth",
 -          gst_structure_get_name (s), vd->vi.channels, width);
 -    }
 -    gst_caps_unref (caps);
 -  }
 -  vd->width = width >> 3;
 +  caps = gst_audio_info_to_caps (&info);
-   gst_pad_set_caps (vd->srcpad, caps);
++  gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (vd), caps);
 +  gst_caps_unref (caps);
  
 +  vd->info = info;
    /* select a copy_samples function, this way we can have specialized versions
     * for mono/stereo and avoid the depth switch in tremor case */
 -  vd->copy_samples = get_copy_sample_func (vd->vi.channels, vd->width);
 -
 -  caps =
 -      gst_caps_copy (gst_pad_get_pad_template_caps
 -      (GST_AUDIO_DECODER_SRC_PAD (vd)));
 -  gst_caps_set_simple (caps, "rate", G_TYPE_INT, vd->vi.rate, "channels",
 -      G_TYPE_INT, vd->vi.channels, "width", G_TYPE_INT, width, NULL);
 -
 -  if (pos) {
 -    gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
 -  }
 -
 -  if (vd->vi.channels > 8) {
 -    g_free ((GstAudioChannelPosition *) pos);
 -  }
 -
 -  gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (vd), caps);
 -  gst_caps_unref (caps);
 +  vd->copy_samples = get_copy_sample_func (info.channels);
  
    return GST_FLOW_OK;
  }
@@@ -721,69 -473,63 +441,71 @@@ header_read_error
  }
  
  static GstFlowReturn
- vorbis_dec_push_forward (GstVorbisDec * dec, GstBuffer * buf)
+ vorbis_dec_handle_header_buffer (GstVorbisDec * vd, GstBuffer * buffer)
  {
-   GstFlowReturn result;
-   /* clip */
-   if (!(buf = gst_audio_buffer_clip (buf, &dec->segment, dec->vi.rate,
-               dec->info.bpf))) {
-     GST_LOG_OBJECT (dec, "clipped buffer");
-     return GST_FLOW_OK;
-   }
+   ogg_packet *packet;
+   ogg_packet_wrapper packet_wrapper;
++  GstFlowReturn ret;
  
-   if (dec->discont) {
-     GST_LOG_OBJECT (dec, "setting DISCONT");
-     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
-     dec->discont = FALSE;
-   }
 -  gst_ogg_packet_wrapper_from_buffer (&packet_wrapper, buffer);
++  gst_ogg_packet_wrapper_map (&packet_wrapper, buffer);
+   packet = gst_ogg_packet_from_wrapper (&packet_wrapper);
  
-   GST_DEBUG_OBJECT (dec,
-       "pushing time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
-       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
-       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
 -  return vorbis_handle_header_packet (vd, packet);
++  ret = vorbis_handle_header_packet (vd, packet);
 +
-   result = gst_pad_push (dec->srcpad, buf);
++  gst_ogg_packet_wrapper_unmap (&packet_wrapper, buffer);
 +
-   return result;
++  return ret;
  }
  
+ #define MIN_NUM_HEADERS 3
  static GstFlowReturn
- vorbis_dec_push_reverse (GstVorbisDec * dec, GstBuffer * buf)
+ vorbis_dec_handle_header_caps (GstVorbisDec * vd)
  {
    GstFlowReturn result = GST_FLOW_OK;
 -  caps = GST_PAD_CAPS (GST_AUDIO_DECODER_SINK_PAD (vd));
+   GstCaps *caps;
+   GstStructure *s = NULL;
+   const GValue *array = NULL;
++  caps = gst_pad_get_current_caps (GST_AUDIO_DECODER_SINK_PAD (vd));
+   if (caps)
+     s = gst_caps_get_structure (caps, 0);
+   if (s)
+     array = gst_structure_get_value (s, "streamheader");
++  if (caps)
++    gst_caps_unref (caps);
++
+   if (array && (gst_value_array_get_size (array) >= MIN_NUM_HEADERS)) {
+     const GValue *value = NULL;
+     GstBuffer *buf = NULL;
+     gint i = 0;
+     while (result == GST_FLOW_OK) {
+       value = gst_value_array_get_value (array, i);
+       buf = gst_value_get_buffer (value);
+       if (!buf)
+         goto null_buffer;
+       result = vorbis_dec_handle_header_buffer (vd, buf);
+       i++;
+     }
+   } else
+     goto array_error;
  
-   dec->queued = g_list_prepend (dec->queued, buf);
-   return result;
- }
+ done:
+   return (result != GST_FLOW_OK ? GST_FLOW_NOT_NEGOTIATED : GST_FLOW_OK);
  
- static void
- vorbis_do_timestamps (GstVorbisDec * vd, GstBuffer * buf, gboolean reverse,
-     GstClockTime timestamp, GstClockTime duration)
- {
-   /* interpolate reverse */
-   if (vd->last_timestamp != -1 && duration != -1 && reverse)
-     vd->last_timestamp -= duration;
-   /* take buffer timestamp, use interpolated timestamp otherwise */
-   if (timestamp != -1)
-     vd->last_timestamp = timestamp;
-   else
-     timestamp = vd->last_timestamp;
-   /* interpolate forwards */
-   if (vd->last_timestamp != -1 && duration != -1 && !reverse)
-     vd->last_timestamp += duration;
-   GST_LOG_OBJECT (vd,
-       "keeping timestamp %" GST_TIME_FORMAT " ts %" GST_TIME_FORMAT " dur %"
-       GST_TIME_FORMAT, GST_TIME_ARGS (vd->last_timestamp),
-       GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
-   if (buf) {
-     GST_BUFFER_TIMESTAMP (buf) = timestamp;
-     GST_BUFFER_DURATION (buf) = duration;
+   /* ERRORS */
+ array_error:
+   {
+     GST_WARNING_OBJECT (vd, "streamheader array not found");
+     result = GST_FLOW_ERROR;
+     goto done;
+   }
+ null_buffer:
+   {
+     GST_WARNING_OBJECT (vd, "streamheader with null buffer received");
+     result = GST_FLOW_ERROR;
+     goto done;
    }
  }
  
@@@ -797,11 -546,13 +522,14 @@@ vorbis_handle_data_packet (GstVorbisDe
    guint sample_count;
    GstBuffer *out = NULL;
    GstFlowReturn result;
 -  gint size;
 +  guint8 *data;
 +  gsize size;
  
-   if (G_UNLIKELY (!vd->initialized))
-     goto not_initialized;
+   if (G_UNLIKELY (!vd->initialized)) {
+     result = vorbis_dec_handle_header_caps (vd);
+     if (result != GST_FLOW_OK)
+       goto not_initialized;
+   }
  
    /* normal data packet */
    /* FIXME, we can skip decoding if the packet is outside of the
    if ((sample_count = vorbis_dsp_pcmout (&vd->vd, NULL, 0)) == 0)
  #else
    if ((sample_count = vorbis_synthesis_pcmout (&vd->vd, NULL)) == 0)
- #endif
      goto done;
+ #endif
  
 -  size = sample_count * vd->vi.channels * vd->width;
 -  GST_LOG_OBJECT (vd, "%d samples ready for reading, size %d", sample_count,
 -      size);
 +  size = sample_count * vd->info.bpf;
 +  GST_LOG_OBJECT (vd, "%d samples ready for reading, size %" G_GSIZE_FORMAT,
 +      sample_count, size);
  
    /* alloc buffer for it */
 -  result =
 -      gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (vd),
 -      GST_BUFFER_OFFSET_NONE, size,
 -      GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (vd)), &out);
 -  if (G_UNLIKELY (result != GST_FLOW_OK))
 -    goto done;
 +  out = gst_buffer_new_and_alloc (size);
  
 +  data = gst_buffer_map (out, NULL, NULL, GST_MAP_WRITE);
    /* get samples ready for reading now, should be sample_count */
  #ifdef USE_TREMOLO
 -  pcm = GST_BUFFER_DATA (out);
 -  if (G_UNLIKELY (vorbis_dsp_pcmout (&vd->vd, pcm, sample_count) !=
 -          sample_count))
 +  if (G_UNLIKELY ((vorbis_dsp_pcmout (&vd->vd, data,
 +                  sample_count)) != sample_count))
  #else
-   if (G_UNLIKELY ((vorbis_synthesis_pcmout (&vd->vd, &pcm)) != sample_count))
+   if (G_UNLIKELY (vorbis_synthesis_pcmout (&vd->vd, &pcm) != sample_count))
  #endif
      goto wrong_samples;
  
  #ifndef USE_TREMOLO
    /* copy samples in buffer */
 -  vd->copy_samples ((vorbis_sample_t *) GST_BUFFER_DATA (out), pcm,
 -      sample_count, vd->vi.channels, vd->width);
 +  vd->copy_samples ((vorbis_sample_t *) data, pcm,
 +      sample_count, vd->info.channels);
  #endif
  
 -  GST_LOG_OBJECT (vd, "setting output size to %d", size);
 -  GST_BUFFER_SIZE (out) = size;
 +  GST_LOG_OBJECT (vd, "setting output size to %" G_GSIZE_FORMAT, size);
 +  gst_buffer_unmap (out, data, size);
  
-   /* this should not overflow */
-   if (duration == -1)
-     duration = sample_count * GST_SECOND / vd->vi.rate;
-   vorbis_do_timestamps (vd, out, FALSE, timestamp, duration);
-   if (vd->segment.rate >= 0.0)
-     result = vorbis_dec_push_forward (vd, out);
-   else
-     result = vorbis_dec_push_reverse (vd, out);
  done:
-   if (out == NULL) {
-     /* no output, still keep track of timestamps */
-     vorbis_do_timestamps (vd, NULL, FALSE, timestamp, duration);
-   }
+   /* whether or not data produced, consume one frame and advance time */
+   result = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (vd), out, 1);
  #ifdef USE_TREMOLO
    vorbis_dsp_read (&vd->vd, sample_count);
  #else
@@@ -915,101 -659,15 +631,15 @@@ vorbis_dec_handle_frame (GstAudioDecode
  {
    ogg_packet *packet;
    ogg_packet_wrapper packet_wrapper;
-   GstFlowReturn ret;
-   gst_ogg_packet_wrapper_map (&packet_wrapper, buffer);
-   packet = gst_ogg_packet_from_wrapper (&packet_wrapper);
-   ret = vorbis_handle_header_packet (vd, packet);
-   gst_ogg_packet_wrapper_unmap (&packet_wrapper, buffer);
-   return ret;
- }
- #define MIN_NUM_HEADERS 3
- static GstFlowReturn
- vorbis_dec_handle_header_caps (GstVorbisDec * vd, GstBuffer * buffer)
- {
    GstFlowReturn result = GST_FLOW_OK;
-   GstCaps *caps;
-   GstStructure *s;
-   const GValue *array;
-   const GValue *value = NULL;
-   GstBuffer *buf = NULL;
-   if ((caps = gst_pad_get_current_caps (vd->sinkpad)) == NULL)
-     goto no_caps;
-   if ((s = gst_caps_get_structure (caps, 0)) == NULL)
-     goto no_caps;
-   array = gst_structure_get_value (s, "streamheader");
-   if (array == NULL || (gst_value_array_get_size (array) < MIN_NUM_HEADERS))
-     goto array_error;
-   /* initial header */
-   value = gst_value_array_get_value (array, 0);
-   buf = gst_value_get_buffer (value);
-   if (!buf)
-     goto null_buffer;
-   result = vorbis_dec_handle_header_buffer (vd, buf);
-   if (result != GST_FLOW_OK)
-     goto buffer_error;
-   /* comment header */
-   value = gst_value_array_get_value (array, 1);
-   buf = gst_value_get_buffer (value);
-   if (!buf)
-     goto null_buffer;
-   result = vorbis_dec_handle_header_buffer (vd, buf);
-   if (result != GST_FLOW_OK)
-     goto buffer_error;
-   /* bitstream codebook header */
-   value = gst_value_array_get_value (array, 2);
-   buf = gst_value_get_buffer (value);
-   if (!buf)
-     goto null_buffer;
-   result = vorbis_dec_handle_header_buffer (vd, buf);
-   if (result != GST_FLOW_OK)
-     goto buffer_error;
+   GstVorbisDec *vd = GST_VORBIS_DEC (dec);
  
-   return result;
- no_caps:
-   {
-     GST_WARNING_OBJECT (vd, "no caps negotiated");
-     return GST_FLOW_NOT_NEGOTIATED;
-   }
- array_error:
-   {
-     GST_WARNING_OBJECT (vd, "streamheader array not found");
-     return GST_FLOW_NOT_NEGOTIATED;
-   }
- null_buffer:
-   {
-     GST_WARNING_OBJECT (vd, "streamheader with null buffer received");
-     return GST_FLOW_NOT_NEGOTIATED;
-   }
- buffer_error:
-   {
-     GST_WARNING_OBJECT (vd, "error handling buffer");
-     return GST_FLOW_NOT_NEGOTIATED;
-   }
- }
- static GstFlowReturn
- vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer)
- {
-   ogg_packet *packet;
-   ogg_packet_wrapper packet_wrapper;
-   GstFlowReturn result = GST_FLOW_OK;
+   /* no draining etc */
+   if (G_UNLIKELY (!buffer))
+     return GST_FLOW_OK;
  
    /* make ogg_packet out of the buffer */
 -  gst_ogg_packet_wrapper_from_buffer (&packet_wrapper, buffer);
 +  gst_ogg_packet_wrapper_map (&packet_wrapper, buffer);
    packet = gst_ogg_packet_from_wrapper (&packet_wrapper);
    /* set some more stuff */
    packet->granulepos = -1;
@@@ -65,23 -62,10 +62,10 @@@ struct _GstVorbisDec 
  #endif
  
    gboolean          initialized;
 -  guint             width;
 +  GstAudioInfo      info;
  
-   /* list of buffers that need timestamps */
-   GList            *queued;
-   /* gather/decode queues for reverse playback */
-   GList            *gather;
-   GList            *decode;
-   GstSegment        segment;
-   gboolean          discont;
-   guint32           seqnum;
-   GstClockTime      last_timestamp;
-   GList            *pendingevents;
    GstTagList       *taglist;
-   
    CopySampleFunc    copy_samples;
  };
  
@@@ -118,8 -97,16 +96,17 @@@ static GstFlowReturn gst_vorbis_enc_out
  #define LOWEST_BITRATE          6000    /* lowest allowed for a 8 kHz stream */
  #define HIGHEST_BITRATE         250001  /* highest allowed for a 44 kHz stream */
  
- static gboolean gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event);
- static GstFlowReturn gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer);
+ static gboolean gst_vorbis_enc_start (GstAudioEncoder * enc);
+ static gboolean gst_vorbis_enc_stop (GstAudioEncoder * enc);
+ static gboolean gst_vorbis_enc_set_format (GstAudioEncoder * enc,
+     GstAudioInfo * info);
+ static GstFlowReturn gst_vorbis_enc_handle_frame (GstAudioEncoder * enc,
+     GstBuffer * in_buf);
 -static GstCaps *gst_vorbis_enc_getcaps (GstAudioEncoder * enc);
++static GstCaps *gst_vorbis_enc_getcaps (GstAudioEncoder * enc,
++    GstCaps * filter);
+ static gboolean gst_vorbis_enc_sink_event (GstAudioEncoder * enc,
+     GstEvent * event);
  static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc);
  
  static void gst_vorbis_enc_dispose (GObject * object);
@@@ -127,33 -114,44 +114,21 @@@ static void gst_vorbis_enc_get_propert
      GValue * value, GParamSpec * pspec);
  static void gst_vorbis_enc_set_property (GObject * object, guint prop_id,
      const GValue * value, GParamSpec * pspec);
- static GstStateChangeReturn gst_vorbis_enc_change_state (GstElement * element,
-     GstStateChange transition);
--static void gst_vorbis_enc_add_interfaces (GType vorbisenc_type);
  
 -GST_BOILERPLATE_FULL (GstVorbisEnc, gst_vorbis_enc, GstAudioEncoder,
 -    GST_TYPE_AUDIO_ENCODER, gst_vorbis_enc_add_interfaces);
 -
 -static void
 -gst_vorbis_enc_add_interfaces (GType vorbisenc_type)
 -{
 -  static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
 -
 -  g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER,
 -      &tag_setter_info);
 -}
 -
 -static void
 -gst_vorbis_enc_base_init (gpointer g_class)
 -{
 -  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 -
 -  gst_element_class_add_pad_template (element_class,
 -      gst_static_pad_template_get (&vorbis_enc_src_factory));
 -  gst_element_class_add_pad_template (element_class,
 -      gst_static_pad_template_get (&vorbis_enc_sink_factory));
 -
 -  gst_element_class_set_details_simple (element_class,
 -      "Vorbis audio encoder", "Codec/Encoder/Audio",
 -      "Encodes audio in Vorbis format",
 -      "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
 -}
 +#define gst_vorbis_enc_parent_class parent_class
 +G_DEFINE_TYPE_WITH_CODE (GstVorbisEnc, gst_vorbis_enc,
-     GST_TYPE_ELEMENT, gst_vorbis_enc_add_interfaces (g_define_type_id));
- static void
- gst_vorbis_enc_add_interfaces (GType vorbisenc_type)
- {
-   static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
-   static const GInterfaceInfo preset_info = { NULL, NULL, NULL };
-   g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER,
-       &tag_setter_info);
-   g_type_add_interface_static (vorbisenc_type, GST_TYPE_PRESET, &preset_info);
- }
++    GST_TYPE_AUDIO_ENCODER, G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
  
  static void
  gst_vorbis_enc_class_init (GstVorbisEncClass * klass)
  {
    GObjectClass *gobject_class;
 +  GstElementClass *gstelement_class;
+   GstAudioEncoderClass *base_class;
  
    gobject_class = (GObjectClass *) klass;
 +  gstelement_class = (GstElementClass *) klass;
+   base_class = (GstAudioEncoderClass *) (klass);
  
    gobject_class->set_property = gst_vorbis_enc_set_property;
    gobject_class->get_property = gst_vorbis_enc_get_property;
        g_param_spec_string ("last-message", "last-message",
            "The last status message", NULL,
            G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-   gstelement_class->change_state =
-       GST_DEBUG_FUNCPTR (gst_vorbis_enc_change_state);
 +
 +  gst_element_class_add_pad_template (gstelement_class,
 +      gst_static_pad_template_get (&vorbis_enc_src_factory));
 +  gst_element_class_add_pad_template (gstelement_class,
 +      gst_static_pad_template_get (&vorbis_enc_sink_factory));
++
 +  gst_element_class_set_details_simple (gstelement_class,
 +      "Vorbis audio encoder", "Codec/Encoder/Audio",
 +      "Encodes audio in Vorbis format",
 +      "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
 +
 -gst_vorbis_enc_init (GstVorbisEnc * vorbisenc, GstVorbisEncClass * klass)
++  base_class->start = GST_DEBUG_FUNCPTR (gst_vorbis_enc_start);
++  base_class->stop = GST_DEBUG_FUNCPTR (gst_vorbis_enc_stop);
++  base_class->set_format = GST_DEBUG_FUNCPTR (gst_vorbis_enc_set_format);
++  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vorbis_enc_handle_frame);
++  base_class->getcaps = GST_DEBUG_FUNCPTR (gst_vorbis_enc_getcaps);
++  base_class->event = GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_event);
+ }
+ static void
++gst_vorbis_enc_init (GstVorbisEnc * vorbisenc)
+ {
+   GstAudioEncoder *enc = GST_AUDIO_ENCODER (vorbisenc);
+   vorbisenc->channels = -1;
+   vorbisenc->frequency = -1;
+   vorbisenc->managed = FALSE;
+   vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
+   vorbisenc->bitrate = BITRATE_DEFAULT;
+   vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
+   vorbisenc->quality = QUALITY_DEFAULT;
+   vorbisenc->quality_set = FALSE;
+   vorbisenc->last_message = NULL;
+   /* arrange granulepos marking (and required perfect ts) */
+   gst_audio_encoder_set_mark_granule (enc, TRUE);
+   gst_audio_encoder_set_perfect_timestamp (enc, TRUE);
  }
  
  static void
@@@ -264,9 -311,9 +294,9 @@@ gst_vorbis_enc_generate_sink_caps (void
  }
  
  static GstCaps *
- gst_vorbis_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
 -gst_vorbis_enc_getcaps (GstAudioEncoder * enc)
++gst_vorbis_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
  {
-   GstVorbisEnc *vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
+   GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
  
    if (vorbisenc->sinkcaps == NULL)
      vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();
@@@ -856,8 -579,8 +562,8 @@@ gst_vorbis_enc_buffer_from_header_packe
    GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
    GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
  
-   GST_DEBUG ("created header packet buffer, %" G_GSIZE_FORMAT " bytes",
+   GST_DEBUG ("created header packet buffer, %d bytes",
 -      GST_BUFFER_SIZE (outbuf));
 +      gst_buffer_get_size (outbuf));
    return outbuf;
  }
  
@@@ -966,59 -602,82 +585,82 @@@ gst_vorbis_enc_sink_event (GstAudioEnco
        } else {
          g_assert_not_reached ();
        }
-       res = gst_pad_push_event (vorbisenc->srcpad, event);
        break;
-     case GST_EVENT_SEGMENT:
-     {
-       const GstSegment *segment;
-       gst_event_parse_segment (event, &segment);
-       if (segment->format == GST_FORMAT_TIME) {
-         gst_segment_copy_into (segment, &vorbisenc->segment);
-       }
-     }
        /* fall through */
      default:
-       res = gst_pad_push_event (vorbisenc->srcpad, event);
        break;
    }
-   return res;
+   /* we only peeked, let base class handle it */
+   return FALSE;
  }
  
- static gboolean
- gst_vorbis_enc_buffer_check_discontinuous (GstVorbisEnc * vorbisenc,
    GstClockTime timestamp, GstClockTime duration)
+ /* push out the buffer and do internal bookkeeping */
+ static GstFlowReturn
gst_vorbis_enc_push_header (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
  {
-   gboolean ret = FALSE;
-   GST_DEBUG_OBJECT (vorbisenc, "exp %" GST_TIME_FORMAT " time %" GST_TIME_FORMAT
-       "dur %" GST_TIME_FORMAT, GST_TIME_ARGS (vorbisenc->expected_ts),
-       GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
-   if (timestamp != GST_CLOCK_TIME_NONE &&
-       vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
-       timestamp + duration != vorbisenc->expected_ts) {
-     /* It turns out that a lot of elements don't generate perfect streams due
-      * to rounding errors. So, we permit small errors (< 3 samples) without
-      * causing a discont.
-      */
-     int threesample = GST_SECOND / vorbisenc->frequency * 3;
-     if ((GstClockTimeDiff) (timestamp - vorbisenc->expected_ts) > threesample) {
-       GST_DEBUG_OBJECT (vorbisenc, "Expected TS %" GST_TIME_FORMAT
-           ", buffer TS %" GST_TIME_FORMAT,
-           GST_TIME_ARGS (vorbisenc->expected_ts), GST_TIME_ARGS (timestamp));
-       ret = TRUE;
-     }
+   GST_DEBUG_OBJECT (vorbisenc,
+       "Pushing buffer with GP %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT,
+       GST_BUFFER_OFFSET_END (buffer),
+       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+   return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc), buffer);
+ }
+ /*
+  * (really really) FIXME: move into core (dixit tpm)
+  */
+ /**
+  * _gst_caps_set_buffer_array:
+  * @caps: a #GstCaps
+  * @field: field in caps to set
+  * @buf: header buffers
+  *
+  * Adds given buffers to an array of buffers set as the given @field
+  * on the given @caps.  List of buffer arguments must be NULL-terminated.
+  *
+  * Returns: input caps with a streamheader field added, or NULL if some error
+  */
+ static GstCaps *
+ _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
+     GstBuffer * buf, ...)
+ {
+   GstStructure *structure = NULL;
+   va_list va;
+   GValue array = { 0 };
+   GValue value = { 0 };
+   g_return_val_if_fail (caps != NULL, NULL);
+   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+   g_return_val_if_fail (field != NULL, NULL);
+   caps = gst_caps_make_writable (caps);
+   structure = gst_caps_get_structure (caps, 0);
+   g_value_init (&array, GST_TYPE_ARRAY);
+   va_start (va, buf);
+   /* put buffers in a fixed list */
+   while (buf) {
 -    g_assert (gst_buffer_is_metadata_writable (buf));
++    g_assert (gst_buffer_is_writable (buf));
+     /* mark buffer */
+     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+     g_value_init (&value, GST_TYPE_BUFFER);
+     buf = gst_buffer_copy (buf);
+     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+     gst_value_set_buffer (&value, buf);
+     gst_buffer_unref (buf);
+     gst_value_array_append_value (&array, &value);
+     g_value_unset (&value);
+     buf = va_arg (va, GstBuffer *);
    }
  
-   if (timestamp != GST_CLOCK_TIME_NONE && duration != GST_CLOCK_TIME_NONE) {
-     vorbisenc->expected_ts = timestamp + duration;
-   } else
-     vorbisenc->expected_ts = GST_CLOCK_TIME_NONE;
+   gst_structure_set_value (structure, field, &array);
+   g_value_unset (&array);
  
-   return ret;
+   return caps;
  }
  
  static GstFlowReturn
@@@ -1026,8 -685,8 +668,9 @@@ gst_vorbis_enc_handle_frame (GstAudioEn
  {
    GstVorbisEnc *vorbisenc;
    GstFlowReturn ret = GST_FLOW_OK;
 -  gfloat *data;
 +  gfloat *data, *ptr;
    gulong size;
++  gsize bsize;
    gulong i, j;
    float **vorbis_buffer;
    GstBuffer *buf1, *buf2, *buf3;
      buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);
  
      /* mark and put on caps */
-     vorbisenc->srccaps = gst_caps_new_simple ("audio/x-vorbis", NULL);
-     caps = vorbisenc->srccaps;
-     caps = gst_vorbis_enc_set_header_on_caps (caps, buf1, buf2, buf3);
+     caps = gst_caps_new_simple ("audio/x-vorbis", NULL);
+     caps = _gst_caps_set_buffer_array (caps, "streamheader",
+         buf1, buf2, buf3, NULL);
  
      /* negotiate with these caps */
-     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
-     gst_pad_set_caps (vorbisenc->srcpad, caps);
+     GST_DEBUG_OBJECT (vorbisenc, "here are the caps: %" GST_PTR_FORMAT, caps);
 -
 -    gst_buffer_set_caps (buf1, caps);
 -    gst_buffer_set_caps (buf2, caps);
 -    gst_buffer_set_caps (buf3, caps);
 -    gst_caps_unref (caps);
++    gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc), caps);
  
      /* push out buffers */
      /* push_buffer takes the reference even for failure */
        goto failed_header_push;
      }
  
-     /* now adjust starting granulepos accordingly if the buffer's timestamp is
-        nonzero */
-     vorbisenc->next_ts = timestamp;
-     vorbisenc->expected_ts = timestamp;
-     vorbisenc->granulepos_offset = gst_util_uint64_scale
-         (running_time, vorbisenc->frequency, GST_SECOND);
-     vorbisenc->subgranule_offset = 0;
-     vorbisenc->subgranule_offset =
-         vorbisenc->next_ts - granulepos_to_timestamp_offset (vorbisenc, 0);
      vorbisenc->header_sent = TRUE;
-     first = TRUE;
    }
  
-   if (vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
-       timestamp < vorbisenc->expected_ts) {
-     int threesample = GST_SECOND / vorbisenc->frequency * 3;
-     guint64 diff = vorbisenc->expected_ts - timestamp;
-     guint64 diff_bytes;
-     gsize size;
-     /* Don't freak out on tiny jitters; use the same < 3 sample
-        tolerance as in the discontinuous detection */
-     if ((GstClockTimeDiff) (vorbisenc->expected_ts - timestamp) > threesample) {
-       GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous "
-           "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
-           "), cannot handle. Clipping buffer.",
-           GST_TIME_ARGS (timestamp), GST_TIME_ARGS (vorbisenc->expected_ts));
-       size = gst_buffer_get_size (buffer);
-       diff_bytes =
-           GST_CLOCK_TIME_TO_FRAMES (diff,
-           vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat);
-       if (diff_bytes >= size) {
-         gst_buffer_unref (buffer);
-         return GST_FLOW_OK;
-       }
-       buffer = gst_buffer_make_writable (buffer);
-       gst_buffer_resize (buffer, diff_bytes, size - diff_bytes);
-       if (GST_BUFFER_DURATION_IS_VALID (buffer))
-         GST_BUFFER_DURATION (buffer) -= diff;
-     }
-     /* adjust the input timestamp in either case */
-     GST_BUFFER_TIMESTAMP (buffer) += diff;
-   }
-   if (gst_vorbis_enc_buffer_check_discontinuous (vorbisenc, timestamp,
-           GST_BUFFER_DURATION (buffer)) && !first) {
-     GST_WARNING_OBJECT (vorbisenc,
-         "Buffer is discontinuous, flushing encoder "
-         "and restarting (Discont from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT
-         ")", GST_TIME_ARGS (vorbisenc->next_ts), GST_TIME_ARGS (timestamp));
-     /* Re-initialise encoder (there's unfortunately no API to flush it) */
-     if ((ret = gst_vorbis_enc_clear (vorbisenc)) != GST_FLOW_OK)
-       return ret;
-     if (!gst_vorbis_enc_setup (vorbisenc))
-       return GST_FLOW_ERROR;    /* Should be impossible, we can only get here if
-                                    we successfully initialised earlier */
-     /* Now, set our granulepos offset appropriately. */
-     vorbisenc->next_ts = timestamp;
-     /* We need to round to the nearest whole number of samples, not just do
-      * a truncating division here */
-     vorbisenc->granulepos_offset = gst_util_uint64_scale
-         (running_time + GST_SECOND / vorbisenc->frequency / 2
-         - vorbisenc->subgranule_offset, vorbisenc->frequency, GST_SECOND);
-     vorbisenc->header_sent = TRUE;
-     /* And our next output buffer must have DISCONT set on it */
-     vorbisenc->next_discont = TRUE;
-   }
+   if (!buffer)
+     return gst_vorbis_enc_clear (vorbisenc);
  
-   /* Sending zero samples to libvorbis marks EOS, so we mustn't do that */
 +  data = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_WRITE);
-   if (bsize == 0) {
-     gst_buffer_unmap (buffer, data, bsize);
-     gst_buffer_unref (buffer);
-     return GST_FLOW_OK;
-   }
 +
    /* data to encode */
 -  data = (gfloat *) GST_BUFFER_DATA (buffer);
 -  size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float));
 +  size = bsize / (vorbisenc->channels * sizeof (float));
 +
 +  ptr = data;
  
    /* expose the buffer to submit data */
    vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
@@@ -1256,8 -817,16 +801,16 @@@ gst_vorbis_enc_output_buffers (GstVorbi
      vorbis_bitrate_addblock (&vorbisenc->vb);
  
      while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
+       GstBuffer *buf;
        GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
-       ret = gst_vorbis_enc_push_packet (vorbisenc, &op);
+       buf = gst_buffer_new_and_alloc (op.bytes);
 -      memcpy (GST_BUFFER_DATA (buf), op.packet, op.bytes);
++      gst_buffer_fill (buf, 0, op.packet, op.bytes);
+       /* tracking granulepos should tell us samples accounted for */
+       ret =
+           gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER
+           (vorbisenc), buf, op.granulepos - vorbisenc->samples_out);
+       vorbisenc->samples_out = op.granulepos;
  
        if (ret != GST_FLOW_OK)
          return ret;
Simple merge
Simple merge
@@@ -782,14 -846,13 +782,14 @@@ gst_audio_test_src_create_red_noise_##t
    gint i, c; \
    gdouble amp = (src->volume * scale); \
    gdouble state = src->red.state; \
 +  gint channels = GST_AUDIO_INFO_CHANNELS (&src->info); \
    \
 -  for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \
 -    for (c = 0; c < src->channels; ++c) { \
 +  for (i = 0; i < src->generate_samples_per_buffer * channels; ) { \
 +    for (c = 0; c < channels; ++c) { \
        while (TRUE) { \
-         gdouble  r = g_rand_double_range (src->gen, -1.0, 1.0); \
+         gdouble r = g_rand_double_range (src->gen, -1.0, 1.0); \
          state += r; \
-         if (state<-8.0f || state>8.0f) state -= r; \
+         if (state < -8.0f || state > 8.0f) state -= r; \
          else break; \
        } \
        samples[i++] = (g##type) (amp * state * 0.0625f); /* /16.0 */ \
@@@ -957,7 -1003,8 +957,8 @@@ gst_audio_test_src_change_wave (GstAudi
        if (!(src->gen))
          src->gen = g_rand_new ();
        src->red.state = 0.0;
 -      src->process = violet_noise_funcs[src->format];
 +      src->process = violet_noise_funcs[idx];
+       break;
      default:
        GST_ERROR ("invalid wave-form");
        break;
Simple merge
Simple merge
Simple merge
Simple merge