From: Akihiro Sagawa Subject: [RFC PATCH 5/5] quartz/tests: Add MPEG video parser tests for MPEG splitter. (resend) Message-Id: <20200621161233.8735.375B48EC@gmail.com> Date: Sun, 21 Jun 2020 16:15:54 +0900 Signed-off-by: Akihiro Sagawa --- dlls/quartz/tests/mpegsplit.c | 596 ++++++++++++++++++++++++++++------ dlls/quartz/tests/rsrc.rc | 4 + dlls/quartz/tests/video.mpg | Bin 0 -> 617 bytes 3 files changed, 500 insertions(+), 100 deletions(-) create mode 100644 dlls/quartz/tests/video.mpg diff --git a/dlls/quartz/tests/mpegsplit.c b/dlls/quartz/tests/mpegsplit.c index 2553742e56..dcb425f32c 100644 --- a/dlls/quartz/tests/mpegsplit.c +++ b/dlls/quartz/tests/mpegsplit.c @@ -119,7 +119,7 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO IUnknown_Release(unk); } -static void test_interfaces(const WCHAR* resource) +static void test_interfaces(const WCHAR* resource, const WCHAR* pin_name) { const WCHAR *filename = load_resource(resource); IBaseFilter *filter = create_mpeg_splitter(); @@ -158,7 +158,7 @@ static void test_interfaces(const WCHAR* resource) IPin_Release(pin); - IBaseFilter_FindPin(filter, L"Audio", &pin); + IBaseFilter_FindPin(filter, pin_name, &pin); check_interface(pin, &IID_IMediaSeeking, TRUE); check_interface(pin, &IID_IPin, TRUE); @@ -270,14 +270,14 @@ static void test_aggregation(void) ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); } -static void test_enum_pins(const WCHAR *resource) +static void test_enum_pins(const WCHAR *resource, DWORD pin_nums) { const WCHAR *filename = load_resource(resource); IBaseFilter *filter = create_mpeg_splitter(); IEnumPins *enum1, *enum2; IFilterGraph2 *graph; - ULONG count, ref; - IPin *pins[3]; + ULONG count, ref, i; + IPin *pins[4]; HRESULT hr; BOOL ret; @@ -359,13 +359,12 @@ static void test_enum_pins(const WCHAR *resource) hr = IEnumPins_Reset(enum1); ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumPins_Next(enum1, 1, pins, NULL); - ok(hr == S_OK, "Got hr %#x.\n", hr); - IPin_Release(pins[0]); - - hr = IEnumPins_Next(enum1, 1, pins, NULL); - ok(hr == S_OK, "Got hr %#x.\n", hr); - IPin_Release(pins[0]); + for (i = 0; i < pin_nums; ++i) + { + hr = IEnumPins_Next(enum1, 1, pins, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IPin_Release(pins[0]); + } hr = IEnumPins_Next(enum1, 1, pins, NULL); ok(hr == S_FALSE, "Got hr %#x.\n", hr); @@ -373,20 +372,20 @@ static void test_enum_pins(const WCHAR *resource) hr = IEnumPins_Reset(enum1); ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumPins_Next(enum1, 2, pins, &count); + hr = IEnumPins_Next(enum1, pin_nums, pins, &count); ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(count == 2, "Got count %u.\n", count); - IPin_Release(pins[0]); - IPin_Release(pins[1]); + ok(count == pin_nums, "Got count %u.\n", count); + for (i = 0; i < count; ++i) + IPin_Release(pins[i]); hr = IEnumPins_Reset(enum1); ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumPins_Next(enum1, 3, pins, &count); + hr = IEnumPins_Next(enum1, pin_nums + 1, pins, &count); ok(hr == S_FALSE, "Got hr %#x.\n", hr); - ok(count == 2, "Got count %u.\n", count); - IPin_Release(pins[0]); - IPin_Release(pins[1]); + ok(count == pin_nums, "Got count %u.\n", count); + for (i = 0; i < count; ++i) + IPin_Release(pins[i]); IEnumPins_Release(enum1); IFilterGraph2_Release(graph); @@ -396,7 +395,7 @@ static void test_enum_pins(const WCHAR *resource) ok(ret, "Failed to delete file, error %u.\n", GetLastError()); } -static void test_find_pin(const WCHAR* resource) +static void test_find_pin(const WCHAR* resource, const WCHAR* pin_name) { const WCHAR *filename = load_resource(resource); IBaseFilter *filter = create_mpeg_splitter(); @@ -424,7 +423,7 @@ static void test_find_pin(const WCHAR* resource) hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL); ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IBaseFilter_FindPin(filter, L"Audio", &pin); + hr = IBaseFilter_FindPin(filter, pin_name, &pin); ok(hr == S_OK, "Got hr %#x.\n", hr); ok(pin == pin2, "Expected pin %p, got %p.\n", pin2, pin); IPin_Release(pin); @@ -462,7 +461,7 @@ static void test_find_pin_unconnected(void) ok(!ref, "Got outstanding refcount %d.\n", ref); } -static void test_pin_info(const WCHAR* resource) +static void test_pin_info(const WCHAR* resource, const WCHAR* pin_name) { const WCHAR *filename = load_resource(resource); IBaseFilter *filter = create_mpeg_splitter(); @@ -505,14 +504,14 @@ static void test_pin_info(const WCHAR* resource) IPin_Release(pin); - hr = IBaseFilter_FindPin(filter, L"Audio", &pin); + hr = IBaseFilter_FindPin(filter, pin_name, &pin); ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IPin_QueryPinInfo(pin, &info); ok(hr == S_OK, "Got hr %#x.\n", hr); ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter); ok(info.dir == PINDIR_OUTPUT, "Got direction %d.\n", info.dir); - ok(!wcscmp(info.achName, L"Audio"), "Got name %s.\n", wine_dbgstr_w(info.achName)); + ok(!wcscmp(info.achName, pin_name), "Got name %s.\n", wine_dbgstr_w(info.achName)); IBaseFilter_Release(info.pFilter); hr = IPin_QueryDirection(pin, &dir); @@ -521,7 +520,7 @@ static void test_pin_info(const WCHAR* resource) hr = IPin_QueryId(pin, &id); ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(!wcscmp(id, L"Audio"), "Got id %s.\n", wine_dbgstr_w(id)); + ok(!wcscmp(id, pin_name), "Got id %s.\n", wine_dbgstr_w(id)); CoTaskMemFree(id); IPin_Release(pin); @@ -861,15 +860,164 @@ done: ok(ret, "Failed to delete file, error %u.\n", GetLastError()); } -static void test_enum_media_types(const WCHAR *resource) +static void test_video_media_types(void) { + static const BYTE expect_seq_header[] = { 0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, + 0x18, 0x13, 0xff, 0xff, 0xe0, 0x18 }; + static const MPEG1VIDEOINFO expect_vinfo = + { + .hdr.rcSource = { 0, 0, 32, 24 }, + .hdr.AvgTimePerFrame = 400000, + .hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .hdr.bmiHeader.biWidth = 32, + .hdr.bmiHeader.biHeight = 24, + .hdr.bmiHeader.biXPelsPerMeter = 2000, + .hdr.bmiHeader.biYPelsPerMeter = 2000, + .dwStartTimeCode = 1 << 12, + .cbSequenceHeader = ARRAY_SIZE(expect_seq_header), + }; + + const WCHAR *filename = load_resource(L"video.mpg"); + AM_MEDIA_TYPE *pmt, expect_mt = {{0}}; + IBaseFilter *filter = create_mpeg_splitter(); + IEnumMediaTypes *enummt; + MPEG1VIDEOINFO *vih; + IFilterGraph2 *graph; + HRESULT hr; + ULONG ref; + IPin *pin; + BOOL ret; + + graph = connect_input(filter, filename); + IBaseFilter_FindPin(filter, L"Input", &pin); + + /* Connecting input doesn't change the reported media types. */ + hr = IPin_EnumMediaTypes(pin, &enummt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + expect_mt.majortype = MEDIATYPE_Stream; + expect_mt.bFixedSizeSamples = TRUE; + expect_mt.bTemporalCompression = TRUE; + expect_mt.lSampleSize = 1; + + hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + expect_mt.subtype = MEDIASUBTYPE_MPEG1System; + ok(!memcmp(pmt, &expect_mt, sizeof(AM_MEDIA_TYPE)), "Media types didn't match.\n"); + DeleteMediaType(pmt); + + IEnumMediaTypes_Release(enummt); + IPin_Release(pin); + + IBaseFilter_FindPin(filter, L"Video", &pin); + + hr = IPin_EnumMediaTypes(pin, &enummt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video), "Got major type %s\n", + wine_dbgstr_guid(&pmt->majortype)); + ok(IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Payload), "Got subtype %s\n", + wine_dbgstr_guid(&pmt->subtype)); + ok(pmt->bFixedSizeSamples, "Got fixed size %d.\n", pmt->bFixedSizeSamples); + ok(!pmt->bTemporalCompression, "Got temporal compression %d.\n", pmt->bTemporalCompression); + ok(pmt->lSampleSize == 1, "Got sample size %u.\n", pmt->lSampleSize); + ok(IsEqualGUID(&pmt->formattype, &FORMAT_MPEGVideo), "Got format type %s.\n", + wine_dbgstr_guid(&pmt->formattype)); + ok(!pmt->pUnk, "Got pUnk %p.\n", pmt->pUnk); + ok(pmt->cbFormat == offsetof(MPEG1VIDEOINFO, bSequenceHeader) + ARRAY_SIZE(expect_seq_header), "Got format size %u.\n", pmt->cbFormat); + ok(!memcmp(pmt->pbFormat, &expect_vinfo, offsetof(MPEG1VIDEOINFO, bSequenceHeader)), "Format blocks didn't match.\n"); + + vih = (MPEG1VIDEOINFO *)pmt->pbFormat; + ok(!memcmp(vih->bSequenceHeader, expect_seq_header, ARRAY_SIZE(expect_seq_header)), "Sequence header didn't match.\n"); + + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + pmt->bFixedSizeSamples = FALSE; + pmt->bTemporalCompression = TRUE; + pmt->lSampleSize = 123; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + pmt->majortype = GUID_NULL; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + pmt->majortype = MEDIATYPE_Video; + + pmt->subtype = MEDIASUBTYPE_MPEG1Audio; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + pmt->subtype = MEDIASUBTYPE_MPEG1Packet; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + pmt->subtype = MEDIASUBTYPE_MPEG1Video; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + pmt->subtype = MEDIASUBTYPE_MPEG1Payload; + + pmt->formattype = GUID_NULL; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + pmt->formattype = FORMAT_None; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + pmt->formattype = FORMAT_MPEGVideo; + + vih = (MPEG1VIDEOINFO *)pmt->pbFormat; + + vih->hdr.AvgTimePerFrame = 10000; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + vih->hdr.AvgTimePerFrame = 400000; + + vih->hdr.dwBitRate = 1000000; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + vih->hdr.dwBitRate = 0; + + SetRect(&vih->hdr.rcSource, 0, 0, 0, 0); + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + SetRect(&vih->hdr.rcSource, 0, 0, 32, 24); + + vih->hdr.bmiHeader.biCompression = mmioFOURCC('I','4','2','0'); + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + vih->hdr.bmiHeader.biCompression = BI_RGB; + + vih->cbSequenceHeader = 0; + hr = IPin_QueryAccept(pin, pmt); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + vih->cbSequenceHeader = ARRAY_SIZE(expect_seq_header); + + CoTaskMemFree(pmt->pbFormat); + CoTaskMemFree(pmt); + + hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + IEnumMediaTypes_Release(enummt); + IPin_Release(pin); + + IFilterGraph2_Release(graph); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ret = DeleteFileW(filename); + ok(ret, "Failed to delete file, error %u.\n", GetLastError()); +} + +static void test_enum_media_types(const WCHAR *resource, ULONG audio_mts, ULONG video_mts) +{ + static const WCHAR *source_pin_name[] = { L"Audio", L"Video" }; const WCHAR *filename = load_resource(resource); IBaseFilter *filter = create_mpeg_splitter(); IFilterGraph2 *graph = connect_input(filter, filename); IEnumMediaTypes *enum1, *enum2; AM_MEDIA_TYPE *mts[5]; + unsigned int i, n; ULONG ref, count; - unsigned int i; HRESULT hr; IPin *pin; BOOL ret; @@ -955,91 +1103,95 @@ static void test_enum_media_types(const WCHAR *resource) IEnumMediaTypes_Release(enum2); IPin_Release(pin); - IBaseFilter_FindPin(filter, L"Audio", &pin); - - hr = IPin_EnumMediaTypes(pin, &enum1); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - for (i = 0; i < 3; ++i) + for (n = 0; n < ARRAY_SIZE(source_pin_name); ++n) { - hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); - todo_wine_if(i) ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr == S_OK) CoTaskMemFree(mts[0]->pbFormat); - if (hr == S_OK) CoTaskMemFree(mts[0]); - } - - hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ULONG num_mts = n ? video_mts : audio_mts; + if (!num_mts) continue; - hr = IEnumMediaTypes_Reset(enum1); - ok(hr == S_OK, "Got hr %#x.\n", hr); + IBaseFilter_FindPin(filter, source_pin_name[n], &pin); - for (i = 0; i < 3; ++i) - { - hr = IEnumMediaTypes_Next(enum1, 1, mts, &count); - todo_wine_if(i) ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine_if(i) ok(count == 1, "Got count %u.\n", count); - if (hr == S_OK) CoTaskMemFree(mts[0]->pbFormat); - if (hr == S_OK) CoTaskMemFree(mts[0]); - } + hr = IPin_EnumMediaTypes(pin, &enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Next(enum1, 1, mts, &count); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); - ok(!count, "Got count %u.\n", count); + for (i = 0; i < num_mts; ++i) + { + hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); + todo_wine_if(i) ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr == S_OK) DeleteMediaType(mts[0]); + } - hr = IEnumMediaTypes_Reset(enum1); - ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Next(enum1, 2, mts, &count); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(count == 2, "Got count %u.\n", count); - CoTaskMemFree(mts[0]->pbFormat); - CoTaskMemFree(mts[0]); - if (count > 1) CoTaskMemFree(mts[1]->pbFormat); - if (count > 1) CoTaskMemFree(mts[1]); + hr = IEnumMediaTypes_Reset(enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Next(enum1, 2, mts, &count); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); - todo_wine ok(count == 1, "Got count %u.\n", count); - if (count) CoTaskMemFree(mts[0]->pbFormat); - if (count) CoTaskMemFree(mts[0]); + for (i = 0; i < num_mts; ++i) + { + hr = IEnumMediaTypes_Next(enum1, 1, mts, &count); + todo_wine_if(i) ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine_if(i) ok(count == 1, "Got count %u.\n", count); + if (hr == S_OK) DeleteMediaType(mts[0]); + } - hr = IEnumMediaTypes_Next(enum1, 2, mts, &count); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); - ok(!count, "Got count %u.\n", count); + hr = IEnumMediaTypes_Next(enum1, 1, mts, &count); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(!count, "Got count %u.\n", count); - hr = IEnumMediaTypes_Reset(enum1); - ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Reset(enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Clone(enum1, &enum2); - ok(hr == S_OK, "Got hr %#x.\n", hr); + if (num_mts > 2) + { + hr = IEnumMediaTypes_Next(enum1, 2, mts, &count); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(count == 2, "Got count %u.\n", count); + for (i = 0; i < count; ++i) + DeleteMediaType(mts[i]); + + hr = IEnumMediaTypes_Next(enum1, num_mts-1, mts, &count); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + todo_wine ok(count == num_mts-2, "Got count %u.\n", count); + for (i = 0; i < count; ++i) + DeleteMediaType(mts[i]); + + hr = IEnumMediaTypes_Next(enum1, 2, mts, &count); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(!count, "Got count %u.\n", count); + + hr = IEnumMediaTypes_Reset(enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + } + + hr = IEnumMediaTypes_Clone(enum1, &enum2); + ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Skip(enum1, 4); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Skip(enum1, num_mts+1); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Skip(enum1, 1); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Skip(enum1, 1); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Reset(enum1); - ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Reset(enum1); + ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Skip(enum1, 3); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Skip(enum1, num_mts); + todo_wine_if(num_mts > 1) ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Skip(enum1, 1); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Skip(enum1, 1); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); - ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); - hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL); - ok(hr == S_OK, "Got hr %#x.\n", hr); - CoTaskMemFree(mts[0]->pbFormat); - CoTaskMemFree(mts[0]); + hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + DeleteMediaType(mts[0]); - IEnumMediaTypes_Release(enum1); - IEnumMediaTypes_Release(enum2); - IPin_Release(pin); + IEnumMediaTypes_Release(enum1); + IEnumMediaTypes_Release(enum2); + IPin_Release(pin); + } IFilterGraph2_Release(graph); ref = IBaseFilter_Release(filter); @@ -1551,6 +1703,243 @@ static void test_audio_connect_pin(void) ok(ret, "Failed to delete file, error %u.\n", GetLastError()); } +static void test_video_source_connect_pin(IFilterGraph2 *graph, IPin *source, struct testfilter *testsink) +{ + AM_MEDIA_TYPE req_mt, mt, *source_mt; + IEnumMediaTypes *enummt; + IPin *peer; + HRESULT hr; + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(source, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(source, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + /* Exact connection. */ + + IPin_EnumMediaTypes(source, &enummt); + IEnumMediaTypes_Next(enummt, 1, &source_mt, NULL); + IEnumMediaTypes_Release(enummt); + CopyMediaType(&req_mt, source_mt); + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_ConnectedTo(source, &peer); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(peer == &testsink->sink.pin.IPin_iface, "Got peer %p.\n", peer); + IPin_Release(peer); + + hr = IPin_ConnectionMediaType(source, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n"); + ok(compare_media_types(&testsink->sink.pin.mt, &req_mt), "Media types didn't match.\n"); + + hr = IFilterGraph2_Disconnect(graph, source); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, source); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(testsink->sink.pin.peer == source, "Got peer %p.\n", testsink->sink.pin.peer); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + req_mt.lSampleSize = 999; + req_mt.bTemporalCompression = TRUE; + req_mt.bFixedSizeSamples = FALSE; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink->sink.pin.mt, &req_mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + req_mt.majortype = MEDIATYPE_Stream; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + req_mt.majortype = MEDIATYPE_Video; + + req_mt.subtype = MEDIASUBTYPE_RGB24; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + req_mt.subtype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + req_mt.subtype = MEDIASUBTYPE_MPEG1Payload; + + /* Connection with wildcards. */ + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink->sink.pin.mt, source_mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + req_mt.majortype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink->sink.pin.mt, source_mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + req_mt.subtype = MEDIASUBTYPE_RGB24; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + req_mt.subtype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink->sink.pin.mt, source_mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + req_mt.formattype = FORMAT_None; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + req_mt.majortype = MEDIATYPE_Video; + req_mt.subtype = MEDIASUBTYPE_MPEG1Payload; + req_mt.formattype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink->sink.pin.mt, source_mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + req_mt.subtype = MEDIASUBTYPE_RGB24; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + req_mt.subtype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink->sink.pin.mt, source_mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + req_mt.majortype = MEDIATYPE_Stream; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + testsink->mt = &req_mt; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, NULL); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + req_mt.majortype = MEDIATYPE_Video; + req_mt.subtype = MEDIASUBTYPE_MPEG1Payload; + req_mt.formattype = FORMAT_MPEGVideo; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + FreeMediaType(&req_mt); + DeleteMediaType(source_mt); +} + +static void test_video_connect_pin(void) +{ + AM_MEDIA_TYPE req_mt = + { + .majortype = MEDIATYPE_Stream, + .subtype = MEDIASUBTYPE_MPEG1Video, + .bFixedSizeSamples = TRUE, + .bTemporalCompression = TRUE, + .lSampleSize = 1, + }; + IBaseFilter *filter = create_mpeg_splitter(), *reader; + const WCHAR *filename = load_resource(L"video.mpg"); + struct testfilter testsource, testsink; + IFileSourceFilter *filesource; + IPin *sink, *source, *peer; + IMediaControl *control; + IFilterGraph2 *graph; + AM_MEDIA_TYPE mt; + HRESULT hr; + ULONG ref; + BOOL ret; + + CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterGraph2, (void **)&graph); + testfilter_init(&testsource); + testfilter_init(&testsink); + IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink"); + IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source"); + IFilterGraph2_AddFilter(graph, filter, L"splitter"); + IBaseFilter_FindPin(filter, L"Input", &sink); + IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); + + CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (void **)&reader); + IBaseFilter_QueryInterface(reader, &IID_IFileSourceFilter, (void **)&filesource); + IFileSourceFilter_Load(filesource, filename, NULL); + IFileSourceFilter_Release(filesource); + IBaseFilter_FindPin(reader, L"Output", &source); + IPin_QueryInterface(source, &IID_IAsyncReader, (void **)&testsource.reader); + IPin_Release(source); + + /* Test sink connection. */ + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(sink, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(sink, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + req_mt.majortype = MEDIATYPE_Video; + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + req_mt.majortype = MEDIATYPE_Stream; + + req_mt.subtype = MEDIASUBTYPE_RGB8; + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + req_mt.subtype = MEDIASUBTYPE_MPEG1Video; + + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_ConnectedTo(sink, &peer); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(peer == &testsource.source.pin.IPin_iface, "Got peer %p.\n", peer); + IPin_Release(peer); + + hr = IPin_ConnectionMediaType(sink, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n"); + ok(compare_media_types(&testsource.source.pin.mt, &req_mt), "Media types didn't match.\n"); + + /* Test source connection. */ + + IBaseFilter_FindPin(filter, L"Video", &source); + + test_video_source_connect_pin(graph, source, &testsink); + + IPin_Release(source); + hr = IFilterGraph2_Disconnect(graph, sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, sink); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(testsource.source.pin.peer == sink, "Got peer %p.\n", testsource.source.pin.peer); + IFilterGraph2_Disconnect(graph, &testsource.source.pin.IPin_iface); + + IAsyncReader_Release(testsource.reader); + IPin_Release(sink); + IMediaControl_Release(control); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(reader); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&testsink.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ret = DeleteFileW(filename); + ok(ret, "Failed to delete file, error %u.\n", GetLastError()); +} + START_TEST(mpegsplit) { IBaseFilter *filter; @@ -1564,17 +1953,24 @@ START_TEST(mpegsplit) return; } IBaseFilter_Release(filter); - test_interfaces(L"test.mp3"); + test_interfaces(L"test.mp3", L"Audio"); + test_interfaces(L"video.mpg", L"Video"); test_aggregation(); - test_enum_pins(L"test.mp3"); + test_enum_pins(L"test.mp3", 2); + test_enum_pins(L"video.mpg", 2); test_find_pin_unconnected(); - test_find_pin(L"test.mp3"); - test_pin_info(L"test.mp3"); + test_find_pin(L"test.mp3", L"Audio"); + test_find_pin(L"video.mpg", L"Video"); + test_pin_info(L"test.mp3", L"Audio"); + test_pin_info(L"video.mpg", L"Video"); test_sink_media_types(); test_audio_media_types(); - test_enum_media_types(L"test.mp3"); + test_video_media_types(); + test_enum_media_types(L"test.mp3", 3, 0); + test_enum_media_types(L"video.mpg", 0, 1); test_unconnected_filter_state(); test_audio_connect_pin(); + test_video_connect_pin(); CoUninitialize(); } diff --git a/dlls/quartz/tests/rsrc.rc b/dlls/quartz/tests/rsrc.rc index d28c2bd6ed..701fec2aea 100644 --- a/dlls/quartz/tests/rsrc.rc +++ b/dlls/quartz/tests/rsrc.rc @@ -28,6 +28,10 @@ test.avi RCDATA "test.avi" /* @makedep: test.mpg */ test.mpg RCDATA "test.mpg" +/* ffmpeg -f lavfi -i smptebars=s=32x24 -t 0.16 -r 25 -f mpeg1video -vcodec mpeg1video video.mpg */ +/* @makedep: video.mpg */ +video.mpg RCDATA "video.mpg" + /* ffmpeg -f lavfi -i "sine=frequency=500" -t 0.5 -ar 48000 -b:a 32k -f mp3 -acodec mp3 -write_xing 0 test.mp3 */ /* @makedep: test.mp3 */ test.mp3 RCDATA "test.mp3" diff --git a/dlls/quartz/tests/video.mpg b/dlls/quartz/tests/video.mpg new file mode 100644 index 0000000000000000000000000000000000000000..7db314ffe8da2d71cce79fd50b4cc5ff5dbbfd85 GIT binary patch literal 617 zcmZQzVBE~aAR+w!{{smI2F4u>91IRXnt_4;{|_L|DEy50{3m#@ zu$;fWi;2Pcr-ltf<~sqV1ec#I4Gunk_tbG@Byb&+KhwflpCB1mp&;2Lw}JV9D8n0} zLk?>{IGC^)6g9Xpn0}wekit=?V8Bv;ByI__gEPAZO9FFzWdfT+`y*xs_dl**4m8Ga zBtKwj=u={K)KOp&YiKm#s9Deu$MH|WkY)b_9tEJon1p{$VvuW?vwl*;wIA%Q3_SW5 z9mJbhA{1g8ESVYD6F3g!v9V2R@Y*J@&Y$p+pY5M?XM@?n85`zEHaQf$ zGk8-hyWWMdfWsk)nJGb3QJ`TZPm7PvqGllp38_fOPVJP%B9kV5vNHS6^Kf~qm#F&