From f840e304f34aa582d394c9e70fa76c740499a69f Mon Sep 17 00:00:00 2001 From: Haihao Xiang Date: Tue, 2 Jul 2019 15:21:24 +0800 Subject: [PATCH] msdkdec: postpone surface free for VC1 For a skipped frame in VC1, MSDK returns the mfx surface of the reference frame, so we have to make sure the corresponding surface for the reference frame is not freed. In this fix, we postpone surface free because we don't know whether a surface is referenced Before this fix, the error is like as below: New clock: GstSystemClock 0:00:00.181793130 23098 0x55f8a9d622d0 ERROR msdkdec gstmsdkdec.c:622:gst_msdkdec_finish_task: Couldn't find the cached MSDK surface Sample pipeline: gst-launch-1.0 filesrc location=input_has_skipped_frame.wmv ! asfdemux ! vc1parse ! msdkvc1dec ! glimagesink --- sys/msdk/gstmsdkdec.c | 24 +++++++++++++++++++++++- sys/msdk/gstmsdkdec.h | 2 ++ sys/msdk/gstmsdkvc1dec.c | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/sys/msdk/gstmsdkdec.c b/sys/msdk/gstmsdkdec.c index e22748a0050..742aaa43313 100644 --- a/sys/msdk/gstmsdkdec.c +++ b/sys/msdk/gstmsdkdec.c @@ -589,6 +589,22 @@ _find_msdk_surface (gconstpointer msdk_surface, gconstpointer comp_surface) return cached_surface ? cached_surface->surface != _surface : -1; } +static void +gst_msdkdec_free_unlocked_msdk_surfaces (GstMsdkDec * thiz, + MsdkSurface * curr_surface) +{ + GList *l; + MsdkSurface *surface; + + for (l = thiz->decoded_msdk_surfaces; l;) { + surface = l->data; + l = l->next; + + if (surface != curr_surface && surface->surface->Data.Locked == 0) + free_surface (thiz, surface); + } +} + static GstFlowReturn gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task) { @@ -632,7 +648,8 @@ gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task) } } - free_surface (thiz, surface); + if (!thiz->postpone_free_surface) + free_surface (thiz, surface); task->sync_point = NULL; task->surface = NULL; task->decode_only = FALSE; @@ -995,6 +1012,8 @@ gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) } for (;;) { + if (thiz->postpone_free_surface) + gst_msdkdec_free_unlocked_msdk_surfaces (thiz, surface); task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task); flow = gst_msdkdec_finish_task (thiz, task); if (flow != GST_FLOW_OK) @@ -1376,6 +1395,8 @@ gst_msdkdec_drain (GstVideoDecoder * decoder) session = gst_msdk_context_get_session (thiz->context); for (;;) { + if (thiz->postpone_free_surface) + gst_msdkdec_free_unlocked_msdk_surfaces (thiz, surface); task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task); if ((flow = gst_msdkdec_finish_task (thiz, task)) != GST_FLOW_OK) { if (flow != GST_FLOW_FLUSHING) @@ -1599,5 +1620,6 @@ gst_msdkdec_init (GstMsdkDec * thiz) thiz->do_renego = TRUE; thiz->do_realloc = TRUE; thiz->force_reset_on_res_change = TRUE; + thiz->postpone_free_surface = FALSE; thiz->adapter = gst_adapter_new (); } diff --git a/sys/msdk/gstmsdkdec.h b/sys/msdk/gstmsdkdec.h index bd3732b33a6..0e8858b8547 100644 --- a/sys/msdk/gstmsdkdec.h +++ b/sys/msdk/gstmsdkdec.h @@ -86,6 +86,8 @@ struct _GstMsdkDec * include downstream requirement, msdk suggestion and extra * surface allocation for smooth display in render pipeline */ guint min_prealloc_buffers; + /* postpone surface free */ + gboolean postpone_free_surface; /* MFX context */ GstMsdkContext *context; diff --git a/sys/msdk/gstmsdkvc1dec.c b/sys/msdk/gstmsdkvc1dec.c index 7828ffb3adc..0b0d78d5fd2 100644 --- a/sys/msdk/gstmsdkvc1dec.c +++ b/sys/msdk/gstmsdkvc1dec.c @@ -82,6 +82,7 @@ gst_msdkvc1dec_configure (GstMsdkDec * decoder) if (!structure) return FALSE; + decoder->postpone_free_surface = TRUE; decoder->param.mfx.CodecId = MFX_CODEC_VC1; profile_str = gst_structure_get_string (structure, "profile");