schedsvc: Fix xml buffer leak (Valgrind).
[wine.git] / dlls / qcap / capturegraph.c
blobbae75f8372585b979d32dec6574606a87b6c8a79
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
20 #include "config.h"
22 #include <stdio.h>
23 #include <stdarg.h>
25 #define COBJMACROS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winerror.h"
31 #include "objbase.h"
33 #include "evcode.h"
34 #include "strmif.h"
35 #include "control.h"
36 #include "vfwmsgs.h"
38 *#include "amvideo.h"
39 *#include "mmreg.h"
40 *#include "dshow.h"
41 *#include "ddraw.h"
43 #include "uuids.h"
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;
58 LONG ref;
59 IGraphBuilder *mygraph;
60 CRITICAL_SECTION csFilter;
61 } CaptureGraphImpl;
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,
78 HRESULT *phr)
80 CaptureGraphImpl * pCapture = NULL;
82 TRACE("(%p, %p)\n", pUnkOuter, phr);
84 *phr = CLASS_E_NOAGGREGATION;
85 if (pUnkOuter)
87 return NULL;
89 *phr = E_OUTOFMEMORY;
91 pCapture = CoTaskMemAlloc(sizeof(CaptureGraphImpl));
92 if (pCapture)
94 pCapture->ICaptureGraphBuilder2_iface.lpVtbl = &builder2_Vtbl;
95 pCapture->ICaptureGraphBuilder_iface.lpVtbl = &builder_Vtbl;
96 pCapture->ref = 1;
97 pCapture->mygraph = NULL;
98 InitializeCriticalSection(&pCapture->csFilter);
99 pCapture->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CaptureGraphImpl.csFilter");
100 *phr = S_OK;
101 ObjectRefCount(TRUE);
103 return (IUnknown *)&pCapture->ICaptureGraphBuilder_iface;
106 static HRESULT WINAPI
107 fnCaptureGraphBuilder2_QueryInterface(ICaptureGraphBuilder2 * iface,
108 REFIID riid,
109 LPVOID * ppv)
111 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
113 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
115 *ppv = NULL;
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;
123 if (*ppv)
125 IUnknown_AddRef((IUnknown *)(*ppv));
126 TRACE ("-- Interface = %p\n", *ppv);
127 return S_OK;
130 TRACE ("-- Interface: E_NOINTERFACE\n");
131 return E_NOINTERFACE;
134 static ULONG WINAPI
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);
141 return ref;
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);
151 if (!ref)
153 This->csFilter.DebugInfo->Spare[0] = 0;
154 DeleteCriticalSection(&This->csFilter);
155 if (This->mygraph)
156 IGraphBuilder_Release(This->mygraph);
157 CoTaskMemFree(This);
158 ObjectRefCount(FALSE);
160 return ref;
163 static HRESULT WINAPI
164 fnCaptureGraphBuilder2_SetFilterGraph(ICaptureGraphBuilder2 * iface,
165 IGraphBuilder *pfg)
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. */
170 IMediaEvent *pmev;
171 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
173 TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
175 if (This->mygraph)
176 return E_UNEXPECTED;
178 if (!pfg)
179 return E_POINTER;
181 This->mygraph = 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);
189 return S_OK;
192 static HRESULT WINAPI
193 fnCaptureGraphBuilder2_GetFilterGraph(ICaptureGraphBuilder2 * iface,
194 IGraphBuilder **pfg)
196 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
198 TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
200 if (!pfg)
201 return E_POINTER;
203 *pfg = This->mygraph;
204 if (!This->mygraph)
206 TRACE("(%p) Getting NULL filtergraph\n", iface);
207 return E_UNEXPECTED;
210 IGraphBuilder_AddRef(This->mygraph);
212 TRACE("(%p) return filtergraph %p\n", iface, *pfg);
213 return S_OK;
216 static HRESULT WINAPI
217 fnCaptureGraphBuilder2_SetOutputFileName(ICaptureGraphBuilder2 * iface,
218 const GUID *pType,
219 LPCOLESTR lpstrFile,
220 IBaseFilter **ppf,
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);
228 return E_NOTIMPL;
231 static HRESULT WINAPI
232 fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2 * iface,
233 const GUID *pCategory,
234 const GUID *pType,
235 IBaseFilter *pf,
236 REFIID riid,
237 void **ppint)
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 match_smart_tee_pin(CaptureGraphImpl *This,
253 const GUID *pCategory,
254 const GUID *pType,
255 IUnknown *pSource,
256 IPin **source_out)
258 static const WCHAR inputW[] = {'I','n','p','u','t',0};
259 static const WCHAR captureW[] = {'C','a','p','t','u','r','e',0};
260 static const WCHAR previewW[] = {'P','r','e','v','i','e','w',0};
261 IPin *capture = NULL;
262 IPin *preview = NULL;
263 IPin *peer = NULL;
264 IBaseFilter *smartTee = NULL;
265 BOOL needSmartTee = FALSE;
266 HRESULT hr;
268 TRACE("(%p, %s, %s, %p, %p)\n", This, debugstr_guid(pCategory), debugstr_guid(pType), pSource, source_out);
269 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
270 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, pType, FALSE, 0, &capture);
271 if (SUCCEEDED(hr)) {
272 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
273 PINDIR_OUTPUT, &PIN_CATEGORY_PREVIEW, pType, FALSE, 0, &preview);
274 if (FAILED(hr))
275 needSmartTee = TRUE;
276 } else {
277 hr = E_INVALIDARG;
278 goto end;
280 if (!needSmartTee) {
281 if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE)) {
282 hr = IPin_ConnectedTo(capture, &peer);
283 if (hr == VFW_E_NOT_CONNECTED) {
284 *source_out = capture;
285 IPin_AddRef(*source_out);
286 hr = S_OK;
287 } else
288 hr = E_INVALIDARG;
289 } else {
290 hr = IPin_ConnectedTo(preview, &peer);
291 if (hr == VFW_E_NOT_CONNECTED) {
292 *source_out = preview;
293 IPin_AddRef(*source_out);
294 hr = S_OK;
295 } else
296 hr = E_INVALIDARG;
298 goto end;
300 hr = IPin_ConnectedTo(capture, &peer);
301 if (SUCCEEDED(hr)) {
302 PIN_INFO pinInfo;
303 GUID classID;
304 hr = IPin_QueryPinInfo(peer, &pinInfo);
305 if (SUCCEEDED(hr)) {
306 hr = IBaseFilter_GetClassID(pinInfo.pFilter, &classID);
307 if (SUCCEEDED(hr)) {
308 if (IsEqualIID(&classID, &CLSID_SmartTee)) {
309 smartTee = pinInfo.pFilter;
310 IBaseFilter_AddRef(smartTee);
313 IBaseFilter_Release(pinInfo.pFilter);
315 if (!smartTee) {
316 hr = E_INVALIDARG;
317 goto end;
319 } else if (hr == VFW_E_NOT_CONNECTED) {
320 hr = CoCreateInstance(&CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER,
321 &IID_IBaseFilter, (LPVOID*)&smartTee);
322 if (SUCCEEDED(hr)) {
323 hr = IGraphBuilder_AddFilter(This->mygraph, smartTee, NULL);
324 if (SUCCEEDED(hr)) {
325 IPin *smartTeeInput = NULL;
326 hr = IBaseFilter_FindPin(smartTee, inputW, &smartTeeInput);
327 if (SUCCEEDED(hr)) {
328 hr = IGraphBuilder_ConnectDirect(This->mygraph, capture, smartTeeInput, NULL);
329 IPin_Release(smartTeeInput);
333 if (FAILED(hr)) {
334 TRACE("adding SmartTee failed with hr=0x%08x\n", hr);
335 hr = E_INVALIDARG;
336 goto end;
338 } else {
339 hr = E_INVALIDARG;
340 goto end;
342 if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE))
343 hr = IBaseFilter_FindPin(smartTee, captureW, source_out);
344 else {
345 hr = IBaseFilter_FindPin(smartTee, previewW, source_out);
346 if (SUCCEEDED(hr))
347 hr = VFW_S_NOPREVIEWPIN;
350 end:
351 if (capture)
352 IPin_Release(capture);
353 if (preview)
354 IPin_Release(preview);
355 if (peer)
356 IPin_Release(peer);
357 if (smartTee)
358 IBaseFilter_Release(smartTee);
359 TRACE("for %s returning hr=0x%08x, *source_out=%p\n", IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) ? "capture" : "preview", hr, source_out ? *source_out : 0);
360 return hr;
363 static HRESULT find_unconnected_pin(CaptureGraphImpl *This,
364 const GUID *pCategory, const GUID *pType, IUnknown *pSource, IPin **out_pin)
366 int index = 0;
367 IPin *source_out;
368 HRESULT hr;
369 BOOL usedSmartTeePreviewPin = FALSE;
371 /* depth-first search the graph for the first unconnected pin that matches
372 * the given category and type */
373 for(;;){
374 IPin *nextpin;
376 if (pCategory && (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) || IsEqualIID(pCategory, &PIN_CATEGORY_PREVIEW))){
377 IBaseFilter *sourceFilter = NULL;
378 hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&sourceFilter);
379 if (SUCCEEDED(hr)) {
380 hr = match_smart_tee_pin(This, pCategory, pType, pSource, &source_out);
381 if (hr == VFW_S_NOPREVIEWPIN)
382 usedSmartTeePreviewPin = TRUE;
383 IBaseFilter_Release(sourceFilter);
384 } else {
385 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource, PINDIR_OUTPUT, pCategory, pType, FALSE, index, &source_out);
387 if (FAILED(hr))
388 return E_INVALIDARG;
389 } else {
390 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource, PINDIR_OUTPUT, pCategory, pType, FALSE, index, &source_out);
391 if (FAILED(hr))
392 return E_INVALIDARG;
395 hr = IPin_ConnectedTo(source_out, &nextpin);
396 if(SUCCEEDED(hr)){
397 PIN_INFO info;
399 IPin_Release(source_out);
401 hr = IPin_QueryPinInfo(nextpin, &info);
402 if(FAILED(hr) || !info.pFilter){
403 WARN("QueryPinInfo failed: %08x\n", hr);
404 return hr;
407 hr = find_unconnected_pin(This, pCategory, pType, (IUnknown*)info.pFilter, out_pin);
409 IBaseFilter_Release(info.pFilter);
411 if(SUCCEEDED(hr))
412 return hr;
413 }else{
414 *out_pin = source_out;
415 if(usedSmartTeePreviewPin)
416 return VFW_S_NOPREVIEWPIN;
417 return S_OK;
420 index++;
424 static HRESULT WINAPI
425 fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
426 const GUID *pCategory,
427 const GUID *pType,
428 IUnknown *pSource,
429 IBaseFilter *pfCompressor,
430 IBaseFilter *pfRenderer)
432 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
433 IPin *source_out = NULL, *renderer_in;
434 BOOL rendererNeedsRelease = FALSE;
435 HRESULT hr, return_hr = S_OK;
437 FIXME("(%p/%p)->(%s, %s, %p, %p, %p) semi-stub!\n", This, iface,
438 debugstr_guid(pCategory), debugstr_guid(pType),
439 pSource, pfCompressor, pfRenderer);
441 if (!This->mygraph)
443 FIXME("Need a capture graph\n");
444 return E_UNEXPECTED;
447 if (pCategory && IsEqualIID(pCategory, &PIN_CATEGORY_VBI)) {
448 FIXME("Tee/Sink-to-Sink filter not supported\n");
449 return E_NOTIMPL;
452 hr = find_unconnected_pin(This, pCategory, pType, pSource, &source_out);
453 if (FAILED(hr))
454 return hr;
455 return_hr = hr;
457 if (!pfRenderer)
459 IEnumMediaTypes *enumMedia = NULL;
460 hr = IPin_EnumMediaTypes(source_out, &enumMedia);
461 if (SUCCEEDED(hr)) {
462 AM_MEDIA_TYPE *mediaType;
463 hr = IEnumMediaTypes_Next(enumMedia, 1, &mediaType, NULL);
464 if (SUCCEEDED(hr)) {
465 if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Video)) {
466 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
467 &IID_IBaseFilter, (void**)&pfRenderer);
468 } else if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Audio)) {
469 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
470 &IID_IBaseFilter, (void**)&pfRenderer);
471 } else {
472 FIXME("cannot automatically load renderer for majortype %s\n", debugstr_guid(&mediaType->majortype));
473 hr = E_FAIL;
475 if (SUCCEEDED(hr)) {
476 rendererNeedsRelease = TRUE;
477 hr = IGraphBuilder_AddFilter(This->mygraph, pfRenderer, NULL);
479 DeleteMediaType(mediaType);
481 IEnumMediaTypes_Release(enumMedia);
483 if (FAILED(hr)) {
484 if (rendererNeedsRelease)
485 IBaseFilter_Release(pfRenderer);
486 IPin_Release(source_out);
487 return hr;
491 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, &renderer_in);
492 if (FAILED(hr))
494 if (rendererNeedsRelease)
495 IBaseFilter_Release(pfRenderer);
496 IPin_Release(source_out);
497 return hr;
500 if (!pfCompressor)
501 hr = IGraphBuilder_Connect(This->mygraph, source_out, renderer_in);
502 else
504 IPin *compressor_in, *compressor_out;
506 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
507 PINDIR_INPUT, NULL, NULL, TRUE, 0, &compressor_in);
508 if (SUCCEEDED(hr))
510 hr = IGraphBuilder_Connect(This->mygraph, source_out, compressor_in);
511 IPin_Release(compressor_in);
514 if (SUCCEEDED(hr))
516 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
517 PINDIR_OUTPUT, NULL, NULL, TRUE, 0, &compressor_out);
518 if (SUCCEEDED(hr))
520 hr = IGraphBuilder_Connect(This->mygraph, compressor_out, renderer_in);
521 IPin_Release(compressor_out);
526 IPin_Release(source_out);
527 IPin_Release(renderer_in);
528 if (rendererNeedsRelease)
529 IBaseFilter_Release(pfRenderer);
530 if (SUCCEEDED(hr))
531 return return_hr;
532 return hr;
535 static HRESULT WINAPI
536 fnCaptureGraphBuilder2_ControlStream(ICaptureGraphBuilder2 * iface,
537 const GUID *pCategory,
538 const GUID *pType,
539 IBaseFilter *pFilter,
540 REFERENCE_TIME *pstart,
541 REFERENCE_TIME *pstop,
542 WORD wStartCookie,
543 WORD wStopCookie)
545 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
547 FIXME("(%p/%p)->(%s, %s, %p, %p, %p, %i, %i) Stub!\n", This, iface,
548 debugstr_guid(pCategory), debugstr_guid(pType),
549 pFilter, pstart, pstop, wStartCookie, wStopCookie);
551 return E_NOTIMPL;
554 static HRESULT WINAPI
555 fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2 * iface,
556 LPCOLESTR lpwstr,
557 DWORDLONG dwlSize)
559 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
561 FIXME("(%p/%p)->(%s, 0x%s) Stub!\n", This, iface,
562 debugstr_w(lpwstr), wine_dbgstr_longlong(dwlSize));
564 return E_NOTIMPL;
567 static HRESULT WINAPI
568 fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2 * iface,
569 LPOLESTR lpwstrOld,
570 LPOLESTR lpwstrNew,
571 int fAllowEscAbort,
572 IAMCopyCaptureFileProgress *pCallback)
574 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
576 FIXME("(%p/%p)->(%s, %s, %i, %p) Stub!\n", This, iface,
577 debugstr_w(lpwstrOld), debugstr_w(lpwstrNew),
578 fAllowEscAbort, pCallback);
580 return E_NOTIMPL;
583 static HRESULT pin_matches(IPin *pin, PIN_DIRECTION direction, const GUID *cat, const GUID *type, BOOL unconnected)
585 IPin *partner;
586 PIN_DIRECTION pindir;
587 HRESULT hr;
589 hr = IPin_QueryDirection(pin, &pindir);
591 if (unconnected && IPin_ConnectedTo(pin, &partner) == S_OK && partner!=NULL)
593 IPin_Release(partner);
594 TRACE("No match, %p already connected to %p\n", pin, partner);
595 return FAILED(hr) ? hr : S_FALSE;
598 if (FAILED(hr))
599 return hr;
600 if (SUCCEEDED(hr) && pindir != direction)
601 return S_FALSE;
603 if (cat)
605 IKsPropertySet *props;
606 GUID category;
607 DWORD fetched;
609 hr = IPin_QueryInterface(pin, &IID_IKsPropertySet, (void**)&props);
610 if (FAILED(hr))
611 return S_FALSE;
613 hr = IKsPropertySet_Get(props, &AMPROPSETID_Pin, 0, NULL,
614 0, &category, sizeof(category), &fetched);
615 IKsPropertySet_Release(props);
616 if (FAILED(hr) || !IsEqualIID(&category, cat))
617 return S_FALSE;
620 if (type)
622 IEnumMediaTypes *types;
623 AM_MEDIA_TYPE *media_type;
624 ULONG fetched;
626 hr = IPin_EnumMediaTypes(pin, &types);
627 if (FAILED(hr))
628 return S_FALSE;
630 IEnumMediaTypes_Reset(types);
631 while (1) {
632 if (IEnumMediaTypes_Next(types, 1, &media_type, &fetched) != S_OK || fetched != 1)
634 IEnumMediaTypes_Release(types);
635 return S_FALSE;
638 if (IsEqualIID(&media_type->majortype, type))
640 DeleteMediaType(media_type);
641 break;
643 DeleteMediaType(media_type);
645 IEnumMediaTypes_Release(types);
648 TRACE("Pin matched\n");
649 return S_OK;
652 static HRESULT WINAPI
653 fnCaptureGraphBuilder2_FindPin(ICaptureGraphBuilder2 * iface,
654 IUnknown *pSource,
655 PIN_DIRECTION pindir,
656 const GUID *pCategory,
657 const GUID *pType,
658 BOOL fUnconnected,
659 INT num,
660 IPin **ppPin)
662 HRESULT hr;
663 IEnumPins *enumpins = NULL;
664 IPin *pin;
665 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
667 TRACE("(%p/%p)->(%p, %x, %s, %s, %d, %i, %p)\n", This, iface,
668 pSource, pindir, debugstr_guid(pCategory), debugstr_guid(pType),
669 fUnconnected, num, ppPin);
671 pin = NULL;
673 hr = IUnknown_QueryInterface(pSource, &IID_IPin, (void**)&pin);
674 if (hr == E_NOINTERFACE)
676 IBaseFilter *filter = NULL;
677 int numcurrent = 0;
679 hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&filter);
680 if (hr == E_NOINTERFACE)
682 WARN("Input not filter or pin?!\n");
683 return E_NOINTERFACE;
686 hr = IBaseFilter_EnumPins(filter, &enumpins);
687 if (FAILED(hr))
689 WARN("Could not enumerate\n");
690 IBaseFilter_Release(filter);
691 return hr;
694 while (1)
696 ULONG fetched;
698 hr = IEnumPins_Next(enumpins, 1, &pin, &fetched);
699 if (hr == VFW_E_ENUM_OUT_OF_SYNC)
701 numcurrent = 0;
702 IEnumPins_Reset(enumpins);
703 pin = NULL;
704 continue;
706 if (hr != S_OK)
707 break;
708 if (fetched != 1)
710 hr = E_FAIL;
711 break;
714 TRACE("Testing match\n");
715 hr = pin_matches(pin, pindir, pCategory, pType, fUnconnected);
716 if (hr == S_OK && numcurrent++ == num)
717 break;
718 IPin_Release(pin);
719 pin = NULL;
720 if (FAILED(hr))
721 break;
723 IEnumPins_Release(enumpins);
724 IBaseFilter_Release(filter);
726 if (hr != S_OK)
728 WARN("Could not find %s pin # %d\n", (pindir == PINDIR_OUTPUT ? "output" : "input"), numcurrent);
729 return E_FAIL;
732 else if (pin_matches(pin, pindir, pCategory, pType, fUnconnected) != S_OK)
734 IPin_Release(pin);
735 return E_FAIL;
738 *ppPin = pin;
739 return S_OK;
742 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl =
744 fnCaptureGraphBuilder2_QueryInterface,
745 fnCaptureGraphBuilder2_AddRef,
746 fnCaptureGraphBuilder2_Release,
747 fnCaptureGraphBuilder2_SetFilterGraph,
748 fnCaptureGraphBuilder2_GetFilterGraph,
749 fnCaptureGraphBuilder2_SetOutputFileName,
750 fnCaptureGraphBuilder2_FindInterface,
751 fnCaptureGraphBuilder2_RenderStream,
752 fnCaptureGraphBuilder2_ControlStream,
753 fnCaptureGraphBuilder2_AllocCapFile,
754 fnCaptureGraphBuilder2_CopyCaptureFile,
755 fnCaptureGraphBuilder2_FindPin
759 static HRESULT WINAPI
760 fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface,
761 REFIID riid, LPVOID * ppv)
763 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
764 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
765 return ICaptureGraphBuilder2_QueryInterface(&This->ICaptureGraphBuilder2_iface, riid, ppv);
768 static ULONG WINAPI
769 fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
771 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
772 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
773 return ICaptureGraphBuilder2_AddRef(&This->ICaptureGraphBuilder2_iface);
776 static ULONG WINAPI
777 fnCaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
779 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
780 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
781 return ICaptureGraphBuilder2_Release(&This->ICaptureGraphBuilder2_iface);
784 static HRESULT WINAPI
785 fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder * iface,
786 IGraphBuilder *pfg)
788 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
789 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
790 return ICaptureGraphBuilder2_SetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
793 static HRESULT WINAPI
794 fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder * iface,
795 IGraphBuilder **pfg)
797 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
798 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
799 return ICaptureGraphBuilder2_GetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
802 static HRESULT WINAPI
803 fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface,
804 const GUID *pType, LPCOLESTR lpstrFile,
805 IBaseFilter **ppf, IFileSinkFilter **ppSink)
807 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
808 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
809 return ICaptureGraphBuilder2_SetOutputFileName(&This->ICaptureGraphBuilder2_iface, pType,
810 lpstrFile, ppf, ppSink);
813 static HRESULT WINAPI
814 fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface,
815 const GUID *pCategory, IBaseFilter *pf,
816 REFIID riid, void **ppint)
818 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
819 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
820 return ICaptureGraphBuilder2_FindInterface(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
821 pf, riid, ppint);
824 static HRESULT WINAPI
825 fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface,
826 const GUID *pCategory, IUnknown *pSource,
827 IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
829 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
830 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
831 return ICaptureGraphBuilder2_RenderStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
832 pSource, pfCompressor, pfRenderer);
835 static HRESULT WINAPI
836 fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface,
837 const GUID *pCategory, IBaseFilter *pFilter,
838 REFERENCE_TIME *pstart, REFERENCE_TIME *pstop,
839 WORD wStartCookie, WORD wStopCookie)
841 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
842 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
843 return ICaptureGraphBuilder2_ControlStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
844 pFilter, pstart, pstop, wStartCookie, wStopCookie);
847 static HRESULT WINAPI
848 fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface,
849 LPCOLESTR lpstr, DWORDLONG dwlSize)
851 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
852 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
853 return ICaptureGraphBuilder2_AllocCapFile(&This->ICaptureGraphBuilder2_iface, lpstr, dwlSize);
856 static HRESULT WINAPI
857 fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface,
858 LPOLESTR lpwstrOld, LPOLESTR lpwstrNew,
859 int fAllowEscAbort,
860 IAMCopyCaptureFileProgress *pCallback)
862 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
863 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
864 return ICaptureGraphBuilder2_CopyCaptureFile(&This->ICaptureGraphBuilder2_iface, lpwstrOld,
865 lpwstrNew, fAllowEscAbort, pCallback);
868 static const ICaptureGraphBuilderVtbl builder_Vtbl =
870 fnCaptureGraphBuilder_QueryInterface,
871 fnCaptureGraphBuilder_AddRef,
872 fnCaptureGraphBuilder_Release,
873 fnCaptureGraphBuilder_SetFiltergraph,
874 fnCaptureGraphBuilder_GetFiltergraph,
875 fnCaptureGraphBuilder_SetOutputFileName,
876 fnCaptureGraphBuilder_FindInterface,
877 fnCaptureGraphBuilder_RenderStream,
878 fnCaptureGraphBuilder_ControlStream,
879 fnCaptureGraphBuilder_AllocCapFile,
880 fnCaptureGraphBuilder_CopyCaptureFile