From 2e9a09628256d116ad934af7f44db4bf270efc67 Mon Sep 17 00:00:00 2001 From: He Junyan Date: Fri, 19 Feb 2021 14:27:39 +0800 Subject: [PATCH] va: vpp: Add raw buffer copy when needed. Just like the decoder, the vapostproc also needs to copy the output buffer to raw buffer if downstream elements only supports raw caps and does not support the video meta. The pipeline like: gst-launch-1.0 filesrc location=xxxx ! h264parse ! vah264dec ! \ vapostproc ! capsfilter caps=video/x-raw,width=55,height=128 ! \ filesink location=xxx needs this logic to dump the data correctly. fixes: #1523 Part-of: --- sys/va/gstvavpp.c | 153 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 142 insertions(+), 11 deletions(-) diff --git a/sys/va/gstvavpp.c b/sys/va/gstvavpp.c index 8a5606dbe1..7f3017615f 100644 --- a/sys/va/gstvavpp.c +++ b/sys/va/gstvavpp.c @@ -105,6 +105,9 @@ struct _GstVaVpp GstBufferPool *sinkpad_pool; GstVideoInfo sinkpad_info; + GstBufferPool *other_pool; + GstVideoInfo srcpad_info; + guint op_flags; /* filters */ @@ -169,6 +172,11 @@ gst_va_vpp_dispose (GObject * object) gst_clear_object (&self->sinkpad_pool); } + if (self->other_pool) { + gst_buffer_pool_set_active (self->other_pool, FALSE); + gst_clear_object (&self->other_pool); + } + gst_clear_caps (&self->incaps); gst_clear_caps (&self->outcaps); @@ -520,6 +528,25 @@ config_failed: } } +static GstBufferPool * +_create_other_pool (GstAllocator * allocator, + GstAllocationParams * params, GstCaps * caps, guint size) +{ + GstBufferPool *pool = NULL; + GstStructure *config; + + pool = gst_video_buffer_pool_new (); + config = gst_buffer_pool_get_config (pool); + + gst_buffer_pool_config_set_params (config, caps, size, 0, 0); + gst_buffer_pool_config_set_allocator (config, allocator, params); + if (!gst_buffer_pool_set_config (pool, config)) { + gst_clear_object (&pool); + } + + return pool; +} + /* configure the allocation query that was answered downstream, we can * configure some properties on it. Only called when not in * passthrough mode. */ @@ -527,33 +554,44 @@ static gboolean gst_va_vpp_decide_allocation (GstBaseTransform * trans, GstQuery * query) { GstVaVpp *self = GST_VA_VPP (trans); - GstAllocator *allocator = NULL; - GstAllocationParams params; - GstBufferPool *pool = NULL; + GstAllocator *allocator = NULL, *other_allocator = NULL; + GstAllocationParams params, other_params; + GstBufferPool *pool = NULL, *other_pool = NULL; GstCaps *outcaps = NULL; GstStructure *config; guint min, max, size = 0, usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_WRITE; - gboolean update_pool, update_allocator; + gboolean update_pool, update_allocator, has_videometa, copy_frames; + GstVideoInfo alloc_info; gst_query_parse_allocation (query, &outcaps, NULL); + gst_allocation_params_init (&other_params); + gst_allocation_params_init (¶ms); + if (gst_query_get_n_allocation_params (query) > 0) { - gst_query_parse_nth_allocation_param (query, 0, &allocator, NULL); + gst_query_parse_nth_allocation_param (query, 0, &allocator, &other_params); if (allocator && !(GST_IS_VA_DMABUF_ALLOCATOR (allocator) - || GST_IS_VA_ALLOCATOR (allocator))) - gst_clear_object (&allocator); + || GST_IS_VA_ALLOCATOR (allocator))) { + /* save the allocator for the other pool */ + other_allocator = allocator; + allocator = NULL; + } update_allocator = TRUE; } else { update_allocator = FALSE; } - gst_allocation_params_init (¶ms); - if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); - if (pool && !GST_IS_VA_POOL (pool)) - gst_clear_object (&pool); + if (pool) { + if (!GST_IS_VA_POOL (pool)) { + GST_DEBUG_OBJECT (self, + "may need other pool for copy frames %" GST_PTR_FORMAT, pool); + other_pool = pool; + pool = NULL; + } + } update_pool = TRUE; } else { @@ -566,6 +604,9 @@ gst_va_vpp_decide_allocation (GstBaseTransform * trans, GstQuery * query) update_pool = FALSE; } + has_videometa = gst_query_find_allocation_meta (query, + GST_VIDEO_META_API_TYPE, NULL); + if (!allocator) { if (!(allocator = _create_allocator (self, outcaps, usage_hint))) return FALSE; @@ -586,17 +627,43 @@ gst_va_vpp_decide_allocation (GstBaseTransform * trans, GstQuery * query) else gst_query_add_allocation_param (query, allocator, ¶ms); + alloc_info = self->out_info; + if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) { + gst_va_dmabuf_allocator_get_format (allocator, &alloc_info, NULL); + } else if (GST_IS_VA_ALLOCATOR (allocator)) { + gst_va_allocator_get_format (allocator, &alloc_info, NULL); + } + self->srcpad_info = alloc_info; + if (update_pool) gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); else gst_query_add_allocation_pool (query, pool, size, min, max); + copy_frames = (!has_videometa && gst_va_pool_requires_video_meta (pool) + && gst_caps_is_raw (outcaps)); + if (copy_frames) { + if (other_pool) { + gst_object_replace ((GstObject **) & self->other_pool, + (GstObject *) other_pool); + } else { + self->other_pool = + _create_other_pool (other_allocator, &other_params, outcaps, size); + } + GST_DEBUG_OBJECT (self, "Use the other pool for copy %" GST_PTR_FORMAT, + self->other_pool); + } else { + gst_clear_object (&self->other_pool); + } + GST_DEBUG_OBJECT (self, "decided pool %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT, pool, allocator); gst_object_unref (allocator); gst_object_unref (pool); + gst_clear_object (&other_allocator); + gst_clear_object (&other_pool); return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans, query); @@ -684,6 +751,11 @@ gst_va_vpp_set_caps (GstBaseTransform * trans, GstCaps * incaps, gst_clear_object (&self->sinkpad_pool); } + if (self->other_pool) { + gst_buffer_pool_set_active (self->other_pool, FALSE); + gst_clear_object (&self->other_pool); + } + gst_caps_replace (&self->incaps, incaps); gst_caps_replace (&self->outcaps, outcaps); @@ -2105,6 +2177,64 @@ gst_va_vpp_sink_event (GstBaseTransform * trans, GstEvent * event) return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event); } +static GstFlowReturn +gst_va_vpp_generate_output (GstBaseTransform * trans, GstBuffer ** outbuf) +{ + GstVaVpp *self = GST_VA_VPP (trans); + GstVideoFrame src_frame; + GstVideoFrame dest_frame; + GstBuffer *buffer = NULL; + GstFlowReturn ret; + + ret = GST_BASE_TRANSFORM_CLASS (parent_class)->generate_output (trans, + outbuf); + + if (ret != GST_FLOW_OK || *outbuf == NULL) + return ret; + + if (!self->other_pool) + return GST_FLOW_OK; + + /* Now need to copy the output buffer */ + ret = GST_FLOW_ERROR; + + if (!gst_buffer_pool_set_active (self->other_pool, TRUE)) { + GST_WARNING_OBJECT (self, "failed to active the other pool %" + GST_PTR_FORMAT, self->other_pool); + goto out; + } + + ret = gst_buffer_pool_acquire_buffer (self->other_pool, &buffer, NULL); + if (ret != GST_FLOW_OK) + goto out; + + if (!gst_video_frame_map (&src_frame, &self->srcpad_info, *outbuf, + GST_MAP_READ)) + goto out; + + if (!gst_video_frame_map (&dest_frame, &self->out_info, buffer, + GST_MAP_WRITE)) { + gst_video_frame_unmap (&src_frame); + goto out; + } + + if (!gst_video_frame_copy (&dest_frame, &src_frame)) { + gst_video_frame_unmap (&src_frame); + gst_video_frame_unmap (&dest_frame); + goto out; + } + + gst_video_frame_unmap (&src_frame); + gst_video_frame_unmap (&dest_frame); + + gst_buffer_replace (outbuf, buffer); + ret = GST_FLOW_OK; + +out: + gst_clear_buffer (&buffer); + return ret; +} + static void gst_va_vpp_class_init (gpointer g_class, gpointer class_data) { @@ -2183,6 +2313,7 @@ gst_va_vpp_class_init (gpointer g_class, gpointer class_data) trans_class->filter_meta = GST_DEBUG_FUNCPTR (gst_va_vpp_filter_meta); trans_class->src_event = GST_DEBUG_FUNCPTR (gst_va_vpp_src_event); trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_va_vpp_sink_event); + trans_class->generate_output = GST_DEBUG_FUNCPTR (gst_va_vpp_generate_output); trans_class->transform_ip_on_passthrough = FALSE;