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 | 7 +--- dlls/winegstreamer/h264_decoder.c | 59 ++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 11 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 31a84e47bc1..e7d8de649ef 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6868,19 +6868,15 @@ static void test_h264_decoder(void) ok(i == 2, "got %lu iterations\n", i); todo_wine ok(h264_encoded_data_len == 48194, "got h264_encoded_data_len %lu\n", h264_encoded_data_len); - todo_wine 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); - if (status == MFT_PROCESS_OUTPUT_STATUS_NEW_STREAMS) - check_sample(output.pSample, NULL, 0, NULL); + check_sample(output.pSample, NULL, 0, NULL); ret = IMFSample_Release(output.pSample); ok(ret == 0, "Release returned %lu\n", ret);
@@ -6922,7 +6918,6 @@ 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); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 8bfa15529db..2fbbefd1e2d 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -50,6 +50,7 @@ struct h264_decoder IMFMediaType *output_type;
struct wg_transform *wg_transform; + struct wg_format output_format; };
static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -60,7 +61,6 @@ static struct h264_decoder *impl_from_IMFTransform(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); @@ -70,11 +70,18 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) 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) + mf_media_type_to_wg_format(decoder->output_type, &decoder->output_format); + if (decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + /* Don't force any output frame size, H264 streams already have the + * metadata for it and will generate a MF_E_TRANSFORM_STREAM_CHANGE + * result later. + */ + decoder->output_format.u.video.width = 0; + decoder->output_format.u.video.height = 0; + + if (!(decoder->wg_transform = wg_transform_create(&input_format, &decoder->output_format))) return E_FAIL;
return S_OK; @@ -369,7 +376,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) goto done;
- hr = fill_output_media_type(media_type, NULL); + hr = fill_output_media_type(media_type, decoder->output_type);
done: if (SUCCEEDED(hr)) @@ -418,6 +425,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF { struct h264_decoder *decoder = impl_from_IMFTransform(iface); GUID major, subtype; + BOOL identical; HRESULT hr; ULONG i;
@@ -440,7 +448,14 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF return MF_E_INVALIDMEDIATYPE;
if (decoder->output_type) + { + fill_output_media_type(decoder->output_type, NULL); + if (SUCCEEDED(hr = IMFMediaType_Compare(decoder->output_type, (IMFAttributes *)type, + MF_ATTRIBUTES_MATCH_THEIR_ITEMS, &identical)) && identical) + return S_OK; IMFMediaType_Release(decoder->output_type); + } + IMFMediaType_AddRef((decoder->output_type = type));
if (FAILED(hr = try_create_wg_transform(decoder))) @@ -490,7 +505,23 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM
static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); + + switch (message) + { + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + /* Call of Duty Black Ops 3 expects to receive an MF_E_TRANSFORM_STREAM_CHANGE result again + * after it has called ProcessMessage with BEGIN_STREAMING. We could destroy and re-create + * the wg_transform instead but resetting the output format should be enough. + */ + memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + break; + default: + break; + } + return S_OK; }
@@ -524,6 +555,8 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, struct h264_decoder *decoder = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; struct wg_sample *wg_sample; + IMFMediaType *media_type; + UINT64 frame_rate; HRESULT hr;
TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -537,6 +570,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (!decoder->wg_transform) return MF_E_TRANSFORM_TYPE_NOT_SET;
+ if (FAILED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))) + frame_rate = (UINT64)30000 << 32 | 1001; + *status = 0; samples[0].dwStatus = 0; if (!samples[0].pSample) return E_INVALIDARG; @@ -544,11 +580,24 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (FAILED(hr = mf_create_wg_sample(samples[0].pSample, &wg_sample))) return hr;
+ wg_sample->format = &decoder->output_format; if (wg_sample->max_size < info.cbSize) hr = MF_E_BUFFERTOOSMALL; else hr = wg_transform_read_data(decoder->wg_transform, wg_sample);
+ if (hr == MF_E_TRANSFORM_STREAM_CHANGE) + { + media_type = mf_media_type_from_wg_format(&decoder->output_format); + IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, frame_rate); + + IMFMediaType_Release(decoder->output_type); + decoder->output_type = media_type; + + samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + } + mf_destroy_wg_sample(wg_sample); return hr; }