1 /* Capture Graph Builder, Minimal edition
3 * Copyright 2005 Maarten Lankhorst
4 * Copyright 2005 Rolf Kalbermatter
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
46 #include "qcap_main.h"
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(qcap
);
53 /***********************************************************************
54 * ICaptureGraphBuilder & ICaptureGraphBuilder2 implementation
56 typedef struct CaptureGraphImpl
58 ICaptureGraphBuilder2 ICaptureGraphBuilder2_iface
;
59 ICaptureGraphBuilder ICaptureGraphBuilder_iface
;
61 IGraphBuilder
*mygraph
;
62 CRITICAL_SECTION csFilter
;
65 static const ICaptureGraphBuilderVtbl builder_Vtbl
;
66 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl
;
68 static inline CaptureGraphImpl
*impl_from_ICaptureGraphBuilder(ICaptureGraphBuilder
*iface
)
70 return CONTAINING_RECORD(iface
, CaptureGraphImpl
, ICaptureGraphBuilder_iface
);
73 static inline CaptureGraphImpl
*impl_from_ICaptureGraphBuilder2(ICaptureGraphBuilder2
*iface
)
75 return CONTAINING_RECORD(iface
, CaptureGraphImpl
, ICaptureGraphBuilder2_iface
);
79 IUnknown
* CALLBACK
QCAP_createCaptureGraphBuilder2(IUnknown
*pUnkOuter
,
82 CaptureGraphImpl
* pCapture
= NULL
;
84 TRACE("(%p, %p)\n", pUnkOuter
, phr
);
86 *phr
= CLASS_E_NOAGGREGATION
;
93 pCapture
= CoTaskMemAlloc(sizeof(CaptureGraphImpl
));
96 pCapture
->ICaptureGraphBuilder2_iface
.lpVtbl
= &builder2_Vtbl
;
97 pCapture
->ICaptureGraphBuilder_iface
.lpVtbl
= &builder_Vtbl
;
99 pCapture
->mygraph
= NULL
;
100 InitializeCriticalSection(&pCapture
->csFilter
);
101 pCapture
->csFilter
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": CaptureGraphImpl.csFilter");
103 ObjectRefCount(TRUE
);
105 return (IUnknown
*)&pCapture
->ICaptureGraphBuilder_iface
;
108 static HRESULT WINAPI
109 fnCaptureGraphBuilder2_QueryInterface(ICaptureGraphBuilder2
* iface
,
113 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
115 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
118 if (IsEqualIID(riid
, &IID_IUnknown
))
119 *ppv
= &This
->ICaptureGraphBuilder2_iface
;
120 else if (IsEqualIID(riid
, &IID_ICaptureGraphBuilder
))
121 *ppv
= &This
->ICaptureGraphBuilder_iface
;
122 else if (IsEqualIID(riid
, &IID_ICaptureGraphBuilder2
))
123 *ppv
= &This
->ICaptureGraphBuilder2_iface
;
127 IUnknown_AddRef((IUnknown
*)(*ppv
));
128 TRACE ("-- Interface = %p\n", *ppv
);
132 TRACE ("-- Interface: E_NOINTERFACE\n");
133 return E_NOINTERFACE
;
137 fnCaptureGraphBuilder2_AddRef(ICaptureGraphBuilder2
* iface
)
139 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
140 DWORD ref
= InterlockedIncrement(&This
->ref
);
142 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, ref
- 1);
146 static ULONG WINAPI
fnCaptureGraphBuilder2_Release(ICaptureGraphBuilder2
* iface
)
148 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
149 DWORD ref
= InterlockedDecrement(&This
->ref
);
151 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, ref
+ 1);
155 This
->csFilter
.DebugInfo
->Spare
[0] = 0;
156 DeleteCriticalSection(&This
->csFilter
);
158 IGraphBuilder_Release(This
->mygraph
);
160 ObjectRefCount(FALSE
);
165 static HRESULT WINAPI
166 fnCaptureGraphBuilder2_SetFilterGraph(ICaptureGraphBuilder2
* iface
,
169 /* The graph builder will automatically create a filter graph if you don't call
170 this method. If you call this method after the graph builder has created its
171 own filter graph, the call will fail. */
173 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
175 TRACE("(%p/%p)->(%p)\n", This
, iface
, pfg
);
184 IGraphBuilder_AddRef(This
->mygraph
);
185 if (SUCCEEDED(IGraphBuilder_QueryInterface(This
->mygraph
,
186 &IID_IMediaEvent
, (LPVOID
*)&pmev
)))
188 IMediaEvent_CancelDefaultHandling(pmev
, EC_REPAINT
);
189 IMediaEvent_Release(pmev
);
194 static HRESULT WINAPI
195 fnCaptureGraphBuilder2_GetFilterGraph(ICaptureGraphBuilder2
* iface
,
198 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
200 TRACE("(%p/%p)->(%p)\n", This
, iface
, pfg
);
205 *pfg
= This
->mygraph
;
208 TRACE("(%p) Getting NULL filtergraph\n", iface
);
212 IGraphBuilder_AddRef(This
->mygraph
);
214 TRACE("(%p) return filtergraph %p\n", iface
, *pfg
);
218 static HRESULT WINAPI
219 fnCaptureGraphBuilder2_SetOutputFileName(ICaptureGraphBuilder2
* iface
,
223 IFileSinkFilter
**ppSink
)
225 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
227 FIXME("(%p/%p)->(%s, %s, %p, %p) Stub!\n", This
, iface
,
228 debugstr_guid(pType
), debugstr_w(lpstrFile
), ppf
, ppSink
);
233 static HRESULT WINAPI
234 fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2
* iface
,
235 const GUID
*pCategory
,
241 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
243 FIXME("(%p/%p)->(%s, %s, %p, %s, %p) - workaround stub!\n", This
, iface
,
244 debugstr_guid(pCategory
), debugstr_guid(pType
),
245 pf
, debugstr_guid(riid
), ppint
);
247 return IBaseFilter_QueryInterface(pf
, riid
, ppint
);
248 /* Looks for the specified interface on the filter, upstream and
249 * downstream from the filter, and, optionally, only on the output
250 * pin of the given category.
254 static HRESULT WINAPI
255 fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2
* iface
,
256 const GUID
*pCategory
,
259 IBaseFilter
*pfCompressor
,
260 IBaseFilter
*pfRenderer
)
262 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
263 IPin
*source_out
, *renderer_in
, *capture
, *preview
;
266 FIXME("(%p/%p)->(%s, %s, %p, %p, %p) semi-stub!\n", This
, iface
,
267 debugstr_guid(pCategory
), debugstr_guid(pType
),
268 pSource
, pfCompressor
, pfRenderer
);
272 FIXME("Need a capture graph\n");
277 FIXME("pfRenderer == NULL not yet supported\n");
281 hr
= ICaptureGraphBuilder2_FindPin(iface
, pSource
, PINDIR_OUTPUT
, pCategory
, pType
, TRUE
, 0, &source_out
);
285 if (pCategory
&& IsEqualIID(pCategory
, &PIN_CATEGORY_VBI
)) {
286 FIXME("Tee/Sink-to-Sink filter not supported\n");
287 IPin_Release(source_out
);
291 hr
= ICaptureGraphBuilder2_FindPin(iface
, pSource
, PINDIR_OUTPUT
, &PIN_CATEGORY_CAPTURE
, NULL
, TRUE
, 0, &capture
);
293 hr
= ICaptureGraphBuilder2_FindPin(iface
, pSource
, PINDIR_OUTPUT
, &PIN_CATEGORY_PREVIEW
, NULL
, TRUE
, 0, &preview
);
295 FIXME("Smart Tee filter not supported - not creating preview pin\n");
297 IPin_Release(preview
);
298 IPin_Release(capture
);
301 hr
= ICaptureGraphBuilder2_FindPin(iface
, (IUnknown
*)pfRenderer
, PINDIR_INPUT
, NULL
, NULL
, TRUE
, 0, &renderer_in
);
304 IPin_Release(source_out
);
309 hr
= IGraphBuilder_Connect(This
->mygraph
, source_out
, renderer_in
);
312 IPin
*compressor_in
, *compressor_out
;
314 hr
= ICaptureGraphBuilder2_FindPin(iface
, (IUnknown
*)pfCompressor
,
315 PINDIR_INPUT
, NULL
, NULL
, TRUE
, 0, &compressor_in
);
318 hr
= IGraphBuilder_Connect(This
->mygraph
, source_out
, compressor_in
);
319 IPin_Release(compressor_in
);
324 hr
= ICaptureGraphBuilder2_FindPin(iface
, (IUnknown
*)pfCompressor
,
325 PINDIR_OUTPUT
, NULL
, NULL
, TRUE
, 0, &compressor_out
);
328 hr
= IGraphBuilder_Connect(This
->mygraph
, compressor_out
, renderer_in
);
329 IPin_Release(compressor_out
);
334 IPin_Release(source_out
);
335 IPin_Release(renderer_in
);
339 static HRESULT WINAPI
340 fnCaptureGraphBuilder2_ControlStream(ICaptureGraphBuilder2
* iface
,
341 const GUID
*pCategory
,
343 IBaseFilter
*pFilter
,
344 REFERENCE_TIME
*pstart
,
345 REFERENCE_TIME
*pstop
,
349 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
351 FIXME("(%p/%p)->(%s, %s, %p, %p, %p, %i, %i) Stub!\n", This
, iface
,
352 debugstr_guid(pCategory
), debugstr_guid(pType
),
353 pFilter
, pstart
, pstop
, wStartCookie
, wStopCookie
);
358 static HRESULT WINAPI
359 fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2
* iface
,
363 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
365 FIXME("(%p/%p)->(%s, 0x%s) Stub!\n", This
, iface
,
366 debugstr_w(lpwstr
), wine_dbgstr_longlong(dwlSize
));
371 static HRESULT WINAPI
372 fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2
* iface
,
376 IAMCopyCaptureFileProgress
*pCallback
)
378 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
380 FIXME("(%p/%p)->(%s, %s, %i, %p) Stub!\n", This
, iface
,
381 debugstr_w(lpwstrOld
), debugstr_w(lpwstrNew
),
382 fAllowEscAbort
, pCallback
);
387 static HRESULT
pin_matches(IPin
*pin
, PIN_DIRECTION direction
, const GUID
*cat
, const GUID
*type
, BOOL unconnected
)
390 PIN_DIRECTION pindir
;
393 hr
= IPin_QueryDirection(pin
, &pindir
);
395 if (unconnected
&& IPin_ConnectedTo(pin
, &partner
) == S_OK
&& partner
!=NULL
)
397 IPin_Release(partner
);
398 TRACE("No match, %p already connected to %p\n", pin
, partner
);
399 return FAILED(hr
) ? hr
: S_FALSE
;
404 if (SUCCEEDED(hr
) && pindir
!= direction
)
409 IKsPropertySet
*props
;
413 hr
= IPin_QueryInterface(pin
, &IID_IKsPropertySet
, (void**)&props
);
417 hr
= IKsPropertySet_Get(props
, &ROPSETID_Pin
, 0, NULL
,
418 0, &category
, sizeof(category
), &fetched
);
419 IKsPropertySet_Release(props
);
420 if (FAILED(hr
) || !IsEqualIID(&category
, cat
))
426 IEnumMediaTypes
*types
;
427 AM_MEDIA_TYPE
*media_type
;
430 hr
= IPin_EnumMediaTypes(pin
, &types
);
434 IEnumMediaTypes_Reset(types
);
436 if (IEnumMediaTypes_Next(types
, 1, &media_type
, &fetched
) != S_OK
|| fetched
!= 1)
438 IEnumMediaTypes_Release(types
);
442 if (IsEqualIID(&media_type
->majortype
, type
))
444 DeleteMediaType(media_type
);
447 DeleteMediaType(media_type
);
449 IEnumMediaTypes_Release(types
);
452 TRACE("Pin matched\n");
456 static HRESULT WINAPI
457 fnCaptureGraphBuilder2_FindPin(ICaptureGraphBuilder2
* iface
,
459 PIN_DIRECTION pindir
,
460 const GUID
*pCategory
,
467 IEnumPins
*enumpins
= NULL
;
469 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
471 TRACE("(%p/%p)->(%p, %x, %s, %s, %d, %i, %p)\n", This
, iface
,
472 pSource
, pindir
, debugstr_guid(pCategory
), debugstr_guid(pType
),
473 fUnconnected
, num
, ppPin
);
477 hr
= IUnknown_QueryInterface(pSource
, &IID_IPin
, (void**)&pin
);
478 if (hr
== E_NOINTERFACE
)
480 IBaseFilter
*filter
= NULL
;
483 hr
= IUnknown_QueryInterface(pSource
, &IID_IBaseFilter
, (void**)&filter
);
484 if (hr
== E_NOINTERFACE
)
486 WARN("Input not filter or pin?!\n");
487 return E_NOINTERFACE
;
490 hr
= IBaseFilter_EnumPins(filter
, &enumpins
);
493 WARN("Could not enumerate\n");
501 hr
= IEnumPins_Next(enumpins
, 1, &pin
, &fetched
);
502 if (hr
== VFW_E_ENUM_OUT_OF_SYNC
)
505 IEnumPins_Reset(enumpins
);
517 TRACE("Testing match\n");
518 hr
= pin_matches(pin
, pindir
, pCategory
, pType
, fUnconnected
);
519 if (hr
== S_OK
&& numcurrent
++ == num
)
526 IEnumPins_Release(enumpins
);
530 WARN("Could not find %s pin # %d\n", (pindir
== PINDIR_OUTPUT
? "output" : "input"), numcurrent
);
534 else if (pin_matches(pin
, pindir
, pCategory
, pType
, fUnconnected
) != S_OK
)
544 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl
=
546 fnCaptureGraphBuilder2_QueryInterface
,
547 fnCaptureGraphBuilder2_AddRef
,
548 fnCaptureGraphBuilder2_Release
,
549 fnCaptureGraphBuilder2_SetFilterGraph
,
550 fnCaptureGraphBuilder2_GetFilterGraph
,
551 fnCaptureGraphBuilder2_SetOutputFileName
,
552 fnCaptureGraphBuilder2_FindInterface
,
553 fnCaptureGraphBuilder2_RenderStream
,
554 fnCaptureGraphBuilder2_ControlStream
,
555 fnCaptureGraphBuilder2_AllocCapFile
,
556 fnCaptureGraphBuilder2_CopyCaptureFile
,
557 fnCaptureGraphBuilder2_FindPin
561 static HRESULT WINAPI
562 fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder
* iface
,
563 REFIID riid
, LPVOID
* ppv
)
565 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
566 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
567 return ICaptureGraphBuilder2_QueryInterface(&This
->ICaptureGraphBuilder2_iface
, riid
, ppv
);
571 fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder
* iface
)
573 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
574 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
575 return ICaptureGraphBuilder2_AddRef(&This
->ICaptureGraphBuilder2_iface
);
579 fnCaptureGraphBuilder_Release(ICaptureGraphBuilder
* iface
)
581 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
582 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
583 return ICaptureGraphBuilder2_Release(&This
->ICaptureGraphBuilder2_iface
);
586 static HRESULT WINAPI
587 fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder
* iface
,
590 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
591 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
592 return ICaptureGraphBuilder2_SetFiltergraph(&This
->ICaptureGraphBuilder2_iface
, pfg
);
595 static HRESULT WINAPI
596 fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder
* iface
,
599 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
600 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
601 return ICaptureGraphBuilder2_GetFiltergraph(&This
->ICaptureGraphBuilder2_iface
, pfg
);
604 static HRESULT WINAPI
605 fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder
* iface
,
606 const GUID
*pType
, LPCOLESTR lpstrFile
,
607 IBaseFilter
**ppf
, IFileSinkFilter
**ppSink
)
609 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
610 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
611 return ICaptureGraphBuilder2_SetOutputFileName(&This
->ICaptureGraphBuilder2_iface
, pType
,
612 lpstrFile
, ppf
, ppSink
);
615 static HRESULT WINAPI
616 fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder
* iface
,
617 const GUID
*pCategory
, IBaseFilter
*pf
,
618 REFIID riid
, void **ppint
)
620 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
621 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
622 return ICaptureGraphBuilder2_FindInterface(&This
->ICaptureGraphBuilder2_iface
, pCategory
, NULL
,
626 static HRESULT WINAPI
627 fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder
* iface
,
628 const GUID
*pCategory
, IUnknown
*pSource
,
629 IBaseFilter
*pfCompressor
, IBaseFilter
*pfRenderer
)
631 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
632 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
633 return ICaptureGraphBuilder2_RenderStream(&This
->ICaptureGraphBuilder2_iface
, pCategory
, NULL
,
634 pSource
, pfCompressor
, pfRenderer
);
637 static HRESULT WINAPI
638 fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder
* iface
,
639 const GUID
*pCategory
, IBaseFilter
*pFilter
,
640 REFERENCE_TIME
*pstart
, REFERENCE_TIME
*pstop
,
641 WORD wStartCookie
, WORD wStopCookie
)
643 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
644 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
645 return ICaptureGraphBuilder2_ControlStream(&This
->ICaptureGraphBuilder2_iface
, pCategory
, NULL
,
646 pFilter
, pstart
, pstop
, wStartCookie
, wStopCookie
);
649 static HRESULT WINAPI
650 fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder
* iface
,
651 LPCOLESTR lpstr
, DWORDLONG dwlSize
)
653 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
654 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
655 return ICaptureGraphBuilder2_AllocCapFile(&This
->ICaptureGraphBuilder2_iface
, lpstr
, dwlSize
);
658 static HRESULT WINAPI
659 fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder
* iface
,
660 LPOLESTR lpwstrOld
, LPOLESTR lpwstrNew
,
662 IAMCopyCaptureFileProgress
*pCallback
)
664 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
665 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
666 return ICaptureGraphBuilder2_CopyCaptureFile(&This
->ICaptureGraphBuilder2_iface
, lpwstrOld
,
667 lpwstrNew
, fAllowEscAbort
, pCallback
);
670 static const ICaptureGraphBuilderVtbl builder_Vtbl
=
672 fnCaptureGraphBuilder_QueryInterface
,
673 fnCaptureGraphBuilder_AddRef
,
674 fnCaptureGraphBuilder_Release
,
675 fnCaptureGraphBuilder_SetFiltergraph
,
676 fnCaptureGraphBuilder_GetFiltergraph
,
677 fnCaptureGraphBuilder_SetOutputFileName
,
678 fnCaptureGraphBuilder_FindInterface
,
679 fnCaptureGraphBuilder_RenderStream
,
680 fnCaptureGraphBuilder_ControlStream
,
681 fnCaptureGraphBuilder_AllocCapFile
,
682 fnCaptureGraphBuilder_CopyCaptureFile