[gst-cvs] gst-plugins-good: matroskademux: skip buffers before a late keyframe (QoS)

Sebastian Dröge slomo at kemper.freedesktop.org
Tue Jun 1 02:21:52 PDT 2010


Module: gst-plugins-good
Branch: master
Commit: 80926a5596bbd3b35795ae135786c5ac29d46a5b
URL:    http://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/?id=80926a5596bbd3b35795ae135786c5ac29d46a5b

Author: Philip Jägenstedt <philipj at opera.com>
Date:   Sun May 23 09:32:08 2010 +0200

matroskademux: skip buffers before a late keyframe (QoS)

Before, vp8dec had no option but to decode all frames even if some/all
of them would be late. With this change, performance when keyframes are
frequent is helped a great deal. On my Thinkpad X60s, decoding a 20 s
1080p sunflower encode with keyframes every 10 frames went from taking
42 s with 5 frames shown to 21 s with 15 frames shown (still slow
enough to count by hand). When keyframes are more sparse, you will
still be able to catch up eventually, but the results won't be as
noticable.

---

 gst/matroska/matroska-demux.c |   65 ++++++++++++++++++++++++++++++++++++++++-
 gst/matroska/matroska-ids.c   |    1 +
 gst/matroska/matroska-ids.h   |    3 ++
 3 files changed, 68 insertions(+), 1 deletions(-)

diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index a5f551d..06a5a69 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -2197,6 +2197,13 @@ gst_matroska_demux_reset_streams (GstMatroskaDemux * demux, GstClockTime time,
     context->from_time = GST_CLOCK_TIME_NONE;
     if (full)
       context->last_flow = GST_FLOW_OK;
+    if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+      GstMatroskaTrackVideoContext *videocontext =
+          (GstMatroskaTrackVideoContext *) context;
+      GST_OBJECT_LOCK (demux);
+      videocontext->earliest_time = GST_CLOCK_TIME_NONE;
+      GST_OBJECT_UNLOCK (demux);
+    }
   }
 }
 
@@ -2496,9 +2503,29 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstEvent * event)
       gst_event_unref (event);
       break;
 
+    case GST_EVENT_QOS:
+    {
+      GstMatroskaTrackContext *context = gst_pad_get_element_private (pad);
+      if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
+        GstMatroskaTrackVideoContext *videocontext =
+            (GstMatroskaTrackVideoContext *) context;
+        gdouble proportion;
+        GstClockTimeDiff diff;
+        GstClockTime timestamp;
+
+        gst_event_parse_qos (event, &proportion, &diff, &timestamp);
+
+        GST_OBJECT_LOCK (demux);
+        videocontext->earliest_time = timestamp + diff;
+        GST_OBJECT_UNLOCK (demux);
+      }
+      res = TRUE;
+      gst_event_unref (event);
+      break;
+    }
+
       /* events we don't need to handle */
     case GST_EVENT_NAVIGATION:
-    case GST_EVENT_QOS:
       gst_event_unref (event);
       res = FALSE;
       break;
@@ -4635,6 +4662,42 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
         break;
       }
 
+      /* QoS for video track with an index. the assumption is that
+         index entries point to keyframes, but if that is not true we
+         will instad skip until the next keyframe. */
+      if (GST_CLOCK_TIME_IS_VALID (lace_time) &&
+          stream->type == GST_MATROSKA_TRACK_TYPE_VIDEO &&
+          stream->index_table) {
+        GstMatroskaTrackVideoContext *videocontext =
+            (GstMatroskaTrackVideoContext *) stream;
+        GstClockTime running_time;
+        GstClockTime earliest_time;
+        running_time = gst_segment_to_running_time (&demux->segment,
+            GST_FORMAT_TIME, lace_time);
+        GST_OBJECT_LOCK (demux);
+        earliest_time = videocontext->earliest_time;
+        GST_OBJECT_UNLOCK (demux);
+        if (GST_CLOCK_TIME_IS_VALID (running_time) &&
+            GST_CLOCK_TIME_IS_VALID (earliest_time) &&
+            running_time <= earliest_time) {
+          /* find index entry (keyframe) <= earliest_time */
+          GstMatroskaIndex *entry =
+              gst_util_array_binary_search (stream->index_table->data,
+              stream->index_table->len, sizeof (GstMatroskaIndex),
+              (GCompareDataFunc) gst_matroska_index_seek_find,
+              GST_SEARCH_MODE_BEFORE, &earliest_time, NULL);
+          /* if that entry (keyframe) is after the current the current
+             buffer, we can skip pushing (and thus decoding) all
+             buffers until that keyframe. */
+          if (entry && GST_CLOCK_TIME_IS_VALID (entry->time) &&
+              entry->time > lace_time) {
+            GST_LOG_OBJECT (demux, "Skipping lace before late keyframe");
+            stream->set_discont = TRUE;
+            goto next_lace;
+          }
+        }
+      }
+
       sub = gst_buffer_create_sub (buf,
           GST_BUFFER_SIZE (buf) - size, lace_size[n]);
       GST_DEBUG_OBJECT (demux, "created subbuffer %p", sub);
diff --git a/gst/matroska/matroska-ids.c b/gst/matroska/matroska-ids.c
index 0ee39d3..5bed5e6 100644
--- a/gst/matroska/matroska-ids.c
+++ b/gst/matroska/matroska-ids.c
@@ -56,6 +56,7 @@ gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context)
   video_context->asr_mode = 0;
   video_context->fourcc = 0;
   video_context->default_fps = 0.0;
+  video_context->earliest_time = GST_CLOCK_TIME_NONE;
   return TRUE;
 }
 
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
index 085bf84..16b5601 100644
--- a/gst/matroska/matroska-ids.h
+++ b/gst/matroska/matroska-ids.h
@@ -545,6 +545,9 @@ typedef struct _GstMatroskaTrackVideoContext {
   GstMatroskaAspectRatioMode asr_mode;
   guint32       fourcc;
 
+  /* QoS */
+  GstClockTime  earliest_time;
+
   GstBuffer     *dirac_unit;
 } GstMatroskaTrackVideoContext;
 





More information about the Gstreamer-commits mailing list