va: filter: Protect filters array of overwrite.

It's possible to modify the filters array from another GStremer
thread, and the post-processing operation is not atomic, so the filter
array is reffed while the VA pipeline is processed.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2495>
This commit is contained in:
Víctor Manuel Jáquez Leal 2021-08-23 16:29:36 +02:00
parent cc91fd0956
commit 51dcba7b1e

View file

@ -1220,33 +1220,28 @@ gst_va_filter_set_video_info (GstVaFilter * self, GstVideoInfo * in_info,
} }
static gboolean static gboolean
_query_pipeline_caps (GstVaFilter * self, VAProcPipelineCaps * caps) _query_pipeline_caps (GstVaFilter * self, GArray * filters,
VAProcPipelineCaps * caps)
{ {
VABufferID *filters = NULL; VABufferID *va_filters = NULL;
VADisplay dpy; VADisplay dpy;
VAStatus status; VAStatus status;
guint32 num_filters = 0; guint32 num_filters = 0;
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
if (self->filters) { if (filters) {
g_array_ref (self->filters); num_filters = filters->len;
num_filters = self->filters->len; va_filters = (num_filters > 0) ? (VABufferID *) filters->data : NULL;
filters = (num_filters > 0) ? (VABufferID *) self->filters->data : NULL;
} }
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);
dpy = gst_va_display_get_va_dpy (self->display); dpy = gst_va_display_get_va_dpy (self->display);
gst_va_display_lock (self->display); gst_va_display_lock (self->display);
status = vaQueryVideoProcPipelineCaps (dpy, self->context, filters, status = vaQueryVideoProcPipelineCaps (dpy, self->context, va_filters,
num_filters, caps); num_filters, caps);
gst_va_display_unlock (self->display); gst_va_display_unlock (self->display);
GST_OBJECT_LOCK (self);
if (self->filters)
g_array_unref (self->filters);
GST_OBJECT_UNLOCK (self);
if (status != VA_STATUS_SUCCESS) { if (status != VA_STATUS_SUCCESS) {
GST_ERROR_OBJECT (self, "vaQueryVideoProcPipelineCaps: %s", GST_ERROR_OBJECT (self, "vaQueryVideoProcPipelineCaps: %s",
vaErrorStr (status)); vaErrorStr (status));
@ -1377,22 +1372,21 @@ _fill_va_sample (GstVaFilter * self, GstVaSample * sample,
static gboolean static gboolean
_create_pipeline_buffer (GstVaFilter * self, GstVaSample * src, _create_pipeline_buffer (GstVaFilter * self, GstVaSample * src,
GstVaSample * dst, VABufferID * buffer) GstVaSample * dst, GArray * filters, VABufferID * buffer)
{ {
VADisplay dpy; VADisplay dpy;
VAStatus status; VAStatus status;
VABufferID *filters = NULL; VABufferID *va_filters = NULL;
VAProcPipelineParameterBuffer params; VAProcPipelineParameterBuffer params;
guint32 num_filters = 0; guint32 num_filters = 0;
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
/* *INDENT-OFF* */ /* *INDENT-OFF* */
if (self->filters) { if (filters) {
num_filters = self->filters->len; num_filters = filters->len;
filters = (num_filters > 0) ? (VABufferID *) self->filters->data : NULL; va_filters = (num_filters > 0) ? (VABufferID *) filters->data : NULL;
} }
params = (VAProcPipelineParameterBuffer) { params = (VAProcPipelineParameterBuffer) {
.surface = src->surface, .surface = src->surface,
.surface_region = &src->rect, .surface_region = &src->rect,
@ -1400,7 +1394,7 @@ _create_pipeline_buffer (GstVaFilter * self, GstVaSample * src,
.output_region = &dst->rect, .output_region = &dst->rect,
.output_background_color = 0xff000000, /* ARGB black */ .output_background_color = 0xff000000, /* ARGB black */
.output_color_standard = self->output_color_standard, .output_color_standard = self->output_color_standard,
.filters = filters, .filters = va_filters,
.num_filters = num_filters, .num_filters = num_filters,
.rotation_state = self->rotation, .rotation_state = self->rotation,
.mirror_state = self->mirror, .mirror_state = self->mirror,
@ -1432,6 +1426,7 @@ _create_pipeline_buffer (GstVaFilter * self, GstVaSample * src,
gboolean gboolean
gst_va_filter_process (GstVaFilter * self, GstVaSample * src, GstVaSample * dst) gst_va_filter_process (GstVaFilter * self, GstVaSample * src, GstVaSample * dst)
{ {
GArray *filters = NULL;
VABufferID buffer; VABufferID buffer;
VADisplay dpy; VADisplay dpy;
VAProcPipelineCaps pipeline_caps = { 0, }; VAProcPipelineCaps pipeline_caps = { 0, };
@ -1449,12 +1444,20 @@ gst_va_filter_process (GstVaFilter * self, GstVaSample * src, GstVaSample * dst)
&& _fill_va_sample (self, dst, GST_PAD_SRC))) && _fill_va_sample (self, dst, GST_PAD_SRC)))
return FALSE; return FALSE;
if (!_query_pipeline_caps (self, &pipeline_caps)) GST_OBJECT_LOCK (self);
if (self->filters)
filters = g_array_ref (self->filters);
GST_OBJECT_UNLOCK (self);
if (!_query_pipeline_caps (self, filters, &pipeline_caps))
return FALSE; return FALSE;
if (!_create_pipeline_buffer (self, src, dst, &buffer)) if (!_create_pipeline_buffer (self, src, dst, filters, &buffer))
return FALSE; return FALSE;
if (filters)
g_array_unref (filters);
dpy = gst_va_display_get_va_dpy (self->display); dpy = gst_va_display_get_va_dpy (self->display);
gst_va_display_lock (self->display); gst_va_display_lock (self->display);
@ -1484,7 +1487,6 @@ gst_va_filter_process (GstVaFilter * self, GstVaSample * src, GstVaSample * dst)
ret = TRUE; ret = TRUE;
bail: bail:
GST_OBJECT_LOCK (self);
gst_va_display_lock (self->display); gst_va_display_lock (self->display);
status = vaDestroyBuffer (dpy, buffer); status = vaDestroyBuffer (dpy, buffer);
gst_va_display_unlock (self->display); gst_va_display_unlock (self->display);
@ -1492,7 +1494,6 @@ bail:
GST_WARNING_OBJECT (self, "Failed to destroy pipeline buffer: %s", GST_WARNING_OBJECT (self, "Failed to destroy pipeline buffer: %s",
vaErrorStr (status)); vaErrorStr (status));
} }
GST_OBJECT_UNLOCK (self);
return ret; return ret;