ext/flac/gstflacenc.*: Fix seeking, so that flacenc can rewrite the header with the...
authorTim-Philipp Müller <tim@centricular.net>
Mon, 24 Oct 2005 15:50:06 +0000 (15:50 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Mon, 24 Oct 2005 15:50:06 +0000 (15:50 +0000)
Original commit message from CVS:
* ext/flac/gstflacenc.c: (gst_flacenc_base_init),
(gst_flacenc_init), (gst_flacenc_sink_setcaps),
(gst_flacenc_seek_callback), (gst_flacenc_write_callback),
(gst_flacenc_sink_event), (gst_flacenc_chain),
(gst_flacenc_set_property), (gst_flacenc_get_property),
(gst_flacenc_change_state):
* ext/flac/gstflacenc.h:
Fix seeking, so that flacenc can rewrite the header with the
correct duration and amount of samples and all that at EOS;
also set timestamps and granulepos on outgoing buffers; add
debug category; fix state change function.

ChangeLog
ext/flac/gstflacenc.c
ext/flac/gstflacenc.h

index d9755cb..5f35c01 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2005-10-24  Tim-Philipp Müller  <tim at centricular dot net>
+
+       * ext/flac/gstflacenc.c: (gst_flacenc_base_init),
+       (gst_flacenc_init), (gst_flacenc_sink_setcaps),
+       (gst_flacenc_seek_callback), (gst_flacenc_write_callback),
+       (gst_flacenc_sink_event), (gst_flacenc_chain),
+       (gst_flacenc_set_property), (gst_flacenc_get_property),
+       (gst_flacenc_change_state):
+       * ext/flac/gstflacenc.h:
+         Fix seeking, so that flacenc can rewrite the header with the
+         correct duration and amount of samples and all that at EOS;
+         also set timestamps and granulepos on outgoing buffers; add
+         debug category; fix state change function.
+         
 2005-10-24  Julien MOUTTE  <julien@moutte.net>
 
        * gst/videomixer/videomixer.c: Don't restrict video geometry
index 84a5682..f947a7b 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include <gstflacenc.h>
+#include <gst/audio/audio.h>
 #include <gst/tag/tag.h>
 #include <gst/gsttagsetter.h>
 #include "flac_compat.h"
@@ -37,6 +38,14 @@ GstElementDetails flacenc_details = {
   "Wim Taymans <wim.taymans@chello.be>",
 };
 
+#define FLAC_SINK_CAPS \
+  "audio/x-raw-int, "               \
+  "endianness = (int) BYTE_ORDER, " \
+  "signed = (boolean) TRUE, "       \
+  "width = (int) 16, "              \
+  "depth = (int) 16, "              \
+  "rate = (int) [ 11025, 48000 ], " \
+  "channels = (int) [ 1, 2 ]"
 
 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
@@ -47,15 +56,9 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-raw-int, "
-        "endianness = (int) BYTE_ORDER, "
-        "signed = (boolean) TRUE, "
-        "width = (int) 16, "
-        "depth = (int) 16, "
-        "rate = (int) [ 11025, 48000 ], " "channels = (int) [ 1, 2 ]")
+    GST_STATIC_CAPS (FLAC_SINK_CAPS)
     );
 
-
 enum
 {
   PROP_0,
@@ -74,6 +77,9 @@ enum
   PROP_RICE_PARAMETER_SEARCH_DIST
 };
 
+GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
+#define GST_CAT_DEFAULT flacenc_debug
+
 
 #define _do_init(type)                                                          \
   G_STMT_START{                                                                 \
@@ -89,7 +95,6 @@ enum
 GST_BOILERPLATE_FULL (GstFlacEnc, gst_flacenc, GstElement, GST_TYPE_ELEMENT,
     _do_init);
 
-
 static void gst_flacenc_finalize (GObject * object);
 
 static gboolean gst_flacenc_sink_setcaps (GstPad * pad, GstCaps * caps);
@@ -183,6 +188,9 @@ gst_flacenc_base_init (gpointer g_class)
       gst_static_pad_template_get (&sink_factory));
 
   gst_element_class_set_details (element_class, &flacenc_details);
+
+  GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
+      "Flac encoding element");
 }
 
 static void
@@ -298,6 +306,7 @@ gst_flacenc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass)
   flacenc->encoder = FLAC__seekable_stream_encoder_new ();
 
   flacenc->offset = 0;
+  flacenc->samples_written = 0;
   gst_flacenc_update_quality (flacenc, DEFAULT_QUALITY);
   flacenc->tags = gst_tag_list_new ();
 }
@@ -378,7 +387,7 @@ gst_flacenc_sink_setcaps (GstPad * pad, GstCaps * caps)
       || !gst_structure_get_int (structure, "depth", &flacenc->depth)
       || !gst_structure_get_int (structure, "rate", &flacenc->sample_rate))
     /* we got caps incompatible with the template? */
-    g_assert_not_reached ();
+    g_return_val_if_reached (FALSE);
 
   caps = gst_caps_new_simple ("audio/x-flac",
       "channels", G_TYPE_INT, flacenc->channels,
@@ -487,27 +496,30 @@ gst_flacenc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
     FLAC__uint64 absolute_byte_offset, void *client_data)
 {
   GstFlacEnc *flacenc;
+  GstEvent *event;
+  GstPad *peerpad;
 
   flacenc = GST_FLACENC (client_data);
 
   if (flacenc->stopped)
     return FLAC__STREAM_ENCODER_OK;
 
-  g_warning ("seeking has not been ported from 0.8 yet");
+  event = gst_event_new_newsegment (TRUE, 1.0, GST_FORMAT_BYTES,
+      absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
 
+  if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
+    gboolean ret = gst_pad_send_event (peerpad, event);
 
-#if 0
-  GstEvent *event;
-
-  event =
-      gst_event_new_seek ((GstSeekType) (int) (GST_FORMAT_BYTES |
-          GST_SEEK_METHOD_SET), absolute_byte_offset);
+    gst_object_unref (peerpad);
 
-  if (event) {
-    gst_pad_push (flacenc->srcpad, GST_DATA (event));
-    flacenc->offset = absolute_byte_offset;
+    GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
+        (ret) ? "succeeded" : "failed");
+  } else {
+    GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
+        absolute_byte_offset);
   }
-#endif
+
+  flacenc->offset = absolute_byte_offset;
 
   return FLAC__STREAM_ENCODER_OK;
 }
@@ -517,23 +529,48 @@ gst_flacenc_write_callback (const FLAC__SeekableStreamEncoder * encoder,
     const FLAC__byte buffer[], unsigned bytes,
     unsigned samples, unsigned current_frame, void *client_data)
 {
+  GstFlowReturn ret;
   GstFlacEnc *flacenc;
   GstBuffer *outbuf;
 
   flacenc = GST_FLACENC (client_data);
 
   if (flacenc->stopped)
-    return FLAC__STREAM_ENCODER_OK;
+    return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
 
-  outbuf = gst_buffer_new_and_alloc (bytes);
+  if (gst_pad_alloc_buffer (flacenc->srcpad, flacenc->offset, bytes,
+          GST_PAD_CAPS (flacenc->srcpad), &outbuf) != GST_FLOW_OK) {
+    return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+  }
 
   memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
-  /* fixme: set timestamps, offsets, durations, your mom's phone # */
 
-  gst_pad_push (flacenc->srcpad, outbuf);
+  if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
+    GST_BUFFER_TIMESTAMP (outbuf) =
+        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 */
+    GST_BUFFER_OFFSET_END (outbuf) = flacenc->samples_written + samples;
+  } else {
+    GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
+    GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
+  }
+
+  GST_DEBUG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
+      "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+      samples, bytes, flacenc->offset);
+
+  ret = gst_pad_push (flacenc->srcpad, outbuf);
+
   flacenc->offset += bytes;
+  flacenc->samples_written += samples;
 
-  return FLAC__STREAM_ENCODER_OK;
+  if (ret != GST_FLOW_OK && GST_FLOW_IS_FATAL (ret))
+    return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+
+  return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
 }
 
 static FLAC__SeekableStreamEncoderTellStatus
@@ -552,14 +589,48 @@ gst_flacenc_sink_event (GstPad * pad, GstEvent * event)
 {
   GstFlacEnc *flacenc;
   GstTagList *taglist;
-  gboolean ret;
+  gboolean ret = TRUE;
 
   flacenc = GST_FLACENC (gst_pad_get_parent (pad));
 
+  GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
+
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NEWSEGMENT:{
+      GstFormat format;
+      gint64 start, stream_time;
+
+      GST_STREAM_LOCK (pad);
+      if (flacenc->offset == 0) {
+        gst_event_parse_newsegment (event, NULL, NULL, &format, &start, NULL,
+            &stream_time);
+      } else {
+        start = -1;
+      }
+      if (start != 0) {
+        if (flacenc->offset > 0)
+          GST_DEBUG ("Not handling mid-stream newsegment event");
+        else
+          GST_DEBUG ("Not handling newsegment event with non-zero start");
+      } else {
+        GstEvent *e = gst_event_new_newsegment (FALSE, 1.0, GST_FORMAT_BYTES,
+            0, -1, 0);
+
+        ret = gst_pad_push_event (flacenc->srcpad, e);
+      }
+      if (stream_time != 0) {
+        GST_DEBUG ("Not handling non-zero stream time");
+      }
+      gst_event_unref (event);
+      /* don't push it downstream, we'll generate our own via seek to 0 */
+      GST_STREAM_UNLOCK (pad);
+      break;
+    }
     case GST_EVENT_EOS:
+      GST_STREAM_LOCK (pad);
       FLAC__seekable_stream_encoder_finish (flacenc->encoder);
       ret = gst_pad_event_default (pad, event);
+      GST_STREAM_UNLOCK (pad);
       break;
     case GST_EVENT_TAG:
       if (flacenc->tags) {
@@ -568,7 +639,9 @@ gst_flacenc_sink_event (GstPad * pad, GstEvent * event)
       } else {
         g_assert_not_reached ();
       }
+      GST_STREAM_LOCK (pad);
       ret = gst_pad_event_default (pad, event);
+      GST_STREAM_UNLOCK (pad);
       break;
     default:
       ret = gst_pad_event_default (pad, event);
@@ -590,7 +663,6 @@ gst_flacenc_chain (GstPad * pad, GstBuffer * buffer)
   gulong i;
   FLAC__bool res;
 
-  /* we now have a ref on flacenc */
   flacenc = GST_FLACENC (gst_pad_get_parent (pad));
 
   depth = flacenc->depth;
@@ -635,6 +707,8 @@ gst_flacenc_set_property (GObject * object, guint prop_id,
 {
   GstFlacEnc *this = GST_FLACENC (object);
 
+  GST_LOCK (this);
+
   switch (prop_id) {
     case PROP_QUALITY:
       gst_flacenc_update_quality (this, g_value_get_enum (value));
@@ -689,8 +763,10 @@ gst_flacenc_set_property (GObject * object, guint prop_id,
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      return;
+      break;
   }
+
+  GST_UNLOCK (this);
 }
 
 static void
@@ -699,6 +775,8 @@ gst_flacenc_get_property (GObject * object, guint prop_id,
 {
   GstFlacEnc *this = GST_FLACENC (object);
 
+  GST_LOCK (this);
+
   switch (prop_id) {
     case PROP_QUALITY:
       g_value_set_enum (value, this->quality);
@@ -762,11 +840,14 @@ gst_flacenc_get_property (GObject * object, guint prop_id,
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
+
+  GST_UNLOCK (this);
 }
 
 static GstStateChangeReturn
 gst_flacenc_change_state (GstElement * element, GstStateChange transition)
 {
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
   GstFlacEnc *flacenc = GST_FLACENC (element);
 
   switch (transition) {
@@ -775,6 +856,13 @@ gst_flacenc_change_state (GstElement * element, GstStateChange transition)
       flacenc->stopped = FALSE;
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
@@ -784,6 +872,7 @@ gst_flacenc_change_state (GstElement * element, GstStateChange transition)
         FLAC__seekable_stream_encoder_finish (flacenc->encoder);
       }
       flacenc->offset = 0;
+      flacenc->samples_written = 0;
       if (flacenc->meta) {
         FLAC__metadata_object_delete (flacenc->meta[0]);
         g_free (flacenc->meta);
@@ -795,8 +884,5 @@ gst_flacenc_change_state (GstElement * element, GstStateChange transition)
       break;
   }
 
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
-  return GST_STATE_CHANGE_SUCCESS;
+  return ret;
 }
index 82a6cb2..73c4028 100644 (file)
@@ -47,6 +47,7 @@ struct _GstFlacEnc {
   gboolean      first;
   GstBuffer    *first_buf;
   guint64       offset;
+  guint64       samples_written;
   gboolean      eos;
   gint                  channels;
   gint                  depth;