[PATCH v2 3/5] winegstreamer: Request native buffer alignment using video pool meta.
Rémi Bernon
wine at gitlab.winehq.org
Mon May 30 03:20:47 CDT 2022
From: Rémi Bernon <rbernon at codeweavers.com>
To support VA-API plugins we need to implement video frame copy as well,
as the plugins simply ignore downstream buffer alignment requirements.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/mf/tests/mf.c | 3 -
dlls/winegstreamer/wg_transform.c | 123 +++++++++++++++++++++++++++---
2 files changed, 114 insertions(+), 12 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 3fe819ba23d..81bfafbda04 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -7284,9 +7284,7 @@ static void test_h264_decoder(void)
ok(hr == S_OK, "ConvertToContiguousBuffer returned %#lx\n", hr);
hr = IMFMediaBuffer_Lock(media_buffer, &data, NULL, &length);
ok(hr == S_OK, "Lock returned %#lx\n", hr);
- todo_wine
ok(length == nv12_frame_len, "got length %lu\n", length);
- if (length != nv12_frame_len) goto skip_nv12_tests;
for (i = 0; i < actual_aperture.Area.cy; ++i)
{
@@ -7302,7 +7300,6 @@ static void test_h264_decoder(void)
check_sample(output.pSample, nv12_frame_data, output_file);
-skip_nv12_tests:
ret = IMFSample_Release(output.pSample);
ok(ret == 0, "Release returned %lu\n", ret);
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c
index f98f3bdd14b..daf5b69cc5c 100644
--- a/dlls/winegstreamer/wg_transform.c
+++ b/dlls/winegstreamer/wg_transform.c
@@ -56,6 +56,7 @@ struct wg_transform
GstSegment segment;
GstBufferList *input;
guint input_max_length;
+ guint output_plane_align;
GstAtomicQueue *output_queue;
GstSample *output_sample;
bool output_caps_changed;
@@ -73,6 +74,20 @@ static bool is_caps_video(GstCaps *caps)
return g_str_has_prefix(media_type, "video/");
}
+static bool align_video_info_planes(gsize plane_align, GstVideoInfo *info, GstVideoAlignment *align)
+{
+ gst_video_alignment_reset(align);
+
+ align->padding_right = ((plane_align + 1) - (info->width & plane_align)) & plane_align;
+ align->padding_bottom = ((plane_align + 1) - (info->height & plane_align)) & plane_align;
+ align->stride_align[0] = plane_align;
+ align->stride_align[1] = plane_align;
+ align->stride_align[2] = plane_align;
+ align->stride_align[3] = plane_align;
+
+ return gst_video_info_align(info, align);
+}
+
static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer)
{
struct wg_transform *transform = gst_pad_get_element_private(pad);
@@ -106,7 +121,9 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery
{
case GST_QUERY_ALLOCATION:
{
- GstStructure *config;
+ gsize plane_align = transform->output_plane_align;
+ GstStructure *config, *params;
+ GstVideoAlignment align;
gboolean needs_pool;
GstBufferPool *pool;
GstVideoInfo info;
@@ -117,19 +134,36 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery
break;
if (!gst_video_info_from_caps(&info, caps)
+ || !align_video_info_planes(plane_align, &info, &align)
|| !(pool = gst_video_buffer_pool_new()))
break;
+ if ((params = gst_structure_new("video-meta",
+ "padding-top", G_TYPE_UINT, align.padding_top,
+ "padding-bottom", G_TYPE_UINT, align.padding_bottom,
+ "padding-left", G_TYPE_UINT, align.padding_left,
+ "padding-right", G_TYPE_UINT, align.padding_right,
+ NULL)))
+ gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, params);
+
if (!(config = gst_buffer_pool_get_config(pool)))
GST_ERROR("Failed to get pool %p config.", pool);
else
{
+ gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_META);
+ gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
+ gst_buffer_pool_config_set_video_alignment(config, &align);
+
gst_buffer_pool_config_set_params(config, caps,
info.size, 0, 0);
if (!gst_buffer_pool_set_config(pool, config))
GST_ERROR("Failed to set pool %p config.", pool);
}
+ /* Prevent pool reconfiguration, we don't want another alignment. */
+ if (!gst_buffer_pool_set_active(pool, true))
+ GST_ERROR("Pool %p failed to activate.", pool);
+
if (gst_query_get_n_allocation_pools(query) > 0)
gst_query_set_nth_allocation_pool(query, 0, pool, info.size, 0, 0);
else
@@ -299,6 +333,7 @@ NTSTATUS wg_transform_create(void *args)
if (!(transform->output_queue = gst_atomic_queue_new(8)))
goto out;
transform->input_max_length = 1;
+ transform->output_plane_align = 0;
if (!(src_caps = wg_format_to_caps(&input_format)))
goto out;
@@ -340,6 +375,7 @@ NTSTATUS wg_transform_create(void *args)
* to match its expectations.
*/
transform->input_max_length = 16;
+ transform->output_plane_align = 15;
if (!(element = create_element("h264parse", "base"))
|| !transform_append_element(transform, element, &first, &last))
goto out;
@@ -501,16 +537,67 @@ NTSTATUS wg_transform_push_data(void *args)
return STATUS_SUCCESS;
}
-static NTSTATUS read_transform_output_data(GstBuffer *buffer, struct wg_sample *sample)
+static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align,
+ struct wg_sample *sample, gsize *total_size)
{
- GstMapInfo info;
+ GstVideoFrame src_frame, dst_frame;
+ GstVideoInfo src_info, *dst_info;
+ GstVideoAlignment align;
+ GstBuffer *dst_buffer;
+ bool ret = false;
- if (!gst_buffer_map(buffer, &info, GST_MAP_READ))
+ if (!gst_video_info_from_caps(&src_info, caps))
+ return false;
+ if (!(dst_info = gst_video_info_copy(&src_info)))
+ return false;
+ if (!(dst_buffer = gst_buffer_new_wrapped_full(0, sample->data, sample->max_size,
+ 0, sample->max_size, 0, NULL)))
+ goto out;
+
+ if (!align_video_info_planes(plane_align, dst_info, &align))
{
- GST_ERROR("Failed to map buffer %p", buffer);
- sample->size = 0;
- return STATUS_UNSUCCESSFUL;
+ GST_ERROR("Failed to align video info.");
+ goto out;
}
+ if (sample->max_size < dst_info->size)
+ {
+ GST_ERROR("Output buffer too small.");
+ goto out;
+ }
+ gst_buffer_set_size(dst_buffer, dst_info->size);
+ *total_size = sample->size = dst_info->size;
+
+ if (!gst_video_frame_map(&src_frame, &src_info, buffer, GST_MAP_READ))
+ GST_ERROR("Failed to map source frame.");
+ else
+ {
+ if (!gst_video_frame_map(&dst_frame, dst_info, dst_buffer, GST_MAP_WRITE))
+ GST_ERROR("Failed to map destination frame.");
+ else
+ {
+ if (!(ret = gst_video_frame_copy(&dst_frame, &src_frame)))
+ GST_ERROR("Failed to copy video frame.");
+ gst_video_frame_unmap(&dst_frame);
+ }
+ gst_video_frame_unmap(&src_frame);
+ }
+
+out:
+ if (dst_buffer)
+ gst_buffer_unref(dst_buffer);
+ if (dst_info)
+ gst_video_info_free(dst_info);
+
+ return ret;
+}
+
+static bool copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample,
+ gsize *total_size)
+{
+ GstMapInfo info;
+
+ if (!gst_buffer_map(buffer, &info, GST_MAP_READ))
+ return false;
if (sample->max_size >= info.size)
sample->size = info.size;
@@ -526,6 +613,23 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, struct wg_sample *
if (sample->flags & WG_SAMPLE_FLAG_INCOMPLETE)
gst_buffer_resize(buffer, sample->size, -1);
+ *total_size = info.size;
+ return true;
+}
+
+static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align,
+ struct wg_sample *sample)
+{
+ gsize total_size;
+
+ if (!(is_caps_video(caps) ? copy_video_buffer(buffer, caps, plane_align, sample, &total_size)
+ : copy_buffer(buffer, caps, sample, &total_size)))
+ {
+ GST_ERROR("Failed to copy buffer %p", buffer);
+ sample->size = 0;
+ return STATUS_UNSUCCESSFUL;
+ }
+
if (GST_BUFFER_PTS_IS_VALID(buffer))
{
sample->flags |= WG_SAMPLE_FLAG_HAS_PTS;
@@ -535,7 +639,7 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, struct wg_sample *
{
GstClockTime duration = GST_BUFFER_DURATION(buffer) / 100;
- duration = (duration * sample->size) / info.size;
+ duration = (duration * sample->size) / total_size;
GST_BUFFER_DURATION(buffer) -= duration * 100;
if (GST_BUFFER_PTS_IS_VALID(buffer))
GST_BUFFER_PTS(buffer) += duration * 100;
@@ -599,7 +703,8 @@ NTSTATUS wg_transform_read_data(void *args)
return STATUS_SUCCESS;
}
- if ((status = read_transform_output_data(output_buffer, sample)))
+ if ((status = read_transform_output_data(output_buffer, output_caps,
+ transform->output_plane_align, sample)))
return status;
if (!(sample->flags & WG_SAMPLE_FLAG_INCOMPLETE))
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/139
More information about the wine-devel
mailing list