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 Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
Resending with the sign-offs but without PATCH 5 which will require some changes.
Supersedes: 230378-230382
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 Signed-off-by: Nikolay Sivov nsivov@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)
Adding H264 format support in wg_format.
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 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/h264_decoder.c | 35 ++++++++++++++- dlls/winegstreamer/mfplat.c | 47 +++++++++++++++++--- dlls/winegstreamer/quartz_parser.c | 11 ++--- dlls/winegstreamer/unixlib.h | 8 ++++ dlls/winegstreamer/wg_format.c | 69 ++++++++++++++++++++++++++++-- dlls/winegstreamer/wg_transform.c | 4 ++ dlls/winegstreamer/wm_reader.c | 8 +++- 7 files changed, 165 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..97e27bb7301 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,38 @@ 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; + + memset(format, 0, sizeof(*format)); + format->major_type = WG_MAJOR_TYPE_H264; + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.h264.width = 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 = frame_rate >> 32; + format->u.h264.fps_d = (UINT32)frame_rate; + } + else + { + format->u.h264.fps_n = 1; + format->u.h264.fps_d = 1; + } + + 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 +882,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..b4455a6e6d0 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -35,6 +35,7 @@ #include <gst/audio/audio.h>
#include "winternl.h" +#include "codecapi.h" #include "dshow.h"
#include "unix_private.h" @@ -431,6 +432,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: profile = "main"; break; + case eAVEncH264VProfile_High: profile = "high"; break; + case eAVEncH264VProfile_444: profile = "high-4:4:4"; break; + default: + GST_FIXME("H264 profile attribute %u not implemented.", format->u.h264.profile); + profile = NULL; + break; + } + if (profile) + gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); + + switch (format->u.h264.level) + { + case eAVEncH264VLevel1: level = "1"; break; + case eAVEncH264VLevel1_1: level = "1.1"; break; + case eAVEncH264VLevel1_2: level = "1.2"; break; + case eAVEncH264VLevel1_3: level = "1.3"; break; + case eAVEncH264VLevel2: level = "2"; break; + case eAVEncH264VLevel2_1: level = "2.1"; break; + case eAVEncH264VLevel2_2: level = "2.2"; break; + case eAVEncH264VLevel3: level = "3"; break; + case eAVEncH264VLevel3_1: level = "3.1"; break; + case eAVEncH264VLevel3_2: level = "3.2"; break; + case eAVEncH264VLevel4: level = "4"; break; + case eAVEncH264VLevel4_1: level = "4.1"; break; + case eAVEncH264VLevel4_2: level = "4.2"; break; + case eAVEncH264VLevel5: level = "5"; break; + case eAVEncH264VLevel5_1: level = "5.1"; break; + case eAVEncH264VLevel5_2: level = "5.2"; break; + default: + GST_FIXME("H264 level attribute %u not implemented.", format->u.h264.level); + level = NULL; + break; + } + 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 +498,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 +516,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;
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 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wg_transform.c | 38 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 0c43a9a0c5a..200dd946e02 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,13 @@ NTSTATUS wg_transform_create(void *args) switch (input_format.major_type) { case WG_MAJOR_TYPE_H264: + /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput + * return values, it calls them in a specific order and and expects the decoder + * transform to be able to queue its input buffers. We need to use a buffer list + * to match its expectations. + */ + 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 +327,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 +345,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 +361,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 +407,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);