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
982be1de
Commit
982be1de
authored
May 31, 2015
by
Damjan Jovanovic
Committed by
Alexandre Julliard
Jun 02, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
qcap: Add the SmartTee filter automatically as necessary, and test this.
parent
419be239
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
592 additions
and
177 deletions
+592
-177
capturegraph.c
dlls/qcap/capturegraph.c
+131
-14
qcap.c
dlls/qcap/tests/qcap.c
+1
-159
smartteefilter.c
dlls/qcap/tests/smartteefilter.c
+460
-4
No files found.
dlls/qcap/capturegraph.c
View file @
982be1de
...
...
@@ -249,6 +249,118 @@ fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2 * iface,
*/
}
static
HRESULT
match_smart_tee_pin
(
CaptureGraphImpl
*
This
,
const
GUID
*
pCategory
,
const
GUID
*
pType
,
IUnknown
*
pSource
,
IPin
**
source_out
)
{
static
const
WCHAR
inputW
[]
=
{
'I'
,
'n'
,
'p'
,
'u'
,
't'
,
0
};
static
const
WCHAR
captureW
[]
=
{
'C'
,
'a'
,
'p'
,
't'
,
'u'
,
'r'
,
'e'
,
0
};
static
const
WCHAR
previewW
[]
=
{
'P'
,
'r'
,
'e'
,
'v'
,
'i'
,
'e'
,
'w'
,
0
};
IPin
*
capture
=
NULL
;
IPin
*
preview
=
NULL
;
IPin
*
peer
=
NULL
;
IBaseFilter
*
smartTee
=
NULL
;
BOOL
needSmartTee
=
FALSE
;
HRESULT
hr
;
TRACE
(
"(%p, %s, %s, %p, %p)
\n
"
,
This
,
debugstr_guid
(
pCategory
),
debugstr_guid
(
pType
),
pSource
,
source_out
);
hr
=
ICaptureGraphBuilder2_FindPin
(
&
This
->
ICaptureGraphBuilder2_iface
,
pSource
,
PINDIR_OUTPUT
,
&
PIN_CATEGORY_CAPTURE
,
pType
,
FALSE
,
0
,
&
capture
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
ICaptureGraphBuilder2_FindPin
(
&
This
->
ICaptureGraphBuilder2_iface
,
pSource
,
PINDIR_OUTPUT
,
&
PIN_CATEGORY_PREVIEW
,
pType
,
FALSE
,
0
,
&
preview
);
if
(
FAILED
(
hr
))
needSmartTee
=
TRUE
;
}
else
{
hr
=
E_INVALIDARG
;
goto
end
;
}
if
(
!
needSmartTee
)
{
if
(
IsEqualIID
(
pCategory
,
&
PIN_CATEGORY_CAPTURE
))
{
hr
=
IPin_ConnectedTo
(
capture
,
&
peer
);
if
(
hr
==
VFW_E_NOT_CONNECTED
)
{
*
source_out
=
capture
;
IPin_AddRef
(
*
source_out
);
hr
=
S_OK
;
}
else
hr
=
E_INVALIDARG
;
}
else
{
hr
=
IPin_ConnectedTo
(
preview
,
&
peer
);
if
(
hr
==
VFW_E_NOT_CONNECTED
)
{
*
source_out
=
preview
;
IPin_AddRef
(
*
source_out
);
hr
=
S_OK
;
}
else
hr
=
E_INVALIDARG
;
}
goto
end
;
}
hr
=
IPin_ConnectedTo
(
capture
,
&
peer
);
if
(
SUCCEEDED
(
hr
))
{
PIN_INFO
pinInfo
;
GUID
classID
;
hr
=
IPin_QueryPinInfo
(
peer
,
&
pinInfo
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
IBaseFilter_GetClassID
(
pinInfo
.
pFilter
,
&
classID
);
if
(
SUCCEEDED
(
hr
))
{
if
(
IsEqualIID
(
&
classID
,
&
CLSID_SmartTee
))
{
smartTee
=
pinInfo
.
pFilter
;
IBaseFilter_AddRef
(
smartTee
);
}
}
IBaseFilter_Release
(
pinInfo
.
pFilter
);
}
if
(
!
smartTee
)
{
hr
=
E_INVALIDARG
;
goto
end
;
}
}
else
if
(
hr
==
VFW_E_NOT_CONNECTED
)
{
hr
=
CoCreateInstance
(
&
CLSID_SmartTee
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IBaseFilter
,
(
LPVOID
*
)
&
smartTee
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
IGraphBuilder_AddFilter
(
This
->
mygraph
,
smartTee
,
NULL
);
if
(
SUCCEEDED
(
hr
))
{
IPin
*
smartTeeInput
=
NULL
;
hr
=
IBaseFilter_FindPin
(
smartTee
,
inputW
,
&
smartTeeInput
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
IGraphBuilder_ConnectDirect
(
This
->
mygraph
,
capture
,
smartTeeInput
,
NULL
);
IPin_Release
(
smartTeeInput
);
}
}
}
if
(
FAILED
(
hr
))
{
TRACE
(
"adding SmartTee failed with hr=0x%08x
\n
"
,
hr
);
hr
=
E_INVALIDARG
;
goto
end
;
}
}
else
{
hr
=
E_INVALIDARG
;
goto
end
;
}
if
(
IsEqualIID
(
pCategory
,
&
PIN_CATEGORY_CAPTURE
))
hr
=
IBaseFilter_FindPin
(
smartTee
,
captureW
,
source_out
);
else
{
hr
=
IBaseFilter_FindPin
(
smartTee
,
previewW
,
source_out
);
if
(
SUCCEEDED
(
hr
))
hr
=
VFW_S_NOPREVIEWPIN
;
}
end:
if
(
capture
)
IPin_Release
(
capture
);
if
(
preview
)
IPin_Release
(
preview
);
if
(
peer
)
IPin_Release
(
peer
);
if
(
smartTee
)
IBaseFilter_Release
(
smartTee
);
TRACE
(
"for %s returning hr=0x%08x, *source_out=%p
\n
"
,
IsEqualIID
(
pCategory
,
&
PIN_CATEGORY_CAPTURE
)
?
"capture"
:
"preview"
,
hr
,
source_out
?
*
source_out
:
0
);
return
hr
;
}
static
HRESULT
WINAPI
fnCaptureGraphBuilder2_RenderStream
(
ICaptureGraphBuilder2
*
iface
,
const
GUID
*
pCategory
,
...
...
@@ -258,7 +370,8 @@ fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
IBaseFilter
*
pfRenderer
)
{
CaptureGraphImpl
*
This
=
impl_from_ICaptureGraphBuilder2
(
iface
);
IPin
*
source_out
,
*
renderer_in
,
*
capture
,
*
preview
;
IPin
*
source_out
=
NULL
,
*
renderer_in
;
BOOL
usedSmartTeePreviewPin
=
FALSE
;
HRESULT
hr
;
FIXME
(
"(%p/%p)->(%s, %s, %p, %p, %p) semi-stub!
\n
"
,
This
,
iface
,
...
...
@@ -276,24 +389,26 @@ fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
return
E_NOTIMPL
;
}
hr
=
ICaptureGraphBuilder2_FindPin
(
iface
,
pSource
,
PINDIR_OUTPUT
,
pCategory
,
pType
,
TRUE
,
0
,
&
source_out
);
if
(
FAILED
(
hr
))
return
E_INVALIDARG
;
if
(
pCategory
&&
IsEqualIID
(
pCategory
,
&
PIN_CATEGORY_VBI
))
{
FIXME
(
"Tee/Sink-to-Sink filter not supported
\n
"
);
IPin_Release
(
source_out
);
return
E_NOTIMPL
;
}
hr
=
ICaptureGraphBuilder2_FindPin
(
iface
,
pSource
,
PINDIR_OUTPUT
,
&
PIN_CATEGORY_CAPTURE
,
NULL
,
TRUE
,
0
,
&
capture
);
}
else
if
(
pCategory
&&
(
IsEqualIID
(
pCategory
,
&
PIN_CATEGORY_CAPTURE
)
||
IsEqualIID
(
pCategory
,
&
PIN_CATEGORY_PREVIEW
))){
IBaseFilter
*
sourceFilter
=
NULL
;
hr
=
IUnknown_QueryInterface
(
pSource
,
&
IID_IBaseFilter
,
(
void
**
)
&
sourceFilter
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
ICaptureGraphBuilder2_FindPin
(
iface
,
pSource
,
PINDIR_OUTPUT
,
&
PIN_CATEGORY_PREVIEW
,
NULL
,
TRUE
,
0
,
&
preview
);
hr
=
match_smart_tee_pin
(
This
,
pCategory
,
pType
,
pSource
,
&
source_out
);
if
(
hr
==
VFW_S_NOPREVIEWPIN
)
usedSmartTeePreviewPin
=
TRUE
;
IBaseFilter_Release
(
sourceFilter
);
}
else
{
hr
=
ICaptureGraphBuilder2_FindPin
(
iface
,
pSource
,
PINDIR_OUTPUT
,
pCategory
,
pType
,
TRUE
,
0
,
&
source_out
);
}
if
(
FAILED
(
hr
))
FIXME
(
"Smart Tee filter not supported - not creating preview pin
\n
"
);
else
IPin_Release
(
preview
);
IPin_Release
(
capture
);
return
E_INVALIDARG
;
}
else
{
hr
=
ICaptureGraphBuilder2_FindPin
(
iface
,
pSource
,
PINDIR_OUTPUT
,
pCategory
,
pType
,
TRUE
,
0
,
&
source_out
);
if
(
FAILED
(
hr
))
return
E_INVALIDARG
;
}
hr
=
ICaptureGraphBuilder2_FindPin
(
iface
,
(
IUnknown
*
)
pfRenderer
,
PINDIR_INPUT
,
NULL
,
NULL
,
TRUE
,
0
,
&
renderer_in
);
...
...
@@ -331,6 +446,8 @@ fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
IPin_Release
(
source_out
);
IPin_Release
(
renderer_in
);
if
(
SUCCEEDED
(
hr
)
&&
usedSmartTeePreviewPin
)
hr
=
VFW_S_NOPREVIEWPIN
;
return
hr
;
}
...
...
dlls/qcap/tests/qcap.c
View file @
982be1de
...
...
@@ -140,121 +140,7 @@ static const struct {
BOOL
wine_extra
;
BOOL
optional
;
/* fails on wine if missing */
BOOL
broken
;
}
renderstream_cat_media
[]
=
{
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
},
{
PIN_ENUMMEDIATYPES
,
SOURCE_FILTER
},
{
ENUMMEDIATYPES_RESET
,
SOURCE_FILTER
},
{
ENUMMEDIATYPES_NEXT
,
SOURCE_FILTER
},
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
},
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
,
TRUE
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
,
TRUE
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
PIN_ENUMMEDIATYPES
,
SOURCE_FILTER
,
TRUE
,
FALSE
,
TRUE
},
{
ENUMMEDIATYPES_NEXT
,
SOURCE_FILTER
,
TRUE
,
FALSE
,
TRUE
},
{
BASEFILTER_QUERYINTERFACE
,
SINK_FILTER
,
FALSE
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SINK_FILTER
},
{
ENUMPINS_NEXT
,
SINK_FILTER
},
{
PIN_QUERYDIRECTION
,
SINK_FILTER
},
{
PIN_CONNECTEDTO
,
SINK_FILTER
},
{
GRAPHBUILDER_CONNECT
,
NOT_FILTER
},
{
BASEFILTER_GETSTATE
,
SOURCE_FILTER
,
TRUE
,
FALSE
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
END
,
NOT_FILTER
}
},
renderstream_intermediate
[]
=
{
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
},
{
PIN_ENUMMEDIATYPES
,
SOURCE_FILTER
},
{
ENUMMEDIATYPES_RESET
,
SOURCE_FILTER
},
{
ENUMMEDIATYPES_NEXT
,
SOURCE_FILTER
},
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
},
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
,
TRUE
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
BASEFILTER_QUERYINTERFACE
,
SOURCE_FILTER
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
,
TRUE
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
,
TRUE
},
{
PIN_QUERYPININFO
,
SOURCE_FILTER
,
TRUE
},
{
KSPROPERTYSET_GET
,
SOURCE_FILTER
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
TRUE
},
{
PIN_ENUMMEDIATYPES
,
SOURCE_FILTER
,
TRUE
,
FALSE
,
TRUE
},
{
ENUMMEDIATYPES_NEXT
,
SOURCE_FILTER
,
TRUE
,
FALSE
,
TRUE
},
{
BASEFILTER_QUERYINTERFACE
,
SINK_FILTER
,
FALSE
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SINK_FILTER
},
{
ENUMPINS_NEXT
,
SINK_FILTER
},
{
PIN_QUERYDIRECTION
,
SINK_FILTER
},
{
PIN_CONNECTEDTO
,
SINK_FILTER
},
{
BASEFILTER_QUERYINTERFACE
,
INTERMEDIATE_FILTER
,
FALSE
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
INTERMEDIATE_FILTER
},
{
ENUMPINS_NEXT
,
INTERMEDIATE_FILTER
},
{
PIN_QUERYDIRECTION
,
INTERMEDIATE_FILTER
},
{
PIN_CONNECTEDTO
,
INTERMEDIATE_FILTER
},
{
ENUMPINS_NEXT
,
INTERMEDIATE_FILTER
},
{
PIN_QUERYDIRECTION
,
INTERMEDIATE_FILTER
},
{
PIN_CONNECTEDTO
,
INTERMEDIATE_FILTER
},
{
GRAPHBUILDER_CONNECT
,
NOT_FILTER
},
{
BASEFILTER_QUERYINTERFACE
,
INTERMEDIATE_FILTER
,
FALSE
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
INTERMEDIATE_FILTER
},
{
ENUMPINS_NEXT
,
INTERMEDIATE_FILTER
},
{
PIN_QUERYDIRECTION
,
INTERMEDIATE_FILTER
},
{
PIN_CONNECTEDTO
,
INTERMEDIATE_FILTER
},
{
GRAPHBUILDER_CONNECT
,
NOT_FILTER
},
{
BASEFILTER_GETSTATE
,
SOURCE_FILTER
,
TRUE
,
FALSE
,
TRUE
},
{
BASEFILTER_ENUMPINS
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
PIN_QUERYDIRECTION
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
PIN_CONNECTEDTO
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
ENUMPINS_NEXT
,
SOURCE_FILTER
,
FALSE
,
FALSE
,
FALSE
,
TRUE
},
{
END
,
NOT_FILTER
}
},
*
current_calls_list
;
}
*
current_calls_list
;
int
call_no
;
static
void
check_calls_list
(
const
char
*
func
,
call_id
id
,
filter_type
type
)
...
...
@@ -1268,49 +1154,6 @@ static void init_test_filter(test_filter *This, PIN_DIRECTION dir, filter_type t
This
->
filter_type
=
type
;
}
static
void
test_CaptureGraphBuilder_RenderStream
(
void
)
{
test_filter
source_filter
,
sink_filter
,
intermediate_filter
;
ICaptureGraphBuilder2
*
cgb
;
HRESULT
hr
;
init_test_filter
(
&
source_filter
,
PINDIR_OUTPUT
,
SOURCE_FILTER
);
init_test_filter
(
&
sink_filter
,
PINDIR_INPUT
,
SINK_FILTER
);
init_test_filter
(
&
intermediate_filter
,
PINDIR_OUTPUT
,
INTERMEDIATE_FILTER
);
hr
=
CoCreateInstance
(
&
CLSID_CaptureGraphBuilder2
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_ICaptureGraphBuilder2
,
(
void
**
)
&
cgb
);
ok
(
hr
==
S_OK
||
broken
(
hr
==
REGDB_E_CLASSNOTREG
),
"couldn't create CaptureGraphBuilder, hr = %08x
\n
"
,
hr
);
if
(
hr
!=
S_OK
)
{
win_skip
(
"CaptureGraphBuilder is not registered
\n
"
);
return
;
}
hr
=
ICaptureGraphBuilder2_SetFiltergraph
(
cgb
,
&
GraphBuilder
);
ok
(
hr
==
S_OK
,
"SetFiltergraph failed: %08x
\n
"
,
hr
);
trace
(
"RenderStream with category and mediatype test
\n
"
);
current_calls_list
=
renderstream_cat_media
;
call_no
=
0
;
hr
=
ICaptureGraphBuilder2_RenderStream
(
cgb
,
&
PIN_CATEGORY_EDS
,
&
MEDIATYPE_Video
,
(
IUnknown
*
)
&
source_filter
.
IBaseFilter_iface
,
NULL
,
&
sink_filter
.
IBaseFilter_iface
);
ok
(
hr
==
S_OK
,
"RenderStream failed: %08x
\n
"
,
hr
);
check_calls_list
(
"test_CaptureGraphBuilder_RenderStream"
,
END
,
NOT_FILTER
);
trace
(
"RenderStream with intermediate filter
\n
"
);
current_calls_list
=
renderstream_intermediate
;
call_no
=
0
;
hr
=
ICaptureGraphBuilder2_RenderStream
(
cgb
,
&
PIN_CATEGORY_EDS
,
&
MEDIATYPE_Video
,
(
IUnknown
*
)
&
source_filter
.
IBaseFilter_iface
,
&
intermediate_filter
.
IBaseFilter_iface
,
&
sink_filter
.
IBaseFilter_iface
);
ok
(
hr
==
S_OK
,
"RenderStream failed: %08x
\n
"
,
hr
);
check_calls_list
(
"test_CaptureGraphBuilder_RenderStream"
,
END
,
NOT_FILTER
);
ICaptureGraphBuilder2_Release
(
cgb
);
}
static
void
test_AviMux_QueryInterface
(
void
)
{
IUnknown
*
avimux
,
*
unk
;
...
...
@@ -2016,7 +1859,6 @@ START_TEST(qcap)
arg_c
=
winetest_get_mainargs
(
&
arg_v
);
test_CaptureGraphBuilder_RenderStream
();
test_AviMux_QueryInterface
();
test_AviMux
(
arg_c
>
2
?
arg_v
[
2
]
:
NULL
);
test_AviCo
();
...
...
dlls/qcap/tests/smartteefilter.c
View file @
982be1de
...
...
@@ -602,12 +602,14 @@ typedef struct {
IBaseFilter
IBaseFilter_iface
;
LONG
ref
;
IPin
IPin_iface
;
IKsPropertySet
IKsPropertySet_iface
;
CRITICAL_SECTION
cs
;
FILTER_STATE
state
;
IReferenceClock
*
referenceClock
;
FILTER_INFO
filterInfo
;
AM_MEDIA_TYPE
mediaType
;
VIDEOINFOHEADER
videoInfo
;
WAVEFORMATEX
audioInfo
;
IPin
*
connectedTo
;
IMemInputPin
*
memInputPin
;
IMemAllocator
*
allocator
;
...
...
@@ -621,9 +623,17 @@ typedef struct {
SourceFilter
*
filter
;
}
SourceEnumPins
;
typedef
struct
{
IEnumMediaTypes
IEnumMediaTypes_iface
;
LONG
ref
;
ULONG
index
;
SourceFilter
*
filter
;
}
SourceEnumMediaTypes
;
static
const
WCHAR
sourcePinName
[]
=
{
'C'
,
'a'
,
'p'
,
't'
,
'u'
,
'r'
,
'e'
,
0
};
static
SourceEnumPins
*
create_SourceEnumPins
(
SourceFilter
*
filter
);
static
SourceEnumMediaTypes
*
create_SourceEnumMediaTypes
(
SourceFilter
*
filter
);
static
inline
SourceFilter
*
impl_from_SourceFilter_IBaseFilter
(
IBaseFilter
*
iface
)
{
...
...
@@ -635,11 +645,21 @@ static inline SourceFilter* impl_from_SourceFilter_IPin(IPin *iface)
return
CONTAINING_RECORD
(
iface
,
SourceFilter
,
IPin_iface
);
}
static
inline
SourceFilter
*
impl_from_SourceFilter_IKsPropertySet
(
IKsPropertySet
*
iface
)
{
return
CONTAINING_RECORD
(
iface
,
SourceFilter
,
IKsPropertySet_iface
);
}
static
inline
SourceEnumPins
*
impl_from_SourceFilter_IEnumPins
(
IEnumPins
*
iface
)
{
return
CONTAINING_RECORD
(
iface
,
SourceEnumPins
,
IEnumPins_iface
);
}
static
inline
SourceEnumMediaTypes
*
impl_from_SourceFilter_IEnumMediaTypes
(
IEnumMediaTypes
*
iface
)
{
return
CONTAINING_RECORD
(
iface
,
SourceEnumMediaTypes
,
IEnumMediaTypes_iface
);
}
static
HRESULT
WINAPI
SourceFilter_QueryInterface
(
IBaseFilter
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IBaseFilter
(
iface
);
...
...
@@ -979,6 +999,122 @@ static SourceEnumPins* create_SourceEnumPins(SourceFilter *filter)
return
This
;
}
static
HRESULT
WINAPI
SourceEnumMediaTypes_QueryInterface
(
IEnumMediaTypes
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
SourceEnumMediaTypes
*
This
=
impl_from_SourceFilter_IEnumMediaTypes
(
iface
);
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
))
{
*
ppv
=
&
This
->
IEnumMediaTypes_iface
;
}
else
if
(
IsEqualIID
(
riid
,
&
IID_IEnumMediaTypes
))
{
*
ppv
=
&
This
->
IEnumMediaTypes_iface
;
}
else
{
trace
(
"no interface for %s
\n
"
,
wine_dbgstr_guid
(
riid
));
*
ppv
=
NULL
;
return
E_NOINTERFACE
;
}
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
static
ULONG
WINAPI
SourceEnumMediaTypes_AddRef
(
IEnumMediaTypes
*
iface
)
{
SourceEnumMediaTypes
*
This
=
impl_from_SourceFilter_IEnumMediaTypes
(
iface
);
return
InterlockedIncrement
(
&
This
->
ref
);
}
static
ULONG
WINAPI
SourceEnumMediaTypes_Release
(
IEnumMediaTypes
*
iface
)
{
SourceEnumMediaTypes
*
This
=
impl_from_SourceFilter_IEnumMediaTypes
(
iface
);
ULONG
ref
;
ref
=
InterlockedDecrement
(
&
This
->
ref
);
if
(
ref
==
0
)
{
IBaseFilter_Release
(
&
This
->
filter
->
IBaseFilter_iface
);
CoTaskMemFree
(
This
);
}
return
ref
;
}
static
HRESULT
WINAPI
SourceEnumMediaTypes_Next
(
IEnumMediaTypes
*
iface
,
ULONG
cMediaTypes
,
AM_MEDIA_TYPE
**
ppMediaTypes
,
ULONG
*
pcFetched
)
{
SourceEnumMediaTypes
*
This
=
impl_from_SourceFilter_IEnumMediaTypes
(
iface
);
if
(
!
ppMediaTypes
)
return
E_POINTER
;
if
(
cMediaTypes
>
1
&&
!
pcFetched
)
return
E_INVALIDARG
;
if
(
pcFetched
)
*
pcFetched
=
0
;
if
(
cMediaTypes
==
0
)
return
S_OK
;
if
(
This
->
index
==
0
)
{
ppMediaTypes
[
0
]
=
CoTaskMemAlloc
(
sizeof
(
AM_MEDIA_TYPE
));
if
(
ppMediaTypes
[
0
])
{
*
ppMediaTypes
[
0
]
=
This
->
filter
->
mediaType
;
ppMediaTypes
[
0
]
->
pbFormat
=
CoTaskMemAlloc
(
This
->
filter
->
mediaType
.
cbFormat
);
if
(
ppMediaTypes
[
0
]
->
pbFormat
)
{
memcpy
(
ppMediaTypes
[
0
]
->
pbFormat
,
This
->
filter
->
mediaType
.
pbFormat
,
This
->
filter
->
mediaType
.
cbFormat
);
++
This
->
index
;
if
(
pcFetched
)
*
pcFetched
=
1
;
return
S_OK
;
}
CoTaskMemFree
(
ppMediaTypes
[
0
]);
}
return
E_OUTOFMEMORY
;
}
return
S_FALSE
;
}
static
HRESULT
WINAPI
SourceEnumMediaTypes_Skip
(
IEnumMediaTypes
*
iface
,
ULONG
cMediaTypes
)
{
SourceEnumMediaTypes
*
This
=
impl_from_SourceFilter_IEnumMediaTypes
(
iface
);
This
->
index
+=
cMediaTypes
;
if
(
This
->
index
>=
1
)
return
S_FALSE
;
return
S_OK
;
}
static
HRESULT
WINAPI
SourceEnumMediaTypes_Reset
(
IEnumMediaTypes
*
iface
)
{
SourceEnumMediaTypes
*
This
=
impl_from_SourceFilter_IEnumMediaTypes
(
iface
);
This
->
index
=
0
;
return
S_OK
;
}
static
HRESULT
WINAPI
SourceEnumMediaTypes_Clone
(
IEnumMediaTypes
*
iface
,
IEnumMediaTypes
**
ppEnum
)
{
SourceEnumMediaTypes
*
This
=
impl_from_SourceFilter_IEnumMediaTypes
(
iface
);
SourceEnumMediaTypes
*
clone
=
create_SourceEnumMediaTypes
(
This
->
filter
);
if
(
clone
==
NULL
)
return
E_OUTOFMEMORY
;
clone
->
index
=
This
->
index
;
return
S_OK
;
}
static
const
IEnumMediaTypesVtbl
SourceEnumMediaTypesVtbl
=
{
SourceEnumMediaTypes_QueryInterface
,
SourceEnumMediaTypes_AddRef
,
SourceEnumMediaTypes_Release
,
SourceEnumMediaTypes_Next
,
SourceEnumMediaTypes_Skip
,
SourceEnumMediaTypes_Reset
,
SourceEnumMediaTypes_Clone
};
static
SourceEnumMediaTypes
*
create_SourceEnumMediaTypes
(
SourceFilter
*
filter
)
{
SourceEnumMediaTypes
*
This
;
This
=
CoTaskMemAlloc
(
sizeof
(
*
This
));
if
(
This
==
NULL
)
{
return
NULL
;
}
This
->
IEnumMediaTypes_iface
.
lpVtbl
=
&
SourceEnumMediaTypesVtbl
;
This
->
ref
=
1
;
This
->
index
=
0
;
This
->
filter
=
filter
;
IBaseFilter_AddRef
(
&
filter
->
IBaseFilter_iface
);
return
This
;
}
static
HRESULT
WINAPI
SourcePin_QueryInterface
(
IPin
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IPin
(
iface
);
...
...
@@ -986,6 +1122,8 @@ static HRESULT WINAPI SourcePin_QueryInterface(IPin *iface, REFIID riid, void **
*
ppv
=
&
This
->
IPin_iface
;
}
else
if
(
IsEqualIID
(
riid
,
&
IID_IPin
))
{
*
ppv
=
&
This
->
IPin_iface
;
}
else
if
(
IsEqualIID
(
riid
,
&
IID_IKsPropertySet
))
{
*
ppv
=
&
This
->
IKsPropertySet_iface
;
}
else
{
trace
(
"no interface for %s
\n
"
,
wine_dbgstr_guid
(
riid
));
*
ppv
=
NULL
;
...
...
@@ -1011,6 +1149,7 @@ static HRESULT WINAPI SourcePin_Connect(IPin *iface, IPin *pReceivePin, const AM
{
SourceFilter
*
This
=
impl_from_SourceFilter_IPin
(
iface
);
HRESULT
hr
;
if
(
pmt
&&
!
IsEqualGUID
(
&
pmt
->
majortype
,
&
GUID_NULL
)
&&
!
IsEqualGUID
(
&
pmt
->
majortype
,
&
MEDIATYPE_Video
))
return
VFW_E_TYPE_NOT_ACCEPTED
;
if
(
pmt
&&
!
IsEqualGUID
(
&
pmt
->
subtype
,
&
GUID_NULL
)
&&
!
IsEqualGUID
(
&
pmt
->
subtype
,
&
MEDIASUBTYPE_RGB32
))
...
...
@@ -1168,7 +1307,14 @@ static HRESULT WINAPI SourcePin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pm
static
HRESULT
WINAPI
SourcePin_EnumMediaTypes
(
IPin
*
iface
,
IEnumMediaTypes
**
ppEnum
)
{
return
VFW_E_NOT_CONNECTED
;
SourceFilter
*
This
=
impl_from_SourceFilter_IPin
(
iface
);
SourceEnumMediaTypes
*
sourceEnumMediaTypes
=
create_SourceEnumMediaTypes
(
This
);
if
(
sourceEnumMediaTypes
)
{
*
ppEnum
=
&
sourceEnumMediaTypes
->
IEnumMediaTypes_iface
;
return
S_OK
;
}
else
return
E_OUTOFMEMORY
;
}
static
HRESULT
WINAPI
SourcePin_QueryInternalConnections
(
IPin
*
iface
,
IPin
**
apPin
,
ULONG
*
nPin
)
...
...
@@ -1218,6 +1364,75 @@ static const IPinVtbl SourcePinVtbl = {
SourcePin_NewSegment
};
static
HRESULT
WINAPI
SourceKSP_QueryInterface
(
IKsPropertySet
*
iface
,
REFIID
riid
,
LPVOID
*
ppv
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IKsPropertySet
(
iface
);
return
IPin_QueryInterface
(
&
This
->
IPin_iface
,
riid
,
ppv
);
}
static
ULONG
WINAPI
SourceKSP_AddRef
(
IKsPropertySet
*
iface
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IKsPropertySet
(
iface
);
return
IBaseFilter_AddRef
(
&
This
->
IBaseFilter_iface
);
}
static
ULONG
WINAPI
SourceKSP_Release
(
IKsPropertySet
*
iface
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IKsPropertySet
(
iface
);
return
IBaseFilter_Release
(
&
This
->
IBaseFilter_iface
);
}
static
HRESULT
WINAPI
SourceKSP_Set
(
IKsPropertySet
*
iface
,
REFGUID
guidPropSet
,
DWORD
dwPropID
,
LPVOID
pInstanceData
,
DWORD
cbInstanceData
,
LPVOID
pPropData
,
DWORD
cbPropData
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IKsPropertySet
(
iface
);
trace
(
"(%p)->(%s, %u, %p, %u, %p, %u): stub
\n
"
,
This
,
wine_dbgstr_guid
(
guidPropSet
),
dwPropID
,
pInstanceData
,
cbInstanceData
,
pPropData
,
cbPropData
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
SourceKSP_Get
(
IKsPropertySet
*
iface
,
REFGUID
guidPropSet
,
DWORD
dwPropID
,
LPVOID
pInstanceData
,
DWORD
cbInstanceData
,
LPVOID
pPropData
,
DWORD
cbPropData
,
DWORD
*
pcbReturned
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IKsPropertySet
(
iface
);
trace
(
"(%p)->(%s, %u, %p, %u, %p, %u, %p)
\n
"
,
This
,
wine_dbgstr_guid
(
guidPropSet
),
dwPropID
,
pInstanceData
,
cbInstanceData
,
pPropData
,
cbPropData
,
pcbReturned
);
if
(
IsEqualIID
(
guidPropSet
,
&
AMPROPSETID_Pin
))
{
if
(
pcbReturned
)
*
pcbReturned
=
sizeof
(
GUID
);
if
(
pPropData
)
{
LPGUID
guid
=
pPropData
;
if
(
cbPropData
>=
sizeof
(
GUID
))
*
guid
=
PIN_CATEGORY_CAPTURE
;
}
else
{
if
(
!
pcbReturned
)
return
E_POINTER
;
}
return
S_OK
;
}
return
E_PROP_SET_UNSUPPORTED
;
}
static
HRESULT
WINAPI
SourceKSP_QuerySupported
(
IKsPropertySet
*
iface
,
REFGUID
guidPropSet
,
DWORD
dwPropID
,
DWORD
*
pTypeSupport
)
{
SourceFilter
*
This
=
impl_from_SourceFilter_IKsPropertySet
(
iface
);
trace
(
"(%p)->(%s, %u, %p): stub
\n
"
,
This
,
wine_dbgstr_guid
(
guidPropSet
),
dwPropID
,
pTypeSupport
);
return
E_NOTIMPL
;
}
static
const
IKsPropertySetVtbl
SourceKSPVtbl
=
{
SourceKSP_QueryInterface
,
SourceKSP_AddRef
,
SourceKSP_Release
,
SourceKSP_Set
,
SourceKSP_Get
,
SourceKSP_QuerySupported
};
static
SourceFilter
*
create_SourceFilter
(
void
)
{
SourceFilter
*
This
=
NULL
;
...
...
@@ -1227,7 +1442,18 @@ static SourceFilter* create_SourceFilter(void)
This
->
IBaseFilter_iface
.
lpVtbl
=
&
SourceFilterVtbl
;
This
->
ref
=
1
;
This
->
IPin_iface
.
lpVtbl
=
&
SourcePinVtbl
;
This
->
IKsPropertySet_iface
.
lpVtbl
=
&
SourceKSPVtbl
;
InitializeCriticalSection
(
&
This
->
cs
);
return
This
;
}
return
NULL
;
}
static
SourceFilter
*
create_video_SourceFilter
(
void
)
{
SourceFilter
*
This
=
create_SourceFilter
();
if
(
!
This
)
return
NULL
;
This
->
mediaType
.
majortype
=
MEDIATYPE_Video
;
This
->
mediaType
.
subtype
=
MEDIASUBTYPE_RGB32
;
This
->
mediaType
.
bFixedSizeSamples
=
FALSE
;
...
...
@@ -1252,8 +1478,30 @@ static SourceFilter* create_SourceFilter(void)
This
->
videoInfo
.
bmiHeader
.
biClrUsed
=
0
;
This
->
videoInfo
.
bmiHeader
.
biClrImportant
=
0
;
return
This
;
}
}
static
SourceFilter
*
create_audio_SourceFilter
(
void
)
{
SourceFilter
*
This
=
create_SourceFilter
();
if
(
!
This
)
return
NULL
;
This
->
mediaType
.
majortype
=
MEDIATYPE_Audio
;
This
->
mediaType
.
subtype
=
MEDIASUBTYPE_PCM
;
This
->
mediaType
.
bFixedSizeSamples
=
FALSE
;
This
->
mediaType
.
bTemporalCompression
=
FALSE
;
This
->
mediaType
.
lSampleSize
=
0
;
This
->
mediaType
.
formattype
=
FORMAT_WaveFormatEx
;
This
->
mediaType
.
pUnk
=
NULL
;
This
->
mediaType
.
cbFormat
=
sizeof
(
WAVEFORMATEX
);
This
->
mediaType
.
pbFormat
=
(
BYTE
*
)
&
This
->
audioInfo
;
This
->
audioInfo
.
wFormatTag
=
WAVE_FORMAT_PCM
;
This
->
audioInfo
.
nChannels
=
1
;
This
->
audioInfo
.
nSamplesPerSec
=
8000
;
This
->
audioInfo
.
nAvgBytesPerSec
=
16000
;
This
->
audioInfo
.
nBlockAlign
=
2
;
This
->
audioInfo
.
wBitsPerSample
=
16
;
This
->
audioInfo
.
cbSize
=
0
;
return
This
;
}
static
BOOL
has_interface
(
IUnknown
*
unknown
,
REFIID
uuid
)
...
...
@@ -1320,7 +1568,7 @@ static void test_smart_tee_filter_in_graph(IBaseFilter *smartTeeFilter, IPin *in
hr
=
IGraphBuilder_Connect
(
graphBuilder
,
previewPin
,
&
previewSinkFilter
->
IPin_iface
);
ok
(
hr
==
VFW_E_NOT_CONNECTED
,
"connecting Preview pin without first connecting Input pin returned 0x%08x
\n
"
,
hr
);
sourceFilter
=
create_SourceFilter
();
sourceFilter
=
create_
video_
SourceFilter
();
if
(
sourceFilter
==
NULL
)
{
skip
(
"couldn't create source filter
\n
"
);
goto
end
;
...
...
@@ -1556,7 +1804,7 @@ end:
static
void
test_smart_tee_filter_aggregation
(
void
)
{
SourceFilter
*
sourceFilter
=
create_SourceFilter
();
SourceFilter
*
sourceFilter
=
create_
video_
SourceFilter
();
if
(
sourceFilter
)
{
IUnknown
*
unknown
=
NULL
;
HRESULT
hr
=
CoCreateInstance
(
&
CLSID_SmartTee
,
(
IUnknown
*
)
&
sourceFilter
->
IBaseFilter_iface
,
...
...
@@ -1569,6 +1817,207 @@ static void test_smart_tee_filter_aggregation(void)
ok
(
0
,
"out of memory allocating SourceFilter for test
\n
"
);
}
static
HRESULT
get_connected_filter_classid
(
IPin
*
pin
,
GUID
*
guid
)
{
IPin
*
connectedPin
=
NULL
;
PIN_INFO
connectedPinInfo
;
HRESULT
hr
=
IPin_ConnectedTo
(
pin
,
&
connectedPin
);
ok
(
SUCCEEDED
(
hr
),
"IPin_ConnectedTo() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
IPin_QueryPinInfo
(
connectedPin
,
&
connectedPinInfo
);
ok
(
SUCCEEDED
(
hr
),
"IPin_QueryPinInfo() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
if
(
connectedPinInfo
.
pFilter
)
{
hr
=
IBaseFilter_GetClassID
(
connectedPinInfo
.
pFilter
,
guid
);
ok
(
SUCCEEDED
(
hr
),
"IBaseFilter_GetClassID() failed, hr=0x%08x
\n
"
,
hr
);
IBaseFilter_Release
(
connectedPinInfo
.
pFilter
);
}
end:
if
(
connectedPin
)
IPin_Release
(
connectedPin
);
return
hr
;
}
static
void
test_audio_preview
(
ICaptureGraphBuilder2
*
captureGraphBuilder
,
IGraphBuilder
*
graphBuilder
,
SourceFilter
*
audioSource
,
IBaseFilter
*
nullRenderer
)
{
GUID
clsid
;
HRESULT
hr
=
ICaptureGraphBuilder2_RenderStream
(
captureGraphBuilder
,
&
PIN_CATEGORY_PREVIEW
,
&
MEDIATYPE_Audio
,
(
IUnknown
*
)
&
audioSource
->
IBaseFilter_iface
,
NULL
,
nullRenderer
);
ok
(
hr
==
VFW_S_NOPREVIEWPIN
,
"ICaptureGraphBuilder2_RenderStream() returned hr=0x%08x
\n
"
,
hr
);
hr
=
get_connected_filter_classid
(
&
audioSource
->
IPin_iface
,
&
clsid
);
if
(
FAILED
(
hr
))
return
;
ok
(
IsEqualIID
(
&
clsid
,
&
CLSID_SmartTee
),
"unexpected connected filter %s
\n
"
,
wine_dbgstr_guid
(
&
clsid
));
}
static
void
test_audio_capture
(
ICaptureGraphBuilder2
*
captureGraphBuilder
,
IGraphBuilder
*
graphBuilder
,
SourceFilter
*
audioSource
,
IBaseFilter
*
nullRenderer
)
{
GUID
clsid
;
HRESULT
hr
=
ICaptureGraphBuilder2_RenderStream
(
captureGraphBuilder
,
&
PIN_CATEGORY_CAPTURE
,
&
MEDIATYPE_Audio
,
(
IUnknown
*
)
&
audioSource
->
IBaseFilter_iface
,
NULL
,
nullRenderer
);
ok
(
hr
==
S_OK
,
"ICaptureGraphBuilder2_RenderStream() returned hr=0x%08x
\n
"
,
hr
);
hr
=
get_connected_filter_classid
(
&
audioSource
->
IPin_iface
,
&
clsid
);
if
(
FAILED
(
hr
))
return
;
ok
(
IsEqualIID
(
&
clsid
,
&
CLSID_SmartTee
),
"unexpected connected filter %s
\n
"
,
wine_dbgstr_guid
(
&
clsid
));
}
static
void
test_video_preview
(
ICaptureGraphBuilder2
*
captureGraphBuilder
,
IGraphBuilder
*
graphBuilder
,
SourceFilter
*
videoSource
,
IBaseFilter
*
nullRenderer
)
{
GUID
clsid
;
HRESULT
hr
=
ICaptureGraphBuilder2_RenderStream
(
captureGraphBuilder
,
&
PIN_CATEGORY_PREVIEW
,
&
MEDIATYPE_Video
,
(
IUnknown
*
)
&
videoSource
->
IBaseFilter_iface
,
NULL
,
nullRenderer
);
ok
(
hr
==
VFW_S_NOPREVIEWPIN
,
"ICaptureGraphBuilder2_RenderStream() failed, hr=0x%08x
\n
"
,
hr
);
hr
=
get_connected_filter_classid
(
&
videoSource
->
IPin_iface
,
&
clsid
);
if
(
FAILED
(
hr
))
return
;
ok
(
IsEqualIID
(
&
clsid
,
&
CLSID_SmartTee
),
"unexpected connected filter %s
\n
"
,
wine_dbgstr_guid
(
&
clsid
));
}
static
void
test_video_capture
(
ICaptureGraphBuilder2
*
captureGraphBuilder
,
IGraphBuilder
*
graphBuilder
,
SourceFilter
*
videoSource
,
IBaseFilter
*
nullRenderer
)
{
GUID
clsid
;
HRESULT
hr
=
ICaptureGraphBuilder2_RenderStream
(
captureGraphBuilder
,
&
PIN_CATEGORY_CAPTURE
,
&
MEDIATYPE_Video
,
(
IUnknown
*
)
&
videoSource
->
IBaseFilter_iface
,
NULL
,
nullRenderer
);
ok
(
hr
==
S_OK
,
"ICaptureGraphBuilder2_RenderStream() failed, hr=0x%08x
\n
"
,
hr
);
hr
=
get_connected_filter_classid
(
&
videoSource
->
IPin_iface
,
&
clsid
);
if
(
FAILED
(
hr
))
return
;
ok
(
IsEqualIID
(
&
clsid
,
&
CLSID_SmartTee
),
"unexpected connected filter %s
\n
"
,
wine_dbgstr_guid
(
&
clsid
));
}
static
void
test_audio_smart_tee_filter_auto_insertion
(
void
(
*
test_function
)(
ICaptureGraphBuilder2
*
cgb
,
IGraphBuilder
*
gb
,
SourceFilter
*
audioSource
,
IBaseFilter
*
nullRenderer
))
{
HRESULT
hr
;
ICaptureGraphBuilder2
*
captureGraphBuilder
=
NULL
;
IGraphBuilder
*
graphBuilder
=
NULL
;
IBaseFilter
*
nullRenderer
=
NULL
;
SourceFilter
*
audioSource
=
NULL
;
hr
=
CoCreateInstance
(
&
CLSID_CaptureGraphBuilder2
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_ICaptureGraphBuilder2
,
(
void
**
)
&
captureGraphBuilder
);
ok
(
SUCCEEDED
(
hr
),
"couldn't create capture graph builder, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
CoCreateInstance
(
&
CLSID_FilterGraph
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IGraphBuilder
,
(
LPVOID
*
)
&
graphBuilder
);
ok
(
SUCCEEDED
(
hr
),
"couldn't create graph builder, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
ICaptureGraphBuilder2_SetFiltergraph
(
captureGraphBuilder
,
graphBuilder
);
ok
(
SUCCEEDED
(
hr
),
"ICaptureGraphBuilder2_SetFilterGraph() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
CoCreateInstance
(
&
CLSID_NullRenderer
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IBaseFilter
,
(
LPVOID
*
)
&
nullRenderer
);
ok
(
SUCCEEDED
(
hr
)
||
/* Windows 2008: http://stackoverflow.com/questions/29410348/initialize-nullrender-failed-with-error-regdb-e-classnotreg-on-win2008-r2 */
broken
(
hr
==
REGDB_E_CLASSNOTREG
),
"couldn't create NullRenderer, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
IGraphBuilder_AddFilter
(
graphBuilder
,
nullRenderer
,
NULL
);
ok
(
SUCCEEDED
(
hr
),
"IGraphBuilder_AddFilter() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
audioSource
=
create_audio_SourceFilter
();
ok
(
audioSource
!=
NULL
,
"couldn't create audio source
\n
"
);
if
(
audioSource
==
NULL
)
goto
end
;
hr
=
IGraphBuilder_AddFilter
(
graphBuilder
,
&
audioSource
->
IBaseFilter_iface
,
NULL
);
ok
(
SUCCEEDED
(
hr
),
"IGraphBuilder_AddFilter() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
test_function
(
captureGraphBuilder
,
graphBuilder
,
audioSource
,
nullRenderer
);
end:
if
(
nullRenderer
)
IBaseFilter_Release
(
nullRenderer
);
if
(
audioSource
)
IBaseFilter_Release
(
&
audioSource
->
IBaseFilter_iface
);
if
(
captureGraphBuilder
)
ICaptureGraphBuilder2_Release
(
captureGraphBuilder
);
if
(
graphBuilder
)
IGraphBuilder_Release
(
graphBuilder
);
}
static
void
test_video_smart_tee_filter_auto_insertion
(
void
(
*
test_function
)(
ICaptureGraphBuilder2
*
cgb
,
IGraphBuilder
*
gb
,
SourceFilter
*
videoSource
,
IBaseFilter
*
nullRenderer
))
{
HRESULT
hr
;
ICaptureGraphBuilder2
*
captureGraphBuilder
=
NULL
;
IGraphBuilder
*
graphBuilder
=
NULL
;
IBaseFilter
*
nullRenderer
=
NULL
;
SourceFilter
*
videoSource
=
NULL
;
hr
=
CoCreateInstance
(
&
CLSID_CaptureGraphBuilder2
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_ICaptureGraphBuilder2
,
(
void
**
)
&
captureGraphBuilder
);
ok
(
SUCCEEDED
(
hr
),
"couldn't create capture graph builder, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
CoCreateInstance
(
&
CLSID_FilterGraph
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IGraphBuilder
,
(
LPVOID
*
)
&
graphBuilder
);
ok
(
SUCCEEDED
(
hr
),
"couldn't create graph builder, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
ICaptureGraphBuilder2_SetFiltergraph
(
captureGraphBuilder
,
graphBuilder
);
ok
(
SUCCEEDED
(
hr
),
"ICaptureGraphBuilder2_SetFilterGraph() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
CoCreateInstance
(
&
CLSID_NullRenderer
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IBaseFilter
,
(
LPVOID
*
)
&
nullRenderer
);
ok
(
SUCCEEDED
(
hr
)
||
/* Windows 2008: http://stackoverflow.com/questions/29410348/initialize-nullrender-failed-with-error-regdb-e-classnotreg-on-win2008-r2 */
broken
(
hr
==
REGDB_E_CLASSNOTREG
),
"couldn't create NullRenderer, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
hr
=
IGraphBuilder_AddFilter
(
graphBuilder
,
nullRenderer
,
NULL
);
ok
(
SUCCEEDED
(
hr
),
"IGraphBuilder_AddFilter() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
videoSource
=
create_video_SourceFilter
();
ok
(
videoSource
!=
NULL
,
"couldn't create audio source
\n
"
);
if
(
videoSource
==
NULL
)
goto
end
;
hr
=
IGraphBuilder_AddFilter
(
graphBuilder
,
&
videoSource
->
IBaseFilter_iface
,
NULL
);
ok
(
SUCCEEDED
(
hr
),
"IGraphBuilder_AddFilter() failed, hr=0x%08x
\n
"
,
hr
);
if
(
FAILED
(
hr
))
goto
end
;
test_function
(
captureGraphBuilder
,
graphBuilder
,
videoSource
,
nullRenderer
);
end:
if
(
nullRenderer
)
IBaseFilter_Release
(
nullRenderer
);
if
(
videoSource
)
IBaseFilter_Release
(
&
videoSource
->
IBaseFilter_iface
);
if
(
captureGraphBuilder
)
ICaptureGraphBuilder2_Release
(
captureGraphBuilder
);
if
(
graphBuilder
)
IGraphBuilder_Release
(
graphBuilder
);
}
START_TEST
(
smartteefilter
)
{
if
(
SUCCEEDED
(
CoInitialize
(
NULL
)))
...
...
@@ -1577,6 +2026,13 @@ START_TEST(smartteefilter)
if
(
event
)
{
test_smart_tee_filter_aggregation
();
test_smart_tee_filter
();
test_audio_smart_tee_filter_auto_insertion
(
test_audio_preview
);
test_audio_smart_tee_filter_auto_insertion
(
test_audio_capture
);
test_video_smart_tee_filter_auto_insertion
(
test_video_preview
);
test_video_smart_tee_filter_auto_insertion
(
test_video_capture
);
CloseHandle
(
event
);
}
else
skip
(
"CreateEvent failed, error=%u
\n
"
,
GetLastError
());
...
...
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