mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
msdkdec: free unlocked msdk surface before output buffer allocation
https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/merge_requests/924 is trying to use video memory for decoding on Linux, which reveals a hidden bug in msdkdec. For video memory, it is possible that a locked mfx surface is not used indeed and it will be un-locked later in MSDK, so we have to check the associated MSDK surface to find out and free un-used surfaces, otherwise it is easy to exhaust all pre-allocated mfx surfaces and get errors below: 0:00:00.777324879 27290 0x564b65a510a0 ERROR default gstmsdkvideomemory.c:77:gst_msdk_video_allocator_get_surface: failed to get surface available 0:00:00.777429079 27290 0x564b65a510a0 ERROR msdkbufferpool gstmsdkbufferpool.c:260:gst_msdk_buffer_pool_alloc_buffer:<msdkbufferpool0> failed to create new MSDK memory Note the sample code in MSDK does similar thing in CBuffering::SyncFrameSurfaces()
This commit is contained in:
parent
66775f3e72
commit
a819f05851
1 changed files with 38 additions and 37 deletions
|
@ -114,6 +114,39 @@ gst_msdkdec_get_oldest_frame (GstVideoDecoder * decoder)
|
|||
return frame;
|
||||
}
|
||||
|
||||
static void
|
||||
free_surface (GstMsdkDec * thiz, MsdkSurface * s)
|
||||
{
|
||||
if (s->copy.buffer) {
|
||||
gst_video_frame_unmap (&s->copy);
|
||||
gst_buffer_unref (s->copy.buffer);
|
||||
}
|
||||
|
||||
if (s->data.buffer)
|
||||
gst_video_frame_unmap (&s->data);
|
||||
|
||||
gst_buffer_unref (s->buf);
|
||||
thiz->decoded_msdk_surfaces = g_list_remove (thiz->decoded_msdk_surfaces, s);
|
||||
|
||||
g_slice_free (MsdkSurface, s);
|
||||
}
|
||||
|
||||
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
|
||||
allocate_output_buffer (GstMsdkDec * thiz, GstBuffer ** buffer)
|
||||
{
|
||||
|
@ -130,6 +163,11 @@ allocate_output_buffer (GstMsdkDec * thiz, GstBuffer ** buffer)
|
|||
}
|
||||
|
||||
if (!frame->output_buffer) {
|
||||
/* Free un-unsed msdk surfaces firstly, hence the associated mfx
|
||||
* surfaces will be moved from used list to available list */
|
||||
if (thiz->postpone_free_surface || thiz->use_video_memory)
|
||||
gst_msdkdec_free_unlocked_msdk_surfaces (thiz, NULL);
|
||||
|
||||
flow = gst_video_decoder_allocate_output_frame (decoder, frame);
|
||||
if (flow != GST_FLOW_OK) {
|
||||
gst_video_codec_frame_unref (frame);
|
||||
|
@ -147,23 +185,6 @@ allocate_output_buffer (GstMsdkDec * thiz, GstBuffer ** buffer)
|
|||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
free_surface (GstMsdkDec * thiz, MsdkSurface * s)
|
||||
{
|
||||
if (s->copy.buffer) {
|
||||
gst_video_frame_unmap (&s->copy);
|
||||
gst_buffer_unref (s->copy.buffer);
|
||||
}
|
||||
|
||||
if (s->data.buffer)
|
||||
gst_video_frame_unmap (&s->data);
|
||||
|
||||
gst_buffer_unref (s->buf);
|
||||
thiz->decoded_msdk_surfaces = g_list_remove (thiz->decoded_msdk_surfaces, s);
|
||||
|
||||
g_slice_free (MsdkSurface, s);
|
||||
}
|
||||
|
||||
static MsdkSurface *
|
||||
get_surface (GstMsdkDec * thiz, GstBuffer * buffer)
|
||||
{
|
||||
|
@ -593,22 +614,6 @@ _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)
|
||||
{
|
||||
|
@ -1016,8 +1021,6 @@ gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
|
|||
gst_video_codec_frame_unref (frame);
|
||||
frame = NULL;
|
||||
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) {
|
||||
|
@ -1435,8 +1438,6 @@ 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)
|
||||
|
|
Loading…
Reference in a new issue