These functions are needed by a steam game called Super Naughty Maid. It uses DMO wrapper filter to play WMV videos.
From: Ziqing Hui zhui@codeweavers.com
--- dlls/wmvcore/tests/wmvcore.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 401856eb744..a2f92e66e40 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1204,6 +1204,16 @@ static void test_sync_reader_streaming(void) ref = IWMStreamConfig_Release(config2); ok(!ref, "Got outstanding refcount %ld.\n", ref);
+ hr = IWMProfile_GetStreamByNumber(profile, i + 1, &config2); + todo_wine + ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(config2 != config, "Expected different objects.\n"); + ref = IWMStreamConfig_Release(config2); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + } + stream_numbers[i] = 0xdead; hr = IWMStreamConfig_GetStreamNumber(config, &stream_numbers[i]); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1215,6 +1225,12 @@ static void test_sync_reader_streaming(void)
hr = IWMProfile_GetStream(profile, 2, &config); ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + hr = IWMProfile_GetStreamByNumber(profile, 0, &config); + todo_wine + ok(hr == NS_E_NO_STREAM, "Got hr %#lx.\n", hr); + hr = IWMProfile_GetStreamByNumber(profile, 3, &config); + todo_wine + ok(hr == NS_E_NO_STREAM, "Got hr %#lx.\n", hr);
while (!eos[0] || !eos[1]) {
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/wm_reader.c | 14 ++++++++++++-- dlls/wmvcore/tests/wmvcore.c | 6 ------ 2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 8ac852a99b0..fd58dab574e 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -777,8 +777,18 @@ static HRESULT WINAPI profile_GetStream(IWMProfile3 *iface, DWORD index, IWMStre
static HRESULT WINAPI profile_GetStreamByNumber(IWMProfile3 *iface, WORD stream_number, IWMStreamConfig **config) { - FIXME("iface %p, stream_number %u, config %p, stub!\n", iface, stream_number, config); - return E_NOTIMPL; + struct wm_reader *reader = impl_from_IWMProfile3(iface); + + TRACE("iface %p, stream_number %u, config %p.\n", iface, stream_number, config); + + EnterCriticalSection(&reader->cs); + if (!stream_number || stream_number > reader->stream_count) + { + LeaveCriticalSection(&reader->cs); + return NS_E_NO_STREAM; + } + + return profile_GetStream(iface, stream_number - 1, config); }
static HRESULT WINAPI profile_RemoveStream(IWMProfile3 *iface, IWMStreamConfig *config) diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index a2f92e66e40..874fca81367 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1205,14 +1205,10 @@ static void test_sync_reader_streaming(void) ok(!ref, "Got outstanding refcount %ld.\n", ref);
hr = IWMProfile_GetStreamByNumber(profile, i + 1, &config2); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr == S_OK) - { ok(config2 != config, "Expected different objects.\n"); ref = IWMStreamConfig_Release(config2); ok(!ref, "Got outstanding refcount %ld.\n", ref); - }
stream_numbers[i] = 0xdead; hr = IWMStreamConfig_GetStreamNumber(config, &stream_numbers[i]); @@ -1226,10 +1222,8 @@ static void test_sync_reader_streaming(void) hr = IWMProfile_GetStream(profile, 2, &config); ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); hr = IWMProfile_GetStreamByNumber(profile, 0, &config); - todo_wine ok(hr == NS_E_NO_STREAM, "Got hr %#lx.\n", hr); hr = IWMProfile_GetStreamByNumber(profile, 3, &config); - todo_wine ok(hr == NS_E_NO_STREAM, "Got hr %#lx.\n", hr);
while (!eos[0] || !eos[1])
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index c85a15926fa..2ff6f7dbfc4 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4475,6 +4475,57 @@ failed: CoUninitialize(); }
+static void test_wmv_decoder_media_object(void) +{ + const GUID *const class_id = &CLSID_CWMVDecMediaObject; + IMediaObject *media_object; + DWORD in_count, out_count; + HRESULT hr; + ULONG ret; + + winetest_push_context("wmvdec"); + + if (!has_video_processor) + { + win_skip("Skipping inconsistent WMV decoder media object tests on Win7.\n"); + winetest_pop_context(); + return; + } + + hr = CoInitialize(NULL); + ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr); + + hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&media_object); + ok(hr == S_OK, "CoCreateInstance returned %#lx.\n", hr); + + /* Test GetStreamCount. */ + in_count = out_count = 0xdeadbeef; + hr = IMediaObject_GetStreamCount(media_object, &in_count, &out_count); + todo_wine + ok(hr == S_OK, "GetStreamCount returned %#lx.\n", hr); + if (hr == S_OK) + { + ok(in_count == 1, "Got unexpected in_count %lu.\n", in_count); + ok(out_count == 1, "Got unexpected in_count %lu.\n", out_count); + } + + /* Test GetStreamCount with invalid arguments. */ + in_count = out_count = 0xdeadbeef; + hr = IMediaObject_GetStreamCount(media_object, NULL, &out_count); + todo_wine + ok(hr == E_POINTER, "GetStreamCount returned %#lx.\n", hr); + ok(out_count == 0xdeadbeef, "Got unexpected out_count %lu.\n", out_count); + hr = IMediaObject_GetStreamCount(media_object, &in_count, NULL); + todo_wine + ok(hr == E_POINTER, "GetStreamCount returned %#lx.\n", hr); + ok(in_count == 0xdeadbeef, "Got unexpected in_count %lu.\n", in_count); + + ret = IMediaObject_Release(media_object); + ok(ret == 0, "Release returned %lu\n", ret); + CoUninitialize(); + winetest_pop_context(); +} + static void test_color_convert(void) { const GUID *const class_id = &CLSID_CColorConvertDMO; @@ -5776,6 +5827,7 @@ START_TEST(transform) test_h264_decoder(); test_wmv_encoder(); test_wmv_decoder(); + test_wmv_decoder_media_object(); test_audio_convert(); test_color_convert(); test_video_processor();
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 6 ------ dlls/winegstreamer/wmv_decoder.c | 10 ++++++++-- 2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 2ff6f7dbfc4..cc8914ff17b 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4501,22 +4501,16 @@ static void test_wmv_decoder_media_object(void) /* Test GetStreamCount. */ in_count = out_count = 0xdeadbeef; hr = IMediaObject_GetStreamCount(media_object, &in_count, &out_count); - todo_wine ok(hr == S_OK, "GetStreamCount returned %#lx.\n", hr); - if (hr == S_OK) - { ok(in_count == 1, "Got unexpected in_count %lu.\n", in_count); ok(out_count == 1, "Got unexpected in_count %lu.\n", out_count); - }
/* Test GetStreamCount with invalid arguments. */ in_count = out_count = 0xdeadbeef; hr = IMediaObject_GetStreamCount(media_object, NULL, &out_count); - todo_wine ok(hr == E_POINTER, "GetStreamCount returned %#lx.\n", hr); ok(out_count == 0xdeadbeef, "Got unexpected out_count %lu.\n", out_count); hr = IMediaObject_GetStreamCount(media_object, &in_count, NULL); - todo_wine ok(hr == E_POINTER, "GetStreamCount returned %#lx.\n", hr); ok(in_count == 0xdeadbeef, "Got unexpected in_count %lu.\n", in_count);
diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index 6ee21e5b5c1..fe9870e1bc3 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -320,8 +320,14 @@ static ULONG WINAPI media_object_Release(IMediaObject *iface)
static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) { - FIXME("iface %p, input %p, output %p stub!\n", iface, input, output); - return E_NOTIMPL; + TRACE("iface %p, input %p, output %p.\n", iface, input, output); + + if (!input || !output) + return E_POINTER; + + *input = *output = 1; + + return S_OK; }
static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 77 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index cc8914ff17b..972e01331b7 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -33,6 +33,7 @@ #include "propvarutil.h" #include "uuids.h" #include "wmcodecdsp.h" +#include "mediaerr.h"
#include "mf_test.h"
@@ -1047,6 +1048,33 @@ DWORD check_mf_sample_collection_(const char *file, int line, IMFCollection *sam return ctx.diff / count; }
+#define check_dmo_media_type(a, b) check_dmo_media_type_(__LINE__, a, b) +static void check_dmo_media_type_(int line, DMO_MEDIA_TYPE *media_type, const DMO_MEDIA_TYPE *expected) +{ + ok_(__FILE__, line)(IsEqualGUID(&media_type->majortype, &expected->majortype), + "Got unexpected majortype %s, expected %s.\n", + debugstr_guid(&media_type->majortype), debugstr_guid(&expected->majortype)); + ok_(__FILE__, line)(IsEqualGUID(&media_type->subtype, &expected->subtype), + "Got unexpected subtype %s, expected %s.\n", + debugstr_guid(&media_type->subtype), debugstr_guid(&expected->subtype)); + ok_(__FILE__, line)(media_type->bFixedSizeSamples == expected->bFixedSizeSamples, + "Got unexpected bFixedSizeSamples %d, expected %d.\n", + media_type->bFixedSizeSamples, expected->bFixedSizeSamples); + ok_(__FILE__, line)(media_type->bTemporalCompression == expected->bTemporalCompression, + "Got unexpected bTemporalCompression %d, expected %d.\n", + media_type->bTemporalCompression, expected->bTemporalCompression); + ok_(__FILE__, line)(media_type->lSampleSize == expected->lSampleSize, + "Got unexpected lSampleSize %lu, expected %lu.\n", + media_type->lSampleSize, expected->lSampleSize); + + ok_(__FILE__, line)(IsEqualGUID(&media_type->formattype, &GUID_NULL), + "Got unexpected formattype %s.\n", + debugstr_guid(&media_type->formattype)); + ok_(__FILE__, line)(media_type->pUnk == NULL, "Got unexpected pUnk %p.\n", media_type->pUnk); + ok_(__FILE__, line)(media_type->cbFormat == 0, "Got unexpected cbFormat %lu.\n", media_type->cbFormat); + ok_(__FILE__, line)(media_type->pbFormat == NULL, "Got unexpected pbFormat %p.\n", media_type->pbFormat); +} + static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -4478,10 +4506,23 @@ failed: static void test_wmv_decoder_media_object(void) { const GUID *const class_id = &CLSID_CWMVDecMediaObject; + const DMO_MEDIA_TYPE expected_input_types[] = + { + {MFMediaType_Video, MFVideoFormat_WMV1, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MFVideoFormat_WMV2, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MEDIASUBTYPE_WMVA, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MEDIASUBTYPE_WMVP, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MEDIASUBTYPE_WVP2, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MFVideoFormat_WMV_Unknown, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MFVideoFormat_WVC1, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MFVideoFormat_WMV3, FALSE, TRUE, FALSE}, + {MFMediaType_Video, MFVideoFormat_VC1S, FALSE, TRUE, FALSE}, + }; IMediaObject *media_object; + DMO_MEDIA_TYPE media_type; DWORD in_count, out_count; + ULONG ret, i; HRESULT hr; - ULONG ret;
winetest_push_context("wmvdec");
@@ -4514,6 +4555,40 @@ static void test_wmv_decoder_media_object(void) ok(hr == E_POINTER, "GetStreamCount returned %#lx.\n", hr); ok(in_count == 0xdeadbeef, "Got unexpected in_count %lu.\n", in_count);
+ /* Test GetInputType. */ + i = -1; + while (SUCCEEDED(hr = IMediaObject_GetInputType(media_object, 0, ++i, &media_type))) + { + winetest_push_context("in %lu", i); + check_dmo_media_type(&media_type, &expected_input_types[i]); + winetest_pop_context(); + } + todo_wine + ok(i == ARRAY_SIZE(expected_input_types), "%lu input types.\n", i); + + /* Test GetInputType with invalid arguments. */ + hr = IMediaObject_GetInputType(media_object, 0, ARRAY_SIZE(expected_input_types) - 1, &media_type); + todo_wine + ok(hr == S_OK, "GetInputType returned unexpected hr %#lx.\n", hr); + hr = IMediaObject_GetInputType(media_object, 0, ARRAY_SIZE(expected_input_types), &media_type); + todo_wine + ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned unexpected hr %#lx.\n", hr); + hr = IMediaObject_GetInputType(media_object, 1, 0, &media_type); + todo_wine + ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned unexpected hr %#lx.\n", hr); + hr = IMediaObject_GetInputType(media_object, 0, 0, NULL); + todo_wine + ok(hr == S_OK, "GetInputType returned unexpected hr %#lx.\n", hr); + hr = IMediaObject_GetInputType(media_object, 1, ARRAY_SIZE(expected_input_types), &media_type); + todo_wine + ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned unexpected hr %#lx.\n", hr); + hr = IMediaObject_GetInputType(media_object, 0, ARRAY_SIZE(expected_input_types), NULL); + todo_wine + ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned unexpected hr %#lx.\n", hr); + hr = IMediaObject_GetInputType(media_object, 1, 0, NULL); + todo_wine + ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned unexpected hr %#lx.\n", hr); + ret = IMediaObject_Release(media_object); ok(ret == 0, "Release returned %lu\n", ret); CoUninitialize();
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 8 ------- dlls/winegstreamer/wmv_decoder.c | 37 ++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 972e01331b7..82817724a78 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4563,30 +4563,22 @@ static void test_wmv_decoder_media_object(void) check_dmo_media_type(&media_type, &expected_input_types[i]); winetest_pop_context(); } - todo_wine ok(i == ARRAY_SIZE(expected_input_types), "%lu input types.\n", i);
/* Test GetInputType with invalid arguments. */ hr = IMediaObject_GetInputType(media_object, 0, ARRAY_SIZE(expected_input_types) - 1, &media_type); - todo_wine ok(hr == S_OK, "GetInputType returned unexpected hr %#lx.\n", hr); hr = IMediaObject_GetInputType(media_object, 0, ARRAY_SIZE(expected_input_types), &media_type); - todo_wine ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned unexpected hr %#lx.\n", hr); hr = IMediaObject_GetInputType(media_object, 1, 0, &media_type); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned unexpected hr %#lx.\n", hr); hr = IMediaObject_GetInputType(media_object, 0, 0, NULL); - todo_wine ok(hr == S_OK, "GetInputType returned unexpected hr %#lx.\n", hr); hr = IMediaObject_GetInputType(media_object, 1, ARRAY_SIZE(expected_input_types), &media_type); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned unexpected hr %#lx.\n", hr); hr = IMediaObject_GetInputType(media_object, 0, ARRAY_SIZE(expected_input_types), NULL); - todo_wine ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned unexpected hr %#lx.\n", hr); hr = IMediaObject_GetInputType(media_object, 1, 0, NULL); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned unexpected hr %#lx.\n", hr);
ret = IMediaObject_Release(media_object); diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index fe9870e1bc3..96a2839660a 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -19,6 +19,7 @@
#include "mfapi.h" #include "mferror.h" +#include "mediaerr.h" #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" @@ -28,6 +29,23 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+extern const GUID MFVideoFormat_VC1S; + +DEFINE_GUID(MFVideoFormat_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); + +static const GUID *const wmv_decoder_input_types[] = +{ + &MFVideoFormat_WMV1, + &MFVideoFormat_WMV2, + &MEDIASUBTYPE_WMVA, + &MEDIASUBTYPE_WMVP, + &MEDIASUBTYPE_WVP2, + &MFVideoFormat_WMV_Unknown, + &MFVideoFormat_WVC1, + &MFVideoFormat_WMV3, + &MFVideoFormat_VC1S, +}; + struct wmv_decoder { IUnknown IUnknown_inner; @@ -345,8 +363,23 @@ static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWOR static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= ARRAY_SIZE(wmv_decoder_input_types)) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Video; + type->subtype = *wmv_decoder_input_types[type_index]; + type->bFixedSizeSamples = FALSE; + type->bTemporalCompression = TRUE; + type->lSampleSize = 0; + + return S_OK; }
static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index,
Zebediah Figura (@zfigura) commented about dlls/winegstreamer/wm_reader.c:
static HRESULT WINAPI profile_GetStreamByNumber(IWMProfile3 *iface, WORD stream_number, IWMStreamConfig **config) {
- FIXME("iface %p, stream_number %u, config %p, stub!\n", iface, stream_number, config);
- return E_NOTIMPL;
- struct wm_reader *reader = impl_from_IWMProfile3(iface);
- TRACE("iface %p, stream_number %u, config %p.\n", iface, stream_number, config);
- EnterCriticalSection(&reader->cs);
- if (!stream_number || stream_number > reader->stream_count)
- {
LeaveCriticalSection(&reader->cs);
return NS_E_NO_STREAM;
- }
- return profile_GetStream(iface, stream_number - 1, config);
This leaves the CS acquired on success. I also think it'd be simpler to save the CS and just do something like
if (!stream_number) return NS_E_NO_STREAM;
hr = profile_GetStream(stream_number - 1); if (hr == E_INVALIDARG) hr = NS_E_NO_STREAM; return hr;
Rémi Bernon (@rbernon) commented about dlls/mf/tests/transform.c:
+static void test_wmv_decoder_media_object(void) +{
- const GUID *const class_id = &CLSID_CWMVDecMediaObject;
- IMediaObject *media_object;
- DWORD in_count, out_count;
- HRESULT hr;
- ULONG ret;
- winetest_push_context("wmvdec");
- if (!has_video_processor)
- {
win_skip("Skipping inconsistent WMV decoder media object tests on Win7.\n");
winetest_pop_context();
return;
- }
Are these tests also inconsistent? They look simple enough at least for now to have a consistent result everywhere.
FWIW, I don't mind having separate tests like that for now, then I think they could also be part of the `test_wmv_decoder` tests. That could be a refactor for later though, once we have a better test coverage of interfaces, and for more decoders (the WMA decoder needs it too).
Ultimately it may be interesting to check if the dual decoders supports some interoperability between both their interfaces, at least to see if we can/should implement them separately or rather on top of each other.
Also, do you intend to implement more of this? FWIW Proton has the DMO interfaces implemented for WMV and WMA, some games required them, though it's missing tests entirely.
I wanted to write tests but had some other things pending and got side tracked a bit. If you're interested I'm happy to leave it to you :).
Looks good otherwise.
On Fri Nov 18 15:19:16 2022 +0000, Rémi Bernon wrote:
Are these tests also inconsistent? They look simple enough at least for now to have a consistent result everywhere.
I see there's the same media types failures with the additional tests. Nevermind then.
On Sat Nov 19 01:41:29 2022 +0000, Rémi Bernon wrote:
FWIW, I don't mind having separate tests like that for now, then I think they could also be part of the `test_wmv_decoder` tests. That could be a refactor for later though, once we have a better test coverage of interfaces, and for more decoders (the WMA decoder needs it too). Ultimately it may be interesting to check if the dual decoders supports some interoperability between both their interfaces, at least to see if we can/should implement them separately or rather on top of each other. Also, do you intend to implement more of this? FWIW Proton has the DMO interfaces implemented for WMV and WMA, some games required them, though it's missing tests entirely. I wanted to write tests but had some other things pending and got side tracked a bit. If you're interested I'm happy to leave it to you :). Looks good otherwise.
Yeah, I'm interested in writting more tests for IMediaObject, and then try to implement them. In this MR, should I merge the MediaOject tests to test_wmv_decoder() or leave them in test_wmv_decoder_media_object() for now?