vaapidecode: drop non-keyframe in reverse playback

To avoid surface-exhausted situation during reverse playback,
drop frames except for key frame.

Also, to avoid the corruption of the parser state, flush() vmethod
doesn't destroy the VA decoder when playing in reverse.

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

Signed-off-by: Víctor Manuel Jáquez Leal <victorx.jaquez@intel.com>
This commit is contained in:
Hyunjun Ko 2016-07-01 14:42:20 +09:00 committed by Víctor Manuel Jáquez Leal
parent c9a5801c35
commit 19c0c8a973
2 changed files with 36 additions and 1 deletions

View file

@ -544,6 +544,13 @@ gst_vaapidecode_push_decoded_frame (GstVideoDecoder * vdec,
#endif
}
if (decode->in_segment.rate < 0.0
&& !GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (out_frame)) {
GST_TRACE_OBJECT (decode, "drop frame in reverse playback");
gst_video_decoder_release_frame (GST_VIDEO_DECODER (decode), out_frame);
return GST_FLOW_OK;
}
ret = gst_video_decoder_finish_frame (vdec, out_frame);
if (ret != GST_FLOW_OK)
goto error_commit_buffer;
@ -994,6 +1001,7 @@ static gboolean
gst_vaapidecode_flush (GstVideoDecoder * vdec)
{
GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
gboolean reverse;
if (!decode->decoder)
return FALSE;
@ -1002,9 +1010,13 @@ gst_vaapidecode_flush (GstVideoDecoder * vdec)
gst_vaapidecode_purge (decode);
/* in reverse playback we cannot destroy the decoder at flush, since
* it will lost the parsing state */
reverse = decode->in_segment.rate < 0;
/* There could be issues if we avoid the reset_full() while doing
* seeking: we have to reset the internal state */
return gst_vaapidecode_reset_full (decode, decode->sinkpad_caps, TRUE);
return gst_vaapidecode_reset_full (decode, decode->sinkpad_caps, !reverse);
}
static gboolean
@ -1225,6 +1237,27 @@ gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query)
return ret;
}
static gboolean
gst_vaapidecode_sink_event (GstVideoDecoder * vdec, GstEvent * event)
{
GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEGMENT:
{
/* Keep segment event to refer to rate so that
* vaapidecode can handle reverse playback
*/
gst_event_copy_segment (event, &decode->in_segment);
break;
}
default:
break;
}
return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (vdec, event);
}
static void
gst_vaapidecode_class_init (GstVaapiDecodeClass * klass)
{
@ -1259,6 +1292,7 @@ gst_vaapidecode_class_init (GstVaapiDecodeClass * klass)
vdec_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_src_query);
vdec_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_query);
vdec_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_getcaps);
vdec_class->sink_event = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_event);
map = (GstVaapiDecoderMap *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
GST_VAAPI_DECODE_PARAMS_QDATA);

View file

@ -54,6 +54,7 @@ struct _GstVaapiDecode {
guint display_height;
GstVideoCodecState *input_state;
GstSegment in_segment;
};
struct _GstVaapiDecodeClass {