qtdemux: fix framerate calculation for fragmented format
authorSeungha Yang <sh.yang@lge.com>
Tue, 26 Jan 2016 13:37:30 +0000 (22:37 +0900)
committerSebastian Dröge <sebastian@centricular.com>
Fri, 29 Jan 2016 10:01:44 +0000 (11:01 +0100)
qtdemux calculates framerate using duration and the number of sample.
In case of fragmented mp4 format, however, the number of sample can
be figure out after parsing every moof box. Because qtdemux does not
parse every moof in QTDEMUX_STATE_HEADER state, it will cause incorrect
framerate calculation.

This patch will triger gst_qtdemux_configure_stream() for every new moof.
Then, framerate will be calculated by using duration and n_samples of the moof.

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

gst/isomp4/qtdemux.c

index f0b368b..de5f5d5 100644 (file)
@@ -253,6 +253,9 @@ struct _QtDemuxStream
   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
   guint32 first_duration;       /* duration in timescale of first sample, used for figuring out
                                    the framerate, in timescale units */
+  guint32 n_samples_moof;       /* sample count in a moof */
+  guint64 duration_moof;        /* duration in timescale of a moof, used for figure out
+                                 * the framerate of fragmented format stream */
   guint32 offset_in_sample;
   guint32 max_buffer_size;
 
@@ -1817,6 +1820,8 @@ _create_stream (void)
   stream->protection_scheme_type = 0;
   stream->protection_scheme_version = 0;
   stream->protection_scheme_info = NULL;
+  stream->n_samples_moof = 0;
+  stream->duration_moof = 0;
   g_queue_init (&stream->protection_scheme_event_queue);
   return stream;
 }
@@ -2293,6 +2298,9 @@ gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
   stream->stbl_index = -1;
   stream->n_samples = 0;
   stream->time_position = 0;
+
+  stream->n_samples_moof = 0;
+  stream->duration_moof = 0;
 }
 
 static void
@@ -2898,6 +2906,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
     *running_offset += size;
     timestamp += dur;
+    stream->duration_moof += dur;
     sample++;
   }
 
@@ -2905,6 +2914,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
 
   stream->n_samples += samples_count;
+  stream->n_samples_moof += samples_count;
 
   if (stream->pending_seek != NULL)
     stream->pending_seek = NULL;
@@ -3498,6 +3508,10 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
     if (qtdemux->upstream_format_is_time)
       gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
 
+    /* initialise moof sample data */
+    stream->n_samples_moof = 0;
+    stream->duration_moof = 0;
+
     /* Track Run node */
     trun_node =
         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
@@ -3514,6 +3528,10 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
      * base is end of current traf */
     base_offset = running_offset;
     running_offset = -1;
+
+    if (stream->n_samples_moof && stream->duration_moof)
+      stream->new_caps = TRUE;
+
   next:
     /* iterate all siblings */
     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
@@ -6940,19 +6958,34 @@ gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
         stream->fps_n = stream->timescale;
         stream->fps_d = 1;
       } else {
+        GstClockTime avg_duration;
+        guint64 duration;
+        guint32 n_samples;
+
+        /* duration and n_samples can be updated for fragmented format
+         * so, framerate of fragmented format is calculated using data in a moof */
+        if (qtdemux->fragmented && stream->n_samples_moof > 0
+            && stream->duration_moof > 0) {
+          n_samples = stream->n_samples_moof;
+          duration = stream->duration_moof;
+        } else {
+          n_samples = stream->n_samples;
+          duration = stream->duration;
+        }
+
         /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
         /* stream->duration is guint64, timescale, n_samples are guint32 */
-        GstClockTime avg_duration =
-            gst_util_uint64_scale_round (stream->duration -
+        avg_duration =
+            gst_util_uint64_scale_round (duration -
             stream->first_duration, GST_SECOND,
-            (guint64) (stream->timescale) * (stream->n_samples - 1));
+            (guint64) (stream->timescale) * (n_samples - 1));
 
         GST_LOG_OBJECT (qtdemux,
-            "Calculating avg sample duration based on stream duration %"
+            "Calculating avg sample duration based on stream (or moof) duration %"
             G_GUINT64_FORMAT
             " minus first sample %u, leaving %d samples gives %"
-            GST_TIME_FORMAT, stream->duration, stream->first_duration,
-            stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
+            GST_TIME_FORMAT, duration, stream->first_duration,
+            n_samples - 1, GST_TIME_ARGS (avg_duration));
 
         gst_video_guess_framerate (avg_duration, &stream->fps_n,
             &stream->fps_d);