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.
This commit is contained in:
Philip Jägenstedt 2010-05-23 09:32:08 +02:00 committed by Sebastian Dröge
parent f5bca501e5
commit 80926a5596
3 changed files with 68 additions and 1 deletions

View file

@ -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);

View file

@ -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;
}

View file

@ -545,6 +545,9 @@ typedef struct _GstMatroskaTrackVideoContext {
GstMatroskaAspectRatioMode asr_mode;
guint32 fourcc;
/* QoS */
GstClockTime earliest_time;
GstBuffer *dirac_unit;
} GstMatroskaTrackVideoContext;