summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Jägenstedt <philipj@opera.com>2010-05-23 09:32:08 +0200
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2010-06-01 11:21:29 +0200
commit80926a5596bbd3b35795ae135786c5ac29d46a5b (patch)
tree14a8b280629f04911dad72a8bd62086d5a356360
parentf5bca501e5eb122a0d511b336293278f49970ef2 (diff)
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.
-rw-r--r--gst/matroska/matroska-demux.c65
-rw-r--r--gst/matroska/matroska-ids.c1
-rw-r--r--gst/matroska/matroska-ids.h3
3 files changed, 68 insertions, 1 deletions
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index a5f551d1d..06a5a69bf 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 0ee39d31e..5bed5e6dd 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 085bf8409..16b56010b 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;