mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 08:39:34 +00:00
winegstreamer: Implement H264 SetOutputType by reconfiguring the pipeline.
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
bc270a5432
commit
e15af49029
|
@ -7818,7 +7818,7 @@ static void test_h264_decoder(void)
|
|||
todo_wine
|
||||
ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
|
||||
|
||||
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
|
||||
while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
|
||||
{
|
||||
hr = IMFTransform_ProcessInput(transform, 0, sample, 0);
|
||||
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
||||
|
@ -7826,16 +7826,14 @@ static void test_h264_decoder(void)
|
|||
ok(ret <= 1, "Release returned %lu\n", ret);
|
||||
sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
||||
hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
|
||||
todo_wine
|
||||
todo_wine_if(hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
|
||||
ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
|
||||
}
|
||||
|
||||
ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID);
|
||||
ok(!!output.pSample, "got pSample %p\n", output.pSample);
|
||||
todo_wine
|
||||
ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got dwStatus %#lx\n", output.dwStatus);
|
||||
ok(!output.pEvents, "got pEvents %p\n", output.pEvents);
|
||||
todo_wine
|
||||
ok(status == MFT_PROCESS_OUTPUT_STATUS_NEW_STREAMS, "got status %#lx\n", status);
|
||||
hr = IMFSample_GetTotalLength(output.pSample, &length);
|
||||
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
||||
|
@ -7858,17 +7856,16 @@ static void test_h264_decoder(void)
|
|||
memset(&output, 0, sizeof(output));
|
||||
output.pSample = create_sample(NULL, actual_width * actual_height * 2);
|
||||
hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
|
||||
todo_wine
|
||||
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
||||
ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID);
|
||||
ok(!!output.pSample, "got pSample %p\n", output.pSample);
|
||||
ok(output.dwStatus == 0, "got dwStatus %#lx\n", output.dwStatus);
|
||||
ok(!output.pEvents, "got pEvents %p\n", output.pEvents);
|
||||
ok(status == 0, "got status %#lx\n", status);
|
||||
if (hr != S_OK) goto skip_i420_tests;
|
||||
|
||||
hr = IMFSample_GetSampleTime(output.pSample, &time);
|
||||
ok(hr == S_OK, "GetSampleTime returned %#lx\n", hr);
|
||||
todo_wine_if(time == 1334666) /* when VA-API plugin is used */
|
||||
ok(time - 333666 <= 2, "got time %I64d\n", time);
|
||||
|
||||
duration = 0xdeadbeef;
|
||||
|
@ -7904,7 +7901,6 @@ static void test_h264_decoder(void)
|
|||
|
||||
check_sample(output.pSample, i420_frame_data, output_file);
|
||||
|
||||
skip_i420_tests:
|
||||
ret = IMFSample_Release(output.pSample);
|
||||
ok(ret == 0, "Release returned %lu\n", ret);
|
||||
|
||||
|
@ -7915,6 +7911,7 @@ skip_i420_tests:
|
|||
memset(&output, 0, sizeof(output));
|
||||
output.pSample = create_sample(NULL, actual_width * actual_height * 2);
|
||||
hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
|
||||
todo_wine_if(hr == S_OK) /* when VA-API plugin is used */
|
||||
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
||||
ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID);
|
||||
ok(!!output.pSample, "got pSample %p\n", output.pSample);
|
||||
|
|
|
@ -102,6 +102,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate,
|
|||
struct wg_transform *wg_transform_create(const struct wg_format *input_format,
|
||||
const struct wg_format *output_format);
|
||||
void wg_transform_destroy(struct wg_transform *transform);
|
||||
bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format);
|
||||
|
||||
unsigned int wg_format_get_max_size(const struct wg_format *format);
|
||||
|
||||
|
|
|
@ -467,7 +467,28 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF
|
|||
IMFMediaType_Release(decoder->output_type);
|
||||
IMFMediaType_AddRef((decoder->output_type = type));
|
||||
|
||||
if (FAILED(hr = try_create_wg_transform(decoder)))
|
||||
if (decoder->wg_transform)
|
||||
{
|
||||
struct wg_format output_format;
|
||||
mf_media_type_to_wg_format(decoder->output_type, &output_format);
|
||||
|
||||
/* Don't force any specific size, H264 streams already have the metadata for it
|
||||
* and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
|
||||
*/
|
||||
output_format.u.video.width = 0;
|
||||
output_format.u.video.height = 0;
|
||||
output_format.u.video.fps_d = 0;
|
||||
output_format.u.video.fps_n = 0;
|
||||
|
||||
if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
|
||||
|| !wg_transform_set_output_format(decoder->wg_transform, &output_format))
|
||||
{
|
||||
IMFMediaType_Release(decoder->output_type);
|
||||
decoder->output_type = NULL;
|
||||
return MF_E_INVALIDMEDIATYPE;
|
||||
}
|
||||
}
|
||||
else if (FAILED(hr = try_create_wg_transform(decoder)))
|
||||
{
|
||||
IMFMediaType_Release(decoder->output_type);
|
||||
decoder->output_type = NULL;
|
||||
|
|
|
@ -348,6 +348,19 @@ HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample
|
|||
return params.result;
|
||||
}
|
||||
|
||||
bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format)
|
||||
{
|
||||
struct wg_transform_set_output_format_params params =
|
||||
{
|
||||
.transform = transform,
|
||||
.format = format,
|
||||
};
|
||||
|
||||
TRACE("transform %p, format %p.\n", transform, format);
|
||||
|
||||
return !__wine_unix_call(unix_handle, unix_wg_transform_set_output_format, ¶ms);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
|
|
|
@ -34,6 +34,7 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE
|
|||
|
||||
extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS wg_transform_set_output_format(void *args) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN;
|
||||
|
||||
|
|
|
@ -263,6 +263,12 @@ struct wg_transform_read_data_params
|
|||
HRESULT result;
|
||||
};
|
||||
|
||||
struct wg_transform_set_output_format_params
|
||||
{
|
||||
struct wg_transform *transform;
|
||||
const struct wg_format *format;
|
||||
};
|
||||
|
||||
enum unix_funcs
|
||||
{
|
||||
unix_wg_parser_create,
|
||||
|
@ -291,6 +297,7 @@ enum unix_funcs
|
|||
|
||||
unix_wg_transform_create,
|
||||
unix_wg_transform_destroy,
|
||||
unix_wg_transform_set_output_format,
|
||||
|
||||
unix_wg_transform_push_data,
|
||||
unix_wg_transform_read_data,
|
||||
|
|
|
@ -1625,6 +1625,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
|
|||
|
||||
X(wg_transform_create),
|
||||
X(wg_transform_destroy),
|
||||
X(wg_transform_set_output_format),
|
||||
|
||||
X(wg_transform_push_data),
|
||||
X(wg_transform_read_data),
|
||||
|
|
|
@ -51,6 +51,7 @@ struct wg_transform
|
|||
GstPad *my_src, *my_sink;
|
||||
GstPad *their_sink, *their_src;
|
||||
GstSegment segment;
|
||||
GstQuery *drain_query;
|
||||
|
||||
guint input_max_length;
|
||||
GstAtomicQueue *input_queue;
|
||||
|
@ -175,6 +176,31 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery
|
|||
g_object_unref(pool);
|
||||
return true;
|
||||
}
|
||||
|
||||
case GST_QUERY_CAPS:
|
||||
{
|
||||
GstCaps *caps, *filter, *temp;
|
||||
gchar *str;
|
||||
|
||||
gst_query_parse_caps(query, &filter);
|
||||
caps = gst_caps_ref(transform->output_caps);
|
||||
|
||||
if (filter)
|
||||
{
|
||||
temp = gst_caps_intersect(caps, filter);
|
||||
gst_caps_unref(caps);
|
||||
caps = temp;
|
||||
}
|
||||
|
||||
str = gst_caps_to_string(caps);
|
||||
GST_INFO("Returning caps %s", str);
|
||||
g_free(str);
|
||||
|
||||
gst_query_set_caps_result(query, caps);
|
||||
gst_caps_unref(caps);
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
GST_WARNING("Ignoring \"%s\" query.", gst_query_type_get_name(query->type));
|
||||
break;
|
||||
|
@ -236,6 +262,7 @@ NTSTATUS wg_transform_destroy(void *args)
|
|||
g_object_unref(transform->container);
|
||||
g_object_unref(transform->my_sink);
|
||||
g_object_unref(transform->my_src);
|
||||
gst_query_unref(transform->drain_query);
|
||||
gst_caps_unref(transform->output_caps);
|
||||
gst_atomic_queue_unref(transform->output_queue);
|
||||
free(transform);
|
||||
|
@ -344,6 +371,8 @@ NTSTATUS wg_transform_create(void *args)
|
|||
goto out;
|
||||
if (!(transform->output_queue = gst_atomic_queue_new(8)))
|
||||
goto out;
|
||||
if (!(transform->drain_query = gst_query_new_drain()))
|
||||
goto out;
|
||||
if (!(transform->allocator = wg_allocator_create(transform_request_sample, transform)))
|
||||
goto out;
|
||||
transform->input_max_length = 1;
|
||||
|
@ -505,6 +534,8 @@ out:
|
|||
gst_caps_unref(src_caps);
|
||||
if (transform->allocator)
|
||||
wg_allocator_destroy(transform->allocator);
|
||||
if (transform->drain_query)
|
||||
gst_query_unref(transform->drain_query);
|
||||
if (transform->output_queue)
|
||||
gst_atomic_queue_unref(transform->output_queue);
|
||||
if (transform->input_queue)
|
||||
|
@ -519,6 +550,59 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wg_transform_set_output_format(void *args)
|
||||
{
|
||||
struct wg_transform_set_output_format_params *params = args;
|
||||
struct wg_transform *transform = params->transform;
|
||||
const struct wg_format *format = params->format;
|
||||
GstSample *sample;
|
||||
GstCaps *caps;
|
||||
gchar *str;
|
||||
|
||||
if (!(caps = wg_format_to_caps(format)))
|
||||
{
|
||||
GST_ERROR("Failed to convert format %p to caps.", format);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if (gst_caps_is_always_compatible(transform->output_caps, caps))
|
||||
{
|
||||
gst_caps_unref(caps);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!gst_pad_peer_query(transform->my_src, transform->drain_query))
|
||||
{
|
||||
GST_ERROR("Failed to drain transform %p.", transform);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
gst_caps_unref(transform->output_caps);
|
||||
transform->output_caps = caps;
|
||||
|
||||
if (!gst_pad_push_event(transform->my_sink, gst_event_new_reconfigure()))
|
||||
{
|
||||
GST_ERROR("Failed to reconfigure transform %p.", transform);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
str = gst_caps_to_string(caps);
|
||||
GST_INFO("Configured new caps %s.", str);
|
||||
g_free(str);
|
||||
|
||||
/* Ideally and to be fully compatible with native transform, the queued
|
||||
* output buffers will need to be converted to the new output format and
|
||||
* kept queued.
|
||||
*/
|
||||
if (transform->output_sample)
|
||||
gst_sample_unref(transform->output_sample);
|
||||
while ((sample = gst_atomic_queue_pop(transform->output_queue)))
|
||||
gst_sample_unref(sample);
|
||||
transform->output_sample = NULL;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void wg_sample_free_notify(void *arg)
|
||||
{
|
||||
struct wg_sample *sample = arg;
|
||||
|
|
Loading…
Reference in a new issue