qtdemux: implement support for trickmode interval
authorMathieu Duponchelle <mathieu@centricular.com>
Fri, 12 Jul 2019 18:51:44 +0000 (20:51 +0200)
committerMathieu Duponchelle <mathieu@centricular.com>
Thu, 18 Jul 2019 15:54:43 +0000 (17:54 +0200)
When the seek event contains a (newly-added) trickmode interval,
and TRICKMODE_KEY_UNITS was requested, only let through keyframes
separated with the required interval

gst/isomp4/qtdemux.c
gst/isomp4/qtdemux.h

index f7994b8..f9c8383 100644 (file)
@@ -452,6 +452,9 @@ struct _QtDemuxStream
   gpointer protection_scheme_info;      /* specific to the protection scheme */
   GQueue protection_scheme_event_queue;
 
+  /* KEY_UNITS trickmode with an interval */
+  GstClockTime last_keyframe_dts;
+
   gint ref_count;               /* atomic */
 };
 
@@ -1608,6 +1611,7 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
     stream->offset_in_sample = 0;
     stream->segment_index = -1;
     stream->sent_eos = FALSE;
+    stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
 
     if (segment->flags & GST_SEEK_FLAG_FLUSH)
       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
@@ -1785,6 +1789,9 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
         goto upstream;
       }
 
+      gst_event_parse_seek_trickmode_interval (event,
+          &qtdemux->trickmode_interval);
+
       /* Build complete index for seeking;
        * if not a fragmented file at least */
       if (!qtdemux->fragmented)
@@ -2165,6 +2172,7 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
 
   if (hard) {
     qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
+    qtdemux->trickmode_interval = 0;
     g_ptr_array_remove_range (qtdemux->active_streams,
         0, qtdemux->active_streams->len);
     g_ptr_array_remove_range (qtdemux->old_streams,
@@ -2204,6 +2212,7 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
       stream->sent_eos = FALSE;
       stream->time_position = 0;
       stream->accumulated_base = 0;
+      stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
     }
   }
 }
@@ -6370,10 +6379,29 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
   if (G_UNLIKELY (qtdemux->segment.
           flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
-    if (stream->subtype == FOURCC_vide && !keyframe) {
-      GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
-          stream->track_id);
-      goto next;
+    if (stream->subtype == FOURCC_vide) {
+      if (!keyframe) {
+        GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
+            stream->track_id);
+        goto next;
+      } else if (qtdemux->trickmode_interval > 0) {
+        GstClockTimeDiff interval;
+
+        if (qtdemux->segment.rate > 0)
+          interval = stream->time_position - stream->last_keyframe_dts;
+        else
+          interval = stream->last_keyframe_dts - stream->time_position;
+
+        if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
+            && interval < qtdemux->trickmode_interval) {
+          GST_LOG_OBJECT (qtdemux,
+              "Skipping keyframe within interval on track-id %u",
+              stream->track_id);
+          goto next;
+        } else {
+          stream->last_keyframe_dts = stream->time_position;
+        }
+      }
     }
   }
 
index 83a050a..f9731b2 100644 (file)
@@ -118,6 +118,9 @@ struct _GstQTDemux {
   /* configured playback region */
   GstSegment segment;
 
+  /* State for key_units trickmode */
+  GstClockTime trickmode_interval;
+
   /* PUSH-BASED only: If the initial segment event, or a segment consequence of
    * a seek or incoming TIME segment from upstream needs to be pushed. This
    * variable is used instead of pushing the event directly because at that