Signed-off-by: Jeff Smith whydoubt@gmail.com --- If no media type is specified, IPin::Connect() currently attempts to connect pins using any accepted media type. With this patch, it first attempts to connect using the source pin's current media type.
dlls/qcap/tests/videocapture.c | 64 ++++++++++++++++++++++++++++++++-- dlls/strmbase/pin.c | 27 ++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/dlls/qcap/tests/videocapture.c b/dlls/qcap/tests/videocapture.c index 80d4899410..7938b48376 100644 --- a/dlls/qcap/tests/videocapture.c +++ b/dlls/qcap/tests/videocapture.c @@ -174,7 +174,51 @@ static void test_stream_config(IPin *pin) IAMStreamConfig_Release(stream_config); }
-static void test_capture(IBaseFilter *filter) +static void test_connect(IPin *source_pin, IPin *sink_pin) +{ + IEnumMediaTypes *enum_media_types; + IAMStreamConfig *stream_config; + AM_MEDIA_TYPE mt, *pmt; + HRESULT hr; + + hr = IPin_QueryInterface(source_pin, &IID_IAMStreamConfig, (void **)&stream_config); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_EnumMediaTypes(source_pin, &enum_media_types); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + while (IEnumMediaTypes_Next(enum_media_types, 1, &pmt, NULL) == S_OK) + { + hr = IAMStreamConfig_SetFormat(stream_config, pmt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_Connect(source_pin, sink_pin, NULL); + if (hr == S_OK) + { + hr = IPin_ConnectionMediaType(source_pin, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(IsEqualGUID(&pmt->majortype, &mt.majortype), "majortype did not match.\n"); + ok(IsEqualGUID(&pmt->subtype, &mt.subtype), "subtype did not match.\n"); + ok(IsEqualGUID(&pmt->formattype, &mt.formattype), "formattype did not match.\n"); + ok(memcmp(pmt->pbFormat, mt.pbFormat, mt.cbFormat) == 0, "format details did not match.\n"); + + FreeMediaType(&mt); + + hr = IPin_Disconnect(source_pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IPin_Disconnect(sink_pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + } + + CoTaskMemFree(pmt); + } + + IEnumMediaTypes_Release(enum_media_types); + IAMStreamConfig_Release(stream_config); +} + +static void test_capture(IBaseFilter *filter, IPin *sink_pin) { IEnumPins *enum_pins; IPin *pin; @@ -209,6 +253,10 @@ static void test_capture(IBaseFilter *filter) check_interface(pin, &IID_IAMVideoCompression, FALSE); check_interface(pin, &IID_IAMVideoProcAmp, FALSE); check_interface(pin, &IID_IPersistPropertyBag, FALSE); + + /* Placed after check_inferface tests, as it can affect the + * result for IID_IAMDroppedFrames on Windows. */ + test_connect(pin, sink_pin); } IPin_Release(pin); } @@ -255,7 +303,8 @@ START_TEST(videocapture) { ICreateDevEnum *dev_enum; IEnumMoniker *class_enum; - IBaseFilter *filter; + IBaseFilter *filter, *null_renderer; + IPin *null_renderer_pin; IMoniker *moniker; WCHAR *name; HRESULT hr; @@ -277,6 +326,13 @@ START_TEST(videocapture) } ok(hr == S_OK, "Got hr=%#x.\n", hr);
+ hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC, + &IID_IBaseFilter, (void **)&null_renderer); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IBaseFilter_FindPin(null_renderer, L"In", &null_renderer_pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + while (IEnumMoniker_Next(class_enum, 1, &moniker, NULL) == S_OK) { hr = IMoniker_GetDisplayName(moniker, NULL, NULL, &name); @@ -287,7 +343,7 @@ START_TEST(videocapture) hr = IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void**)&filter); if (hr == S_OK) { - test_capture(filter); + test_capture(filter, null_renderer_pin); test_misc_flags(filter); ref = IBaseFilter_Release(filter); ok(!ref, "Got outstanding refcount %d.\n", ref); @@ -298,6 +354,8 @@ START_TEST(videocapture) IMoniker_Release(moniker); }
+ IPin_Release(null_renderer_pin); + IBaseFilter_Release(null_renderer); ICreateDevEnum_Release(dev_enum); IEnumMoniker_Release(class_enum); CoUninitialize(); diff --git a/dlls/strmbase/pin.c b/dlls/strmbase/pin.c index e5017c2ff9..35aa6bc77d 100644 --- a/dlls/strmbase/pin.c +++ b/dlls/strmbase/pin.c @@ -510,6 +510,33 @@ static HRESULT WINAPI source_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYP return VFW_E_NOT_STOPPED; }
+ if (!mt) + { + IAMStreamConfig *stream_config = NULL; + + if (pin->pFuncsTable->base.pin_query_interface) + pin->pFuncsTable->base.pin_query_interface(&pin->pin, &IID_IAMStreamConfig, + (void **)&stream_config); + + if (stream_config) + { + AM_MEDIA_TYPE *pmt = NULL; + IAMStreamConfig_GetFormat(stream_config, &pmt); + if (pmt) + { + if (pin->pFuncsTable->pfnAttemptConnection(pin, peer, pmt) == S_OK) + { + LeaveCriticalSection(&pin->pin.filter->csFilter); + DeleteMediaType(pmt); + IAMStreamConfig_Release(stream_config); + return S_OK; + } + DeleteMediaType(pmt); + } + IAMStreamConfig_Release(stream_config); + } + } + /* We don't check the subtype here. The rationale (as given by the DirectX * documentation) is that the format type is supposed to provide at least * as much information as the subtype. */
On 8/26/20 10:29 PM, Jeff Smith wrote:
Signed-off-by: Jeff Smith whydoubt@gmail.com
If no media type is specified, IPin::Connect() currently attempts to connect pins using any accepted media type. With this patch, it first attempts to connect using the source pin's current media type.
More specifically, it attempts to connect pins using the media types returned, in order, from IPin::EnumMediaTypes(). Which leads to the question: does calling IAMStreamConfig::SetFormat() affect the types enumerated? I wrote a brief test, attached, which passes for me on Windows 10 with an Anivia W5, showing that the correct solution here is to always return the current caps *first* from source_get_media_type().
dlls/qcap/tests/videocapture.c | 64 ++++++++++++++++++++++++++++++++-- dlls/strmbase/pin.c | 27 ++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/dlls/qcap/tests/videocapture.c b/dlls/qcap/tests/videocapture.c index 80d4899410..7938b48376 100644 --- a/dlls/qcap/tests/videocapture.c +++ b/dlls/qcap/tests/videocapture.c @@ -174,7 +174,51 @@ static void test_stream_config(IPin *pin) IAMStreamConfig_Release(stream_config); }
-static void test_capture(IBaseFilter *filter) +static void test_connect(IPin *source_pin, IPin *sink_pin) +{
- IEnumMediaTypes *enum_media_types;
- IAMStreamConfig *stream_config;
- AM_MEDIA_TYPE mt, *pmt;
- HRESULT hr;
- hr = IPin_QueryInterface(source_pin, &IID_IAMStreamConfig, (void **)&stream_config);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IPin_EnumMediaTypes(source_pin, &enum_media_types);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- while (IEnumMediaTypes_Next(enum_media_types, 1, &pmt, NULL) == S_OK)
- {
hr = IAMStreamConfig_SetFormat(stream_config, pmt);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IPin_Connect(source_pin, sink_pin, NULL);
if (hr == S_OK)
{
hr = IPin_ConnectionMediaType(source_pin, &mt);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(IsEqualGUID(&pmt->majortype, &mt.majortype), "majortype did not match.\n");
ok(IsEqualGUID(&pmt->subtype, &mt.subtype), "subtype did not match.\n");
ok(IsEqualGUID(&pmt->formattype, &mt.formattype), "formattype did not match.\n");
ok(memcmp(pmt->pbFormat, mt.pbFormat, mt.cbFormat) == 0, "format details did not match.\n");
In general, note that we have a compare_media_types() helper for this, which you can find in e.g. quartz/avisplit.c.
FreeMediaType(&mt);
hr = IPin_Disconnect(source_pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IPin_Disconnect(sink_pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
}
CoTaskMemFree(pmt);
- }
- IEnumMediaTypes_Release(enum_media_types);
- IAMStreamConfig_Release(stream_config);
+}
+static void test_capture(IBaseFilter *filter, IPin *sink_pin) { IEnumPins *enum_pins; IPin *pin; @@ -209,6 +253,10 @@ static void test_capture(IBaseFilter *filter) check_interface(pin, &IID_IAMVideoCompression, FALSE); check_interface(pin, &IID_IAMVideoProcAmp, FALSE); check_interface(pin, &IID_IPersistPropertyBag, FALSE);
/* Placed after check_inferface tests, as it can affect the
* result for IID_IAMDroppedFrames on Windows. */
test_connect(pin, sink_pin);
This should be part of the main loop alongside the call to test_capture(), not part of it. test_capture() should also really be renamed to test_interfaces().
} IPin_Release(pin); }
@@ -255,7 +303,8 @@ START_TEST(videocapture) { ICreateDevEnum *dev_enum; IEnumMoniker *class_enum;
- IBaseFilter *filter;
- IBaseFilter *filter, *null_renderer;
- IPin *null_renderer_pin; IMoniker *moniker; WCHAR *name; HRESULT hr;
@@ -277,6 +326,13 @@ START_TEST(videocapture) } ok(hr == S_OK, "Got hr=%#x.\n", hr);
- hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC,
&IID_IBaseFilter, (void **)&null_renderer);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
We don't particularly want to depend on this being available in tests. qedit is missing on one of the Windows server versions. Instead we want to use a strmbase filter; see e.g. struct testfilter in quartz:avisplit for an example. This also lets us test details of connection.
- hr = IBaseFilter_FindPin(null_renderer, L"In", &null_renderer_pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- while (IEnumMoniker_Next(class_enum, 1, &moniker, NULL) == S_OK) { hr = IMoniker_GetDisplayName(moniker, NULL, NULL, &name);
@@ -287,7 +343,7 @@ START_TEST(videocapture) hr = IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void**)&filter); if (hr == S_OK) {
test_capture(filter);
test_capture(filter, null_renderer_pin); test_misc_flags(filter); ref = IBaseFilter_Release(filter); ok(!ref, "Got outstanding refcount %d.\n", ref);
@@ -298,6 +354,8 @@ START_TEST(videocapture) IMoniker_Release(moniker); }
- IPin_Release(null_renderer_pin);
- IBaseFilter_Release(null_renderer); ICreateDevEnum_Release(dev_enum); IEnumMoniker_Release(class_enum); CoUninitialize();
diff --git a/dlls/strmbase/pin.c b/dlls/strmbase/pin.c index e5017c2ff9..35aa6bc77d 100644 --- a/dlls/strmbase/pin.c +++ b/dlls/strmbase/pin.c @@ -510,6 +510,33 @@ static HRESULT WINAPI source_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYP return VFW_E_NOT_STOPPED; }
- if (!mt)
- {
IAMStreamConfig *stream_config = NULL;
if (pin->pFuncsTable->base.pin_query_interface)
pin->pFuncsTable->base.pin_query_interface(&pin->pin, &IID_IAMStreamConfig,
(void **)&stream_config);
if (stream_config)
{
AM_MEDIA_TYPE *pmt = NULL;
IAMStreamConfig_GetFormat(stream_config, &pmt);
if (pmt)
{
if (pin->pFuncsTable->pfnAttemptConnection(pin, peer, pmt) == S_OK)
{
LeaveCriticalSection(&pin->pin.filter->csFilter);
DeleteMediaType(pmt);
IAMStreamConfig_Release(stream_config);
return S_OK;
}
DeleteMediaType(pmt);
}
IAMStreamConfig_Release(stream_config);
}
- }
- /* We don't check the subtype here. The rationale (as given by the DirectX * documentation) is that the format type is supposed to provide at least * as much information as the subtype. */