mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-15 22:17:17 +00:00
winegstreamer: Request native buffer alignment using video pool meta.
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@codeweavers.com>
This commit is contained in:
parent
f7ca5cfa27
commit
24266121f1
|
@ -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);
|
||||
|
||||
|
|
|
@ -52,6 +52,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;
|
||||
|
@ -69,6 +70,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);
|
||||
|
@ -102,7 +117,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;
|
||||
|
@ -113,19 +130,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);
|
||||
|
||||
gst_query_add_allocation_pool(query, pool, info.size, 0, 0);
|
||||
|
||||
GST_INFO("Proposing pool %p, buffer size %#zx, for query %p.",
|
||||
|
@ -292,6 +326,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;
|
||||
|
@ -333,6 +368,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;
|
||||
|
@ -494,16 +530,68 @@ 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)
|
||||
{
|
||||
GstVideoFrame src_frame, dst_frame;
|
||||
GstVideoInfo src_info, dst_info;
|
||||
GstVideoAlignment align;
|
||||
GstBuffer *dst_buffer;
|
||||
bool ret = false;
|
||||
|
||||
if (!gst_video_info_from_caps(&src_info, caps))
|
||||
{
|
||||
GST_ERROR("Failed to get video info from caps.");
|
||||
return false;
|
||||
}
|
||||
|
||||
dst_info = src_info;
|
||||
if (!align_video_info_planes(plane_align, &dst_info, &align))
|
||||
{
|
||||
GST_ERROR("Failed to align video info.");
|
||||
return false;
|
||||
}
|
||||
if (sample->max_size < dst_info.size)
|
||||
{
|
||||
GST_ERROR("Output buffer is too small.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(dst_buffer = gst_buffer_new_wrapped_full(0, sample->data, sample->max_size,
|
||||
0, sample->max_size, 0, NULL)))
|
||||
{
|
||||
GST_ERROR("Failed to wrap wg_sample into GstBuffer");
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
gst_buffer_unref(dst_buffer);
|
||||
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))
|
||||
{
|
||||
GST_ERROR("Failed to map buffer %p", buffer);
|
||||
sample->size = 0;
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
return false;
|
||||
|
||||
if (sample->max_size >= info.size)
|
||||
sample->size = info.size;
|
||||
|
@ -519,6 +607,28 @@ 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;
|
||||
bool ret;
|
||||
|
||||
if (is_caps_video(caps))
|
||||
ret = copy_video_buffer(buffer, caps, plane_align, sample, &total_size);
|
||||
else
|
||||
ret = copy_buffer(buffer, caps, sample, &total_size);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
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;
|
||||
|
@ -528,7 +638,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;
|
||||
|
@ -592,7 +702,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))
|
||||
|
|
Loading…
Reference in a new issue