Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 28 Sep 2011 15:39:12 +0000 (17:39 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 28 Sep 2011 15:39:12 +0000 (17:39 +0200)
Conflicts:
ext/flac/gstflacenc.c

1  2 
ext/flac/gstflacenc.c

@@@ -149,10 -149,30 +149,19 @@@ enu
  GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
  #define GST_CAT_DEFAULT flacenc_debug
  
 -
 -#define _do_init(type)                                                          \
 -  G_STMT_START{                                                                 \
 -    static const GInterfaceInfo tag_setter_info = {                             \
 -      NULL,                                                                     \
 -      NULL,                                                                     \
 -      NULL                                                                      \
 -    };                                                                          \
 -    g_type_add_interface_static (type, GST_TYPE_TAG_SETTER,                     \
 -                                 &tag_setter_info);                             \
 -  }G_STMT_END
 -
 -GST_BOILERPLATE_FULL (GstFlacEnc, gst_flac_enc, GstAudioEncoder,
 -    GST_TYPE_AUDIO_ENCODER, _do_init);
 +#define gst_flac_enc_parent_class parent_class
 +G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_ELEMENT,
-     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
-     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
++    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
+ static gboolean gst_flac_enc_start (GstAudioEncoder * enc);
+ static gboolean gst_flac_enc_stop (GstAudioEncoder * enc);
+ static gboolean gst_flac_enc_set_format (GstAudioEncoder * enc,
+     GstAudioInfo * info);
+ static GstFlowReturn gst_flac_enc_handle_frame (GstAudioEncoder * enc,
+     GstBuffer * in_buf);
 -static GstCaps *gst_flac_enc_getcaps (GstAudioEncoder * enc);
++static GstCaps *gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter);
+ static gboolean gst_flac_enc_sink_event (GstAudioEncoder * enc,
+     GstEvent * event);
  
  static void gst_flac_enc_finalize (GObject * object);
  
@@@ -244,14 -257,30 +246,16 @@@ static voi
  gst_flac_enc_class_init (GstFlacEncClass * klass)
  {
    GObjectClass *gobject_class;
 +  GstElementClass *gstelement_class;
+   GstAudioEncoderClass *base_class;
  
    gobject_class = (GObjectClass *) klass;
 +  gstelement_class = (GstElementClass *) klass;
+   base_class = (GstAudioEncoderClass *) (klass);
  
 +  GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
 +      "Flac encoding element");
 +
    gobject_class->set_property = gst_flac_enc_set_property;
    gobject_class->get_property = gst_flac_enc_get_property;
    gobject_class->finalize = gst_flac_enc_finalize;
            -G_MAXINT, G_MAXINT,
            DEFAULT_SEEKPOINTS,
            G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
-   gstelement_class->change_state = gst_flac_enc_change_state;
 +
 +  gst_element_class_add_pad_template (gstelement_class,
 +      gst_static_pad_template_get (&src_factory));
 +  gst_element_class_add_pad_template (gstelement_class,
 +      gst_static_pad_template_get (&sink_factory));
 +
 +  gst_element_class_set_details_simple (gstelement_class, "FLAC audio encoder",
 +      "Codec/Encoder/Audio",
 +      "Encodes audio with the FLAC lossless audio encoder",
 +      "Wim Taymans <wim.taymans@chello.be>");
++
++  base_class->start = GST_DEBUG_FUNCPTR (gst_flac_enc_start);
++  base_class->stop = GST_DEBUG_FUNCPTR (gst_flac_enc_stop);
++  base_class->set_format = GST_DEBUG_FUNCPTR (gst_flac_enc_set_format);
++  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_flac_enc_handle_frame);
++  base_class->getcaps = GST_DEBUG_FUNCPTR (gst_flac_enc_getcaps);
++  base_class->event = GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event);
  }
  
  static void
 -gst_flac_enc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass)
 +gst_flac_enc_init (GstFlacEnc * flacenc)
  {
-   flacenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
-   gst_pad_set_chain_function (flacenc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_flac_enc_chain));
-   gst_pad_set_event_function (flacenc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event));
-   gst_pad_set_getcaps_function (flacenc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_flac_enc_sink_getcaps));
-   gst_pad_set_setcaps_function (flacenc->sinkpad,
-       GST_DEBUG_FUNCPTR (gst_flac_enc_sink_setcaps));
-   gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->sinkpad);
-   flacenc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
-   gst_pad_use_fixed_caps (flacenc->srcpad);
-   gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->srcpad);
+   GstAudioEncoder *enc = GST_AUDIO_ENCODER (flacenc);
  
    flacenc->encoder = FLAC__stream_encoder_new ();
-   flacenc->offset = 0;
-   flacenc->samples_written = 0;
-   flacenc->channels = 0;
    gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
-   flacenc->tags = gst_tag_list_new ();
-   flacenc->got_headers = FALSE;
-   flacenc->headers = NULL;
-   flacenc->last_flow = GST_FLOW_OK;
+   /* 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
@@@ -478,12 -535,10 +520,14 @@@ gst_flac_enc_set_metadata (GstFlacEnc 
  
    if (n_images + n_preview_images > 0) {
      GstBuffer *buffer;
++#if 0
      GstCaps *caps;
      GstStructure *structure;
      GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
++#endif
      gint i;
 +    guint8 *data;
 +    gsize size;
  
      for (i = 0; i < n_images + n_preview_images; i++) {
        if (i < n_images) {
        flacenc->meta[entries] =
            FLAC__metadata_object_new (FLAC__METADATA_TYPE_PICTURE);
  
++#if 0
        caps = gst_buffer_get_caps (buffer);
        structure = gst_caps_get_structure (caps, 0);
  
          image_type = (i < n_images) ? 0x00 : 0x01;
        else
          image_type = image_type + 2;
++#endif
  
 +      data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
        FLAC__metadata_object_picture_set_data (flacenc->meta[entries],
 -          GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE);
 +          data, size, TRUE);
 +      gst_buffer_unmap (buffer, data, size);
 +
++#if 0
        /* FIXME: There's no way to set the picture type in libFLAC */
        flacenc->meta[entries]->data.picture.type = image_type;
        FLAC__metadata_object_picture_set_mime_type (flacenc->meta[entries],
            (char *) gst_structure_get_name (structure), TRUE);
--
        gst_caps_unref (caps);
++#endif
++
        gst_buffer_unref (buffer);
        entries++;
      }
@@@ -611,14 -663,17 +659,17 @@@ gst_flac_enc_caps_append_structure_with
  }
  
  static GstCaps *
- gst_flac_enc_sink_getcaps (GstPad * pad)
 -gst_flac_enc_getcaps (GstAudioEncoder * enc)
++gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
  {
-   GstCaps *ret = NULL;
+   GstCaps *ret = NULL, *caps = NULL;
+   GstPad *pad;
+   pad = GST_AUDIO_ENCODER_SINK_PAD (enc);
  
    GST_OBJECT_LOCK (pad);
  
--  if (GST_PAD_CAPS (pad)) {
--    ret = gst_caps_ref (GST_PAD_CAPS (pad));
++  if (gst_pad_has_current_caps (pad)) {
++    ret = gst_pad_get_current_caps (pad);
    } else {
      gint i, c;
  
  static guint64
  gst_flac_enc_query_peer_total_samples (GstFlacEnc * flacenc, GstPad * pad)
  {
--  GstFormat fmt = GST_FORMAT_DEFAULT;
    gint64 duration;
  
    GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
--  if (gst_pad_query_peer_duration (pad, &fmt, &duration)
--      && fmt == GST_FORMAT_DEFAULT && duration != GST_CLOCK_TIME_NONE)
++  if (gst_pad_query_peer_duration (pad, GST_FORMAT_DEFAULT, &duration)
++      && duration != GST_CLOCK_TIME_NONE)
      goto done;
  
--  fmt = GST_FORMAT_TIME;
    GST_DEBUG_OBJECT (flacenc, "querying peer for TIME format duration");
  
--  if (gst_pad_query_peer_duration (pad, &fmt, &duration) &&
--      fmt == GST_FORMAT_TIME && duration != GST_CLOCK_TIME_NONE) {
++  if (gst_pad_query_peer_duration (pad, GST_FORMAT_TIME, &duration)
++      && duration != GST_CLOCK_TIME_NONE) {
      GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
          GST_TIME_ARGS (duration));
      duration = GST_CLOCK_TIME_TO_FRAMES (duration, flacenc->sample_rate);
@@@ -832,16 -885,16 +879,20 @@@ gst_flac_enc_seek_callback (const FLAC_
    GstFlacEnc *flacenc;
    GstEvent *event;
    GstPad *peerpad;
++  GstSegment seg;
  
    flacenc = GST_FLAC_ENC (client_data);
  
    if (flacenc->stopped)
      return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
  
--  event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
--      absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
++  gst_segment_init (&seg, GST_FORMAT_BYTES);
++  seg.start = absolute_byte_offset;
++  seg.stop = GST_BUFFER_OFFSET_NONE;
++  seg.time = 0;
++  event = gst_event_new_segment (&seg);
  
-   if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
+   if ((peerpad = gst_pad_get_peer (GST_AUDIO_ENCODER_SRC_PAD (flacenc)))) {
      gboolean ret = gst_pad_send_event (peerpad, event);
  
      gst_object_unref (peerpad);
@@@ -984,14 -1026,12 +1034,13 @@@ push_headers
      GstBuffer *buf;
  
      buf = GST_BUFFER (l->data);
--    gst_buffer_set_caps (buf, caps);
      GST_LOG_OBJECT (enc, "Pushing header buffer, size %u bytes",
 -        GST_BUFFER_SIZE (buf));
 +        gst_buffer_get_size (buf));
 +#if 0
      GST_MEMDUMP_OBJECT (enc, "header buffer", GST_BUFFER_DATA (buf),
          GST_BUFFER_SIZE (buf));
-     (void) gst_pad_push (enc->srcpad, buf);
 +#endif
+     ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buf);
      l->data = NULL;
    }
    g_list_free (enc->headers);
@@@ -1015,33 -1057,8 +1066,8 @@@ gst_flac_enc_write_callback (const FLAC
      return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
  
    outbuf = gst_buffer_new_and_alloc (bytes);
 -  memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
 +  gst_buffer_fill (outbuf, 0, buffer, bytes);
  
-   if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
-     guint64 granulepos;
-     GST_BUFFER_TIMESTAMP (outbuf) = flacenc->start_ts +
-         GST_FRAMES_TO_CLOCK_TIME (flacenc->samples_written,
-         flacenc->sample_rate);
-     GST_BUFFER_DURATION (outbuf) =
-         GST_FRAMES_TO_CLOCK_TIME (samples, flacenc->sample_rate);
-     /* offset_end = granulepos for ogg muxer */
-     granulepos =
-         flacenc->granulepos_offset + flacenc->samples_written + samples;
-     GST_BUFFER_OFFSET_END (outbuf) = granulepos;
-     /* offset = timestamp corresponding to granulepos for ogg muxer
-      * (see vorbisenc for a much more elaborate version of this) */
-     GST_BUFFER_OFFSET (outbuf) =
-         GST_FRAMES_TO_CLOCK_TIME (granulepos, flacenc->sample_rate);
-   } else {
-     GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
-     GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
-     GST_BUFFER_OFFSET (outbuf) =
-         flacenc->samples_written * flacenc->width * flacenc->channels;
-     GST_BUFFER_OFFSET_END (outbuf) = 0;
-     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_IN_CAPS);
-   }
    /* we assume libflac passes us stuff neatly framed */
    if (!flacenc->got_headers) {
      if (samples == 0) {
        flacenc->got_headers = TRUE;
      }
    } else if (flacenc->got_headers && samples == 0) {
+     /* header fixup, push downstream directly */
      GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT
          ", size=%u", flacenc->offset, (guint) bytes);
 +#if 0
      GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment",
          GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
 -    gst_buffer_set_caps (outbuf,
 -        GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (flacenc)));
 +#endif
+     ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (flacenc), outbuf);
    } else {
+     /* regular frame data, pass to base class */
      GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
          "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
          samples, (guint) bytes, flacenc->offset);
@@@ -1110,13 -1127,13 +1136,14 @@@ gst_flac_enc_sink_event (GstAudioEncode
    GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
  
    switch (GST_EVENT_TYPE (event)) {
--    case GST_EVENT_NEWSEGMENT:{
--      GstFormat format;
++    case GST_EVENT_SEGMENT:{
++      GstSegment seg;
        gint64 start, stream_time;
  
        if (flacenc->offset == 0) {
--        gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
--            &stream_time);
++        gst_event_copy_segment (event, &seg);
++        start = seg.start;
++        stream_time = seg.time;
        } else {
          start = -1;
          stream_time = -1;
          else
            GST_DEBUG ("Not handling newsegment event with non-zero start");
        } else {
--        GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
--            0, -1, 0);
++        GstEvent *e;
  
-         ret = gst_pad_push_event (flacenc->srcpad, e);
++        gst_segment_init (&seg, GST_FORMAT_BYTES);
++        e = gst_event_new_segment (&seg);
+         ret = gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc), e);
        }
  
        if (stream_time > 0) {
@@@ -1197,46 -1188,29 +1199,30 @@@ gst_flac_enc_handle_frame (GstAudioEnco
    gint samples, width;
    gulong i;
    FLAC__bool res;
 +  gpointer bdata;
  
-   flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
+   flacenc = GST_FLAC_ENC (enc);
  
-   /* make sure setcaps has been called and the encoder is set up */
-   if (G_UNLIKELY (flacenc->depth == 0))
-     return GST_FLOW_NOT_NEGOTIATED;
+   /* base class ensures configuration */
+   g_return_val_if_fail (flacenc->depth != 0, GST_FLOW_NOT_NEGOTIATED);
  
    width = flacenc->width;
  
-   /* Save the timestamp of the first buffer. This will be later
-    * used as offset for all following buffers */
-   if (flacenc->start_ts == GST_CLOCK_TIME_NONE) {
-     if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
-       flacenc->start_ts = GST_BUFFER_TIMESTAMP (buffer);
-       flacenc->granulepos_offset = gst_util_uint64_scale
-           (GST_BUFFER_TIMESTAMP (buffer), flacenc->sample_rate, GST_SECOND);
+   if (G_UNLIKELY (!buffer)) {
+     if (flacenc->eos) {
+       FLAC__stream_encoder_finish (flacenc->encoder);
      } else {
-       flacenc->start_ts = 0;
-       flacenc->granulepos_offset = 0;
+       /* can't handle intermittent draining/resyncing */
+       GST_ELEMENT_WARNING (flacenc, STREAM, FORMAT, (NULL),
+           ("Stream discontinuity detected. "
+               "The output may have wrong timestamps, "
+               "consider using audiorate to handle discontinuities"));
      }
+     return flacenc->last_flow;
    }
  
-   /* Check if we have a continous stream, if not drop some samples or the buffer or
-    * insert some silence samples */
-   if (flacenc->next_ts != GST_CLOCK_TIME_NONE
-       && GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
-     gst_flac_enc_check_discont (flacenc, flacenc->next_ts,
-         GST_BUFFER_TIMESTAMP (buffer));
-   }
-   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)
-       && GST_BUFFER_DURATION_IS_VALID (buffer))
-     flacenc->next_ts =
-         GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
-   else
-     flacenc->next_ts = GST_CLOCK_TIME_NONE;
 -  insize = GST_BUFFER_SIZE (buffer);
 -  samples = insize / (width >> 3);
 +  bdata = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_READ);
 +  samples = bsize / (width >> 3);
  
    data = g_malloc (samples * sizeof (FLAC__int32));
  
    } else {
      g_assert_not_reached ();
    }
-   gst_buffer_unref (buffer);
 +  gst_buffer_unmap (buffer, bdata, bsize);
  
    res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
        (const FLAC__int32 *) data, samples / flacenc->channels);