Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
f2a8d535
Commit
f2a8d535
authored
Sep 18, 2018
by
Zebediah Figura
Committed by
Alexandre Julliard
Sep 18, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
quartz/tests: Rewrite test_render_filter_priority().
Signed-off-by:
Zebediah Figura
<
z.figura12@gmail.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
22308340
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
527 additions
and
1195 deletions
+527
-1195
filtergraph.c
dlls/quartz/tests/filtergraph.c
+527
-1195
No files found.
dlls/quartz/tests/filtergraph.c
View file @
f2a8d535
...
...
@@ -22,9 +22,9 @@
#define COBJMACROS
#define CONST_VTABLE
#include "wine/test.h"
#include "dshow.h"
#include "control.h"
#include "wine/heap.h"
#include "wine/test.h"
typedef
struct
TestFilterImpl
{
...
...
@@ -783,1511 +783,843 @@ static void test_graph_builder(void)
IGraphBuilder_Release
(
pgraph
);
}
/* IEnumMediaTypes implementation (supporting code for Render() test.) */
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
)
struct
testpin
{
*
pDest
=
*
pSrc
;
if
(
!
pSrc
->
pbFormat
)
return
S_OK
;
if
(
!
(
pDest
->
pbFormat
=
CoTaskMemAlloc
(
pSrc
->
cbFormat
)))
return
E_OUTOFMEMORY
;
memcpy
(
pDest
->
pbFormat
,
pSrc
->
pbFormat
,
pSrc
->
cbFormat
);
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
);
}
IPin
IPin_iface
;
LONG
ref
;
PIN_DIRECTION
dir
;
IBaseFilter
*
filter
;
IPin
*
peer
;
typedef
struct
IEnumMediaTypesImpl
{
IEnumMediaTypes
IEnumMediaTypes_iface
;
LONG
refCount
;
AM_MEDIA_TYPE
*
pMediaTypes
;
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
);
}
const
AM_MEDIA_TYPE
*
types
;
unsigned
int
type_count
,
enum_idx
;
};
static
HRESULT
IEnumMediaTypesImpl_Construct
(
const
AM_MEDIA_TYPE
*
pMediaTypes
,
ULONG
cMediaTypes
,
IEnumMediaTypes
**
ppEnum
)
static
inline
struct
testpin
*
impl_from_IEnumMediaTypes
(
IEnumMediaTypes
*
iface
)
{
ULONG
i
;
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
;
return
CONTAINING_RECORD
(
iface
,
struct
testpin
,
IEnumMediaTypes_iface
);
}
static
HRESULT
WINAPI
IEnumMediaTypesImpl_QueryInterface
(
IEnumMediaTypes
*
iface
,
REFIID
riid
,
LPVOID
*
ppv
)
static
HRESULT
WINAPI
testenummt_QueryInterface
(
IEnumMediaTypes
*
iface
,
REFIID
iid
,
void
**
out
)
{
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
))
*
ppv
=
iface
;
else
if
(
IsEqualIID
(
riid
,
&
IID_IEnumMediaTypes
))
*
ppv
=
iface
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)(
*
ppv
));
return
S_OK
;
}
struct
testpin
*
pin
=
impl_from_IEnumMediaTypes
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->QueryInterface(%s)
\n
"
,
pin
,
wine_dbgstr_guid
(
iid
));
*
out
=
NULL
;
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
IEnumMediaTypesImpl_AddRef
(
IEnumMediaTypes
*
iface
)
static
ULONG
WINAPI
testenummt_AddRef
(
IEnumMediaTypes
*
iface
)
{
IEnumMediaTypesImpl
*
This
=
impl_from_IEnumMediaTypes
(
iface
);
ULONG
refCount
=
InterlockedIncrement
(
&
This
->
refCount
);
return
refCount
;
struct
testpin
*
pin
=
impl_from_IEnumMediaTypes
(
iface
);
return
InterlockedIncrement
(
&
pin
->
ref
);
}
static
ULONG
WINAPI
IEnumMediaTypesImpl_Release
(
IEnumMediaTypes
*
iface
)
static
ULONG
WINAPI
testenummt_Release
(
IEnumMediaTypes
*
iface
)
{
IEnumMediaTypesImpl
*
This
=
impl_from_IEnumMediaTypes
(
iface
);
ULONG
refCount
=
InterlockedDecrement
(
&
This
->
refCount
);
if
(
!
refCount
)
{
int
i
;
for
(
i
=
0
;
i
<
This
->
cMediaTypes
;
i
++
)
FreeMediaType
(
&
This
->
pMediaTypes
[
i
]);
CoTaskMemFree
(
This
->
pMediaTypes
);
CoTaskMemFree
(
This
);
}
return
refCount
;
struct
testpin
*
pin
=
impl_from_IEnumMediaTypes
(
iface
);
return
InterlockedDecrement
(
&
pin
->
ref
);
}
static
HRESULT
WINAPI
IEnumMediaTypesImpl_Next
(
IEnumMediaTypes
*
iface
,
ULONG
cMediaTypes
,
AM_MEDIA_TYPE
**
ppMediaTypes
,
ULONG
*
pcF
etched
)
static
HRESULT
WINAPI
testenummt_Next
(
IEnumMediaTypes
*
iface
,
ULONG
count
,
AM_MEDIA_TYPE
**
out
,
ULONG
*
f
etched
)
{
ULONG
cFetched
;
IEnumMediaTypesImpl
*
This
=
impl_from_IEnumMediaTypes
(
iface
);
cFetched
=
min
(
This
->
cMediaTypes
,
This
->
uIndex
+
cMediaTypes
)
-
This
->
uIndex
;
struct
testpin
*
pin
=
impl_from_IEnumMediaTypes
(
iface
);
unsigned
int
i
;
if
(
cFetched
>
0
)
for
(
i
=
0
;
i
<
count
;
++
i
)
{
ULONG
i
;
for
(
i
=
0
;
i
<
cFetched
;
i
++
)
if
(
!
(
ppMediaTypes
[
i
]
=
CreateMediaType
(
&
This
->
pMediaTypes
[
This
->
uIndex
+
i
])))
{
while
(
i
--
)
DeleteMediaType
(
ppMediaTypes
[
i
]);
*
pcFetched
=
0
;
return
E_OUTOFMEMORY
;
}
}
if
(
pin
->
enum_idx
+
i
>=
pin
->
type_count
)
break
;
if
((
cMediaTypes
!=
1
)
||
pcFetched
)
*
pcFetched
=
cFetched
;
out
[
i
]
=
CoTaskMemAlloc
(
sizeof
(
*
out
[
i
]));
*
out
[
i
]
=
pin
->
types
[
pin
->
enum_idx
+
i
];
}
This
->
uIndex
+=
cFetched
;
if
(
fetched
)
*
fetched
=
i
;
pin
->
enum_idx
+=
i
;
if
(
cFetched
!=
cMediaTypes
)
return
S_FALSE
;
return
S_OK
;
return
(
i
==
count
)
?
S_OK
:
S_FALSE
;
}
static
HRESULT
WINAPI
IEnumMediaTypesImpl_Skip
(
IEnumMediaTypes
*
iface
,
ULONG
cMediaTypes
)
static
HRESULT
WINAPI
testenummt_Skip
(
IEnumMediaTypes
*
iface
,
ULONG
count
)
{
IEnumMediaTypesImpl
*
This
=
impl_from_IEnumMediaTypes
(
iface
);
if
(
This
->
uIndex
+
cMediaTypes
<
This
->
cMediaTypes
)
{
This
->
uIndex
+=
cMediaTypes
;
return
S_OK
;
}
return
S_FALSE
;
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
IEnumMediaTypesImpl_Reset
(
IEnumMediaTypes
*
iface
)
static
HRESULT
WINAPI
testenummt_Reset
(
IEnumMediaTypes
*
iface
)
{
IEnumMediaTypesImpl
*
This
=
impl_from_IEnumMediaTypes
(
iface
);
This
->
uIndex
=
0
;
struct
testpin
*
pin
=
impl_from_IEnumMediaTypes
(
iface
);
pin
->
enum_idx
=
0
;
return
S_OK
;
}
static
HRESULT
WINAPI
IEnumMediaTypesImpl_Clone
(
IEnumMediaTypes
*
iface
,
IEnumMediaTypes
**
ppEnum
)
static
HRESULT
WINAPI
testenummt_Clone
(
IEnumMediaTypes
*
iface
,
IEnumMediaTypes
**
out
)
{
HRESULT
hr
;
IEnumMediaTypesImpl
*
This
=
impl_from_IEnumMediaTypes
(
iface
);
hr
=
IEnumMediaTypesImpl_Construct
(
This
->
pMediaTypes
,
This
->
cMediaTypes
,
ppEnum
);
if
(
FAILED
(
hr
))
return
hr
;
return
IEnumMediaTypes_Skip
(
*
ppEnum
,
This
->
uIndex
);
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
const
IEnumMediaTypesVtbl
IEnumMediaTypesImpl_V
tbl
=
static
const
IEnumMediaTypesVtbl
testenummt_v
tbl
=
{
IEnumMediaTypesImpl
_QueryInterface
,
IEnumMediaTypesImpl
_AddRef
,
IEnumMediaTypesImpl
_Release
,
IEnumMediaTypesImpl
_Next
,
IEnumMediaTypesImpl
_Skip
,
IEnumMediaTypesImpl
_Reset
,
IEnumMediaTypesImpl_Clone
testenummt
_QueryInterface
,
testenummt
_AddRef
,
testenummt
_Release
,
testenummt
_Next
,
testenummt
_Skip
,
testenummt
_Reset
,
testenummt_Clone
,
};
/* Implementation of a very stripped down pin for the test filter. Just enough
functionality for connecting and Render() to work. */
static
void
Copy_PinInfo
(
PIN_INFO
*
pDest
,
const
PIN_INFO
*
pSrc
)
static
inline
struct
testpin
*
impl_from_IPin
(
IPin
*
iface
)
{
lstrcpyW
(
pDest
->
achName
,
pSrc
->
achName
);
pDest
->
dir
=
pSrc
->
dir
;
pDest
->
pFilter
=
pSrc
->
pFilter
;
return
CONTAINING_RECORD
(
iface
,
struct
testpin
,
IPin_iface
);
}
typedef
struct
ITestPinImpl
static
HRESULT
WINAPI
testpin_QueryInterface
(
IPin
*
iface
,
REFIID
iid
,
void
**
out
)
{
IPin
IPin_iface
;
LONG
refCount
;
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
);
}
struct
testpin
*
pin
=
impl_from_IPin
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->QueryInterface(%s)
\n
"
,
pin
,
wine_dbgstr_guid
(
iid
));
static
HRESULT
WINAPI
TestFilter_Pin_QueryInterface
(
IPin
*
iface
,
REFIID
riid
,
LPVOID
*
ppv
)
{
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
))
*
ppv
=
iface
;
else
if
(
IsEqualIID
(
riid
,
&
IID_IPin
))
*
ppv
=
iface
;
if
(
*
ppv
)
if
(
IsEqualGUID
(
iid
,
&
IID_IUnknown
)
||
IsEqualGUID
(
iid
,
&
IID_IPin
))
{
IUnknown_AddRef
((
IUnknown
*
)(
*
ppv
));
*
out
=
&
pin
->
IPin_iface
;
IPin_AddRef
(
*
out
);
return
S_OK
;
}
*
out
=
NULL
;
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
TestFilter_Pin_AddRef
(
IPin
*
iface
)
{
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
ULONG
refCount
=
InterlockedIncrement
(
&
This
->
refCount
);
return
refCount
;
}
static
ULONG
WINAPI
TestFilter_Pin_Release
(
IPin
*
iface
)
ULONG
WINAPI
testpin_AddRef
(
IPin
*
iface
)
{
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
ULONG
refCount
=
InterlockedDecrement
(
&
This
->
refCount
);
if
(
!
refCount
)
{
FreeMediaType
(
&
This
->
mtCurrent
);
CoTaskMemFree
(
This
);
return
0
;
}
else
return
refCount
;
struct
testpin
*
pin
=
impl_from_IPin
(
iface
);
return
InterlockedIncrement
(
&
pin
->
ref
);
}
static
HRESULT
WINAPI
TestFilter_InputPin_Connect
(
IPin
*
iface
,
IPin
*
pConnector
,
const
AM_MEDIA_TYPE
*
pmt
)
ULONG
WINAPI
testpin_Release
(
IPin
*
iface
)
{
return
E_UNEXPECTED
;
}
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
;
struct
testpin
*
pin
=
impl_from_IPin
(
iface
);
return
InterlockedDecrement
(
&
pin
->
ref
);
}
static
HRESULT
WINAPI
TestFilter_Pin_Disconnect
(
IPin
*
iface
)
static
HRESULT
WINAPI
testpin_Disconnect
(
IPin
*
iface
)
{
HRESULT
hr
;
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
struct
testpin
*
pin
=
impl_from_IPin
(
iface
)
;
if
(
winetest_debug
>
1
)
trace
(
"%p->Disconnect()
\n
"
,
pin
);
EnterCriticalSection
(
This
->
pCritSec
);
{
if
(
This
->
pConnectedTo
)
{
IPin_Release
(
This
->
pConnectedTo
);
This
->
pConnectedTo
=
NULL
;
hr
=
S_OK
;
}
else
hr
=
S_FALSE
;
}
LeaveCriticalSection
(
This
->
pCritSec
);
if
(
!
pin
->
peer
)
return
S_FALSE
;
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
;
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
struct
testpin
*
pin
=
impl_from_IPin
(
iface
)
;
if
(
winetest_debug
>
1
)
trace
(
"%p->ConnectedTo()
\n
"
,
pin
);
EnterCriticalSection
(
This
->
pCritSec
);
*
peer
=
pin
->
peer
;
if
(
*
peer
)
{
if
(
This
->
pConnectedTo
)
{
*
ppPin
=
This
->
pConnectedTo
;
IPin_AddRef
(
*
ppPin
);
hr
=
S_OK
;
}
else
{
hr
=
VFW_E_NOT_CONNECTED
;
*
ppPin
=
NULL
;
}
IPin_AddRef
(
*
peer
);
return
S_OK
;
}
LeaveCriticalSection
(
This
->
pCritSec
);
return
hr
;
return
VFW_E_NOT_CONNECTED
;
}
static
HRESULT
WINAPI
TestFilter_Pin_ConnectionMediaType
(
IPin
*
iface
,
AM_MEDIA_TYPE
*
p
mt
)
static
HRESULT
WINAPI
testpin_ConnectionMediaType
(
IPin
*
iface
,
AM_MEDIA_TYPE
*
mt
)
{
HRESULT
hr
;
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
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
;
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_Pin_QueryPinInfo
(
IPin
*
iface
,
PIN_INFO
*
pI
nfo
)
static
HRESULT
WINAPI
testpin_QueryPinInfo
(
IPin
*
iface
,
PIN_INFO
*
i
nfo
)
{
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
Copy_PinInfo
(
pInfo
,
&
This
->
pinInfo
);
IBaseFilter_AddRef
(
pInfo
->
pFilter
);
struct
testpin
*
pin
=
impl_from_IPin
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->QueryPinInfo()
\n
"
,
pin
);
info
->
pFilter
=
pin
->
filter
;
IBaseFilter_AddRef
(
pin
->
filter
);
info
->
dir
=
pin
->
dir
;
info
->
achName
[
0
]
=
0
;
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
;
}
static
HRESULT
WINAPI
TestFilter_Pin_QueryId
(
IPin
*
iface
,
LPWSTR
*
I
d
)
static
HRESULT
WINAPI
testpin_QueryId
(
IPin
*
iface
,
WCHAR
**
i
d
)
{
if
(
winetest_debug
>
1
)
trace
(
"%p->QueryId()
\n
"
,
iface
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_Pin_QueryAccept
(
IPin
*
iface
,
const
AM_MEDIA_TYPE
*
p
mt
)
static
HRESULT
WINAPI
testpin_QueryAccept
(
IPin
*
iface
,
const
AM_MEDIA_TYPE
*
mt
)
{
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
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
;
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
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
;
}
static
HRESULT
WINAPI
TestFilter_Pin_BeginFlush
(
IPin
*
iface
)
static
HRESULT
WINAPI
testpin_BeginFlush
(
IPin
*
iface
)
{
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_P
in_EndFlush
(
IPin
*
iface
)
static
HRESULT
WINAPI
testp
in_EndFlush
(
IPin
*
iface
)
{
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_Pin_NewSegment
(
IPin
*
iface
,
REFERENCE_TIME
tStart
,
REFERENCE_TIME
tStop
,
double
dR
ate
)
static
HRESULT
WINAPI
testpin_NewSegment
(
IPin
*
iface
,
REFERENCE_TIME
start
,
REFERENCE_TIME
stop
,
double
r
ate
)
{
ok
(
0
,
"Unexpected call.
\n
"
);
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
;
}
static
const
IPinVtbl
TestFilter_InputPin_Vtbl
=
{
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
)
static
HRESULT
WINAPI
testsink_Connect
(
IPin
*
iface
,
IPin
*
peer
,
const
AM_MEDIA_TYPE
*
mt
)
{
return
E_UNEXPECTED
;
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
/* Private helper function */
static
HRESULT
TestFilter_OutputPin_ConnectSpecific
(
ITestPinImpl
*
This
,
IPin
*
pReceivePin
,
const
AM_MEDIA_TYPE
*
pmt
)
static
HRESULT
WINAPI
testsink_ReceiveConnection
(
IPin
*
iface
,
IPin
*
peer
,
const
AM_MEDIA_TYPE
*
mt
)
{
HRESULT
hr
;
This
->
pConnectedTo
=
pReceivePin
;
IPin_AddRef
(
pReceivePin
);
struct
testpin
*
pin
=
impl_from_IPin
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->ReceiveConnection(%p)
\n
"
,
pin
,
peer
);
hr
=
IPin_ReceiveConnection
(
pReceivePin
,
&
This
->
IPin_iface
,
pmt
);
if
(
FAILED
(
hr
))
{
IPin_Release
(
This
->
pConnectedTo
);
This
->
pConnectedTo
=
NULL
;
}
return
hr
;
pin
->
peer
=
peer
;
IPin_AddRef
(
peer
);
return
S_OK
;
}
static
HRESULT
WINAPI
TestFilter_OutputPin_Connect
(
IPin
*
iface
,
IPin
*
pReceivePin
,
const
AM_MEDIA_TYPE
*
pm
t
)
static
HRESULT
WINAPI
testsink_EnumMediaTypes
(
IPin
*
iface
,
IEnumMediaTypes
**
ou
t
)
{
ITestPinImpl
*
This
=
impl_from_IPin
(
iface
);
HRESULT
hr
;
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
;
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
const
IPinVtbl
TestFilter_OutputPin_V
tbl
=
{
TestFilter_P
in_QueryInterface
,
TestFilter_P
in_AddRef
,
TestFilter_P
in_Release
,
TestFilter_OutputPin
_Connect
,
TestFilter_OutputPin
_ReceiveConnection
,
TestFilter_P
in_Disconnect
,
TestFilter_P
in_ConnectedTo
,
TestFilter_P
in_ConnectionMediaType
,
TestFilter_P
in_QueryPinInfo
,
TestFilter_P
in_QueryDirection
,
TestFilter_P
in_QueryId
,
TestFilter_P
in_QueryAccept
,
TestFilter_Pin
_EnumMediaTypes
,
TestFilter_P
in_QueryInternalConnections
,
TestFilter_P
in_EndOfStream
,
TestFilter_P
in_BeginFlush
,
TestFilter_P
in_EndFlush
,
TestFilter_P
in_NewSegment
static
const
IPinVtbl
testsink_v
tbl
=
{
testp
in_QueryInterface
,
testp
in_AddRef
,
testp
in_Release
,
testsink
_Connect
,
testsink
_ReceiveConnection
,
testp
in_Disconnect
,
testp
in_ConnectedTo
,
testp
in_ConnectionMediaType
,
testp
in_QueryPinInfo
,
testp
in_QueryDirection
,
testp
in_QueryId
,
testp
in_QueryAccept
,
testsink
_EnumMediaTypes
,
testp
in_QueryInternalConnections
,
testp
in_EndOfStream
,
testp
in_BeginFlush
,
testp
in_EndFlush
,
testp
in_NewSegment
};
static
HRESULT
TestFilter_Pin_Construct
(
const
IPinVtbl
*
Pin_Vtbl
,
const
PIN_INFO
*
pPinInfo
,
AM_MEDIA_TYPE
*
pinmt
,
LPCRITICAL_SECTION
pCritSec
,
IPin
**
ppPin
)
static
void
testsink_init
(
struct
testpin
*
pin
)
{
ITestPinImpl
*
pPinImpl
;
*
ppPin
=
NULL
;
pPinImpl
=
CoTaskMemAlloc
(
sizeof
(
ITestPinImpl
));
if
(
!
pPinImpl
)
return
E_OUTOFMEMORY
;
memset
(
pin
,
0
,
sizeof
(
*
pin
));
pin
->
IPin_iface
.
lpVtbl
=
&
testsink_vtbl
;
pin
->
ref
=
1
;
pin
->
dir
=
PINDIR_INPUT
;
pPinImpl
->
refCount
=
1
;
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
;
pin
->
IEnumMediaTypes_iface
.
lpVtbl
=
&
testenummt_vtbl
;
}
/* IEnumPins implementation */
typedef
HRESULT
(
*
FNOBTAINPIN
)(
TestFilterImpl
*
tf
,
ULONG
pos
,
IPin
**
pin
,
DWORD
*
lastsynctick
);
typedef
struct
IEnumPinsImpl
static
HRESULT
WINAPI
testsource_Connect
(
IPin
*
iface
,
IPin
*
peer
,
const
AM_MEDIA_TYPE
*
mt
)
{
IEnumPins
IEnumPins_iface
;
LONG
refCount
;
ULONG
uIndex
;
TestFilterImpl
*
base
;
FNOBTAINPIN
receive_pin
;
DWORD
synctime
;
}
IEnumPinsImpl
;
struct
testpin
*
pin
=
impl_from_IPin
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->Connect(%p)
\n
"
,
pin
,
peer
);
static
const
struct
IEnumPinsVtbl
IEnumPinsImpl_Vtbl
;
ok
(
!
mt
,
"Got media type %p.
\n
"
,
mt
)
;
static
inline
IEnumPinsImpl
*
impl_from_IEnumPins
(
IEnumPins
*
iface
)
{
return
CONTAINING_RECORD
(
iface
,
IEnumPinsImpl
,
IEnumPins_iface
);
pin
->
peer
=
peer
;
IPin_AddRef
(
peer
);
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
;
if
(
!
ppEnum
)
return
E_POINTER
;
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
pEnumPins
=
CoTaskMemAlloc
(
sizeof
(
IEnumPinsImpl
));
if
(
!
pEnumPins
)
{
*
ppEnum
=
NULL
;
return
E_OUTOFMEMORY
;
}
pEnumPins
->
IEnumPins_iface
.
lpVtbl
=
&
IEnumPinsImpl_Vtbl
;
pEnumPins
->
refCount
=
1
;
pEnumPins
->
uIndex
=
0
;
pEnumPins
->
receive_pin
=
receive_pin
;
pEnumPins
->
base
=
base
;
IBaseFilter_AddRef
(
&
base
->
IBaseFilter_iface
);
*
ppEnum
=
&
pEnumPins
->
IEnumPins_iface
;
static
const
IPinVtbl
testsource_vtbl
=
{
testpin_QueryInterface
,
testpin_AddRef
,
testpin_Release
,
testsource_Connect
,
testsource_ReceiveConnection
,
testpin_Disconnect
,
testpin_ConnectedTo
,
testpin_ConnectionMediaType
,
testpin_QueryPinInfo
,
testpin_QueryDirection
,
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
;
}
st
atic
HRESULT
WINAPI
IEnumPinsImpl_QueryInterface
(
IEnumPins
*
iface
,
REFIID
riid
,
LPVOID
*
ppv
)
st
ruct
testfilter
{
*
ppv
=
NULL
;
IBaseFilter
IBaseFilter_iface
;
LONG
ref
;
IFilterGraph
*
graph
;
WCHAR
*
name
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
))
*
ppv
=
iface
;
else
if
(
IsEqualIID
(
riid
,
&
IID_IEnumPins
))
*
ppv
=
iface
;
IEnumPins
IEnumPins_iface
;
struct
testpin
*
pins
;
unsigned
int
pin_count
,
enum_idx
;
}
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)(
*
ppv
));
return
S_OK
;
}
static
inline
struct
testfilter
*
impl_from_IEnumPins
(
IEnumPins
*
iface
)
{
return
CONTAINING_RECORD
(
iface
,
struct
testfilter
,
IEnumPins_iface
);
}
static
HRESULT
WINAPI
testenumpins_QueryInterface
(
IEnumPins
*
iface
,
REFIID
iid
,
void
**
out
)
{
ok
(
0
,
"Unexpected iid %s.
\n
"
,
wine_dbgstr_guid
(
iid
));
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
IEnumPinsImpl
_AddRef
(
IEnumPins
*
iface
)
static
ULONG
WINAPI
testenumpins
_AddRef
(
IEnumPins
*
iface
)
{
IEnumPinsImpl
*
This
=
impl_from_IEnumPins
(
iface
);
ULONG
refCount
=
InterlockedIncrement
(
&
This
->
refCount
);
return
refCount
;
struct
testfilter
*
filter
=
impl_from_IEnumPins
(
iface
);
return
InterlockedIncrement
(
&
filter
->
ref
);
}
static
ULONG
WINAPI
IEnumPinsImpl
_Release
(
IEnumPins
*
iface
)
static
ULONG
WINAPI
testenumpins
_Release
(
IEnumPins
*
iface
)
{
IEnumPinsImpl
*
This
=
impl_from_IEnumPins
(
iface
);
ULONG
refCount
=
InterlockedDecrement
(
&
This
->
refCount
);
if
(
!
refCount
)
{
IBaseFilter_Release
(
&
This
->
base
->
IBaseFilter_iface
);
CoTaskMemFree
(
This
);
return
0
;
}
else
return
refCount
;
struct
testfilter
*
filter
=
impl_from_IEnumPins
(
iface
);
return
InterlockedDecrement
(
&
filter
->
ref
);
}
static
HRESULT
WINAPI
IEnumPinsImpl_Next
(
IEnumPins
*
iface
,
ULONG
cPins
,
IPin
**
ppPins
,
ULONG
*
pcF
etched
)
static
HRESULT
WINAPI
testenumpins_Next
(
IEnumPins
*
iface
,
ULONG
count
,
IPin
**
out
,
ULONG
*
f
etched
)
{
IEnumPinsImpl
*
This
=
impl_from_IEnumPins
(
iface
);
DWORD
synctime
=
This
->
synctime
;
HRESULT
hr
=
S_OK
;
ULONG
i
=
0
;
if
(
!
ppPins
)
return
E_POINTER
;
struct
testfilter
*
filter
=
impl_from_IEnumPins
(
iface
);
unsigned
int
i
;
if
(
cPins
>
1
&&
!
pcFetched
)
return
E_INVALIDARG
;
if
(
pcFetched
)
*
pcFetched
=
0
;
while
(
i
<
cPins
&&
hr
==
S_OK
)
for
(
i
=
0
;
i
<
count
;
++
i
)
{
hr
=
This
->
receive_pin
(
This
->
base
,
This
->
uIndex
+
i
,
&
ppPins
[
i
],
&
synctime
);
if
(
hr
==
S_OK
)
++
i
;
if
(
synctime
!=
This
->
synctime
)
if
(
filter
->
enum_idx
+
i
>=
filter
->
pin_count
)
break
;
}
if
(
!
i
&&
synctime
!=
This
->
synctime
)
return
VFW_E_ENUM_OUT_OF_SYNC
;
out
[
i
]
=
&
filter
->
pins
[
filter
->
enum_idx
+
i
].
IPin_iface
;
IPin_AddRef
(
out
[
i
]);
}
if
(
pcF
etched
)
*
pcF
etched
=
i
;
This
->
uInde
x
+=
i
;
if
(
f
etched
)
*
f
etched
=
i
;
filter
->
enum_id
x
+=
i
;
if
(
i
<
cPins
)
return
S_FALSE
;
return
S_OK
;
return
(
i
==
count
)
?
S_OK
:
S_FALSE
;
}
static
HRESULT
WINAPI
IEnumPinsImpl_Skip
(
IEnumPins
*
iface
,
ULONG
cPins
)
static
HRESULT
WINAPI
testenumpins_Skip
(
IEnumPins
*
iface
,
ULONG
count
)
{
IEnumPinsImpl
*
This
=
impl_from_IEnumPins
(
iface
);
DWORD
synctime
=
This
->
synctime
;
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
;
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
IEnumPinsImpl_Reset
(
IEnumPins
*
iface
)
static
HRESULT
WINAPI
testenumpins_Reset
(
IEnumPins
*
iface
)
{
IEnumPinsImpl
*
This
=
impl_from_IEnumPins
(
iface
);
This
->
receive_pin
(
This
->
base
,
~
0
,
NULL
,
&
This
->
synctime
);
This
->
uIndex
=
0
;
struct
testfilter
*
filter
=
impl_from_IEnumPins
(
iface
);
filter
->
enum_idx
=
0
;
return
S_OK
;
}
static
HRESULT
WINAPI
IEnumPinsImpl_Clone
(
IEnumPins
*
iface
,
IEnumPins
**
ppEnum
)
static
HRESULT
WINAPI
testenumpins_Clone
(
IEnumPins
*
iface
,
IEnumPins
**
out
)
{
HRESULT
hr
;
IEnumPinsImpl
*
This
=
impl_from_IEnumPins
(
iface
);
hr
=
createenumpins
(
ppEnum
,
This
->
receive_pin
,
This
->
base
);
if
(
FAILED
(
hr
))
return
hr
;
return
IEnumPins_Skip
(
*
ppEnum
,
This
->
uIndex
);
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
const
IEnumPinsVtbl
IEnumPinsImpl_V
tbl
=
static
const
IEnumPinsVtbl
testenumpins_v
tbl
=
{
IEnumPinsImpl
_QueryInterface
,
IEnumPinsImpl
_AddRef
,
IEnumPinsImpl
_Release
,
IEnumPinsImpl
_Next
,
IEnumPinsImpl
_Skip
,
IEnumPinsImpl
_Reset
,
IEnumPinsImpl_Clone
testenumpins
_QueryInterface
,
testenumpins
_AddRef
,
testenumpins
_Release
,
testenumpins
_Next
,
testenumpins
_Skip
,
testenumpins
_Reset
,
testenumpins_Clone
,
};
/* Test filter implementation - a filter that has few predefined pins with single media type
* 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
inline
struct
testfilter
*
impl_from_IBaseFilter
(
IBaseFilter
*
iface
)
{
static
const
WCHAR
wcsInputPinName
[]
=
{
'i'
,
'n'
,
'p'
,
'u'
,
't'
,
' '
,
'p'
,
'i'
,
'n'
,
0
};
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
;
return
CONTAINING_RECORD
(
iface
,
struct
testfilter
,
IBaseFilter_iface
);
}
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
);
*
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
;
struct
testfilter
*
filter
=
impl_from_IBaseFilter
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->QueryInterface(%s)
\n
"
,
filter
,
wine_dbgstr_guid
(
iid
));
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
;
}
*
out
=
NULL
;
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
TestFilter_AddRef
(
IBaseFilter
*
iface
)
static
ULONG
WINAPI
testfilter_AddRef
(
IBaseFilter
*
iface
)
{
TestFilterImpl
*
This
=
impl_from_IBaseFilter
(
iface
);
ULONG
refCount
=
InterlockedIncrement
(
&
This
->
refCount
);
return
refCount
;
struct
testfilter
*
filter
=
impl_from_IBaseFilter
(
iface
);
return
InterlockedIncrement
(
&
filter
->
ref
);
}
static
ULONG
WINAPI
TestFilter_Release
(
IBaseFilter
*
iface
)
static
ULONG
WINAPI
testfilter_Release
(
IBaseFilter
*
iface
)
{
TestFilterImpl
*
This
=
impl_from_IBaseFilter
(
iface
);
ULONG
refCount
=
InterlockedDecrement
(
&
This
->
refCount
);
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
;
struct
testfilter
*
filter
=
impl_from_IBaseFilter
(
iface
);
return
InterlockedDecrement
(
&
filter
->
ref
);
}
/** IPersist methods **/
static
HRESULT
WINAPI
TestFilter_GetClassID
(
IBaseFilter
*
iface
,
CLSID
*
pC
lsid
)
static
HRESULT
WINAPI
testfilter_GetClassID
(
IBaseFilter
*
iface
,
CLSID
*
c
lsid
)
{
TestFilterImpl
*
This
=
impl_from_IBaseFilter
(
iface
);
*
pClsid
=
This
->
clsid
;
return
S_OK
;
if
(
winetest_debug
>
1
)
trace
(
"%p->GetClassID()
\n
"
,
iface
);
return
E_NOTIMPL
;
}
/** 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
;
}
static
HRESULT
WINAPI
TestFilter_Pause
(
IBaseFilter
*
iface
)
static
HRESULT
WINAPI
testfilter_Pause
(
IBaseFilter
*
iface
)
{
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_Run
(
IBaseFilter
*
iface
,
REFERENCE_TIME
tS
tart
)
static
HRESULT
WINAPI
testfilter_Run
(
IBaseFilter
*
iface
,
REFERENCE_TIME
s
tart
)
{
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_GetState
(
IBaseFilter
*
iface
,
DWORD
dwMilliSecsTimeout
,
FILTER_STATE
*
pS
tate
)
static
HRESULT
WINAPI
testfilter_GetState
(
IBaseFilter
*
iface
,
DWORD
timeout
,
FILTER_STATE
*
s
tate
)
{
TestFilterImpl
*
This
=
impl_from_IBaseFilter
(
iface
);
EnterCriticalSection
(
&
This
->
csFilter
);
{
*
pState
=
This
->
state
;
}
LeaveCriticalSection
(
&
This
->
csFilter
);
return
S_OK
;
if
(
winetest_debug
>
1
)
trace
(
"%p->GetState()
\n
"
,
iface
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_SetSyncSource
(
IBaseFilter
*
iface
,
IReferenceClock
*
pC
lock
)
static
HRESULT
WINAPI
testfilter_SetSyncSource
(
IBaseFilter
*
iface
,
IReferenceClock
*
c
lock
)
{
if
(
winetest_debug
>
1
)
trace
(
"%p->SetSyncSource(%p)
\n
"
,
iface
,
clock
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_GetSyncSource
(
IBaseFilter
*
iface
,
IReferenceClock
**
ppC
lock
)
static
HRESULT
WINAPI
testfilter_GetSyncSource
(
IBaseFilter
*
iface
,
IReferenceClock
**
c
lock
)
{
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
/** IBaseFilter implementation **/
static
HRESULT
getpin_callback
(
TestFilterImpl
*
tf
,
ULONG
pos
,
IPin
**
pin
,
DWORD
*
lastsynctick
)
static
HRESULT
WINAPI
testfilter_EnumPins
(
IBaseFilter
*
iface
,
IEnumPins
**
out
)
{
/* Our pins are static, not changing so setting static tick count is ok */
*
lastsynctick
=
0
;
if
(
pos
>=
tf
->
nPins
)
return
S_FALSE
;
struct
testfilter
*
filter
=
impl_from_IBaseFilter
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->EnumPins()
\n
"
,
filter
);
*
pin
=
tf
->
ppPins
[
pos
];
IPin_AddRef
(
*
pin
);
*
out
=
&
filter
->
IEnumPins_iface
;
IEnumPins_AddRef
(
*
out
);
filter
->
enum_idx
=
0
;
return
S_OK
;
}
static
HRESULT
WINAPI
TestFilter_EnumPins
(
IBaseFilter
*
iface
,
IEnumPins
**
ppEnum
)
{
TestFilterImpl
*
This
=
impl_from_IBaseFilter
(
iface
);
return
createenumpins
(
ppEnum
,
getpin_callback
,
This
);
}
static
HRESULT
WINAPI
TestFilter_FindPin
(
IBaseFilter
*
iface
,
LPCWSTR
Id
,
IPin
**
ppPin
)
static
HRESULT
WINAPI
testfilter_FindPin
(
IBaseFilter
*
iface
,
const
WCHAR
*
id
,
IPin
**
pin
)
{
ok
(
0
,
"Unexpected call.
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
TestFilter_QueryFilterInfo
(
IBaseFilter
*
iface
,
FILTER_INFO
*
pI
nfo
)
static
HRESULT
WINAPI
testfilter_QueryFilterInfo
(
IBaseFilter
*
iface
,
FILTER_INFO
*
i
nfo
)
{
TestFilterImpl
*
This
=
impl_from_IBaseFilter
(
iface
);
lstrcpyW
(
pInfo
->
achName
,
This
->
filterInfo
.
achName
);
pInfo
->
pGraph
=
This
->
filterInfo
.
pGraph
;
if
(
pInfo
->
pGraph
)
IFilterGraph_AddRef
(
pInfo
->
pGraph
);
struct
testfilter
*
filter
=
impl_from_IBaseFilter
(
iface
);
if
(
winetest_debug
>
1
)
trace
(
"%p->QueryFilterInfo()
\n
"
,
filter
);
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
;
}
static
HRESULT
WINAPI
TestFilter_JoinFilterGraph
(
IBaseFilter
*
iface
,
IFilterGraph
*
pGraph
,
LPCWSTR
pN
ame
)
static
HRESULT
WINAPI
testfilter_JoinFilterGraph
(
IBaseFilter
*
iface
,
IFilterGraph
*
graph
,
const
WCHAR
*
n
ame
)
{
HRESULT
hr
=
S_OK
;
TestFilterImpl
*
This
=
impl_from_IBaseFilter
(
iface
);
struct
testfilter
*
filter
=
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
)
lstrcpyW
(
This
->
filterInfo
.
achName
,
pName
);
else
*
This
->
filterInfo
.
achName
=
'\0'
;
This
->
filterInfo
.
pGraph
=
pGraph
;
/* NOTE: do NOT increase ref. count */
filter
->
name
=
heap_alloc
((
lstrlenW
(
name
)
+
1
)
*
sizeof
(
WCHAR
));
lstrcpyW
(
filter
->
name
,
name
);
}
LeaveCriticalSection
(
&
This
->
csFilter
);
return
hr
;
else
filter
->
name
=
NULL
;
return
S_OK
;
}
static
HRESULT
WINAPI
TestFilter_QueryVendorInfo
(
IBaseFilter
*
iface
,
LPWSTR
*
pVendorI
nfo
)
static
HRESULT
WINAPI
testfilter_QueryVendorInfo
(
IBaseFilter
*
iface
,
WCHAR
**
i
nfo
)
{
return
E_NOTIMPL
;
}
static
const
IBaseFilterVtbl
TestFilter_V
tbl
=
{
TestF
ilter_QueryInterface
,
TestF
ilter_AddRef
,
TestF
ilter_Release
,
TestF
ilter_GetClassID
,
TestF
ilter_Stop
,
TestF
ilter_Pause
,
TestF
ilter_Run
,
TestF
ilter_GetState
,
TestF
ilter_SetSyncSource
,
TestF
ilter_GetSyncSource
,
TestF
ilter_EnumPins
,
TestF
ilter_FindPin
,
TestF
ilter_QueryFilterInfo
,
TestF
ilter_JoinFilterGraph
,
TestF
ilter_QueryVendorInfo
static
const
IBaseFilterVtbl
testfilter_v
tbl
=
{
testf
ilter_QueryInterface
,
testf
ilter_AddRef
,
testf
ilter_Release
,
testf
ilter_GetClassID
,
testf
ilter_Stop
,
testf
ilter_Pause
,
testf
ilter_Run
,
testf
ilter_GetState
,
testf
ilter_SetSyncSource
,
testf
ilter_GetSyncSource
,
testf
ilter_EnumPins
,
testf
ilter_FindPin
,
testf
ilter_QueryFilterInfo
,
testf
ilter_JoinFilterGraph
,
testf
ilter_QueryVendorInfo
};
/* IClassFactory implementation */
typedef
struct
TestClassFactoryImpl
struct
testfilter_cf
{
IClassFactory
IClassFactory_iface
;
const
TestFilterPinData
*
filterPinData
;
const
CLSID
*
clsid
;
}
TestClassFactoryImpl
;
struct
testfilter
*
filter
;
};
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
(
LPCLASSFACTORY
iface
,
REFIID
riid
,
LPVOID
*
ppvObj
)
static
HRESULT
WINAPI
testfilter_cf_QueryInterface
(
IClassFactory
*
iface
,
REFIID
iid
,
void
**
out
)
{
if
(
ppvObj
==
NULL
)
return
E_POINTER
;
if
(
IsEqualGUID
(
riid
,
&
IID_IUnknown
)
||
IsEqualGUID
(
riid
,
&
IID_IClassFactory
))
if
(
IsEqualGUID
(
iid
,
&
IID_IUnknown
)
||
IsEqualGUID
(
iid
,
&
IID_IClassFactory
))
{
*
ppvObj
=
iface
;
IClassFactory_AddRef
(
iface
);
*
out
=
iface
;
return
S_OK
;
}
*
ppvObj
=
NULL
;
*
out
=
NULL
;
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
(
LPCLASSFACTORY
iface
,
LPUNKNOWN
pUnkOuter
,
REFIID
riid
,
LPVOID
*
ppvObj
)
static
HRESULT
WINAPI
testfilter_cf_CreateInstance
(
IClassFactory
*
iface
,
IUnknown
*
outer
,
REFIID
iid
,
void
**
out
)
{
TestClassFactoryImpl
*
This
=
impl_from_IClassFactory
(
iface
);
HRESULT
hr
;
TestFilterImpl
*
testfilter
;
*
ppvObj
=
NULL
;
if
(
pUnkOuter
)
return
CLASS_E_NOAGGREGATION
;
struct
testfilter_cf
*
factory
=
CONTAINING_RECORD
(
iface
,
struct
testfilter_cf
,
IClassFactory_iface
);
hr
=
createtestfilter
(
This
->
clsid
,
This
->
filterPinData
,
&
testfilter
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
IBaseFilter_QueryInterface
(
&
testfilter
->
IBaseFilter_iface
,
riid
,
ppvObj
);
IBaseFilter_Release
(
&
testfilter
->
IBaseFilter_iface
);
}
return
hr
;
return
IBaseFilter_QueryInterface
(
&
factory
->
filter
->
IBaseFilter_iface
,
iid
,
out
);
}
static
HRESULT
WINAPI
Test_IClassFactory_LockServer
(
LPCLASSFACTORY
iface
,
BOOL
fLock
)
static
HRESULT
WINAPI
testfilter_cf_LockServer
(
IClassFactory
*
iface
,
BOOL
lock
)
{
return
S_OK
;
return
E_NOTIMPL
;
}
static
IClassFactoryVtbl
TestClassFactory_V
tbl
=
static
IClassFactoryVtbl
testfilter_cf_v
tbl
=
{
Test_IClassFactory
_QueryInterface
,
Test_IClassFactory
_AddRef
,
Test_IClassFactory
_Release
,
Test_IClassFactory
_CreateInstance
,
Test_IClassFactory_LockServer
testfilter_cf
_QueryInterface
,
testfilter_cf
_AddRef
,
testfilter_cf
_Release
,
testfilter_cf
_CreateInstance
,
testfilter_cf_LockServer
,
};
static
HRESULT
get_connected_filter_name
(
TestFilterImpl
*
pFilter
,
char
*
FilterName
)
static
void
test_graph_builder_render
(
void
)
{
IPin
*
pin
=
NULL
;
PIN_INFO
pinInfo
;
FILTER_INFO
filterInfo
;
HRESULT
hr
;
FilterName
[
0
]
=
0
;
hr
=
IPin_ConnectedTo
(
pFilter
->
ppPins
[
0
],
&
pin
);
ok
(
hr
==
S_OK
,
"IPin_ConnectedTo failed with %x
\n
"
,
hr
);
static
const
WCHAR
testW
[]
=
{
't'
,
'e'
,
's'
,
't'
,
0
};
static
const
GUID
sink1_clsid
=
{
0x12345678
};
static
const
GUID
sink2_clsid
=
{
0x87654321
};
AM_MEDIA_TYPE
source_type
=
{{
0
}};
struct
testpin
source_pin
,
sink1_pin
,
sink2_pin
,
parser_pins
[
2
];
struct
testfilter
source
,
sink1
,
sink2
,
parser
;
struct
testfilter_cf
sink1_cf
=
{
{
&
testfilter_cf_vtbl
},
&
sink1
};
struct
testfilter_cf
sink2_cf
=
{
{
&
testfilter_cf_vtbl
},
&
sink2
};
hr
=
IPin_QueryPinInfo
(
pin
,
&
pinInfo
);
ok
(
hr
==
S_OK
,
"IPin_QueryPinInfo failed with %x
\n
"
,
hr
);
IPin_Release
(
pin
);
SetLastError
(
0xdeadbeef
);
hr
=
IBaseFilter_QueryFilterInfo
(
pinInfo
.
pFilter
,
&
filterInfo
);
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
;
IFilterGraph2
*
graph
=
create_graph
();
REGFILTERPINS2
regpins
=
{
0
};
REGPINTYPES
regtypes
=
{
0
};
REGFILTER2
regfilter
=
{
0
};
IFilterMapper2
*
mapper
;
DWORD
cookie1
,
cookie2
;
HRESULT
hr
;
IFilterGraph2
*
pgraph2
=
NULL
;
IFilterMapper2
*
pMapper2
=
NULL
;
TestFilterImpl
*
ptestfilter
=
NULL
;
TestFilterImpl
*
ptestfilter2
=
NULL
;
static
const
CLSID
CLSID_TestFilter2
=
{
0x37a4edb0
,
0x4d13
,
0x11dd
,
{
0xe8
,
0x9b
,
0x00
,
0x19
,
0x66
,
0x2f
,
0xf0
,
0xce
}
};
static
const
CLSID
CLSID_TestFilter3
=
{
0x37a4f2d8
,
0x4d13
,
0x11dd
,
{
0xe8
,
0x9b
,
0x00
,
0x19
,
0x66
,
0x2f
,
0xf0
,
0xce
}
};
static
const
CLSID
CLSID_TestFilter4
=
{
0x37a4f3b4
,
0x4d13
,
0x11dd
,
{
0xe8
,
0x9b
,
0x00
,
0x19
,
0x66
,
0x2f
,
0xf0
,
0xce
}
};
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
();
ULONG
ref
;
memset
(
&
source_type
.
majortype
,
0xcc
,
sizeof
(
GUID
));
testsource_init
(
&
source_pin
,
&
source_type
,
1
);
testfilter_init
(
&
source
,
&
source_pin
,
1
);
testsink_init
(
&
sink1_pin
);
testfilter_init
(
&
sink1
,
&
sink1_pin
,
1
);
testsink_init
(
&
sink2_pin
);
testfilter_init
(
&
sink2
,
&
sink2_pin
,
1
);
testsink_init
(
&
parser_pins
[
0
]);
testsource_init
(
&
parser_pins
[
1
],
&
source_type
,
1
);
testfilter_init
(
&
parser
,
parser_pins
,
2
);
IFilterGraph2_AddFilter
(
graph
,
&
source
.
IBaseFilter_iface
,
NULL
);
IFilterGraph2_AddFilter
(
graph
,
&
sink1
.
IBaseFilter_iface
,
NULL
);
IFilterGraph2_AddFilter
(
graph
,
&
sink2
.
IBaseFilter_iface
,
NULL
);
hr
=
IFilterGraph2_Render
(
graph
,
&
source_pin
.
IPin_iface
);
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
source_pin
.
peer
==
&
sink2_pin
.
IPin_iface
,
"Got peer %p.
\n
"
,
source_pin
.
peer
);
IFilterGraph2_Disconnect
(
graph
,
source_pin
.
peer
);
IFilterGraph2_Disconnect
(
graph
,
&
source_pin
.
IPin_iface
);
hr
=
createtestfilter
(
&
GUID_NULL
,
PinData1
,
&
ptestfilter
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
IFilterGraph2_RemoveFilter
(
graph
,
&
sink1
.
IBaseFilter_iface
);
IFilterGraph2_AddFilter
(
graph
,
&
sink1
.
IBaseFilter_iface
,
NULL
);
hr
=
IFilterGraph2_AddFilter
(
pgraph2
,
&
ptestfilter
->
IBaseFilter_iface
,
wszFilterInstanceName1
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
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
,
PinData2
,
&
ptestfilter2
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
IFilterGraph2_Disconnect
(
graph
,
&
source_pin
.
IPin_iface
);
IFilterGraph2_Disconnect
(
graph
,
&
sink1_pin
.
IPin_iface
);
hr
=
IFilterGraph2_AddFilter
(
pgraph2
,
&
ptestfilter2
->
IBaseFilter_iface
,
wszFilterInstanceName2
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
/* No preference is given to smaller chains. */
I
BaseFilter_Release
(
&
ptestfilter2
->
IBaseFilter_iface
);
I
FilterGraph2_AddFilter
(
graph
,
&
parser
.
IBaseFilter_iface
,
NULL
);
hr
=
createtestfilter
(
&
GUID_NULL
,
PinData4
,
&
ptestfilter2
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
hr
=
IFilterGraph2_Render
(
graph
,
&
source_pin
.
IPin_iface
);
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
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
IFilterGraph2_RemoveFilter
(
graph
,
&
sink1
.
IBaseFilter_iface
);
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
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
ref
=
IFilterGraph2_Release
(
graph
);
ok
(
!
ref
,
"Got outstanding refcount %d.
\n
"
,
ref
);
hr
=
IFilterGraph2_AddFilter
(
pgraph2
,
&
ptestfilter2
->
IBaseFilter_iface
,
wszFilterInstanceName4
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
/* Test enumeration of filters from the registry. */
hr
=
IFilterGraph2_Render
(
pgraph2
,
ptestfilter
->
ppPins
[
0
]);
ok
(
hr
==
S_OK
,
"IFilterGraph2_Render failed with %08x
\n
"
,
hr
);
graph
=
create_graph
();
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
);
ok
(
!
strcmp
(
ConnectedFilterName1
,
"TestfilterInstance3"
)
||
!
strcmp
(
ConnectedFilterName1
,
"TestfilterInstance2"
),
"unexpected connected filter: %s
\n
"
,
ConnectedFilterName1
);
regpins
.
dwFlags
=
REG_PINFLAG_B_RENDERER
;
IFilterMapper2_RegisterFilter
(
mapper
,
&
sink2_clsid
,
testW
,
NULL
,
NULL
,
NULL
,
&
regfilter
);
IFilterGraph2_Release
(
pgraph2
);
IBaseFilter_Release
(
&
ptestfilter
->
IBaseFilter_iface
);
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
==
&
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
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
/* Preference is given to filters already in the graph. */
hr
=
IFilterGraph2_AddFilter
(
pgraph2
,
&
ptestfilter
->
IBaseFilter_iface
,
wszFilterInstanceName1
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
graph
=
create_graph
();
IFilterGraph2_AddFilter
(
graph
,
&
source
.
IBaseFilter_iface
,
NULL
);
IFilterGraph2_AddFilter
(
graph
,
&
sink2
.
IBaseFilter_iface
,
NULL
);
hr
=
createtestfilter
(
&
GUID_NULL
,
PinData4
,
&
ptestfilter2
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
hr
=
IFilterGraph2_Render
(
graph
,
&
source_pin
.
IPin_iface
);
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
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
ref
=
IFilterGraph2_Release
(
graph
);
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
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
graph
=
create_graph
(
);
IFilterGraph2_AddFilter
(
graph
,
&
source
.
IBaseFilter_iface
,
NULL
);
hr
=
IFilterGraph2_AddFilter
(
pgraph2
,
&
ptestfilter2
->
IBaseFilter_iface
,
wszFilterInstanceName4
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
IFilterMapper2_UnregisterFilter
(
mapper
,
NULL
,
NULL
,
&
sink1_clsid
);
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
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
hr
=
IFilterGraph2_Render
(
graph
,
&
source_pin
.
IPin_iface
);
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
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
ref
=
IFilterGraph2_Release
(
graph
);
ok
(
!
ref
,
"Got outstanding refcount %d.
\n
"
,
ref
);
hr
=
IFilterGraph2_Render
(
pgraph2
,
ptestfilter
->
ppPins
[
0
]);
ok
(
hr
==
S_OK
,
"IFilterGraph2_Render failed with %08x
\n
"
,
hr
);
/* Preference is given to filters with higher merit. */
get_connected_filter_name
(
ptestfilter
,
ConnectedFilterName2
);
ok
(
!
strcmp
(
ConnectedFilterName2
,
"TestfilterInstance3"
)
||
!
strcmp
(
ConnectedFilterName2
,
"TestfilterInstance2"
),
"unexpected connected filter: %s
\n
"
,
ConnectedFilterName2
);
ok
(
strcmp
(
ConnectedFilterName1
,
ConnectedFilterName2
),
"expected connected filters to be different but got %s both times
\n
"
,
ConnectedFilterName1
);
graph
=
create_graph
();
IFilterGraph2_AddFilter
(
graph
,
&
source
.
IBaseFilter_iface
,
NULL
);
IFilterGraph2_Release
(
pgraph2
);
IBaseFilter_Release
(
&
ptestfilter
->
IBaseFilter_iface
);
IBaseFilter_Release
(
&
ptestfilter2
->
IBaseFilter_iface
);
IFilterMapper2_UnregisterFilter
(
mapper
,
NULL
,
NULL
,
&
sink1_clsid
);
IFilterMapper2_UnregisterFilter
(
mapper
,
NULL
,
NULL
,
&
sink2_clsid
);
/* Test if renderers are tried before non-renderers (intermediary filters). */
pgraph2
=
create_graph
();
regfilter
.
dwMerit
=
MERIT_UNLIKELY
;
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
);
ok
(
hr
==
S_OK
,
"CoCreateInstance failed with %08x
\n
"
,
hr
);
hr
=
IFilterGraph2_Render
(
graph
,
&
source_pin
.
IPin_iface
);
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
);
ok
(
hr
==
S_OK
,
"createtestfilter failed with %08x
\n
"
,
hr
);
ref
=
IFilterGraph2_Release
(
graph
);
ok
(
!
ref
,
"Got outstanding refcount %d.
\n
"
,
ref
);
hr
=
IFilterGraph2_AddFilter
(
pgraph2
,
&
ptestfilter
->
IBaseFilter_iface
,
wszFilterInstanceName1
);
ok
(
hr
==
S_OK
,
"IFilterGraph2_AddFilter failed with %08x
\n
"
,
hr
);
graph
=
create_graph
(
);
IFilterGraph2_AddFilter
(
graph
,
&
source
.
IBaseFilter_iface
,
NULL
);
/* Register our filters with COM and with Filtermapper. */
hr
=
CoRegisterClassObject
(
Filter1ClassFactory
.
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
);
IFilterMapper2_UnregisterFilter
(
mapper
,
NULL
,
NULL
,
&
sink1_clsid
);
IFilterMapper2_UnregisterFilter
(
mapper
,
NULL
,
NULL
,
&
sink2_clsid
);
rgf2
.
dwVersion
=
2
;
rgf2
.
dwMerit
=
MERIT_UNLIKELY
;
S2
(
U
(
rgf2
)).
cPins2
=
1
;
S2
(
U
(
rgf2
)).
rgPins2
=
rgPins2
;
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
;
regfilter
.
dwMerit
=
MERIT_PREFERRED
;
IFilterMapper2_RegisterFilter
(
mapper
,
&
sink1_clsid
,
testW
,
NULL
,
NULL
,
NULL
,
&
regfilter
);
regfilter
.
dwMerit
=
MERIT_UNLIKELY
;
IFilterMapper2_RegisterFilter
(
mapper
,
&
sink2_clsid
,
testW
,
NULL
,
NULL
,
NULL
,
&
regfilter
);
hr
=
IFilterMapper2_RegisterFilter
(
pMapper2
,
&
CLSID_TestFilter2
,
wszFilterInstanceName2
,
NULL
,
&
CLSID_LegacyAmFilterCategory
,
NULL
,
&
rgf2
);
if
(
hr
==
E_ACCESSDENIED
)
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
);
}
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
);
IBaseFilter_Release
(
&
ptestfilter
->
IBaseFilter_iface
);
IFilterGraph2_Release
(
pgraph2
);
IFilterMapper2_Release
(
pMapper2
);
IFilterMapper2_UnregisterFilter
(
mapper
,
NULL
,
NULL
,
&
sink1_clsid
);
IFilterMapper2_UnregisterFilter
(
mapper
,
NULL
,
NULL
,
&
sink2_clsid
);
hr
=
CoRevokeClassObject
(
cookie1
);
ok
(
hr
==
S_OK
,
"CoRevokeClassObject failed with %08x
\n
"
,
hr
);
hr
=
CoRevokeClassObject
(
cookie2
);
ok
(
hr
==
S_OK
,
"CoRevokeClassObject failed with %08x
\n
"
,
hr
);
hr
=
CoRevokeClassObject
(
cookie3
);
ok
(
hr
==
S_OK
,
"CoRevokeClassObject failed with %08x
\n
"
,
hr
);
out:
CoRevokeClassObject
(
cookie1
);
CoRevokeClassObject
(
cookie2
);
IFilterMapper2_Release
(
mapper
);
ref
=
IFilterGraph2_Release
(
graph
);
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
...
...
@@ -2499,7 +1831,7 @@ START_TEST(filtergraph)
test_render_run
(
mpegfile
);
test_enum_filters
();
test_graph_builder
();
test_
render_filter_priority
();
test_
graph_builder_render
();
test_aggregate_filter_graph
();
test_control_delegation
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment