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
44 #include "qcap_main.h"
46 #include "wine/unicode.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(qcap
);
51 /***********************************************************************
52 * ICaptureGraphBuilder & ICaptureGraphBuilder2 implementation
54 typedef struct CaptureGraphImpl
56 ICaptureGraphBuilder2 ICaptureGraphBuilder2_iface
;
57 ICaptureGraphBuilder ICaptureGraphBuilder_iface
;
59 IGraphBuilder
*mygraph
;
60 CRITICAL_SECTION csFilter
;
63 static const ICaptureGraphBuilderVtbl builder_Vtbl
;
64 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl
;
66 static inline CaptureGraphImpl
*impl_from_ICaptureGraphBuilder(ICaptureGraphBuilder
*iface
)
68 return CONTAINING_RECORD(iface
, CaptureGraphImpl
, ICaptureGraphBuilder_iface
);
71 static inline CaptureGraphImpl
*impl_from_ICaptureGraphBuilder2(ICaptureGraphBuilder2
*iface
)
73 return CONTAINING_RECORD(iface
, CaptureGraphImpl
, ICaptureGraphBuilder2_iface
);
77 IUnknown
* CALLBACK
QCAP_createCaptureGraphBuilder2(IUnknown
*pUnkOuter
,
80 CaptureGraphImpl
* pCapture
= NULL
;
82 TRACE("(%p, %p)\n", pUnkOuter
, phr
);
84 *phr
= CLASS_E_NOAGGREGATION
;
91 pCapture
= CoTaskMemAlloc(sizeof(CaptureGraphImpl
));
94 pCapture
->ICaptureGraphBuilder2_iface
.lpVtbl
= &builder2_Vtbl
;
95 pCapture
->ICaptureGraphBuilder_iface
.lpVtbl
= &builder_Vtbl
;
97 pCapture
->mygraph
= NULL
;
98 InitializeCriticalSection(&pCapture
->csFilter
);
99 pCapture
->csFilter
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": CaptureGraphImpl.csFilter");
101 ObjectRefCount(TRUE
);
103 return (IUnknown
*)&pCapture
->ICaptureGraphBuilder_iface
;
106 static HRESULT WINAPI
107 fnCaptureGraphBuilder2_QueryInterface(ICaptureGraphBuilder2
* iface
,
111 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
113 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
116 if (IsEqualIID(riid
, &IID_IUnknown
))
117 *ppv
= &This
->ICaptureGraphBuilder2_iface
;
118 else if (IsEqualIID(riid
, &IID_ICaptureGraphBuilder
))
119 *ppv
= &This
->ICaptureGraphBuilder_iface
;
120 else if (IsEqualIID(riid
, &IID_ICaptureGraphBuilder2
))
121 *ppv
= &This
->ICaptureGraphBuilder2_iface
;
125 IUnknown_AddRef((IUnknown
*)(*ppv
));
126 TRACE ("-- Interface = %p\n", *ppv
);
130 TRACE ("-- Interface: E_NOINTERFACE\n");
131 return E_NOINTERFACE
;
135 fnCaptureGraphBuilder2_AddRef(ICaptureGraphBuilder2
* iface
)
137 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
138 DWORD ref
= InterlockedIncrement(&This
->ref
);
140 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, ref
- 1);
144 static ULONG WINAPI
fnCaptureGraphBuilder2_Release(ICaptureGraphBuilder2
* iface
)
146 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
147 DWORD ref
= InterlockedDecrement(&This
->ref
);
149 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, ref
+ 1);
153 This
->csFilter
.DebugInfo
->Spare
[0] = 0;
154 DeleteCriticalSection(&This
->csFilter
);
156 IGraphBuilder_Release(This
->mygraph
);
158 ObjectRefCount(FALSE
);
163 static HRESULT WINAPI
164 fnCaptureGraphBuilder2_SetFilterGraph(ICaptureGraphBuilder2
* iface
,
167 /* The graph builder will automatically create a filter graph if you don't call
168 this method. If you call this method after the graph builder has created its
169 own filter graph, the call will fail. */
171 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
173 TRACE("(%p/%p)->(%p)\n", This
, iface
, pfg
);
182 IGraphBuilder_AddRef(This
->mygraph
);
183 if (SUCCEEDED(IGraphBuilder_QueryInterface(This
->mygraph
,
184 &IID_IMediaEvent
, (LPVOID
*)&pmev
)))
186 IMediaEvent_CancelDefaultHandling(pmev
, EC_REPAINT
);
187 IMediaEvent_Release(pmev
);
192 static HRESULT WINAPI
193 fnCaptureGraphBuilder2_GetFilterGraph(ICaptureGraphBuilder2
* iface
,
196 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
198 TRACE("(%p/%p)->(%p)\n", This
, iface
, pfg
);
203 *pfg
= This
->mygraph
;
206 TRACE("(%p) Getting NULL filtergraph\n", iface
);
210 IGraphBuilder_AddRef(This
->mygraph
);
212 TRACE("(%p) return filtergraph %p\n", iface
, *pfg
);
216 static HRESULT WINAPI
217 fnCaptureGraphBuilder2_SetOutputFileName(ICaptureGraphBuilder2
* iface
,
221 IFileSinkFilter
**ppSink
)
223 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
225 FIXME("(%p/%p)->(%s, %s, %p, %p) Stub!\n", This
, iface
,
226 debugstr_guid(pType
), debugstr_w(lpstrFile
), ppf
, ppSink
);
231 static HRESULT WINAPI
232 fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2
* iface
,
233 const GUID
*pCategory
,
239 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
241 FIXME("(%p/%p)->(%s, %s, %p, %s, %p) - workaround stub!\n", This
, iface
,
242 debugstr_guid(pCategory
), debugstr_guid(pType
),
243 pf
, debugstr_guid(riid
), ppint
);
245 return IBaseFilter_QueryInterface(pf
, riid
, ppint
);
246 /* Looks for the specified interface on the filter, upstream and
247 * downstream from the filter, and, optionally, only on the output
248 * pin of the given category.
252 static HRESULT WINAPI
253 fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2
* iface
,
254 const GUID
*pCategory
,
257 IBaseFilter
*pfCompressor
,
258 IBaseFilter
*pfRenderer
)
260 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
261 IPin
*source_out
, *renderer_in
, *capture
, *preview
;
264 FIXME("(%p/%p)->(%s, %s, %p, %p, %p) semi-stub!\n", This
, iface
,
265 debugstr_guid(pCategory
), debugstr_guid(pType
),
266 pSource
, pfCompressor
, pfRenderer
);
270 FIXME("Need a capture graph\n");
275 FIXME("pfRenderer == NULL not yet supported\n");
279 hr
= ICaptureGraphBuilder2_FindPin(iface
, pSource
, PINDIR_OUTPUT
, pCategory
, pType
, TRUE
, 0, &source_out
);
283 if (pCategory
&& IsEqualIID(pCategory
, &PIN_CATEGORY_VBI
)) {
284 FIXME("Tee/Sink-to-Sink filter not supported\n");
285 IPin_Release(source_out
);
289 hr
= ICaptureGraphBuilder2_FindPin(iface
, pSource
, PINDIR_OUTPUT
, &PIN_CATEGORY_CAPTURE
, NULL
, TRUE
, 0, &capture
);
291 hr
= ICaptureGraphBuilder2_FindPin(iface
, pSource
, PINDIR_OUTPUT
, &PIN_CATEGORY_PREVIEW
, NULL
, TRUE
, 0, &preview
);
293 FIXME("Smart Tee filter not supported - not creating preview pin\n");
295 IPin_Release(preview
);
296 IPin_Release(capture
);
299 hr
= ICaptureGraphBuilder2_FindPin(iface
, (IUnknown
*)pfRenderer
, PINDIR_INPUT
, NULL
, NULL
, TRUE
, 0, &renderer_in
);
302 IPin_Release(source_out
);
307 hr
= IGraphBuilder_Connect(This
->mygraph
, source_out
, renderer_in
);
310 IPin
*compressor_in
, *compressor_out
;
312 hr
= ICaptureGraphBuilder2_FindPin(iface
, (IUnknown
*)pfCompressor
,
313 PINDIR_INPUT
, NULL
, NULL
, TRUE
, 0, &compressor_in
);
316 hr
= IGraphBuilder_Connect(This
->mygraph
, source_out
, compressor_in
);
317 IPin_Release(compressor_in
);
322 hr
= ICaptureGraphBuilder2_FindPin(iface
, (IUnknown
*)pfCompressor
,
323 PINDIR_OUTPUT
, NULL
, NULL
, TRUE
, 0, &compressor_out
);
326 hr
= IGraphBuilder_Connect(This
->mygraph
, compressor_out
, renderer_in
);
327 IPin_Release(compressor_out
);
332 IPin_Release(source_out
);
333 IPin_Release(renderer_in
);
337 static HRESULT WINAPI
338 fnCaptureGraphBuilder2_ControlStream(ICaptureGraphBuilder2
* iface
,
339 const GUID
*pCategory
,
341 IBaseFilter
*pFilter
,
342 REFERENCE_TIME
*pstart
,
343 REFERENCE_TIME
*pstop
,
347 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
349 FIXME("(%p/%p)->(%s, %s, %p, %p, %p, %i, %i) Stub!\n", This
, iface
,
350 debugstr_guid(pCategory
), debugstr_guid(pType
),
351 pFilter
, pstart
, pstop
, wStartCookie
, wStopCookie
);
356 static HRESULT WINAPI
357 fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2
* iface
,
361 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
363 FIXME("(%p/%p)->(%s, 0x%s) Stub!\n", This
, iface
,
364 debugstr_w(lpwstr
), wine_dbgstr_longlong(dwlSize
));
369 static HRESULT WINAPI
370 fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2
* iface
,
374 IAMCopyCaptureFileProgress
*pCallback
)
376 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
378 FIXME("(%p/%p)->(%s, %s, %i, %p) Stub!\n", This
, iface
,
379 debugstr_w(lpwstrOld
), debugstr_w(lpwstrNew
),
380 fAllowEscAbort
, pCallback
);
385 static HRESULT
pin_matches(IPin
*pin
, PIN_DIRECTION direction
, const GUID
*cat
, const GUID
*type
, BOOL unconnected
)
388 PIN_DIRECTION pindir
;
391 hr
= IPin_QueryDirection(pin
, &pindir
);
393 if (unconnected
&& IPin_ConnectedTo(pin
, &partner
) == S_OK
&& partner
!=NULL
)
395 IPin_Release(partner
);
396 TRACE("No match, %p already connected to %p\n", pin
, partner
);
397 return FAILED(hr
) ? hr
: S_FALSE
;
402 if (SUCCEEDED(hr
) && pindir
!= direction
)
407 IKsPropertySet
*props
;
411 hr
= IPin_QueryInterface(pin
, &IID_IKsPropertySet
, (void**)&props
);
415 hr
= IKsPropertySet_Get(props
, &ROPSETID_Pin
, 0, NULL
,
416 0, &category
, sizeof(category
), &fetched
);
417 IKsPropertySet_Release(props
);
418 if (FAILED(hr
) || !IsEqualIID(&category
, cat
))
424 IEnumMediaTypes
*types
;
425 AM_MEDIA_TYPE
*media_type
;
428 hr
= IPin_EnumMediaTypes(pin
, &types
);
432 IEnumMediaTypes_Reset(types
);
434 if (IEnumMediaTypes_Next(types
, 1, &media_type
, &fetched
) != S_OK
|| fetched
!= 1)
436 IEnumMediaTypes_Release(types
);
440 if (IsEqualIID(&media_type
->majortype
, type
))
442 DeleteMediaType(media_type
);
445 DeleteMediaType(media_type
);
447 IEnumMediaTypes_Release(types
);
450 TRACE("Pin matched\n");
454 static HRESULT WINAPI
455 fnCaptureGraphBuilder2_FindPin(ICaptureGraphBuilder2
* iface
,
457 PIN_DIRECTION pindir
,
458 const GUID
*pCategory
,
465 IEnumPins
*enumpins
= NULL
;
467 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder2(iface
);
469 TRACE("(%p/%p)->(%p, %x, %s, %s, %d, %i, %p)\n", This
, iface
,
470 pSource
, pindir
, debugstr_guid(pCategory
), debugstr_guid(pType
),
471 fUnconnected
, num
, ppPin
);
475 hr
= IUnknown_QueryInterface(pSource
, &IID_IPin
, (void**)&pin
);
476 if (hr
== E_NOINTERFACE
)
478 IBaseFilter
*filter
= NULL
;
481 hr
= IUnknown_QueryInterface(pSource
, &IID_IBaseFilter
, (void**)&filter
);
482 if (hr
== E_NOINTERFACE
)
484 WARN("Input not filter or pin?!\n");
485 return E_NOINTERFACE
;
488 hr
= IBaseFilter_EnumPins(filter
, &enumpins
);
491 WARN("Could not enumerate\n");
499 hr
= IEnumPins_Next(enumpins
, 1, &pin
, &fetched
);
500 if (hr
== VFW_E_ENUM_OUT_OF_SYNC
)
503 IEnumPins_Reset(enumpins
);
515 TRACE("Testing match\n");
516 hr
= pin_matches(pin
, pindir
, pCategory
, pType
, fUnconnected
);
517 if (hr
== S_OK
&& numcurrent
++ == num
)
524 IEnumPins_Release(enumpins
);
528 WARN("Could not find %s pin # %d\n", (pindir
== PINDIR_OUTPUT
? "output" : "input"), numcurrent
);
532 else if (pin_matches(pin
, pindir
, pCategory
, pType
, fUnconnected
) != S_OK
)
542 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl
=
544 fnCaptureGraphBuilder2_QueryInterface
,
545 fnCaptureGraphBuilder2_AddRef
,
546 fnCaptureGraphBuilder2_Release
,
547 fnCaptureGraphBuilder2_SetFilterGraph
,
548 fnCaptureGraphBuilder2_GetFilterGraph
,
549 fnCaptureGraphBuilder2_SetOutputFileName
,
550 fnCaptureGraphBuilder2_FindInterface
,
551 fnCaptureGraphBuilder2_RenderStream
,
552 fnCaptureGraphBuilder2_ControlStream
,
553 fnCaptureGraphBuilder2_AllocCapFile
,
554 fnCaptureGraphBuilder2_CopyCaptureFile
,
555 fnCaptureGraphBuilder2_FindPin
559 static HRESULT WINAPI
560 fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder
* iface
,
561 REFIID riid
, LPVOID
* ppv
)
563 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
564 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
565 return ICaptureGraphBuilder2_QueryInterface(&This
->ICaptureGraphBuilder2_iface
, riid
, ppv
);
569 fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder
* iface
)
571 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
572 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
573 return ICaptureGraphBuilder2_AddRef(&This
->ICaptureGraphBuilder2_iface
);
577 fnCaptureGraphBuilder_Release(ICaptureGraphBuilder
* iface
)
579 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
580 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
581 return ICaptureGraphBuilder2_Release(&This
->ICaptureGraphBuilder2_iface
);
584 static HRESULT WINAPI
585 fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder
* iface
,
588 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
589 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
590 return ICaptureGraphBuilder2_SetFiltergraph(&This
->ICaptureGraphBuilder2_iface
, pfg
);
593 static HRESULT WINAPI
594 fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder
* iface
,
597 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
598 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
599 return ICaptureGraphBuilder2_GetFiltergraph(&This
->ICaptureGraphBuilder2_iface
, pfg
);
602 static HRESULT WINAPI
603 fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder
* iface
,
604 const GUID
*pType
, LPCOLESTR lpstrFile
,
605 IBaseFilter
**ppf
, IFileSinkFilter
**ppSink
)
607 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
608 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
609 return ICaptureGraphBuilder2_SetOutputFileName(&This
->ICaptureGraphBuilder2_iface
, pType
,
610 lpstrFile
, ppf
, ppSink
);
613 static HRESULT WINAPI
614 fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder
* iface
,
615 const GUID
*pCategory
, IBaseFilter
*pf
,
616 REFIID riid
, void **ppint
)
618 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
619 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
620 return ICaptureGraphBuilder2_FindInterface(&This
->ICaptureGraphBuilder2_iface
, pCategory
, NULL
,
624 static HRESULT WINAPI
625 fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder
* iface
,
626 const GUID
*pCategory
, IUnknown
*pSource
,
627 IBaseFilter
*pfCompressor
, IBaseFilter
*pfRenderer
)
629 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
630 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
631 return ICaptureGraphBuilder2_RenderStream(&This
->ICaptureGraphBuilder2_iface
, pCategory
, NULL
,
632 pSource
, pfCompressor
, pfRenderer
);
635 static HRESULT WINAPI
636 fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder
* iface
,
637 const GUID
*pCategory
, IBaseFilter
*pFilter
,
638 REFERENCE_TIME
*pstart
, REFERENCE_TIME
*pstop
,
639 WORD wStartCookie
, WORD wStopCookie
)
641 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
642 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
643 return ICaptureGraphBuilder2_ControlStream(&This
->ICaptureGraphBuilder2_iface
, pCategory
, NULL
,
644 pFilter
, pstart
, pstop
, wStartCookie
, wStopCookie
);
647 static HRESULT WINAPI
648 fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder
* iface
,
649 LPCOLESTR lpstr
, DWORDLONG dwlSize
)
651 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
652 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
653 return ICaptureGraphBuilder2_AllocCapFile(&This
->ICaptureGraphBuilder2_iface
, lpstr
, dwlSize
);
656 static HRESULT WINAPI
657 fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder
* iface
,
658 LPOLESTR lpwstrOld
, LPOLESTR lpwstrNew
,
660 IAMCopyCaptureFileProgress
*pCallback
)
662 CaptureGraphImpl
*This
= impl_from_ICaptureGraphBuilder(iface
);
663 TRACE("%p --> Forwarding to v2 (%p)\n", iface
, This
);
664 return ICaptureGraphBuilder2_CopyCaptureFile(&This
->ICaptureGraphBuilder2_iface
, lpwstrOld
,
665 lpwstrNew
, fAllowEscAbort
, pCallback
);
668 static const ICaptureGraphBuilderVtbl builder_Vtbl
=
670 fnCaptureGraphBuilder_QueryInterface
,
671 fnCaptureGraphBuilder_AddRef
,
672 fnCaptureGraphBuilder_Release
,
673 fnCaptureGraphBuilder_SetFiltergraph
,
674 fnCaptureGraphBuilder_GetFiltergraph
,
675 fnCaptureGraphBuilder_SetOutputFileName
,
676 fnCaptureGraphBuilder_FindInterface
,
677 fnCaptureGraphBuilder_RenderStream
,
678 fnCaptureGraphBuilder_ControlStream
,
679 fnCaptureGraphBuilder_AllocCapFile
,
680 fnCaptureGraphBuilder_CopyCaptureFile