matroskamux: For audio tracks, take the default duration from the first buffer
authorSebastian Dröge <sebastian@centricular.com>
Tue, 18 Jul 2017 07:41:40 +0000 (10:41 +0300)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 25 Jul 2017 08:28:46 +0000 (11:28 +0300)
... if we don't have any better idea from the caps. This allows writing
SimpleBlocks for a majority of audio streams where the duration of
frames is usually fixed. And as a side effect, allows VLC to play
streams with Opus as it only works with SimpleBlocks currently:
  https://trac.videolan.org/vlc/ticket/18545

https://bugzilla.gnome.org/show_bug.cgi?id=784969

gst/matroska/matroska-mux.c

index fdabe5b..6af282b 100644 (file)
@@ -2723,7 +2723,8 @@ gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
  * Start a new matroska file (write headers etc...)
  */
 static void
-gst_matroska_mux_start (GstMatroskaMux * mux)
+gst_matroska_mux_start (GstMatroskaMux * mux, GstMatroskaPad * first_pad,
+    GstBuffer * first_pad_buf)
 {
   GstEbmlWrite *ebml = mux->ebml_write;
   const gchar *doctype;
@@ -2893,6 +2894,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
   for (collected = mux->collect->data; collected;
       collected = g_slist_next (collected)) {
     GstMatroskaPad *collect_pad;
+    GstBuffer *buf;
 
     collect_pad = (GstMatroskaPad *) collected->data;
 
@@ -2900,6 +2902,23 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
     if (collect_pad->track->codec_id == NULL)
       continue;
 
+    /* For audio tracks, use the first buffers duration as the default
+     * duration if we didn't get any better idea from the caps event already
+     */
+    if (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO &&
+        collect_pad->track->default_duration == 0) {
+      if (collect_pad == first_pad)
+        buf = first_pad_buf ? gst_buffer_ref (first_pad_buf) : NULL;
+      else
+        buf = gst_collect_pads_peek (mux->collect, collected->data);
+
+      if (buf && GST_BUFFER_DURATION_IS_VALID (buf))
+        collect_pad->track->default_duration =
+            GST_BUFFER_DURATION (buf) + collect_pad->track->codec_delay;
+      if (buf)
+        gst_buffer_unref (buf);
+    }
+
     collect_pad->track->num = tracknum++;
     child = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TRACKENTRY);
     gst_matroska_mux_track_header (mux, collect_pad->track);
@@ -3814,7 +3833,7 @@ gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
   GstClockTime buffer_timestamp;
   GstMatroskaMux *mux = GST_MATROSKA_MUX (user_data);
   GstEbmlWrite *ebml = mux->ebml_write;
-  GstMatroskaPad *best;
+  GstMatroskaPad *best = (GstMatroskaPad *) data;
   GstFlowReturn ret = GST_FLOW_OK;
   GST_DEBUG_OBJECT (mux, "Collected pads");
 
@@ -3827,14 +3846,11 @@ gst_matroska_mux_handle_buffer (GstCollectPads * pads, GstCollectData * data,
     }
     mux->state = GST_MATROSKA_MUX_STATE_HEADER;
     gst_ebml_start_streamheader (ebml);
-    gst_matroska_mux_start (mux);
+    gst_matroska_mux_start (mux, best, buf);
     gst_matroska_mux_stop_streamheader (mux);
     mux->state = GST_MATROSKA_MUX_STATE_DATA;
   }
 
-  /* provided with stream to write from */
-  best = (GstMatroskaPad *) data;
-
   /* if there is no best pad, we have reached EOS */
   if (best == NULL) {
     GST_DEBUG_OBJECT (mux, "No best pad. Finishing...");