vorbisenc: only push header buffers following initial events
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Sun, 9 Oct 2011 19:19:32 +0000 (21:19 +0200)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Sun, 9 Oct 2011 19:20:35 +0000 (21:20 +0200)
ext/vorbis/gstvorbisenc.c
ext/vorbis/gstvorbisenc.h

index 6aac4ab..b490d10 100644 (file)
@@ -106,6 +106,8 @@ static GstFlowReturn gst_vorbis_enc_handle_frame (GstAudioEncoder * enc,
 static GstCaps *gst_vorbis_enc_getcaps (GstAudioEncoder * enc);
 static gboolean gst_vorbis_enc_sink_event (GstAudioEncoder * enc,
     GstEvent * event);
+static GstFlowReturn gst_vorbis_enc_pre_push (GstAudioEncoder * enc,
+    GstBuffer ** buffer);
 
 static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc);
 
@@ -163,6 +165,7 @@ gst_vorbis_enc_class_init (GstVorbisEncClass * klass)
   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);
+  base_class->pre_push = GST_DEBUG_FUNCPTR (gst_vorbis_enc_pre_push);
 
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
       g_param_spec_int ("max-bitrate", "Maximum Bitrate",
@@ -255,6 +258,8 @@ gst_vorbis_enc_stop (GstAudioEncoder * enc)
   vorbisenc->last_message = NULL;
   gst_tag_list_free (vorbisenc->tags);
   vorbisenc->tags = NULL;
+  g_slist_foreach (vorbisenc->headers, (GFunc) gst_buffer_unref, NULL);
+  vorbisenc->headers = NULL;
 
   return TRUE;
 }
@@ -620,6 +625,8 @@ gst_vorbis_enc_push_header (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
       "Pushing buffer with GP %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT,
       GST_BUFFER_OFFSET_END (buffer),
       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+  gst_buffer_set_caps (buffer,
+      GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc)));
   return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc), buffer);
 }
 
@@ -740,20 +747,16 @@ gst_vorbis_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
     gst_buffer_set_caps (buf1, caps);
     gst_buffer_set_caps (buf2, caps);
     gst_buffer_set_caps (buf3, caps);
+    gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc), caps);
     gst_caps_unref (caps);
 
-    /* push out buffers */
-    /* push_buffer takes the reference even for failure */
-    if ((ret = gst_vorbis_enc_push_header (vorbisenc, buf1)) != GST_FLOW_OK)
-      goto failed_header_push;
-    if ((ret = gst_vorbis_enc_push_header (vorbisenc, buf2)) != GST_FLOW_OK) {
-      buf2 = NULL;
-      goto failed_header_push;
-    }
-    if ((ret = gst_vorbis_enc_push_header (vorbisenc, buf3)) != GST_FLOW_OK) {
-      buf3 = NULL;
-      goto failed_header_push;
-    }
+    /* store buffers for later pre_push sending */
+    g_slist_foreach (vorbisenc->headers, (GFunc) gst_buffer_unref, NULL);
+    vorbisenc->headers = NULL;
+    GST_DEBUG_OBJECT (vorbisenc, "storing header buffers");
+    vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf3);
+    vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf2);
+    vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf1);
 
     vorbisenc->header_sent = TRUE;
   }
@@ -785,18 +788,6 @@ gst_vorbis_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
   ret = gst_vorbis_enc_output_buffers (vorbisenc);
 
   return ret;
-
-  /* error cases */
-failed_header_push:
-  {
-    GST_WARNING_OBJECT (vorbisenc, "Failed to push headers");
-    /* buf1 is always already unreffed */
-    if (buf2)
-      gst_buffer_unref (buf2);
-    if (buf3)
-      gst_buffer_unref (buf3);
-    return ret;
-  }
 }
 
 static GstFlowReturn
@@ -836,6 +827,36 @@ gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc)
   return GST_FLOW_OK;
 }
 
+static GstFlowReturn
+gst_vorbis_enc_pre_push (GstAudioEncoder * enc, GstBuffer ** buffer)
+{
+  GstVorbisEnc *vorbisenc;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  vorbisenc = GST_VORBISENC (enc);
+
+  /* FIXME 0.11 ? get rid of this special ogg stuff and have it
+   * put and use 'codec data' in caps like anything else,
+   * with all the usual out-of-band advantage etc */
+  if (G_UNLIKELY (vorbisenc->headers)) {
+    GSList *header = vorbisenc->headers;
+
+    /* try to push all of these, if we lose one, might as well lose all */
+    while (header) {
+      if (ret == GST_FLOW_OK)
+        ret = gst_vorbis_enc_push_header (vorbisenc, header->data);
+      else
+        gst_vorbis_enc_push_header (vorbisenc, header->data);
+      header = g_slist_next (header);
+    }
+
+    g_slist_free (vorbisenc->headers);
+    vorbisenc->headers = NULL;
+  }
+
+  return ret;
+}
+
 static void
 gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value,
     GParamSpec * pspec)
index 18d1e55..ffc60e6 100644 (file)
@@ -81,6 +81,7 @@ struct _GstVorbisEnc {
   gboolean         setup;
   gboolean         header_sent;
   gchar           *last_message;
+  GSList          *headers;
 };
 
 struct _GstVorbisEncClass {