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 ---
v2: Remove useless MF_MT_FRAME_RATE query from patch 5.
dlls/mf/tests/mf.c | 6 ------ dlls/winegstreamer/h264_decoder.c | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index e58d8278b82..6563ca81b29 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6790,17 +6790,11 @@ static void test_h264_decoder(void) flags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; memset(&input_info, 0xcd, sizeof(input_info)); hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info); - todo_wine ok(hr == S_OK, "GetInputStreamInfo returned %#lx\n", hr); - todo_wine ok(input_info.hnsMaxLatency == 0, "got hnsMaxLatency %s\n", wine_dbgstr_longlong(input_info.hnsMaxLatency)); - todo_wine ok(input_info.dwFlags == flags, "got dwFlags %#lx\n", input_info.dwFlags); - todo_wine ok(input_info.cbSize == 0x1000, "got cbSize %lu\n", input_info.cbSize); - todo_wine ok(input_info.cbMaxLookahead == 0, "got cbMaxLookahead %#lx\n", input_info.cbMaxLookahead); - todo_wine ok(input_info.cbAlignment == 0, "got cbAlignment %#lx\n", input_info.cbAlignment);
flags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 2f4b42ed101..f24b07ef496 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -217,8 +217,20 @@ static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_si
static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) { - FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); - return E_NOTIMPL; + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); + + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + info->hnsMaxLatency = 0; + info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; + info->cbSize = 0x1000; + info->cbMaxLookahead = 0; + info->cbAlignment = 0; + + return S_OK; }
static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
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 --- dlls/mf/tests/mf.c | 22 ++++------------------ dlls/winegstreamer/h264_decoder.c | 23 +++++++++++++++++++++-- 2 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 6563ca81b29..0df524b4e16 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6688,13 +6688,9 @@ static void test_h264_decoder(void) flags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; memset(&output_info, 0xcd, sizeof(output_info)); hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); - todo_wine ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); - todo_wine ok(output_info.dwFlags == flags, "got dwFlags %#lx\n", output_info.dwFlags); - todo_wine - ok(output_info.cbSize == 0x3fc000, "got cbSize %#lx\n", output_info.cbSize); - todo_wine + ok(output_info.cbSize == 1920 * 1088 * 2, "got cbSize %#lx\n", output_info.cbSize); ok(output_info.cbAlignment == 0, "got cbAlignment %#lx\n", output_info.cbAlignment);
i = -1; @@ -6729,14 +6725,11 @@ static void test_h264_decoder(void) flags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; memset(&output_info, 0xcd, sizeof(output_info)); hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); - todo_wine ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); - todo_wine ok(output_info.dwFlags == flags, "got dwFlags %#lx\n", output_info.dwFlags); todo_wine - ok(output_info.cbSize == 0x3f4800 || broken(output_info.cbSize == 0x3fc000) /* Win7 */, + ok(output_info.cbSize == 1920 * 1080 * 2 || broken(output_info.cbSize == 1920 * 1088 * 2) /* Win7 */, "got cbSize %#lx\n", output_info.cbSize); - todo_wine ok(output_info.cbAlignment == 0, "got cbAlignment %#lx\n", output_info.cbAlignment);
/* output types can now be enumerated (though they are actually the same for all input types) */ @@ -6800,14 +6793,10 @@ static void test_h264_decoder(void) flags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; memset(&output_info, 0xcd, sizeof(output_info)); hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); - todo_wine ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); - todo_wine ok(output_info.dwFlags == flags, "got dwFlags %#lx\n", output_info.dwFlags); - todo_wine - ok(output_info.cbSize == 0x3f4800 || broken(output_info.cbSize == 0x3fc000) /* Win7 */, + ok(output_info.cbSize == 1920 * 1080 * 2 || broken(output_info.cbSize == 1920 * 1088 * 2) /* Win7 */, "got cbSize %#lx\n", output_info.cbSize); - todo_wine ok(output_info.cbAlignment == 0, "got cbAlignment %#lx\n", output_info.cbAlignment);
input_count = output_count = 0xdeadbeef; @@ -6846,7 +6835,7 @@ static void test_h264_decoder(void) { status = 0; memset(&output, 0, sizeof(output)); - output.pSample = create_sample(NULL, 0x3fc000); + output.pSample = create_sample(NULL, output_info.cbSize); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT) break; ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); @@ -6900,13 +6889,10 @@ static void test_h264_decoder(void) flags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; memset(&output_info, 0xcd, sizeof(output_info)); hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); - todo_wine ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); - todo_wine ok(output_info.dwFlags == flags, "got dwFlags %#lx\n", output_info.dwFlags); todo_wine ok(output_info.cbSize == 0x3200, "got cbSize %#lx\n", output_info.cbSize); - todo_wine ok(output_info.cbAlignment == 0, "got cbAlignment %#lx\n", output_info.cbAlignment);
i = -1; diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index f24b07ef496..36ca33ceca3 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -235,8 +235,27 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id
static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { - FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); - return E_NOTIMPL; + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + UINT32 sample_size; + UINT64 frame_size; + + TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); + + if (!decoder->output_type) + sample_size = 1920 * 1088 * 2; + else if (FAILED(IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_SAMPLE_SIZE, &sample_size))) + { + if (FAILED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size))) + sample_size = 1920 * 1088 * 2; + else + sample_size = (frame_size >> 32) * (UINT32)frame_size * 2; + } + + info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; + info->cbSize = sample_size; + info->cbAlignment = 0; + + return S_OK; }
static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
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 --- dlls/winegstreamer/h264_decoder.c | 35 ++++++++++++++- dlls/winegstreamer/mfplat.c | 45 +++++++++++++++++--- dlls/winegstreamer/quartz_parser.c | 11 ++--- dlls/winegstreamer/unixlib.h | 8 ++++ dlls/winegstreamer/wg_format.c | 68 ++++++++++++++++++++++++++++-- dlls/winegstreamer/wg_transform.c | 4 ++ dlls/winegstreamer/wm_reader.c | 8 +++- 7 files changed, 162 insertions(+), 17 deletions(-)
diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 36ca33ceca3..4edd4cdf39c 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -48,6 +48,8 @@ struct h264_decoder LONG refcount; IMFMediaType *input_type; IMFMediaType *output_type; + + struct wg_transform *wg_transform; };
static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -55,6 +57,29 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); }
+static HRESULT try_create_wg_transform(struct h264_decoder *decoder) +{ + struct wg_format input_format; + struct wg_format output_format; + + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + + mf_media_type_to_wg_format(decoder->input_type, &input_format); + if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + mf_media_type_to_wg_format(decoder->output_type, &output_format); + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + return E_FAIL; + + return S_OK; +} + static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) { UINT32 value, width, height; @@ -183,6 +208,8 @@ static ULONG WINAPI transform_Release(IMFTransform *iface)
if (!refcount) { + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); if (decoder->input_type) IMFMediaType_Release(decoder->input_type); if (decoder->output_type) @@ -416,7 +443,13 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF IMFMediaType_Release(decoder->output_type); IMFMediaType_AddRef((decoder->output_type = type));
- return S_OK; + if (FAILED(hr = try_create_wg_transform(decoder))) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + + return hr; }
static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index ed460144e8b..218f889bd9d 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -659,11 +659,11 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) { switch (format->major_type) { - case WG_MAJOR_TYPE_UNKNOWN: - return NULL; - + case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: - FIXME("WMA format not implemented!\n"); + FIXME("Format %u not implemented!\n", format->major_type); + /* fallthrough */ + case WG_MAJOR_TYPE_UNKNOWN: return NULL;
case WG_MAJOR_TYPE_AUDIO: @@ -822,6 +822,36 @@ static void mf_media_type_to_wg_format_wma(IMFMediaType *type, const GUID *subty memcpy(format->u.wma.codec_data, codec_data, codec_data_len); }
+static void mf_media_type_to_wg_format_h264(IMFMediaType *type, struct wg_format *format) +{ + UINT64 frame_rate, frame_size; + UINT32 profile, level; + + format->major_type = WG_MAJOR_TYPE_H264; + format->u.h264.width = 0; + format->u.h264.height = 0; + format->u.h264.fps_n = 1; + format->u.h264.fps_d = 1; + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.h264.width = (UINT32)(frame_size >> 32); + format->u.h264.height = (UINT32)frame_size; + } + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.h264.fps_n = (UINT32)(frame_rate >> 32); + format->u.h264.fps_d = (UINT32)frame_rate; + } + + if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) + format->u.h264.profile = profile; + + if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) + format->u.h264.level = level; +} + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { GUID major_type, subtype; @@ -850,7 +880,12 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) mf_media_type_to_wg_format_audio(type, &subtype, format); } else if (IsEqualGUID(&major_type, &MFMediaType_Video)) - mf_media_type_to_wg_format_video(type, &subtype, format); + { + if (IsEqualGUID(&subtype, &MFVideoFormat_H264)) + mf_media_type_to_wg_format_h264(type, format); + else + mf_media_type_to_wg_format_video(type, &subtype, format); + } else FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); } diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index d369d4c7f20..bb7a71283c3 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -328,8 +328,9 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) break; }
+ case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: - FIXME("WMA format not implemented!\n"); + FIXME("Format %u not implemented!\n", format->major_type); return 0;
case WG_MAJOR_TYPE_UNKNOWN: @@ -423,11 +424,11 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool
switch (format->major_type) { - case WG_MAJOR_TYPE_UNKNOWN: - return false; - + case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: - FIXME("WMA format not implemented!\n"); + FIXME("Format %u not implemented!\n", format->major_type); + /* fallthrough */ + case WG_MAJOR_TYPE_UNKNOWN: return false;
case WG_MAJOR_TYPE_AUDIO: diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index e1c0ec3f3b7..f4e2ea4966b 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -38,6 +38,7 @@ struct wg_format WG_MAJOR_TYPE_VIDEO, WG_MAJOR_TYPE_AUDIO, WG_MAJOR_TYPE_WMA, + WG_MAJOR_TYPE_H264, } major_type;
union @@ -100,6 +101,13 @@ struct wg_format uint32_t codec_data_len; unsigned char codec_data[64]; } wma; + struct + { + int32_t width, height; + uint32_t fps_n, fps_d; + uint32_t profile; + uint32_t level; + } h264; } u; };
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index fc50fad6d12..6d6f3eec18b 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -431,6 +431,64 @@ static GstCaps *wg_format_to_caps_wma(const struct wg_format *format) return caps; }
+static GstCaps *wg_format_to_caps_h264(const struct wg_format *format) +{ + const char *profile, *level; + GstCaps *caps; + + caps = gst_caps_new_empty_simple("video/x-h264"); + gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); + gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); + + if (format->u.h264.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.h264.width, NULL); + if (format->u.h264.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.h264.height, NULL); + if (format->u.h264.fps_n || format->u.h264.fps_d) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.h264.fps_n, format->u.h264.fps_d, NULL); + + switch (format->u.h264.profile) + { + case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break; + case /* eAVEncH264VProfile_High */ 100: profile = "high"; break; + case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break; + default: + GST_ERROR("Unrecognized H.264 profile attribute %u.", format->u.h264.profile); + /* fallthrough */ + case 0: profile = NULL; + } + if (profile) + gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); + + switch (format->u.h264.level) + { + case /* eAVEncH264VLevel1 */ 10: level = "1"; break; + case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break; + case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break; + case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break; + case /* eAVEncH264VLevel2 */ 20: level = "2"; break; + case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break; + case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break; + case /* eAVEncH264VLevel3 */ 30: level = "3"; break; + case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break; + case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break; + case /* eAVEncH264VLevel4 */ 40: level = "4"; break; + case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break; + case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break; + case /* eAVEncH264VLevel5 */ 50: level = "5"; break; + case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break; + case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break; + default: + GST_ERROR("Unrecognized H.264 level attribute %u.", format->u.h264.level); + /* fallthrough */ + case 0: level = NULL; + } + if (level) + gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); + + return caps; +} + GstCaps *wg_format_to_caps(const struct wg_format *format) { switch (format->major_type) @@ -439,6 +497,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) return NULL; case WG_MAJOR_TYPE_WMA: return wg_format_to_caps_wma(format); + case WG_MAJOR_TYPE_H264: + return wg_format_to_caps_h264(format); case WG_MAJOR_TYPE_AUDIO: return wg_format_to_caps_audio(format); case WG_MAJOR_TYPE_VIDEO: @@ -455,11 +515,11 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
switch (a->major_type) { - case WG_MAJOR_TYPE_UNKNOWN: - return false; - case WG_MAJOR_TYPE_WMA: - GST_FIXME("WMA format not implemented!\n"); + case WG_MAJOR_TYPE_H264: + GST_FIXME("Format %u not implemented!", a->major_type); + /* fallthrough */ + case WG_MAJOR_TYPE_UNKNOWN: return false;
case WG_MAJOR_TYPE_AUDIO: diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 6e272634653..0c43a9a0c5a 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -211,6 +211,7 @@ NTSTATUS wg_transform_create(void *args)
switch (input_format.major_type) { + case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) || !transform_append_element(transform, element, &first, &last)) @@ -251,6 +252,9 @@ NTSTATUS wg_transform_create(void *args) break;
case WG_MAJOR_TYPE_VIDEO: + break; + + case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", output_format.major_type); diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index c911cb59d1f..57ba8633a84 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1687,7 +1687,8 @@ HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output break;
case WG_MAJOR_TYPE_WMA: - FIXME("WMA format not implemented!\n"); + case WG_MAJOR_TYPE_H264: + FIXME("Format %u not implemented!\n", format.major_type); /* fallthrough */ case WG_MAJOR_TYPE_AUDIO: case WG_MAJOR_TYPE_UNKNOWN: @@ -1736,7 +1737,8 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output, break;
case WG_MAJOR_TYPE_WMA: - FIXME("WMA format not implemented!\n"); + case WG_MAJOR_TYPE_H264: + FIXME("Format %u not implemented!\n", format.major_type); break; case WG_MAJOR_TYPE_UNKNOWN: break; @@ -1815,6 +1817,8 @@ static const char *get_major_type_string(enum wg_major_type type) return "unknown"; case WG_MAJOR_TYPE_WMA: return "wma"; + case WG_MAJOR_TYPE_H264: + return "h264"; } assert(0); return NULL;
On 3/21/22 03:42, Rémi Bernon wrote:
+static void mf_media_type_to_wg_format_h264(IMFMediaType *type, struct wg_format *format) +{
- UINT64 frame_rate, frame_size;
- UINT32 profile, level;
- format->major_type = WG_MAJOR_TYPE_H264;
- format->u.h264.width = 0;
- format->u.h264.height = 0;
- format->u.h264.fps_n = 1;
- format->u.h264.fps_d = 1;
Something of a nitpick, but it looks wrong to partially zero-initialize here. If we're relying on the struct to be zeroed I'd rather be consistent about it.
- if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
- {
format->u.h264.width = (UINT32)(frame_size >> 32);
format->u.h264.height = (UINT32)frame_size;
- }
- if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate)
- {
format->u.h264.fps_n = (UINT32)(frame_rate >> 32);
format->u.h264.fps_d = (UINT32)frame_rate;
- }
These casts are redundant.
- if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile)))
format->u.h264.profile = profile;
- if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level)))
format->u.h264.level = level;
+}
...
+static GstCaps *wg_format_to_caps_h264(const struct wg_format *format) +{
- const char *profile, *level;
- GstCaps *caps;
- caps = gst_caps_new_empty_simple("video/x-h264");
- gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL);
- gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL);
- if (format->u.h264.width)
gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.h264.width, NULL);
- if (format->u.h264.height)
gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.h264.height, NULL);
- if (format->u.h264.fps_n || format->u.h264.fps_d)
gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.h264.fps_n, format->u.h264.fps_d, NULL);
- switch (format->u.h264.profile)
- {
case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break;
case /* eAVEncH264VProfile_High */ 100: profile = "high"; break;
case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break;
default:
GST_ERROR("Unrecognized H.264 profile attribute %u.", format->u.h264.profile);
/* fallthrough */
case 0: profile = NULL;
- }
- if (profile)
gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL);
- switch (format->u.h264.level)
- {
case /* eAVEncH264VLevel1 */ 10: level = "1"; break;
case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break;
case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break;
case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break;
case /* eAVEncH264VLevel2 */ 20: level = "2"; break;
case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break;
case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break;
case /* eAVEncH264VLevel3 */ 30: level = "3"; break;
case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break;
case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break;
case /* eAVEncH264VLevel4 */ 40: level = "4"; break;
case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break;
case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break;
case /* eAVEncH264VLevel5 */ 50: level = "5"; break;
case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break;
case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break;
default:
GST_ERROR("Unrecognized H.264 level attribute %u.", format->u.h264.level);
/* fallthrough */
case 0: level = NULL;
- }
- if (level)
gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL);
- return caps;
+}
Any reason not to use these constants?
@@ -251,6 +252,9 @@ NTSTATUS wg_transform_create(void *args) break;
case WG_MAJOR_TYPE_VIDEO:
break;
case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", output_format.major_type);
This hunk doesn't seem like it belongs in this patch...
On 3/21/22 18:55, Zebediah Figura wrote:
On 3/21/22 03:42, Rémi Bernon wrote:
+static void mf_media_type_to_wg_format_h264(IMFMediaType *type, struct wg_format *format) +{ + UINT64 frame_rate, frame_size; + UINT32 profile, level;
+ format->major_type = WG_MAJOR_TYPE_H264; + format->u.h264.width = 0; + format->u.h264.height = 0; + format->u.h264.fps_n = 1; + format->u.h264.fps_d = 1;
Something of a nitpick, but it looks wrong to partially zero-initialize here. If we're relying on the struct to be zeroed I'd rather be consistent about it.
Sure.
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.h264.width = (UINT32)(frame_size >> 32); + format->u.h264.height = (UINT32)frame_size; + }
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.h264.fps_n = (UINT32)(frame_rate >> 32); + format->u.h264.fps_d = (UINT32)frame_rate; + }
These casts are redundant.
Yes, but in the case of a later type change for the struct members, this will go very wrong and unnoticed.
I think it's best cast there (at least the lower bits) to make sure we extract the right values from the ratio, regardless to where we store them.
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) + format->u.h264.profile = profile;
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) + format->u.h264.level = level; +}
...
+static GstCaps *wg_format_to_caps_h264(const struct wg_format *format) +{ + const char *profile, *level; + GstCaps *caps;
+ caps = gst_caps_new_empty_simple("video/x-h264"); + gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); + gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL);
+ if (format->u.h264.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.h264.width, NULL); + if (format->u.h264.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.h264.height, NULL); + if (format->u.h264.fps_n || format->u.h264.fps_d) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.h264.fps_n, format->u.h264.fps_d, NULL);
+ switch (format->u.h264.profile) + { + case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break; + case /* eAVEncH264VProfile_High */ 100: profile = "high"; break; + case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break; + default: + GST_ERROR("Unrecognized H.264 profile attribute %u.", format->u.h264.profile); + /* fallthrough */ + case 0: profile = NULL; + } + if (profile) + gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL);
+ switch (format->u.h264.level) + { + case /* eAVEncH264VLevel1 */ 10: level = "1"; break; + case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break; + case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break; + case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break; + case /* eAVEncH264VLevel2 */ 20: level = "2"; break; + case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break; + case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break; + case /* eAVEncH264VLevel3 */ 30: level = "3"; break; + case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break; + case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break; + case /* eAVEncH264VLevel4 */ 40: level = "4"; break; + case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break; + case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break; + case /* eAVEncH264VLevel5 */ 50: level = "5"; break; + case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break; + case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break; + default: + GST_ERROR("Unrecognized H.264 level attribute %u.", format->u.h264.level); + /* fallthrough */ + case 0: level = NULL; + } + if (level) + gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL);
+ return caps; +}
Any reason not to use these constants?
@@ -251,6 +252,9 @@ NTSTATUS wg_transform_create(void *args) break; case WG_MAJOR_TYPE_VIDEO: + break;
+ case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", output_format.major_type);
This hunk doesn't seem like it belongs in this patch...
I think it does, the patch adds support for H264 formats, and creates a wg_transform in the H264 decoder to use it, the transform has a decoded video output format, which would cause an error if the hunk was not there.
On 3/21/22 14:55, Rémi Bernon wrote:
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.h264.width = (UINT32)(frame_size >> 32); + format->u.h264.height = (UINT32)frame_size; + }
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.h264.fps_n = (UINT32)(frame_rate >> 32); + format->u.h264.fps_d = (UINT32)frame_rate; + }
These casts are redundant.
Yes, but in the case of a later type change for the struct members, this will go very wrong and unnoticed.
I think it's best cast there (at least the lower bits) to make sure we extract the right values from the ratio, regardless to where we store them.
Okay, fair enough.
@@ -251,6 +252,9 @@ NTSTATUS wg_transform_create(void *args) break; case WG_MAJOR_TYPE_VIDEO: + break;
+ case WG_MAJOR_TYPE_H264: case WG_MAJOR_TYPE_WMA: case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", output_format.major_type);
This hunk doesn't seem like it belongs in this patch...
I think it does, the patch adds support for H264 formats, and creates a wg_transform in the H264 decoder to use it, the transform has a decoded video output format, which would cause an error if the hunk was not there.
I'm sorry, I can't read. I mixed up which enumeration this is, and thought it was the other one...
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 --- dlls/winegstreamer/wg_transform.c | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 0c43a9a0c5a..5f6477c96a0 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -48,7 +48,8 @@ struct wg_transform GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; GstSegment segment; - GstBuffer *input; + GstBufferList *input; + guint input_max_length;
pthread_mutex_t mutex; GstBuffer *output; @@ -75,7 +76,7 @@ NTSTATUS wg_transform_destroy(void *args) struct wg_transform *transform = args;
if (transform->input) - gst_buffer_unref(transform->input); + gst_buffer_list_unref(transform->input); if (transform->output) gst_buffer_unref(transform->output);
@@ -179,6 +180,9 @@ NTSTATUS wg_transform_create(void *args) return STATUS_NO_MEMORY; if (!(transform->container = gst_bin_new("wg_transform"))) goto out; + if (!(transform->input = gst_buffer_list_new())) + goto out; + transform->input_max_length = 1;
if (!(src_caps = wg_format_to_caps(&input_format))) goto out; @@ -212,6 +216,8 @@ NTSTATUS wg_transform_create(void *args) switch (input_format.major_type) { case WG_MAJOR_TYPE_H264: + transform->input_max_length = 16; + /* fallthrough */ case WG_MAJOR_TYPE_WMA: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) || !transform_append_element(transform, element, &first, &last)) @@ -316,6 +322,8 @@ out: gst_object_unref(transform->my_src); if (src_caps) gst_caps_unref(src_caps); + if (transform->input) + gst_buffer_list_unref(transform->input); if (transform->container) { gst_element_set_state(transform->container, GST_STATE_NULL); @@ -332,10 +340,12 @@ NTSTATUS wg_transform_push_data(void *args) struct wg_transform *transform = params->transform; struct wg_sample *sample = params->sample; GstBuffer *buffer; + guint length;
- if (transform->input) + length = gst_buffer_list_length(transform->input); + if (length >= transform->input_max_length) { - GST_INFO("Refusing %u bytes, a buffer is already queued", sample->size); + GST_INFO("Refusing %u bytes, %u buffers already queued", sample->size, length); params->result = MF_E_NOTACCEPTING; return STATUS_SUCCESS; } @@ -346,9 +356,9 @@ NTSTATUS wg_transform_push_data(void *args) return STATUS_NO_MEMORY; } gst_buffer_fill(buffer, 0, sample->data, sample->size); - transform->input = buffer; + gst_buffer_list_insert(transform->input, -1, buffer);
- GST_INFO("Copied %u bytes from sample %p to input buffer", sample->size, sample); + GST_INFO("Copied %u bytes from sample %p to input buffer list", sample->size, sample); params->result = S_OK; return STATUS_SUCCESS; } @@ -392,17 +402,22 @@ NTSTATUS wg_transform_read_data(void *args) struct wg_transform_read_data_params *params = args; struct wg_transform *transform = params->transform; struct wg_sample *sample = params->sample; + GstBufferList *input = transform->input; GstFlowReturn ret; NTSTATUS status;
- if (!transform->input) + if (!gst_buffer_list_length(transform->input)) GST_DEBUG("Not input buffer queued"); - else if ((ret = gst_pad_push(transform->my_src, transform->input))) + else if (!(transform->input = gst_buffer_list_new())) + { + GST_ERROR("Failed to allocate new input queue"); + return STATUS_NO_MEMORY; + } + else if ((ret = gst_pad_push_list(transform->my_src, input))) { GST_ERROR("Failed to push transform input, error %d", ret); return STATUS_UNSUCCESSFUL; } - transform->input = NULL;
sample->size = 0; pthread_mutex_lock(&transform->mutex);
On 3/21/22 03:42, Rémi Bernon wrote:
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
dlls/winegstreamer/wg_transform.c | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
As far as I'm aware, the only reason to use a GstBufferList is to reduce the overhead of pushing multiple buffers simultaneously. Can you please add an explanation, either in the commit message or (ideally) in the code?
On 3/21/22 18:55, Zebediah Figura wrote:
On 3/21/22 03:42, Rémi Bernon wrote:
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
dlls/winegstreamer/wg_transform.c | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
As far as I'm aware, the only reason to use a GstBufferList is to reduce the overhead of pushing multiple buffers simultaneously. Can you please add an explanation, either in the commit message or (ideally) in the code?
It also, and primarily, lets us keep multiple input buffers queued without having to reimplement a buffer list, as the H264 transform behavior, expected by some games, and the tests, require it.
I can add a comment I guess.
On 3/21/22 14:43, Rémi Bernon wrote:
On 3/21/22 18:55, Zebediah Figura wrote:
On 3/21/22 03:42, Rémi Bernon wrote:
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
dlls/winegstreamer/wg_transform.c | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
As far as I'm aware, the only reason to use a GstBufferList is to reduce the overhead of pushing multiple buffers simultaneously. Can you please add an explanation, either in the commit message or (ideally) in the code?
It also, and primarily, lets us keep multiple input buffers queued without having to reimplement a buffer list, as the H264 transform behavior, expected by some games, and the tests, require it.
I can add a comment I guess.
Okay, I had forgotten that we defer pushing data until wg_transform_read_data(). The comment does help, though, so thank you for that.
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 --- dlls/mf/tests/mf.c | 3 -- dlls/winegstreamer/h264_decoder.c | 54 ++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0df524b4e16..0c1065572ca 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6821,7 +6821,6 @@ static void test_h264_decoder(void) status = 0; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == E_INVALIDARG || 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); @@ -6849,14 +6848,12 @@ static void test_h264_decoder(void) ok(ret == 0, "Release returned %lu\n", ret);
hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); ret = IMFSample_Release(sample); ok(ret <= 1, "Release returned %lu\n", ret); sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); ret = IMFSample_Release(sample); ok(ret <= 1, "Release returned %lu\n", ret); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 4edd4cdf39c..950d9ebf335 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -496,15 +496,61 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_
static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); - return E_NOTIMPL; + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + struct wg_sample *wg_sample; + MFT_INPUT_STREAM_INFO info; + HRESULT hr; + + TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + + if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) + return hr; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = mf_create_wg_sample(sample, &wg_sample))) + return hr; + + hr = wg_transform_push_data(decoder->wg_transform, wg_sample); + + mf_destroy_wg_sample(wg_sample); + return hr; }
static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { - FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); - return E_NOTIMPL; + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + MFT_OUTPUT_STREAM_INFO info; + struct wg_sample *wg_sample; + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + + if (count != 1) + return E_INVALIDARG; + + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) + return hr; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *status = 0; + samples[0].dwStatus = 0; + if (!samples[0].pSample) return E_INVALIDARG; + + if (FAILED(hr = mf_create_wg_sample(samples[0].pSample, &wg_sample))) + return hr; + + if (wg_sample->max_size < info.cbSize) + hr = MF_E_BUFFERTOOSMALL; + else + hr = wg_transform_read_data(decoder->wg_transform, wg_sample); + + mf_destroy_wg_sample(wg_sample); + return hr; }
static const IMFTransformVtbl transform_vtbl =
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110818
Your paranoid android.
=== w8adm (32 bit report) ===
mf: mf.c:4425: Test failed: Unexpected hr 0x800401f0.