Commit f2a8d535 authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

quartz/tests: Rewrite test_render_filter_priority().

parent 22308340
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
#define COBJMACROS #define COBJMACROS
#define CONST_VTABLE #define CONST_VTABLE
#include "wine/test.h"
#include "dshow.h" #include "dshow.h"
#include "control.h" #include "wine/heap.h"
#include "wine/test.h"
typedef struct TestFilterImpl typedef struct TestFilterImpl
{ {
...@@ -783,1511 +783,843 @@ static void test_graph_builder(void) ...@@ -783,1511 +783,843 @@ static void test_graph_builder(void)
IGraphBuilder_Release(pgraph); IGraphBuilder_Release(pgraph);
} }
/* IEnumMediaTypes implementation (supporting code for Render() test.) */ struct testpin
static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
{
if (pMediaType->pbFormat)
{
CoTaskMemFree(pMediaType->pbFormat);
pMediaType->pbFormat = NULL;
}
if (pMediaType->pUnk)
{
IUnknown_Release(pMediaType->pUnk);
pMediaType->pUnk = NULL;
}
}
static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
{ {
*pDest = *pSrc; IPin IPin_iface;
if (!pSrc->pbFormat) return S_OK; LONG ref;
if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat))) PIN_DIRECTION dir;
return E_OUTOFMEMORY; IBaseFilter *filter;
memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat); IPin *peer;
if (pDest->pUnk)
IUnknown_AddRef(pDest->pUnk);
return S_OK;
}
static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
{
AM_MEDIA_TYPE * pDest;
pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
if (!pDest)
return NULL;
if (FAILED(CopyMediaType(pDest, pSrc)))
{
CoTaskMemFree(pDest);
return NULL;
}
return pDest;
}
static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
{
return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
}
static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
{
FreeMediaType(pMediaType);
CoTaskMemFree(pMediaType);
}
typedef struct IEnumMediaTypesImpl
{
IEnumMediaTypes IEnumMediaTypes_iface; IEnumMediaTypes IEnumMediaTypes_iface;
LONG refCount; const AM_MEDIA_TYPE *types;
AM_MEDIA_TYPE *pMediaTypes; unsigned int type_count, enum_idx;
ULONG cMediaTypes; };
ULONG uIndex;
} IEnumMediaTypesImpl;
static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
{
return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
}
static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum) static inline struct testpin *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
{ {
ULONG i; return CONTAINING_RECORD(iface, struct testpin, IEnumMediaTypes_iface);
IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
if (!pEnumMediaTypes)
{
*ppEnum = NULL;
return E_OUTOFMEMORY;
}
pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
pEnumMediaTypes->refCount = 1;
pEnumMediaTypes->uIndex = 0;
pEnumMediaTypes->cMediaTypes = cMediaTypes;
pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
for (i = 0; i < cMediaTypes; i++)
if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
{
while (i--)
FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
return E_OUTOFMEMORY;
}
*ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
return S_OK;
} }
static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv) static HRESULT WINAPI testenummt_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
{ {
*ppv = NULL; struct testpin *pin = impl_from_IEnumMediaTypes(iface);
if (winetest_debug > 1) trace("%p->QueryInterface(%s)\n", pin, wine_dbgstr_guid(iid));
if (IsEqualIID(riid, &IID_IUnknown))
*ppv = iface;
else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
*ppv = iface;
if (*ppv)
{
IUnknown_AddRef((IUnknown *)(*ppv));
return S_OK;
}
*out = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface) static ULONG WINAPI testenummt_AddRef(IEnumMediaTypes *iface)
{ {
IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface); struct testpin *pin = impl_from_IEnumMediaTypes(iface);
ULONG refCount = InterlockedIncrement(&This->refCount); return InterlockedIncrement(&pin->ref);
return refCount;
} }
static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface) static ULONG WINAPI testenummt_Release(IEnumMediaTypes *iface)
{ {
IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface); struct testpin *pin = impl_from_IEnumMediaTypes(iface);
ULONG refCount = InterlockedDecrement(&This->refCount); return InterlockedDecrement(&pin->ref);
if (!refCount)
{
int i;
for (i = 0; i < This->cMediaTypes; i++)
FreeMediaType(&This->pMediaTypes[i]);
CoTaskMemFree(This->pMediaTypes);
CoTaskMemFree(This);
}
return refCount;
} }
static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched) static HRESULT WINAPI testenummt_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **out, ULONG *fetched)
{ {
ULONG cFetched; struct testpin *pin = impl_from_IEnumMediaTypes(iface);
IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface); unsigned int i;
cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
if (cFetched > 0) for (i = 0; i < count; ++i)
{ {
ULONG i; if (pin->enum_idx + i >= pin->type_count)
for (i = 0; i < cFetched; i++) break;
if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
{
while (i--)
DeleteMediaType(ppMediaTypes[i]);
*pcFetched = 0;
return E_OUTOFMEMORY;
}
}
if ((cMediaTypes != 1) || pcFetched) out[i] = CoTaskMemAlloc(sizeof(*out[i]));
*pcFetched = cFetched; *out[i] = pin->types[pin->enum_idx + i];
}
This->uIndex += cFetched; if (fetched)
*fetched = i;
pin->enum_idx += i;
if (cFetched != cMediaTypes) return (i == count) ? S_OK : S_FALSE;
return S_FALSE;
return S_OK;
} }
static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes) static HRESULT WINAPI testenummt_Skip(IEnumMediaTypes *iface, ULONG count)
{ {
IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface); ok(0, "Unexpected call.\n");
return E_NOTIMPL;
if (This->uIndex + cMediaTypes < This->cMediaTypes)
{
This->uIndex += cMediaTypes;
return S_OK;
}
return S_FALSE;
} }
static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface) static HRESULT WINAPI testenummt_Reset(IEnumMediaTypes *iface)
{ {
IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface); struct testpin *pin = impl_from_IEnumMediaTypes(iface);
pin->enum_idx = 0;
This->uIndex = 0;
return S_OK; return S_OK;
} }
static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum) static HRESULT WINAPI testenummt_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
{ {
HRESULT hr; ok(0, "Unexpected call.\n");
IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface); return E_NOTIMPL;
hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
if (FAILED(hr))
return hr;
return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
} }
static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl = static const IEnumMediaTypesVtbl testenummt_vtbl =
{ {
IEnumMediaTypesImpl_QueryInterface, testenummt_QueryInterface,
IEnumMediaTypesImpl_AddRef, testenummt_AddRef,
IEnumMediaTypesImpl_Release, testenummt_Release,
IEnumMediaTypesImpl_Next, testenummt_Next,
IEnumMediaTypesImpl_Skip, testenummt_Skip,
IEnumMediaTypesImpl_Reset, testenummt_Reset,
IEnumMediaTypesImpl_Clone testenummt_Clone,
}; };
/* Implementation of a very stripped down pin for the test filter. Just enough static inline struct testpin *impl_from_IPin(IPin *iface)
functionality for connecting and Render() to work. */
static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
{ {
lstrcpyW(pDest->achName, pSrc->achName); return CONTAINING_RECORD(iface, struct testpin, IPin_iface);
pDest->dir = pSrc->dir;
pDest->pFilter = pSrc->pFilter;
} }
typedef struct ITestPinImpl static HRESULT WINAPI testpin_QueryInterface(IPin *iface, REFIID iid, void **out)
{ {
IPin IPin_iface; struct testpin *pin = impl_from_IPin(iface);
LONG refCount; if (winetest_debug > 1) trace("%p->QueryInterface(%s)\n", pin, wine_dbgstr_guid(iid));
LPCRITICAL_SECTION pCritSec;
PIN_INFO pinInfo;
IPin * pConnectedTo;
AM_MEDIA_TYPE mtCurrent;
LPVOID pUserData;
} ITestPinImpl;
static inline ITestPinImpl *impl_from_IPin(IPin *iface)
{
return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
}
static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IPin))
{
*ppv = NULL;
if (IsEqualIID(riid, &IID_IUnknown))
*ppv = iface;
else if (IsEqualIID(riid, &IID_IPin))
*ppv = iface;
if (*ppv)
{ {
IUnknown_AddRef((IUnknown *)(*ppv)); *out = &pin->IPin_iface;
IPin_AddRef(*out);
return S_OK; return S_OK;
} }
*out = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface) ULONG WINAPI testpin_AddRef(IPin *iface)
{
ITestPinImpl *This = impl_from_IPin(iface);
ULONG refCount = InterlockedIncrement(&This->refCount);
return refCount;
}
static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
{ {
ITestPinImpl *This = impl_from_IPin(iface); struct testpin *pin = impl_from_IPin(iface);
ULONG refCount = InterlockedDecrement(&This->refCount); return InterlockedIncrement(&pin->ref);
if (!refCount)
{
FreeMediaType(&This->mtCurrent);
CoTaskMemFree(This);
return 0;
}
else
return refCount;
} }
static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt) ULONG WINAPI testpin_Release(IPin *iface)
{ {
return E_UNEXPECTED; struct testpin *pin = impl_from_IPin(iface);
} return InterlockedDecrement(&pin->ref);
static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
{
ITestPinImpl *This = impl_from_IPin(iface);
PIN_DIRECTION pindirReceive;
HRESULT hr = S_OK;
EnterCriticalSection(This->pCritSec);
{
if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
hr = VFW_E_TYPE_NOT_ACCEPTED;
if (This->pConnectedTo)
hr = VFW_E_ALREADY_CONNECTED;
if (SUCCEEDED(hr))
{
IPin_QueryDirection(pReceivePin, &pindirReceive);
if (pindirReceive != PINDIR_OUTPUT)
{
hr = VFW_E_INVALID_DIRECTION;
}
}
if (SUCCEEDED(hr))
{
CopyMediaType(&This->mtCurrent, pmt);
This->pConnectedTo = pReceivePin;
IPin_AddRef(pReceivePin);
}
}
LeaveCriticalSection(This->pCritSec);
return hr;
} }
static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface) static HRESULT WINAPI testpin_Disconnect(IPin *iface)
{ {
HRESULT hr; struct testpin *pin = impl_from_IPin(iface);
ITestPinImpl *This = impl_from_IPin(iface); if (winetest_debug > 1) trace("%p->Disconnect()\n", pin);
EnterCriticalSection(This->pCritSec); if (!pin->peer)
{ return S_FALSE;
if (This->pConnectedTo)
{
IPin_Release(This->pConnectedTo);
This->pConnectedTo = NULL;
hr = S_OK;
}
else
hr = S_FALSE;
}
LeaveCriticalSection(This->pCritSec);
return hr; IPin_Release(pin->peer);
pin->peer = NULL;
return S_OK;
} }
static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin) static HRESULT WINAPI testpin_ConnectedTo(IPin *iface, IPin **peer)
{ {
HRESULT hr; struct testpin *pin = impl_from_IPin(iface);
ITestPinImpl *This = impl_from_IPin(iface); if (winetest_debug > 1) trace("%p->ConnectedTo()\n", pin);
EnterCriticalSection(This->pCritSec); *peer = pin->peer;
if (*peer)
{ {
if (This->pConnectedTo) IPin_AddRef(*peer);
{ return S_OK;
*ppPin = This->pConnectedTo;
IPin_AddRef(*ppPin);
hr = S_OK;
}
else
{
hr = VFW_E_NOT_CONNECTED;
*ppPin = NULL;
}
} }
LeaveCriticalSection(This->pCritSec); return VFW_E_NOT_CONNECTED;
return hr;
} }
static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt) static HRESULT WINAPI testpin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
{ {
HRESULT hr; ok(0, "Unexpected call.\n");
ITestPinImpl *This = impl_from_IPin(iface); return E_NOTIMPL;
EnterCriticalSection(This->pCritSec);
{
if (This->pConnectedTo)
{
CopyMediaType(pmt, &This->mtCurrent);
hr = S_OK;
}
else
{
ZeroMemory(pmt, sizeof(*pmt));
hr = VFW_E_NOT_CONNECTED;
}
}
LeaveCriticalSection(This->pCritSec);
return hr;
} }
static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo) static HRESULT WINAPI testpin_QueryPinInfo(IPin *iface, PIN_INFO *info)
{ {
ITestPinImpl *This = impl_from_IPin(iface); struct testpin *pin = impl_from_IPin(iface);
if (winetest_debug > 1) trace("%p->QueryPinInfo()\n", pin);
Copy_PinInfo(pInfo, &This->pinInfo);
IBaseFilter_AddRef(pInfo->pFilter);
info->pFilter = pin->filter;
IBaseFilter_AddRef(pin->filter);
info->dir = pin->dir;
info->achName[0] = 0;
return S_OK; return S_OK;
} }
static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
{
ITestPinImpl *This = impl_from_IPin(iface);
*pPinDir = This->pinInfo.dir; static HRESULT WINAPI testpin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
{
struct testpin *pin = impl_from_IPin(iface);
if (winetest_debug > 1) trace("%p->QueryDirection()\n", pin);
*dir = pin->dir;
return S_OK; return S_OK;
} }
static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id) static HRESULT WINAPI testpin_QueryId(IPin *iface, WCHAR **id)
{ {
if (winetest_debug > 1) trace("%p->QueryId()\n", iface);
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) static HRESULT WINAPI testpin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
{ {
ITestPinImpl *This = impl_from_IPin(iface); ok(0, "Unexpected call.\n");
return E_NOTIMPL;
if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
return S_OK;
else
return VFW_E_TYPE_NOT_ACCEPTED;
} }
static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) static HRESULT WINAPI testpin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **out)
{ {
ITestPinImpl *This = impl_from_IPin(iface); struct testpin *pin = impl_from_IPin(iface);
if (winetest_debug > 1) trace("%p->EnumMediaTypes()\n", pin);
return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum); *out = &pin->IEnumMediaTypes_iface;
IEnumMediaTypes_AddRef(*out);
pin->enum_idx = 0;
return S_OK;
} }
static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) static HRESULT WINAPI testpin_QueryInternalConnections(IPin *iface, IPin **out, ULONG *count)
{ {
if (winetest_debug > 1) trace("%p->QueryInternalConnections()\n", iface);
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface) static HRESULT WINAPI testpin_BeginFlush(IPin *iface)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface) static HRESULT WINAPI testpin_EndFlush(IPin * iface)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) static HRESULT WINAPI testpin_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface) static HRESULT WINAPI testpin_EndOfStream(IPin *iface)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
static const IPinVtbl TestFilter_InputPin_Vtbl = static HRESULT WINAPI testsink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
{
TestFilter_Pin_QueryInterface,
TestFilter_Pin_AddRef,
TestFilter_Pin_Release,
TestFilter_InputPin_Connect,
TestFilter_InputPin_ReceiveConnection,
TestFilter_Pin_Disconnect,
TestFilter_Pin_ConnectedTo,
TestFilter_Pin_ConnectionMediaType,
TestFilter_Pin_QueryPinInfo,
TestFilter_Pin_QueryDirection,
TestFilter_Pin_QueryId,
TestFilter_Pin_QueryAccept,
TestFilter_Pin_EnumMediaTypes,
TestFilter_Pin_QueryInternalConnections,
TestFilter_Pin_EndOfStream,
TestFilter_Pin_BeginFlush,
TestFilter_Pin_EndFlush,
TestFilter_Pin_NewSegment
};
static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
{ {
return E_UNEXPECTED; ok(0, "Unexpected call.\n");
return E_NOTIMPL;
} }
/* Private helper function */ static HRESULT WINAPI testsink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
const AM_MEDIA_TYPE * pmt)
{ {
HRESULT hr; struct testpin *pin = impl_from_IPin(iface);
if (winetest_debug > 1) trace("%p->ReceiveConnection(%p)\n", pin, peer);
This->pConnectedTo = pReceivePin;
IPin_AddRef(pReceivePin);
hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt); pin->peer = peer;
IPin_AddRef(peer);
if (FAILED(hr)) return S_OK;
{
IPin_Release(This->pConnectedTo);
This->pConnectedTo = NULL;
}
return hr;
} }
static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) static HRESULT WINAPI testsink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **out)
{ {
ITestPinImpl *This = impl_from_IPin(iface); ok(0, "Unexpected call.\n");
HRESULT hr; return E_NOTIMPL;
EnterCriticalSection(This->pCritSec);
{
/* if we have been a specific type to connect with, then we can either connect
* with that or fail. We cannot choose different AM_MEDIA_TYPE */
if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
else
{
if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
(TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
hr = S_OK;
else hr = VFW_E_NO_ACCEPTABLE_TYPES;
} /* if negotiate media type */
} /* if succeeded */
LeaveCriticalSection(This->pCritSec);
return hr;
} }
static const IPinVtbl TestFilter_OutputPin_Vtbl = static const IPinVtbl testsink_vtbl =
{ {
TestFilter_Pin_QueryInterface, testpin_QueryInterface,
TestFilter_Pin_AddRef, testpin_AddRef,
TestFilter_Pin_Release, testpin_Release,
TestFilter_OutputPin_Connect, testsink_Connect,
TestFilter_OutputPin_ReceiveConnection, testsink_ReceiveConnection,
TestFilter_Pin_Disconnect, testpin_Disconnect,
TestFilter_Pin_ConnectedTo, testpin_ConnectedTo,
TestFilter_Pin_ConnectionMediaType, testpin_ConnectionMediaType,
TestFilter_Pin_QueryPinInfo, testpin_QueryPinInfo,
TestFilter_Pin_QueryDirection, testpin_QueryDirection,
TestFilter_Pin_QueryId, testpin_QueryId,
TestFilter_Pin_QueryAccept, testpin_QueryAccept,
TestFilter_Pin_EnumMediaTypes, testsink_EnumMediaTypes,
TestFilter_Pin_QueryInternalConnections, testpin_QueryInternalConnections,
TestFilter_Pin_EndOfStream, testpin_EndOfStream,
TestFilter_Pin_BeginFlush, testpin_BeginFlush,
TestFilter_Pin_EndFlush, testpin_EndFlush,
TestFilter_Pin_NewSegment testpin_NewSegment
}; };
static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt, static void testsink_init(struct testpin *pin)
LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
{ {
ITestPinImpl * pPinImpl; memset(pin, 0, sizeof(*pin));
pin->IPin_iface.lpVtbl = &testsink_vtbl;
*ppPin = NULL; pin->ref = 1;
pin->dir = PINDIR_INPUT;
pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
if (!pPinImpl)
return E_OUTOFMEMORY;
pPinImpl->refCount = 1; pin->IEnumMediaTypes_iface.lpVtbl = &testenummt_vtbl;
pPinImpl->pConnectedTo = NULL;
pPinImpl->pCritSec = pCritSec;
Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
pPinImpl->mtCurrent = *pinmt;
pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
*ppPin = &pPinImpl->IPin_iface;
return S_OK;
} }
/* IEnumPins implementation */ static HRESULT WINAPI testsource_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
typedef struct IEnumPinsImpl
{ {
IEnumPins IEnumPins_iface; struct testpin *pin = impl_from_IPin(iface);
LONG refCount; if (winetest_debug > 1) trace("%p->Connect(%p)\n", pin, peer);
ULONG uIndex;
TestFilterImpl *base;
FNOBTAINPIN receive_pin;
DWORD synctime;
} IEnumPinsImpl;
static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl; ok(!mt, "Got media type %p.\n", mt);
static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface) pin->peer = peer;
{ IPin_AddRef(peer);
return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface); return IPin_ReceiveConnection(peer, &pin->IPin_iface, mt);
} }
static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base) static HRESULT WINAPI testsource_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
{ {
IEnumPinsImpl * pEnumPins; ok(0, "Unexpected call.\n");
return E_NOTIMPL;
if (!ppEnum) }
return E_POINTER;
pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl)); static const IPinVtbl testsource_vtbl =
if (!pEnumPins) {
{ testpin_QueryInterface,
*ppEnum = NULL; testpin_AddRef,
return E_OUTOFMEMORY; testpin_Release,
} testsource_Connect,
pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl; testsource_ReceiveConnection,
pEnumPins->refCount = 1; testpin_Disconnect,
pEnumPins->uIndex = 0; testpin_ConnectedTo,
pEnumPins->receive_pin = receive_pin; testpin_ConnectionMediaType,
pEnumPins->base = base; testpin_QueryPinInfo,
IBaseFilter_AddRef(&base->IBaseFilter_iface); testpin_QueryDirection,
*ppEnum = &pEnumPins->IEnumPins_iface; testpin_QueryId,
testpin_QueryAccept,
testpin_EnumMediaTypes,
testpin_QueryInternalConnections,
testpin_EndOfStream,
testpin_BeginFlush,
testpin_EndFlush,
testpin_NewSegment
};
receive_pin(base, ~0, NULL, &pEnumPins->synctime); static void testsource_init(struct testpin *pin, const AM_MEDIA_TYPE *types, int type_count)
{
memset(pin, 0, sizeof(*pin));
pin->IPin_iface.lpVtbl = &testsource_vtbl;
pin->ref = 1;
pin->dir = PINDIR_OUTPUT;
return S_OK; pin->IEnumMediaTypes_iface.lpVtbl = &testenummt_vtbl;
pin->types = types;
pin->type_count = type_count;
} }
static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv) struct testfilter
{ {
*ppv = NULL; IBaseFilter IBaseFilter_iface;
LONG ref;
IFilterGraph *graph;
WCHAR *name;
if (IsEqualIID(riid, &IID_IUnknown)) IEnumPins IEnumPins_iface;
*ppv = iface; struct testpin *pins;
else if (IsEqualIID(riid, &IID_IEnumPins)) unsigned int pin_count, enum_idx;
*ppv = iface; };
if (*ppv) static inline struct testfilter *impl_from_IEnumPins(IEnumPins *iface)
{ {
IUnknown_AddRef((IUnknown *)(*ppv)); return CONTAINING_RECORD(iface, struct testfilter, IEnumPins_iface);
return S_OK; }
}
static HRESULT WINAPI testenumpins_QueryInterface(IEnumPins *iface, REFIID iid, void **out)
{
ok(0, "Unexpected iid %s.\n", wine_dbgstr_guid(iid));
return E_NOINTERFACE; return E_NOINTERFACE;
} }
static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface) static ULONG WINAPI testenumpins_AddRef(IEnumPins * iface)
{ {
IEnumPinsImpl *This = impl_from_IEnumPins(iface); struct testfilter *filter = impl_from_IEnumPins(iface);
ULONG refCount = InterlockedIncrement(&This->refCount); return InterlockedIncrement(&filter->ref);
return refCount;
} }
static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface) static ULONG WINAPI testenumpins_Release(IEnumPins * iface)
{ {
IEnumPinsImpl *This = impl_from_IEnumPins(iface); struct testfilter *filter = impl_from_IEnumPins(iface);
ULONG refCount = InterlockedDecrement(&This->refCount); return InterlockedDecrement(&filter->ref);
if (!refCount)
{
IBaseFilter_Release(&This->base->IBaseFilter_iface);
CoTaskMemFree(This);
return 0;
}
else
return refCount;
} }
static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched) static HRESULT WINAPI testenumpins_Next(IEnumPins *iface, ULONG count, IPin **out, ULONG *fetched)
{ {
IEnumPinsImpl *This = impl_from_IEnumPins(iface); struct testfilter *filter = impl_from_IEnumPins(iface);
DWORD synctime = This->synctime; unsigned int i;
HRESULT hr = S_OK;
ULONG i = 0;
if (!ppPins)
return E_POINTER;
if (cPins > 1 && !pcFetched) for (i = 0; i < count; ++i)
return E_INVALIDARG;
if (pcFetched)
*pcFetched = 0;
while (i < cPins && hr == S_OK)
{ {
hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime); if (filter->enum_idx + i >= filter->pin_count)
if (hr == S_OK)
++i;
if (synctime != This->synctime)
break; break;
}
if (!i && synctime != This->synctime) out[i] = &filter->pins[filter->enum_idx + i].IPin_iface;
return VFW_E_ENUM_OUT_OF_SYNC; IPin_AddRef(out[i]);
}
if (pcFetched) if (fetched)
*pcFetched = i; *fetched = i;
This->uIndex += i; filter->enum_idx += i;
if (i < cPins) return (i == count) ? S_OK : S_FALSE;
return S_FALSE;
return S_OK;
} }
static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins) static HRESULT WINAPI testenumpins_Skip(IEnumPins *iface, ULONG count)
{ {
IEnumPinsImpl *This = impl_from_IEnumPins(iface); ok(0, "Unexpected call.\n");
DWORD synctime = This->synctime; return E_NOTIMPL;
HRESULT hr;
IPin *pin = NULL;
hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
if (pin)
IPin_Release(pin);
if (synctime != This->synctime)
return VFW_E_ENUM_OUT_OF_SYNC;
if (hr == S_OK)
This->uIndex += cPins;
return hr;
} }
static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface) static HRESULT WINAPI testenumpins_Reset(IEnumPins *iface)
{ {
IEnumPinsImpl *This = impl_from_IEnumPins(iface); struct testfilter *filter = impl_from_IEnumPins(iface);
filter->enum_idx = 0;
This->receive_pin(This->base, ~0, NULL, &This->synctime);
This->uIndex = 0;
return S_OK; return S_OK;
} }
static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum) static HRESULT WINAPI testenumpins_Clone(IEnumPins *iface, IEnumPins **out)
{ {
HRESULT hr; ok(0, "Unexpected call.\n");
IEnumPinsImpl *This = impl_from_IEnumPins(iface); return E_NOTIMPL;
hr = createenumpins(ppEnum, This->receive_pin, This->base);
if (FAILED(hr))
return hr;
return IEnumPins_Skip(*ppEnum, This->uIndex);
} }
static const IEnumPinsVtbl IEnumPinsImpl_Vtbl = static const IEnumPinsVtbl testenumpins_vtbl =
{ {
IEnumPinsImpl_QueryInterface, testenumpins_QueryInterface,
IEnumPinsImpl_AddRef, testenumpins_AddRef,
IEnumPinsImpl_Release, testenumpins_Release,
IEnumPinsImpl_Next, testenumpins_Next,
IEnumPinsImpl_Skip, testenumpins_Skip,
IEnumPinsImpl_Reset, testenumpins_Reset,
IEnumPinsImpl_Clone testenumpins_Clone,
}; };
/* Test filter implementation - a filter that has few predefined pins with single media type static inline struct testfilter *impl_from_IBaseFilter(IBaseFilter *iface)
* that accept only this single media type. Enough for Render(). */
typedef struct TestFilterPinData
{
PIN_DIRECTION pinDir;
const GUID *mediasubtype;
} TestFilterPinData;
static const IBaseFilterVtbl TestFilter_Vtbl;
static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
{
return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
}
static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
TestFilterImpl **tf)
{ {
static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; return CONTAINING_RECORD(iface, struct testfilter, IBaseFilter_iface);
static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
HRESULT hr;
PIN_INFO pinInfo;
TestFilterImpl* pTestFilter = NULL;
UINT nPins, i;
AM_MEDIA_TYPE mt;
pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
if (!pTestFilter) return E_OUTOFMEMORY;
pTestFilter->clsid = *pClsid;
pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
pTestFilter->refCount = 1;
InitializeCriticalSection(&pTestFilter->csFilter);
pTestFilter->state = State_Stopped;
ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
nPins = 0;
while(pinData[nPins].mediasubtype) ++nPins;
pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
if (!pTestFilter->ppPins)
{
hr = E_OUTOFMEMORY;
goto error;
}
ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
for (i = 0; i < nPins; i++)
{
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Video;
mt.formattype = FORMAT_None;
mt.subtype = *pinData[i].mediasubtype;
pinInfo.dir = pinData[i].pinDir;
pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
if (pinInfo.dir == PINDIR_INPUT)
{
lstrcpynW(pinInfo.achName, wcsInputPinName, ARRAY_SIZE(pinInfo.achName));
hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
&pTestFilter->ppPins[i]);
}
else
{
lstrcpynW(pinInfo.achName, wcsOutputPinName, ARRAY_SIZE(pinInfo.achName));
hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
&pTestFilter->ppPins[i]);
}
if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
}
pTestFilter->nPins = nPins;
*tf = pTestFilter;
return S_OK;
error:
if (pTestFilter->ppPins)
{
for (i = 0; i < nPins; i++)
{
if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
}
}
CoTaskMemFree(pTestFilter->ppPins);
DeleteCriticalSection(&pTestFilter->csFilter);
CoTaskMemFree(pTestFilter);
return hr;
} }
static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) static HRESULT WINAPI testfilter_QueryInterface(IBaseFilter *iface, REFIID iid, void **out)
{ {
TestFilterImpl *This = impl_from_IBaseFilter(iface); struct testfilter *filter = impl_from_IBaseFilter(iface);
if (winetest_debug > 1) trace("%p->QueryInterface(%s)\n", filter, wine_dbgstr_guid(iid));
*ppv = NULL;
if (IsEqualIID(riid, &IID_IUnknown))
*ppv = This;
else if (IsEqualIID(riid, &IID_IPersist))
*ppv = This;
else if (IsEqualIID(riid, &IID_IMediaFilter))
*ppv = This;
else if (IsEqualIID(riid, &IID_IBaseFilter))
*ppv = This;
if (*ppv) if (IsEqualGUID(iid, &IID_IUnknown)
|| IsEqualGUID(iid, &IID_IPersist)
|| IsEqualGUID(iid, &IID_IMediaFilter)
|| IsEqualGUID(iid, &IID_IBaseFilter))
{ {
IUnknown_AddRef((IUnknown *)(*ppv)); *out = &filter->IBaseFilter_iface;
IBaseFilter_AddRef(*out);
return S_OK; return S_OK;
} }
*out = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface) static ULONG WINAPI testfilter_AddRef(IBaseFilter *iface)
{ {
TestFilterImpl *This = impl_from_IBaseFilter(iface); struct testfilter *filter = impl_from_IBaseFilter(iface);
ULONG refCount = InterlockedIncrement(&This->refCount); return InterlockedIncrement(&filter->ref);
return refCount;
} }
static ULONG WINAPI TestFilter_Release(IBaseFilter * iface) static ULONG WINAPI testfilter_Release(IBaseFilter *iface)
{ {
TestFilterImpl *This = impl_from_IBaseFilter(iface); struct testfilter *filter = impl_from_IBaseFilter(iface);
ULONG refCount = InterlockedDecrement(&This->refCount); return InterlockedDecrement(&filter->ref);
if (!refCount)
{
ULONG i;
for (i = 0; i < This->nPins; i++)
{
IPin *pConnectedTo;
if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
{
IPin_Disconnect(pConnectedTo);
IPin_Release(pConnectedTo);
}
IPin_Disconnect(This->ppPins[i]);
IPin_Release(This->ppPins[i]);
}
CoTaskMemFree(This->ppPins);
DeleteCriticalSection(&This->csFilter);
CoTaskMemFree(This);
return 0;
}
else
return refCount;
} }
/** IPersist methods **/
static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid) static HRESULT WINAPI testfilter_GetClassID(IBaseFilter *iface, CLSID *clsid)
{ {
TestFilterImpl *This = impl_from_IBaseFilter(iface); if (winetest_debug > 1) trace("%p->GetClassID()\n", iface);
return E_NOTIMPL;
*pClsid = This->clsid;
return S_OK;
} }
/** IMediaFilter methods **/ static HRESULT WINAPI testfilter_Stop(IBaseFilter *iface)
static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
{ {
if (winetest_debug > 1) trace("%p->Stop()\n", iface);
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface) static HRESULT WINAPI testfilter_Pause(IBaseFilter *iface)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart) static HRESULT WINAPI testfilter_Run(IBaseFilter *iface, REFERENCE_TIME start)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) static HRESULT WINAPI testfilter_GetState(IBaseFilter *iface, DWORD timeout, FILTER_STATE *state)
{ {
TestFilterImpl *This = impl_from_IBaseFilter(iface); if (winetest_debug > 1) trace("%p->GetState()\n", iface);
return E_NOTIMPL;
EnterCriticalSection(&This->csFilter);
{
*pState = This->state;
}
LeaveCriticalSection(&This->csFilter);
return S_OK;
} }
static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) static HRESULT WINAPI testfilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
{ {
if (winetest_debug > 1) trace("%p->SetSyncSource(%p)\n", iface, clock);
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) static HRESULT WINAPI testfilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
/** IBaseFilter implementation **/ static HRESULT WINAPI testfilter_EnumPins(IBaseFilter *iface, IEnumPins **out)
static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
{ {
/* Our pins are static, not changing so setting static tick count is ok */ struct testfilter *filter = impl_from_IBaseFilter(iface);
*lastsynctick = 0; if (winetest_debug > 1) trace("%p->EnumPins()\n", filter);
if (pos >= tf->nPins)
return S_FALSE;
*pin = tf->ppPins[pos]; *out = &filter->IEnumPins_iface;
IPin_AddRef(*pin); IEnumPins_AddRef(*out);
filter->enum_idx = 0;
return S_OK; return S_OK;
} }
static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) static HRESULT WINAPI testfilter_FindPin(IBaseFilter *iface, const WCHAR *id, IPin **pin)
{
TestFilterImpl *This = impl_from_IBaseFilter(iface);
return createenumpins(ppEnum, getpin_callback, This);
}
static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
{ {
ok(0, "Unexpected call.\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) static HRESULT WINAPI testfilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
{ {
TestFilterImpl *This = impl_from_IBaseFilter(iface); struct testfilter *filter = impl_from_IBaseFilter(iface);
if (winetest_debug > 1) trace("%p->QueryFilterInfo()\n", filter);
lstrcpyW(pInfo->achName, This->filterInfo.achName);
pInfo->pGraph = This->filterInfo.pGraph;
if (pInfo->pGraph)
IFilterGraph_AddRef(pInfo->pGraph);
info->pGraph = filter->graph;
if (filter->graph)
IFilterGraph_AddRef(filter->graph);
if (filter->name)
lstrcpyW(info->achName, filter->name);
else
info->achName[0] = 0;
return S_OK; return S_OK;
} }
static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) static HRESULT WINAPI testfilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, const WCHAR *name)
{ {
HRESULT hr = S_OK; struct testfilter *filter = impl_from_IBaseFilter(iface);
TestFilterImpl *This = impl_from_IBaseFilter(iface); if (winetest_debug > 1) trace("%p->JoinFilterGraph(%p, %s)\n", filter, graph, wine_dbgstr_w(name));
EnterCriticalSection(&This->csFilter); filter->graph = graph;
heap_free(filter->name);
if (name)
{ {
if (pName) filter->name = heap_alloc((lstrlenW(name)+1)*sizeof(WCHAR));
lstrcpyW(This->filterInfo.achName, pName); lstrcpyW(filter->name, name);
else
*This->filterInfo.achName = '\0';
This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
} }
LeaveCriticalSection(&This->csFilter); else
filter->name = NULL;
return hr; return S_OK;
} }
static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) static HRESULT WINAPI testfilter_QueryVendorInfo(IBaseFilter * iface, WCHAR **info)
{ {
return E_NOTIMPL; return E_NOTIMPL;
} }
static const IBaseFilterVtbl TestFilter_Vtbl = static const IBaseFilterVtbl testfilter_vtbl =
{ {
TestFilter_QueryInterface, testfilter_QueryInterface,
TestFilter_AddRef, testfilter_AddRef,
TestFilter_Release, testfilter_Release,
TestFilter_GetClassID, testfilter_GetClassID,
TestFilter_Stop, testfilter_Stop,
TestFilter_Pause, testfilter_Pause,
TestFilter_Run, testfilter_Run,
TestFilter_GetState, testfilter_GetState,
TestFilter_SetSyncSource, testfilter_SetSyncSource,
TestFilter_GetSyncSource, testfilter_GetSyncSource,
TestFilter_EnumPins, testfilter_EnumPins,
TestFilter_FindPin, testfilter_FindPin,
TestFilter_QueryFilterInfo, testfilter_QueryFilterInfo,
TestFilter_JoinFilterGraph, testfilter_JoinFilterGraph,
TestFilter_QueryVendorInfo testfilter_QueryVendorInfo
}; };
/* IClassFactory implementation */ struct testfilter_cf
typedef struct TestClassFactoryImpl
{ {
IClassFactory IClassFactory_iface; IClassFactory IClassFactory_iface;
const TestFilterPinData *filterPinData; struct testfilter *filter;
const CLSID *clsid; };
} TestClassFactoryImpl;
static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) static void testfilter_init(struct testfilter *filter, struct testpin *pins, int pin_count)
{ {
return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface); unsigned int i;
memset(filter, 0, sizeof(*filter));
filter->IBaseFilter_iface.lpVtbl = &testfilter_vtbl;
filter->IEnumPins_iface.lpVtbl = &testenumpins_vtbl;
filter->ref = 1;
filter->pins = pins;
filter->pin_count = pin_count;
for (i = 0; i < pin_count; i++)
pins[i].filter = &filter->IBaseFilter_iface;
} }
static HRESULT WINAPI Test_IClassFactory_QueryInterface( static HRESULT WINAPI testfilter_cf_QueryInterface(IClassFactory *iface, REFIID iid, void **out)
LPCLASSFACTORY iface,
REFIID riid,
LPVOID *ppvObj)
{ {
if (ppvObj == NULL) return E_POINTER; if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory))
if (IsEqualGUID(riid, &IID_IUnknown) ||
IsEqualGUID(riid, &IID_IClassFactory))
{ {
*ppvObj = iface; *out = iface;
IClassFactory_AddRef(iface);
return S_OK; return S_OK;
} }
*ppvObj = NULL; *out = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface) static ULONG WINAPI testfilter_cf_AddRef(IClassFactory *iface)
{ {
return 2; /* non-heap-based object */ return 2;
} }
static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface) static ULONG WINAPI testfilter_cf_Release(IClassFactory *iface)
{ {
return 1; /* non-heap-based object */ return 1;
} }
static HRESULT WINAPI Test_IClassFactory_CreateInstance( static HRESULT WINAPI testfilter_cf_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out)
LPCLASSFACTORY iface,
LPUNKNOWN pUnkOuter,
REFIID riid,
LPVOID *ppvObj)
{ {
TestClassFactoryImpl *This = impl_from_IClassFactory(iface); struct testfilter_cf *factory = CONTAINING_RECORD(iface, struct testfilter_cf, IClassFactory_iface);
HRESULT hr;
TestFilterImpl *testfilter;
*ppvObj = NULL;
if (pUnkOuter) return CLASS_E_NOAGGREGATION;
hr = createtestfilter(This->clsid, This->filterPinData, &testfilter); return IBaseFilter_QueryInterface(&factory->filter->IBaseFilter_iface, iid, out);
if (SUCCEEDED(hr)) {
hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
IBaseFilter_Release(&testfilter->IBaseFilter_iface);
}
return hr;
} }
static HRESULT WINAPI Test_IClassFactory_LockServer( static HRESULT WINAPI testfilter_cf_LockServer(IClassFactory *iface, BOOL lock)
LPCLASSFACTORY iface,
BOOL fLock)
{ {
return S_OK; return E_NOTIMPL;
} }
static IClassFactoryVtbl TestClassFactory_Vtbl = static IClassFactoryVtbl testfilter_cf_vtbl =
{ {
Test_IClassFactory_QueryInterface, testfilter_cf_QueryInterface,
Test_IClassFactory_AddRef, testfilter_cf_AddRef,
Test_IClassFactory_Release, testfilter_cf_Release,
Test_IClassFactory_CreateInstance, testfilter_cf_CreateInstance,
Test_IClassFactory_LockServer testfilter_cf_LockServer,
}; };
static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName) static void test_graph_builder_render(void)
{ {
IPin *pin = NULL; static const WCHAR testW[] = {'t','e','s','t',0};
PIN_INFO pinInfo; static const GUID sink1_clsid = {0x12345678};
FILTER_INFO filterInfo; static const GUID sink2_clsid = {0x87654321};
HRESULT hr; AM_MEDIA_TYPE source_type = {{0}};
struct testpin source_pin, sink1_pin, sink2_pin, parser_pins[2];
FilterName[0] = 0; struct testfilter source, sink1, sink2, parser;
struct testfilter_cf sink1_cf = { {&testfilter_cf_vtbl}, &sink1 };
hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin); struct testfilter_cf sink2_cf = { {&testfilter_cf_vtbl}, &sink2 };
ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
hr = IPin_QueryPinInfo(pin, &pinInfo); IFilterGraph2 *graph = create_graph();
ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr); REGFILTERPINS2 regpins = {0};
IPin_Release(pin); REGPINTYPES regtypes = {0};
REGFILTER2 regfilter = {0};
SetLastError(0xdeadbeef); IFilterMapper2 *mapper;
hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo); DWORD cookie1, cookie2;
if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
IBaseFilter_Release(pinInfo.pFilter);
return E_NOTIMPL;
}
ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
IBaseFilter_Release(pinInfo.pFilter);
IFilterGraph_Release(filterInfo.pGraph);
WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
return S_OK;
}
static void test_render_filter_priority(void)
{
/* Tests filter choice priorities in Render(). */
DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
HRESULT hr; HRESULT hr;
IFilterGraph2* pgraph2 = NULL; ULONG ref;
IFilterMapper2 *pMapper2 = NULL;
TestFilterImpl *ptestfilter = NULL; memset(&source_type.majortype, 0xcc, sizeof(GUID));
TestFilterImpl *ptestfilter2 = NULL; testsource_init(&source_pin, &source_type, 1);
static const CLSID CLSID_TestFilter2 = { testfilter_init(&source, &source_pin, 1);
0x37a4edb0, testsink_init(&sink1_pin);
0x4d13, testfilter_init(&sink1, &sink1_pin, 1);
0x11dd, testsink_init(&sink2_pin);
{0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} testfilter_init(&sink2, &sink2_pin, 1);
}; testsink_init(&parser_pins[0]);
static const CLSID CLSID_TestFilter3 = { testsource_init(&parser_pins[1], &source_type, 1);
0x37a4f2d8, testfilter_init(&parser, parser_pins, 2);
0x4d13,
0x11dd, IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
{0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} IFilterGraph2_AddFilter(graph, &sink1.IBaseFilter_iface, NULL);
}; IFilterGraph2_AddFilter(graph, &sink2.IBaseFilter_iface, NULL);
static const CLSID CLSID_TestFilter4 = {
0x37a4f3b4, hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
0x4d13, ok(hr == S_OK, "Got hr %#x.\n", hr);
0x11dd, ok(source_pin.peer == &sink2_pin.IPin_iface, "Got peer %p.\n", source_pin.peer);
{0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} IFilterGraph2_Disconnect(graph, source_pin.peer);
}; IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface);
static const GUID mediasubtype1 = {
0x37a4f51c,
0x4d13,
0x11dd,
{0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
};
static const GUID mediasubtype2 = {
0x37a4f5c6,
0x4d13,
0x11dd,
{0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
};
static const TestFilterPinData PinData1[] = {
{ PINDIR_OUTPUT, &mediasubtype1 },
{ 0, 0 }
};
static const TestFilterPinData PinData2[] = {
{ PINDIR_INPUT, &mediasubtype1 },
{ 0, 0 }
};
static const TestFilterPinData PinData3[] = {
{ PINDIR_INPUT, &GUID_NULL },
{ 0, 0 }
};
static const TestFilterPinData PinData4[] = {
{ PINDIR_INPUT, &mediasubtype1 },
{ PINDIR_OUTPUT, &mediasubtype2 },
{ 0, 0 }
};
static const TestFilterPinData PinData5[] = {
{ PINDIR_INPUT, &mediasubtype2 },
{ 0, 0 }
};
TestClassFactoryImpl Filter1ClassFactory = {
{ &TestClassFactory_Vtbl },
PinData2, &CLSID_TestFilter2
};
TestClassFactoryImpl Filter2ClassFactory = {
{ &TestClassFactory_Vtbl },
PinData4, &CLSID_TestFilter3
};
TestClassFactoryImpl Filter3ClassFactory = {
{ &TestClassFactory_Vtbl },
PinData5, &CLSID_TestFilter4
};
char ConnectedFilterName1[MAX_FILTER_NAME];
char ConnectedFilterName2[MAX_FILTER_NAME];
REGFILTER2 rgf2;
REGFILTERPINS2 rgPins2[2];
REGPINTYPES rgPinType[2];
static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
/* Test which renderer of two already added to the graph will be chosen
* (one is "exact" match, other is "wildcard" match. Seems to depend
* on the order in which filters are added to the graph, thus indicating
* no preference given to exact match. */
pgraph2 = create_graph();
hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
IFilterGraph2_Release(pgraph2);
IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
pgraph2 = create_graph();
hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
hr = IFilterGraph2_Disconnect(pgraph2, NULL);
ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
get_connected_filter_name(ptestfilter, ConnectedFilterName2);
ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
"expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
IFilterGraph2_Release(pgraph2);
IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
/* Test if any preference is given to existing renderer which renders the pin directly vs
an existing renderer which renders the pin indirectly, through an additional middle filter,
again trying different orders of creation. Native appears not to give a preference. */
pgraph2 = create_graph();
hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter); IFilterGraph2_RemoveFilter(graph, &sink1.IBaseFilter_iface);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); IFilterGraph2_AddFilter(graph, &sink1.IBaseFilter_iface, NULL);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1); hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(source_pin.peer == &sink1_pin.IPin_iface, "Got peer %p.\n", source_pin.peer);
hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2); IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); IFilterGraph2_Disconnect(graph, &sink1_pin.IPin_iface);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2); /* No preference is given to smaller chains. */
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface); IFilterGraph2_AddFilter(graph, &parser.IBaseFilter_iface, NULL);
hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2); hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(source_pin.peer == &parser_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer);
ok(parser_pins[1].peer == &sink1_pin.IPin_iface, "Got peer %p.\n", parser_pins[1].peer);
IFilterGraph2_Disconnect(graph, source_pin.peer);
IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3); IFilterGraph2_RemoveFilter(graph, &sink1.IBaseFilter_iface);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); IFilterGraph2_AddFilter(graph, &sink1.IBaseFilter_iface, NULL);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface); hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(source_pin.peer == &sink1_pin.IPin_iface, "Got peer %p.\n", source_pin.peer);
hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2); ref = IFilterGraph2_Release(graph);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4); /* Test enumeration of filters from the registry. */
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]); graph = create_graph();
ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr); IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
CoRegisterClassObject(&sink1_clsid, (IUnknown *)&sink1_cf.IClassFactory_iface,
CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
CoRegisterClassObject(&sink2_clsid, (IUnknown *)&sink2_cf.IClassFactory_iface,
CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
&IID_IFilterMapper2, (void **)&mapper);
regfilter.dwVersion = 2;
regfilter.dwMerit = MERIT_UNLIKELY;
regfilter.cPins2 = 1;
regfilter.rgPins2 = &regpins;
regpins.dwFlags = 0;
regpins.cInstances = 1;
regpins.nMediaTypes = 1;
regpins.lpMediaType = &regtypes;
regtypes.clsMajorType = &source_type.majortype;
regtypes.clsMinorType = &MEDIASUBTYPE_NULL;
hr = IFilterMapper2_RegisterFilter(mapper, &sink1_clsid, testW, NULL, NULL, NULL, &regfilter);
if (hr == E_ACCESSDENIED)
{
skip("Not enough permission to register filters.\n");
goto out;
}
ok(hr == S_OK, "Got hr %#x.\n", hr);
get_connected_filter_name(ptestfilter, ConnectedFilterName1); regpins.dwFlags = REG_PINFLAG_B_RENDERER;
ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3") || !strcmp(ConnectedFilterName1, "TestfilterInstance2"), IFilterMapper2_RegisterFilter(mapper, &sink2_clsid, testW, NULL, NULL, NULL, &regfilter);
"unexpected connected filter: %s\n", ConnectedFilterName1);
IFilterGraph2_Release(pgraph2); hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
IBaseFilter_Release(&ptestfilter->IBaseFilter_iface); ok(hr == S_OK, "Got hr %#x.\n", hr);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface); ok(source_pin.peer == &sink2_pin.IPin_iface || source_pin.peer == &sink1_pin.IPin_iface,
"Got peer %p.\n", source_pin.peer);
pgraph2 = create_graph(); ref = IFilterGraph2_Release(graph);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter); /* Preference is given to filters already in the graph. */
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1); graph = create_graph();
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
IFilterGraph2_AddFilter(graph, &sink2.IBaseFilter_iface, NULL);
hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2); hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(source_pin.peer == &sink2_pin.IPin_iface, "Got peer %p.\n", source_pin.peer);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3); ref = IFilterGraph2_Release(graph);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); ok(!ref, "Got outstanding refcount %d.\n", ref);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface); /* No preference is given to renderer filters. */
hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2); graph = create_graph();
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink1_clsid);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink2_clsid);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface); IFilterMapper2_RegisterFilter(mapper, &sink1_clsid, testW, NULL, NULL, NULL, &regfilter);
regpins.dwFlags = 0;
IFilterMapper2_RegisterFilter(mapper, &sink2_clsid, testW, NULL, NULL, NULL, &regfilter);
hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2); hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(source_pin.peer == &sink2_pin.IPin_iface || source_pin.peer == &sink1_pin.IPin_iface,
"Got peer %p.\n", source_pin.peer);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2); ref = IFilterGraph2_Release(graph);
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]); /* Preference is given to filters with higher merit. */
ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
get_connected_filter_name(ptestfilter, ConnectedFilterName2); graph = create_graph();
ok(!strcmp(ConnectedFilterName2, "TestfilterInstance3") || !strcmp(ConnectedFilterName2, "TestfilterInstance2"), IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
"unexpected connected filter: %s\n", ConnectedFilterName2);
ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
"expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
IFilterGraph2_Release(pgraph2); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink1_clsid);
IBaseFilter_Release(&ptestfilter->IBaseFilter_iface); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink2_clsid);
IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
/* Test if renderers are tried before non-renderers (intermediary filters). */ regfilter.dwMerit = MERIT_UNLIKELY;
pgraph2 = create_graph(); IFilterMapper2_RegisterFilter(mapper, &sink1_clsid, testW, NULL, NULL, NULL, &regfilter);
regfilter.dwMerit = MERIT_PREFERRED;
IFilterMapper2_RegisterFilter(mapper, &sink2_clsid, testW, NULL, NULL, NULL, &regfilter);
hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2); hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(source_pin.peer == &sink2_pin.IPin_iface, "Got peer %p.\n", source_pin.peer);
hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter); ref = IFilterGraph2_Release(graph);
ok(hr == S_OK, "createtestfilter failed with %08x\n", hr); ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1); graph = create_graph();
ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
/* Register our filters with COM and with Filtermapper. */ IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink1_clsid);
hr = CoRegisterClassObject(Filter1ClassFactory.clsid, IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink2_clsid);
(IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
REGCLS_MULTIPLEUSE, &cookie1);
ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
(IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
REGCLS_MULTIPLEUSE, &cookie2);
ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
(IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
REGCLS_MULTIPLEUSE, &cookie3);
ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
rgf2.dwVersion = 2; regfilter.dwMerit = MERIT_PREFERRED;
rgf2.dwMerit = MERIT_UNLIKELY; IFilterMapper2_RegisterFilter(mapper, &sink1_clsid, testW, NULL, NULL, NULL, &regfilter);
S2(U(rgf2)).cPins2 = 1; regfilter.dwMerit = MERIT_UNLIKELY;
S2(U(rgf2)).rgPins2 = rgPins2; IFilterMapper2_RegisterFilter(mapper, &sink2_clsid, testW, NULL, NULL, NULL, &regfilter);
rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
rgPins2[0].cInstances = 1;
rgPins2[0].nMediaTypes = 1;
rgPins2[0].lpMediaType = &rgPinType[0];
rgPins2[0].nMediums = 0;
rgPins2[0].lpMedium = NULL;
rgPins2[0].clsPinCategory = NULL;
rgPinType[0].clsMajorType = &MEDIATYPE_Video;
rgPinType[0].clsMinorType = &mediasubtype1;
hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL, hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
&CLSID_LegacyAmFilterCategory, NULL, &rgf2); ok(hr == S_OK, "Got hr %#x.\n", hr);
if (hr == E_ACCESSDENIED) ok(source_pin.peer == &sink1_pin.IPin_iface, "Got peer %p.\n", source_pin.peer);
skip("Not authorized to register filters\n");
else
{
ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
rgf2.dwMerit = MERIT_PREFERRED;
rgPinType[0].clsMinorType = &mediasubtype2;
hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
&CLSID_LegacyAmFilterCategory, NULL, &rgf2);
ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
S2(U(rgf2)).cPins2 = 2;
rgPins2[0].dwFlags = 0;
rgPinType[0].clsMinorType = &mediasubtype1;
rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
rgPins2[1].cInstances = 1;
rgPins2[1].nMediaTypes = 1;
rgPins2[1].lpMediaType = &rgPinType[1];
rgPins2[1].nMediums = 0;
rgPins2[1].lpMedium = NULL;
rgPins2[1].clsPinCategory = NULL;
rgPinType[1].clsMajorType = &MEDIATYPE_Video;
rgPinType[1].clsMinorType = &mediasubtype2;
hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
&CLSID_LegacyAmFilterCategory, NULL, &rgf2);
ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
get_connected_filter_name(ptestfilter, ConnectedFilterName1);
ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3"),
"unexpected connected filter: %s\n", ConnectedFilterName1);
hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
&CLSID_TestFilter2);
ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
&CLSID_TestFilter3);
ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
&CLSID_TestFilter4);
ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
}
IBaseFilter_Release(&ptestfilter->IBaseFilter_iface); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink1_clsid);
IFilterGraph2_Release(pgraph2); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink2_clsid);
IFilterMapper2_Release(pMapper2);
hr = CoRevokeClassObject(cookie1); out:
ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr); CoRevokeClassObject(cookie1);
hr = CoRevokeClassObject(cookie2); CoRevokeClassObject(cookie2);
ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr); IFilterMapper2_Release(mapper);
hr = CoRevokeClassObject(cookie3); ref = IFilterGraph2_Release(graph);
ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr); ok(!ref, "Got outstanding refcount %d.\n", ref);
ok(source.ref == 1, "Got outstanding refcount %d.\n", source.ref);
ok(source_pin.ref == 1, "Got outstanding refcount %d.\n", source_pin.ref);
ok(sink1.ref == 1, "Got outstanding refcount %d.\n", sink1.ref);
ok(sink1_pin.ref == 1, "Got outstanding refcount %d.\n", sink1_pin.ref);
ok(sink2.ref == 1, "Got outstanding refcount %d.\n", sink2.ref);
ok(sink2_pin.ref == 1, "Got outstanding refcount %d.\n", sink2_pin.ref);
ok(parser.ref == 1, "Got outstanding refcount %d.\n", parser.ref);
ok(parser_pins[0].ref == 1, "Got outstanding refcount %d.\n", parser_pins[0].ref);
ok(parser_pins[1].ref == 1, "Got outstanding refcount %d.\n", parser_pins[1].ref);
} }
typedef struct IUnknownImpl typedef struct IUnknownImpl
...@@ -2499,7 +1831,7 @@ START_TEST(filtergraph) ...@@ -2499,7 +1831,7 @@ START_TEST(filtergraph)
test_render_run(mpegfile); test_render_run(mpegfile);
test_enum_filters(); test_enum_filters();
test_graph_builder(); test_graph_builder();
test_render_filter_priority(); test_graph_builder_render();
test_aggregate_filter_graph(); test_aggregate_filter_graph();
test_control_delegation(); test_control_delegation();
......
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