Commit 982be1de authored by Damjan Jovanovic's avatar Damjan Jovanovic Committed by Alexandre Julliard

qcap: Add the SmartTee filter automatically as necessary, and test this.

parent 419be239
......@@ -249,6 +249,118 @@ fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2 * iface,
*/
}
static HRESULT match_smart_tee_pin(CaptureGraphImpl *This,
const GUID *pCategory,
const GUID *pType,
IUnknown *pSource,
IPin **source_out)
{
static const WCHAR inputW[] = {'I','n','p','u','t',0};
static const WCHAR captureW[] = {'C','a','p','t','u','r','e',0};
static const WCHAR previewW[] = {'P','r','e','v','i','e','w',0};
IPin *capture = NULL;
IPin *preview = NULL;
IPin *peer = NULL;
IBaseFilter *smartTee = NULL;
BOOL needSmartTee = FALSE;
HRESULT hr;
TRACE("(%p, %s, %s, %p, %p)\n", This, debugstr_guid(pCategory), debugstr_guid(pType), pSource, source_out);
hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, pType, FALSE, 0, &capture);
if (SUCCEEDED(hr)) {
hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
PINDIR_OUTPUT, &PIN_CATEGORY_PREVIEW, pType, FALSE, 0, &preview);
if (FAILED(hr))
needSmartTee = TRUE;
} else {
hr = E_INVALIDARG;
goto end;
}
if (!needSmartTee) {
if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE)) {
hr = IPin_ConnectedTo(capture, &peer);
if (hr == VFW_E_NOT_CONNECTED) {
*source_out = capture;
IPin_AddRef(*source_out);
hr = S_OK;
} else
hr = E_INVALIDARG;
} else {
hr = IPin_ConnectedTo(preview, &peer);
if (hr == VFW_E_NOT_CONNECTED) {
*source_out = preview;
IPin_AddRef(*source_out);
hr = S_OK;
} else
hr = E_INVALIDARG;
}
goto end;
}
hr = IPin_ConnectedTo(capture, &peer);
if (SUCCEEDED(hr)) {
PIN_INFO pinInfo;
GUID classID;
hr = IPin_QueryPinInfo(peer, &pinInfo);
if (SUCCEEDED(hr)) {
hr = IBaseFilter_GetClassID(pinInfo.pFilter, &classID);
if (SUCCEEDED(hr)) {
if (IsEqualIID(&classID, &CLSID_SmartTee)) {
smartTee = pinInfo.pFilter;
IBaseFilter_AddRef(smartTee);
}
}
IBaseFilter_Release(pinInfo.pFilter);
}
if (!smartTee) {
hr = E_INVALIDARG;
goto end;
}
} else if (hr == VFW_E_NOT_CONNECTED) {
hr = CoCreateInstance(&CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER,
&IID_IBaseFilter, (LPVOID*)&smartTee);
if (SUCCEEDED(hr)) {
hr = IGraphBuilder_AddFilter(This->mygraph, smartTee, NULL);
if (SUCCEEDED(hr)) {
IPin *smartTeeInput = NULL;
hr = IBaseFilter_FindPin(smartTee, inputW, &smartTeeInput);
if (SUCCEEDED(hr)) {
hr = IGraphBuilder_ConnectDirect(This->mygraph, capture, smartTeeInput, NULL);
IPin_Release(smartTeeInput);
}
}
}
if (FAILED(hr)) {
TRACE("adding SmartTee failed with hr=0x%08x\n", hr);
hr = E_INVALIDARG;
goto end;
}
} else {
hr = E_INVALIDARG;
goto end;
}
if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE))
hr = IBaseFilter_FindPin(smartTee, captureW, source_out);
else {
hr = IBaseFilter_FindPin(smartTee, previewW, source_out);
if (SUCCEEDED(hr))
hr = VFW_S_NOPREVIEWPIN;
}
end:
if (capture)
IPin_Release(capture);
if (preview)
IPin_Release(preview);
if (peer)
IPin_Release(peer);
if (smartTee)
IBaseFilter_Release(smartTee);
TRACE("for %s returning hr=0x%08x, *source_out=%p\n", IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) ? "capture" : "preview", hr, source_out ? *source_out : 0);
return hr;
}
static HRESULT WINAPI
fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
const GUID *pCategory,
......@@ -258,7 +370,8 @@ fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
IBaseFilter *pfRenderer)
{
CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
IPin *source_out, *renderer_in, *capture, *preview;
IPin *source_out = NULL, *renderer_in;
BOOL usedSmartTeePreviewPin = FALSE;
HRESULT hr;
FIXME("(%p/%p)->(%s, %s, %p, %p, %p) semi-stub!\n", This, iface,
......@@ -276,24 +389,26 @@ fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
return E_NOTIMPL;
}
hr = ICaptureGraphBuilder2_FindPin(iface, pSource, PINDIR_OUTPUT, pCategory, pType, TRUE, 0, &source_out);
if (FAILED(hr))
return E_INVALIDARG;
if (pCategory && IsEqualIID(pCategory, &PIN_CATEGORY_VBI)) {
FIXME("Tee/Sink-to-Sink filter not supported\n");
IPin_Release(source_out);
return E_NOTIMPL;
}
hr = ICaptureGraphBuilder2_FindPin(iface, pSource, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, NULL, TRUE, 0, &capture);
if (SUCCEEDED(hr)) {
hr = ICaptureGraphBuilder2_FindPin(iface, pSource, PINDIR_OUTPUT, &PIN_CATEGORY_PREVIEW, NULL, TRUE, 0, &preview);
} else if (pCategory && (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) || IsEqualIID(pCategory, &PIN_CATEGORY_PREVIEW))){
IBaseFilter *sourceFilter = NULL;
hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&sourceFilter);
if (SUCCEEDED(hr)) {
hr = match_smart_tee_pin(This, pCategory, pType, pSource, &source_out);
if (hr == VFW_S_NOPREVIEWPIN)
usedSmartTeePreviewPin = TRUE;
IBaseFilter_Release(sourceFilter);
} else {
hr = ICaptureGraphBuilder2_FindPin(iface, pSource, PINDIR_OUTPUT, pCategory, pType, TRUE, 0, &source_out);
}
if (FAILED(hr))
FIXME("Smart Tee filter not supported - not creating preview pin\n");
else
IPin_Release(preview);
IPin_Release(capture);
return E_INVALIDARG;
} else {
hr = ICaptureGraphBuilder2_FindPin(iface, pSource, PINDIR_OUTPUT, pCategory, pType, TRUE, 0, &source_out);
if (FAILED(hr))
return E_INVALIDARG;
}
hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, &renderer_in);
......@@ -331,6 +446,8 @@ fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
IPin_Release(source_out);
IPin_Release(renderer_in);
if (SUCCEEDED(hr) && usedSmartTeePreviewPin)
hr = VFW_S_NOPREVIEWPIN;
return hr;
}
......
......@@ -140,121 +140,7 @@ static const struct {
BOOL wine_extra;
BOOL optional; /* fails on wine if missing */
BOOL broken;
} renderstream_cat_media[] = {
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER},
{BASEFILTER_ENUMPINS, SOURCE_FILTER},
{ENUMPINS_NEXT, SOURCE_FILTER},
{PIN_QUERYDIRECTION, SOURCE_FILTER},
{PIN_CONNECTEDTO, SOURCE_FILTER},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER},
{PIN_ENUMMEDIATYPES, SOURCE_FILTER},
{ENUMMEDIATYPES_RESET, SOURCE_FILTER},
{ENUMMEDIATYPES_NEXT, SOURCE_FILTER},
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER},
{BASEFILTER_ENUMPINS, SOURCE_FILTER},
{ENUMPINS_NEXT, SOURCE_FILTER},
{PIN_QUERYDIRECTION, SOURCE_FILTER},
{PIN_CONNECTEDTO, SOURCE_FILTER},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER},
{ENUMPINS_NEXT, SOURCE_FILTER},
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER, TRUE},
{BASEFILTER_ENUMPINS, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{PIN_QUERYDIRECTION, SOURCE_FILTER, TRUE},
{PIN_CONNECTEDTO, SOURCE_FILTER, TRUE},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER, TRUE},
{BASEFILTER_ENUMPINS, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{PIN_QUERYDIRECTION, SOURCE_FILTER, TRUE},
{PIN_CONNECTEDTO, SOURCE_FILTER, TRUE},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{PIN_ENUMMEDIATYPES, SOURCE_FILTER, TRUE, FALSE, TRUE},
{ENUMMEDIATYPES_NEXT, SOURCE_FILTER, TRUE, FALSE, TRUE},
{BASEFILTER_QUERYINTERFACE, SINK_FILTER, FALSE, TRUE},
{BASEFILTER_ENUMPINS, SINK_FILTER},
{ENUMPINS_NEXT, SINK_FILTER},
{PIN_QUERYDIRECTION, SINK_FILTER},
{PIN_CONNECTEDTO, SINK_FILTER},
{GRAPHBUILDER_CONNECT, NOT_FILTER},
{BASEFILTER_GETSTATE, SOURCE_FILTER, TRUE, FALSE, TRUE},
{BASEFILTER_ENUMPINS, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{PIN_QUERYDIRECTION, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{PIN_CONNECTEDTO, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{END, NOT_FILTER}
}, renderstream_intermediate[] = {
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER},
{BASEFILTER_ENUMPINS, SOURCE_FILTER},
{ENUMPINS_NEXT, SOURCE_FILTER},
{PIN_QUERYDIRECTION, SOURCE_FILTER},
{PIN_CONNECTEDTO, SOURCE_FILTER},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER},
{PIN_ENUMMEDIATYPES, SOURCE_FILTER},
{ENUMMEDIATYPES_RESET, SOURCE_FILTER},
{ENUMMEDIATYPES_NEXT, SOURCE_FILTER},
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER},
{BASEFILTER_ENUMPINS, SOURCE_FILTER},
{ENUMPINS_NEXT, SOURCE_FILTER},
{PIN_QUERYDIRECTION, SOURCE_FILTER},
{PIN_CONNECTEDTO, SOURCE_FILTER},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER},
{ENUMPINS_NEXT, SOURCE_FILTER},
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER, TRUE},
{BASEFILTER_ENUMPINS, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{PIN_QUERYDIRECTION, SOURCE_FILTER, TRUE},
{PIN_CONNECTEDTO, SOURCE_FILTER, TRUE},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{BASEFILTER_QUERYINTERFACE, SOURCE_FILTER, TRUE},
{BASEFILTER_ENUMPINS, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{PIN_QUERYDIRECTION, SOURCE_FILTER, TRUE},
{PIN_CONNECTEDTO, SOURCE_FILTER, TRUE},
{PIN_QUERYPININFO, SOURCE_FILTER, TRUE},
{KSPROPERTYSET_GET, SOURCE_FILTER, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, TRUE},
{PIN_ENUMMEDIATYPES, SOURCE_FILTER, TRUE, FALSE, TRUE},
{ENUMMEDIATYPES_NEXT, SOURCE_FILTER, TRUE, FALSE, TRUE},
{BASEFILTER_QUERYINTERFACE, SINK_FILTER, FALSE, TRUE},
{BASEFILTER_ENUMPINS, SINK_FILTER},
{ENUMPINS_NEXT, SINK_FILTER},
{PIN_QUERYDIRECTION, SINK_FILTER},
{PIN_CONNECTEDTO, SINK_FILTER},
{BASEFILTER_QUERYINTERFACE, INTERMEDIATE_FILTER, FALSE, TRUE},
{BASEFILTER_ENUMPINS, INTERMEDIATE_FILTER},
{ENUMPINS_NEXT, INTERMEDIATE_FILTER},
{PIN_QUERYDIRECTION, INTERMEDIATE_FILTER},
{PIN_CONNECTEDTO, INTERMEDIATE_FILTER},
{ENUMPINS_NEXT, INTERMEDIATE_FILTER},
{PIN_QUERYDIRECTION, INTERMEDIATE_FILTER},
{PIN_CONNECTEDTO, INTERMEDIATE_FILTER},
{GRAPHBUILDER_CONNECT, NOT_FILTER},
{BASEFILTER_QUERYINTERFACE, INTERMEDIATE_FILTER, FALSE, TRUE},
{BASEFILTER_ENUMPINS, INTERMEDIATE_FILTER},
{ENUMPINS_NEXT, INTERMEDIATE_FILTER},
{PIN_QUERYDIRECTION, INTERMEDIATE_FILTER},
{PIN_CONNECTEDTO, INTERMEDIATE_FILTER},
{GRAPHBUILDER_CONNECT, NOT_FILTER},
{BASEFILTER_GETSTATE, SOURCE_FILTER, TRUE, FALSE, TRUE},
{BASEFILTER_ENUMPINS, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{PIN_QUERYDIRECTION, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{PIN_CONNECTEDTO, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{ENUMPINS_NEXT, SOURCE_FILTER, FALSE, FALSE, FALSE, TRUE},
{END, NOT_FILTER}
}, *current_calls_list;
} *current_calls_list;
int call_no;
static void check_calls_list(const char *func, call_id id, filter_type type)
......@@ -1268,49 +1154,6 @@ static void init_test_filter(test_filter *This, PIN_DIRECTION dir, filter_type t
This->filter_type = type;
}
static void test_CaptureGraphBuilder_RenderStream(void)
{
test_filter source_filter, sink_filter, intermediate_filter;
ICaptureGraphBuilder2 *cgb;
HRESULT hr;
init_test_filter(&source_filter, PINDIR_OUTPUT, SOURCE_FILTER);
init_test_filter(&sink_filter, PINDIR_INPUT, SINK_FILTER);
init_test_filter(&intermediate_filter, PINDIR_OUTPUT, INTERMEDIATE_FILTER);
hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
&IID_ICaptureGraphBuilder2, (void**)&cgb);
ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG),
"couldn't create CaptureGraphBuilder, hr = %08x\n", hr);
if(hr != S_OK) {
win_skip("CaptureGraphBuilder is not registered\n");
return;
}
hr = ICaptureGraphBuilder2_SetFiltergraph(cgb, &GraphBuilder);
ok(hr == S_OK, "SetFiltergraph failed: %08x\n", hr);
trace("RenderStream with category and mediatype test\n");
current_calls_list = renderstream_cat_media;
call_no = 0;
hr = ICaptureGraphBuilder2_RenderStream(cgb, &PIN_CATEGORY_EDS,
&MEDIATYPE_Video, (IUnknown*)&source_filter.IBaseFilter_iface,
NULL, &sink_filter.IBaseFilter_iface);
ok(hr == S_OK, "RenderStream failed: %08x\n", hr);
check_calls_list("test_CaptureGraphBuilder_RenderStream", END, NOT_FILTER);
trace("RenderStream with intermediate filter\n");
current_calls_list = renderstream_intermediate;
call_no = 0;
hr = ICaptureGraphBuilder2_RenderStream(cgb, &PIN_CATEGORY_EDS,
&MEDIATYPE_Video, (IUnknown*)&source_filter.IBaseFilter_iface,
&intermediate_filter.IBaseFilter_iface, &sink_filter.IBaseFilter_iface);
ok(hr == S_OK, "RenderStream failed: %08x\n", hr);
check_calls_list("test_CaptureGraphBuilder_RenderStream", END, NOT_FILTER);
ICaptureGraphBuilder2_Release(cgb);
}
static void test_AviMux_QueryInterface(void)
{
IUnknown *avimux, *unk;
......@@ -2016,7 +1859,6 @@ START_TEST(qcap)
arg_c = winetest_get_mainargs(&arg_v);
test_CaptureGraphBuilder_RenderStream();
test_AviMux_QueryInterface();
test_AviMux(arg_c>2 ? arg_v[2] : NULL);
test_AviCo();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment