server: Support unbound console input device.
[wine.git] / dlls / qcap / capturegraph.c
blobb98a321cb3a127bea8a7c8c6ef942737278364c0
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
21 #include "qcap_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
25 /***********************************************************************
26 * ICaptureGraphBuilder & ICaptureGraphBuilder2 implementation
28 typedef struct CaptureGraphImpl
30 ICaptureGraphBuilder2 ICaptureGraphBuilder2_iface;
31 ICaptureGraphBuilder ICaptureGraphBuilder_iface;
32 LONG ref;
33 IGraphBuilder *mygraph;
34 CRITICAL_SECTION csFilter;
35 } CaptureGraphImpl;
37 static const ICaptureGraphBuilderVtbl builder_Vtbl;
38 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl;
40 static inline CaptureGraphImpl *impl_from_ICaptureGraphBuilder(ICaptureGraphBuilder *iface)
42 return CONTAINING_RECORD(iface, CaptureGraphImpl, ICaptureGraphBuilder_iface);
45 static inline CaptureGraphImpl *impl_from_ICaptureGraphBuilder2(ICaptureGraphBuilder2 *iface)
47 return CONTAINING_RECORD(iface, CaptureGraphImpl, ICaptureGraphBuilder2_iface);
51 HRESULT capture_graph_create(IUnknown *outer, IUnknown **out)
53 CaptureGraphImpl *object;
55 if (outer)
56 return CLASS_E_NOAGGREGATION;
58 if (!(object = CoTaskMemAlloc(sizeof(*object))))
59 return E_OUTOFMEMORY;
61 object->ICaptureGraphBuilder2_iface.lpVtbl = &builder2_Vtbl;
62 object->ICaptureGraphBuilder_iface.lpVtbl = &builder_Vtbl;
63 object->ref = 1;
64 object->mygraph = NULL;
65 InitializeCriticalSection(&object->csFilter);
66 object->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CaptureGraphImpl.csFilter");
68 TRACE("Created capture graph builder %p.\n", object);
69 ObjectRefCount(TRUE);
70 *out = (IUnknown *)&object->ICaptureGraphBuilder_iface;
71 return S_OK;
74 static HRESULT WINAPI
75 fnCaptureGraphBuilder2_QueryInterface(ICaptureGraphBuilder2 * iface,
76 REFIID riid,
77 LPVOID * ppv)
79 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
81 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
83 *ppv = NULL;
84 if (IsEqualIID(riid, &IID_IUnknown))
85 *ppv = &This->ICaptureGraphBuilder2_iface;
86 else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder))
87 *ppv = &This->ICaptureGraphBuilder_iface;
88 else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder2))
89 *ppv = &This->ICaptureGraphBuilder2_iface;
91 if (*ppv)
93 IUnknown_AddRef((IUnknown *)(*ppv));
94 TRACE ("-- Interface = %p\n", *ppv);
95 return S_OK;
98 TRACE ("-- Interface: E_NOINTERFACE\n");
99 return E_NOINTERFACE;
102 static ULONG WINAPI
103 fnCaptureGraphBuilder2_AddRef(ICaptureGraphBuilder2 * iface)
105 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
106 DWORD ref = InterlockedIncrement(&This->ref);
108 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, ref - 1);
109 return ref;
112 static ULONG WINAPI fnCaptureGraphBuilder2_Release(ICaptureGraphBuilder2 * iface)
114 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
115 DWORD ref = InterlockedDecrement(&This->ref);
117 TRACE("(%p/%p)->() Release from %d\n", This, iface, ref + 1);
119 if (!ref)
121 This->csFilter.DebugInfo->Spare[0] = 0;
122 DeleteCriticalSection(&This->csFilter);
123 if (This->mygraph)
124 IGraphBuilder_Release(This->mygraph);
125 CoTaskMemFree(This);
126 ObjectRefCount(FALSE);
128 return ref;
131 static HRESULT WINAPI
132 fnCaptureGraphBuilder2_SetFilterGraph(ICaptureGraphBuilder2 * iface,
133 IGraphBuilder *pfg)
135 /* The graph builder will automatically create a filter graph if you don't call
136 this method. If you call this method after the graph builder has created its
137 own filter graph, the call will fail. */
138 IMediaEvent *pmev;
139 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
141 TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
143 if (This->mygraph)
144 return E_UNEXPECTED;
146 if (!pfg)
147 return E_POINTER;
149 This->mygraph = pfg;
150 IGraphBuilder_AddRef(This->mygraph);
151 if (SUCCEEDED(IGraphBuilder_QueryInterface(This->mygraph,
152 &IID_IMediaEvent, (LPVOID *)&pmev)))
154 IMediaEvent_CancelDefaultHandling(pmev, EC_REPAINT);
155 IMediaEvent_Release(pmev);
157 return S_OK;
160 static HRESULT WINAPI
161 fnCaptureGraphBuilder2_GetFilterGraph(ICaptureGraphBuilder2 * iface,
162 IGraphBuilder **pfg)
164 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
166 TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
168 if (!pfg)
169 return E_POINTER;
171 *pfg = This->mygraph;
172 if (!This->mygraph)
174 TRACE("(%p) Getting NULL filtergraph\n", iface);
175 return E_UNEXPECTED;
178 IGraphBuilder_AddRef(This->mygraph);
180 TRACE("(%p) return filtergraph %p\n", iface, *pfg);
181 return S_OK;
184 static HRESULT WINAPI
185 fnCaptureGraphBuilder2_SetOutputFileName(ICaptureGraphBuilder2 * iface,
186 const GUID *pType,
187 LPCOLESTR lpstrFile,
188 IBaseFilter **ppf,
189 IFileSinkFilter **ppSink)
191 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
193 FIXME("(%p/%p)->(%s, %s, %p, %p) Stub!\n", This, iface,
194 debugstr_guid(pType), debugstr_w(lpstrFile), ppf, ppSink);
196 return E_NOTIMPL;
199 static BOOL pin_has_majortype(IPin *pin, const GUID *majortype)
201 IEnumMediaTypes *enummt;
202 AM_MEDIA_TYPE *mt;
204 if (FAILED(IPin_EnumMediaTypes(pin, &enummt)))
205 return FALSE;
207 while (IEnumMediaTypes_Next(enummt, 1, &mt, NULL) == S_OK)
209 if (IsEqualGUID(&mt->majortype, majortype))
211 DeleteMediaType(mt);
212 IEnumMediaTypes_Release(enummt);
213 return TRUE;
215 DeleteMediaType(mt);
217 IEnumMediaTypes_Release(enummt);
218 return FALSE;
221 static BOOL pin_matches(IPin *pin, PIN_DIRECTION dir, const GUID *category,
222 const GUID *majortype, BOOL unconnected)
224 PIN_DIRECTION candidate_dir;
225 HRESULT hr;
226 IPin *peer;
228 if (FAILED(hr = IPin_QueryDirection(pin, &candidate_dir)))
229 ERR("Failed to query direction, hr %#x.\n", hr);
231 if (dir != candidate_dir)
232 return FALSE;
234 if (unconnected && IPin_ConnectedTo(pin, &peer) == S_OK && peer)
236 IPin_Release(peer);
237 return FALSE;
240 if (category)
242 IKsPropertySet *set;
243 GUID property;
244 DWORD size;
246 if (FAILED(IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **)&set)))
247 return FALSE;
249 hr = IKsPropertySet_Get(set, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
250 NULL, 0, &property, sizeof(property), &size);
251 IKsPropertySet_Release(set);
252 if (FAILED(hr) || !IsEqualGUID(&property, category))
253 return FALSE;
256 if (majortype && !pin_has_majortype(pin, majortype))
257 return FALSE;
259 return TRUE;
262 static HRESULT find_interface_recurse(PIN_DIRECTION dir, const GUID *category,
263 const GUID *majortype, IBaseFilter *filter, REFIID iid, void **out)
265 BOOL found_category = FALSE;
266 IEnumPins *enumpins;
267 IPin *pin, *peer;
268 PIN_INFO info;
269 HRESULT hr;
271 TRACE("Looking for %s pins, category %s, majortype %s from filter %p.\n",
272 dir == PINDIR_INPUT ? "sink" : "source", debugstr_guid(category),
273 debugstr_guid(majortype), filter);
275 if (FAILED(hr = IBaseFilter_EnumPins(filter, &enumpins)))
277 ERR("Failed to enumerate pins, hr %#x.\n", hr);
278 return hr;
281 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
283 if (!pin_matches(pin, dir, category, majortype, FALSE))
285 IPin_Release(pin);
286 continue;
289 if (category)
290 found_category = TRUE;
292 if (IPin_QueryInterface(pin, iid, out) == S_OK)
294 IPin_Release(pin);
295 IEnumPins_Release(enumpins);
296 return S_OK;
299 hr = IPin_ConnectedTo(pin, &peer);
300 IPin_Release(pin);
301 if (hr == S_OK)
303 if (IPin_QueryInterface(peer, iid, out) == S_OK)
305 IPin_Release(peer);
306 IEnumPins_Release(enumpins);
307 return S_OK;
310 IPin_QueryPinInfo(peer, &info);
311 IPin_Release(peer);
313 if (IBaseFilter_QueryInterface(info.pFilter, iid, out) == S_OK)
315 IBaseFilter_Release(info.pFilter);
316 IEnumPins_Release(enumpins);
317 return S_OK;
320 hr = find_interface_recurse(dir, NULL, NULL, info.pFilter, iid, out);
321 IBaseFilter_Release(info.pFilter);
322 if (hr == S_OK)
324 IEnumPins_Release(enumpins);
325 return S_OK;
329 IEnumPins_Release(enumpins);
331 if (category && !found_category)
332 return E_NOINTERFACE;
334 return E_FAIL;
337 static HRESULT WINAPI fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2 *iface,
338 const GUID *category, const GUID *majortype, IBaseFilter *filter, REFIID iid, void **out)
340 CaptureGraphImpl *graph = impl_from_ICaptureGraphBuilder2(iface);
341 HRESULT hr;
343 TRACE("graph %p, category %s, majortype %s, filter %p, iid %s, out %p.\n",
344 graph, debugstr_guid(category), debugstr_guid(majortype), filter, debugstr_guid(iid), out);
346 if (!filter)
347 return E_POINTER;
349 if (category && IsEqualGUID(category, &LOOK_DOWNSTREAM_ONLY))
350 return find_interface_recurse(PINDIR_OUTPUT, NULL, NULL, filter, iid, out);
352 if (category && IsEqualGUID(category, &LOOK_UPSTREAM_ONLY))
353 return find_interface_recurse(PINDIR_INPUT, NULL, NULL, filter, iid, out);
355 if (IBaseFilter_QueryInterface(filter, iid, out) == S_OK)
356 return S_OK;
358 if (!category)
359 majortype = NULL;
361 hr = find_interface_recurse(PINDIR_OUTPUT, category, majortype, filter, iid, out);
362 if (hr == S_OK || hr == E_NOINTERFACE)
363 return hr;
365 return find_interface_recurse(PINDIR_INPUT, NULL, NULL, filter, iid, out);
368 static HRESULT match_smart_tee_pin(CaptureGraphImpl *This,
369 const GUID *pCategory,
370 const GUID *pType,
371 IUnknown *pSource,
372 IPin **source_out)
374 static const WCHAR inputW[] = {'I','n','p','u','t',0};
375 static const WCHAR captureW[] = {'C','a','p','t','u','r','e',0};
376 static const WCHAR previewW[] = {'P','r','e','v','i','e','w',0};
377 IPin *capture = NULL;
378 IPin *preview = NULL;
379 IPin *peer = NULL;
380 IBaseFilter *smartTee = NULL;
381 BOOL needSmartTee = FALSE;
382 HRESULT hr;
384 TRACE("(%p, %s, %s, %p, %p)\n", This, debugstr_guid(pCategory), debugstr_guid(pType), pSource, source_out);
385 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
386 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, pType, FALSE, 0, &capture);
387 if (SUCCEEDED(hr)) {
388 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
389 PINDIR_OUTPUT, &PIN_CATEGORY_PREVIEW, pType, FALSE, 0, &preview);
390 if (FAILED(hr))
391 needSmartTee = TRUE;
392 } else {
393 hr = E_INVALIDARG;
394 goto end;
396 if (!needSmartTee) {
397 if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE)) {
398 hr = IPin_ConnectedTo(capture, &peer);
399 if (hr == VFW_E_NOT_CONNECTED) {
400 *source_out = capture;
401 IPin_AddRef(*source_out);
402 hr = S_OK;
403 } else
404 hr = E_INVALIDARG;
405 } else {
406 hr = IPin_ConnectedTo(preview, &peer);
407 if (hr == VFW_E_NOT_CONNECTED) {
408 *source_out = preview;
409 IPin_AddRef(*source_out);
410 hr = S_OK;
411 } else
412 hr = E_INVALIDARG;
414 goto end;
416 hr = IPin_ConnectedTo(capture, &peer);
417 if (SUCCEEDED(hr)) {
418 PIN_INFO pinInfo;
419 GUID classID;
420 hr = IPin_QueryPinInfo(peer, &pinInfo);
421 if (SUCCEEDED(hr)) {
422 hr = IBaseFilter_GetClassID(pinInfo.pFilter, &classID);
423 if (SUCCEEDED(hr)) {
424 if (IsEqualIID(&classID, &CLSID_SmartTee)) {
425 smartTee = pinInfo.pFilter;
426 IBaseFilter_AddRef(smartTee);
429 IBaseFilter_Release(pinInfo.pFilter);
431 if (!smartTee) {
432 hr = E_INVALIDARG;
433 goto end;
435 } else if (hr == VFW_E_NOT_CONNECTED) {
436 hr = CoCreateInstance(&CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER,
437 &IID_IBaseFilter, (LPVOID*)&smartTee);
438 if (SUCCEEDED(hr)) {
439 hr = IGraphBuilder_AddFilter(This->mygraph, smartTee, NULL);
440 if (SUCCEEDED(hr)) {
441 IPin *smartTeeInput = NULL;
442 hr = IBaseFilter_FindPin(smartTee, inputW, &smartTeeInput);
443 if (SUCCEEDED(hr)) {
444 hr = IGraphBuilder_ConnectDirect(This->mygraph, capture, smartTeeInput, NULL);
445 IPin_Release(smartTeeInput);
449 if (FAILED(hr)) {
450 TRACE("adding SmartTee failed with hr=0x%08x\n", hr);
451 hr = E_INVALIDARG;
452 goto end;
454 } else {
455 hr = E_INVALIDARG;
456 goto end;
458 if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE))
459 hr = IBaseFilter_FindPin(smartTee, captureW, source_out);
460 else {
461 hr = IBaseFilter_FindPin(smartTee, previewW, source_out);
462 if (SUCCEEDED(hr))
463 hr = VFW_S_NOPREVIEWPIN;
466 end:
467 if (capture)
468 IPin_Release(capture);
469 if (preview)
470 IPin_Release(preview);
471 if (peer)
472 IPin_Release(peer);
473 if (smartTee)
474 IBaseFilter_Release(smartTee);
475 TRACE("for %s returning hr=0x%08x, *source_out=%p\n", IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) ? "capture" : "preview", hr, source_out ? *source_out : 0);
476 return hr;
479 static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_graph,
480 const GUID *category, const GUID *majortype, IBaseFilter *filter, IPin **ret);
482 static HRESULT find_unconnected_source_from_pin(CaptureGraphImpl *capture_graph,
483 const GUID *category, const GUID *majortype, IPin *pin, IPin **ret)
485 PIN_DIRECTION dir;
486 PIN_INFO info;
487 HRESULT hr;
488 IPin *peer;
490 IPin_QueryDirection(pin, &dir);
491 if (dir != PINDIR_OUTPUT)
492 return VFW_E_INVALID_DIRECTION;
494 if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE)
495 || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW)))
497 if (FAILED(hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)pin, &pin)))
498 return hr;
500 if (FAILED(IPin_ConnectedTo(pin, &peer)))
502 *ret = pin;
503 return S_OK;
506 else
508 if (FAILED(IPin_ConnectedTo(pin, &peer)))
510 if (!pin_matches(pin, PINDIR_OUTPUT, category, majortype, FALSE))
511 return E_FAIL;
513 IPin_AddRef(*ret = pin);
514 return S_OK;
516 IPin_AddRef(pin);
519 IPin_QueryPinInfo(peer, &info);
520 hr = find_unconnected_source_from_filter(capture_graph, category, majortype, info.pFilter, ret);
521 IBaseFilter_Release(info.pFilter);
522 IPin_Release(peer);
523 IPin_Release(pin);
524 return hr;
527 static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_graph,
528 const GUID *category, const GUID *majortype, IBaseFilter *filter, IPin **ret)
530 IEnumPins *enumpins;
531 IPin *pin, *peer;
532 HRESULT hr;
534 if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE)
535 || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW)))
537 if (FAILED(hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)filter, &pin)))
538 return hr;
540 if (FAILED(IPin_ConnectedTo(pin, &peer)))
542 *ret = pin;
543 return hr;
546 IPin_Release(peer);
547 IPin_Release(pin);
548 return E_INVALIDARG;
551 if (FAILED(hr = IBaseFilter_EnumPins(filter, &enumpins)))
552 return hr;
554 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
556 if (SUCCEEDED(hr = find_unconnected_source_from_pin(capture_graph, category, majortype, pin, ret)))
558 IEnumPins_Release(enumpins);
559 IPin_Release(pin);
560 return hr;
562 IPin_Release(pin);
564 IEnumPins_Release(enumpins);
566 return E_INVALIDARG;
569 static HRESULT WINAPI fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 *iface,
570 const GUID *category, const GUID *majortype, IUnknown *source,
571 IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
573 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
574 IPin *source_out = NULL, *renderer_in;
575 BOOL rendererNeedsRelease = FALSE;
576 HRESULT hr, return_hr = S_OK;
577 IBaseFilter *filter;
578 IPin *pin;
580 TRACE("graph %p, category %s, majortype %s, source %p, intermediate %p, sink %p.\n",
581 This, debugstr_guid(category), debugstr_guid(majortype), source, pfCompressor, pfRenderer);
583 if (!This->mygraph)
585 FIXME("Need a capture graph\n");
586 return E_UNEXPECTED;
589 if (category && IsEqualGUID(category, &PIN_CATEGORY_VBI))
591 FIXME("Tee/Sink-to-Sink filter not supported\n");
592 return E_NOTIMPL;
595 if (IUnknown_QueryInterface(source, &IID_IPin, (void **)&pin) == S_OK)
597 hr = find_unconnected_source_from_pin(This, category, majortype, pin, &source_out);
598 IPin_Release(pin);
600 else if (IUnknown_QueryInterface(source, &IID_IBaseFilter, (void **)&filter) == S_OK)
602 hr = find_unconnected_source_from_filter(This, category, majortype, filter, &source_out);
603 IBaseFilter_Release(filter);
605 else
607 WARN("Source object does not expose IBaseFilter or IPin.\n");
608 return E_INVALIDARG;
610 if (FAILED(hr))
611 return hr;
612 return_hr = hr;
614 if (!pfRenderer)
616 IEnumMediaTypes *enumMedia = NULL;
617 hr = IPin_EnumMediaTypes(source_out, &enumMedia);
618 if (SUCCEEDED(hr)) {
619 AM_MEDIA_TYPE *mediaType;
620 hr = IEnumMediaTypes_Next(enumMedia, 1, &mediaType, NULL);
621 if (SUCCEEDED(hr)) {
622 if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Video)) {
623 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
624 &IID_IBaseFilter, (void**)&pfRenderer);
625 } else if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Audio)) {
626 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
627 &IID_IBaseFilter, (void**)&pfRenderer);
628 } else {
629 FIXME("cannot automatically load renderer for majortype %s\n", debugstr_guid(&mediaType->majortype));
630 hr = E_FAIL;
632 if (SUCCEEDED(hr)) {
633 rendererNeedsRelease = TRUE;
634 hr = IGraphBuilder_AddFilter(This->mygraph, pfRenderer, NULL);
636 DeleteMediaType(mediaType);
638 IEnumMediaTypes_Release(enumMedia);
640 if (FAILED(hr)) {
641 if (rendererNeedsRelease)
642 IBaseFilter_Release(pfRenderer);
643 IPin_Release(source_out);
644 return hr;
648 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, &renderer_in);
649 if (FAILED(hr))
651 if (rendererNeedsRelease)
652 IBaseFilter_Release(pfRenderer);
653 IPin_Release(source_out);
654 return hr;
657 if (!pfCompressor)
658 hr = IGraphBuilder_Connect(This->mygraph, source_out, renderer_in);
659 else
661 IPin *compressor_in, *compressor_out;
663 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
664 PINDIR_INPUT, NULL, NULL, TRUE, 0, &compressor_in);
665 if (SUCCEEDED(hr))
667 hr = IGraphBuilder_Connect(This->mygraph, source_out, compressor_in);
668 IPin_Release(compressor_in);
671 if (SUCCEEDED(hr))
673 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
674 PINDIR_OUTPUT, NULL, NULL, TRUE, 0, &compressor_out);
675 if (SUCCEEDED(hr))
677 hr = IGraphBuilder_Connect(This->mygraph, compressor_out, renderer_in);
678 IPin_Release(compressor_out);
683 IPin_Release(source_out);
684 IPin_Release(renderer_in);
685 if (rendererNeedsRelease)
686 IBaseFilter_Release(pfRenderer);
687 if (SUCCEEDED(hr))
688 return return_hr;
689 return hr;
692 static HRESULT WINAPI
693 fnCaptureGraphBuilder2_ControlStream(ICaptureGraphBuilder2 * iface,
694 const GUID *pCategory,
695 const GUID *pType,
696 IBaseFilter *pFilter,
697 REFERENCE_TIME *pstart,
698 REFERENCE_TIME *pstop,
699 WORD wStartCookie,
700 WORD wStopCookie)
702 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
704 FIXME("(%p/%p)->(%s, %s, %p, %p, %p, %i, %i) Stub!\n", This, iface,
705 debugstr_guid(pCategory), debugstr_guid(pType),
706 pFilter, pstart, pstop, wStartCookie, wStopCookie);
708 return E_NOTIMPL;
711 static HRESULT WINAPI
712 fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2 * iface,
713 LPCOLESTR lpwstr,
714 DWORDLONG dwlSize)
716 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
718 FIXME("(%p/%p)->(%s, 0x%s) Stub!\n", This, iface,
719 debugstr_w(lpwstr), wine_dbgstr_longlong(dwlSize));
721 return E_NOTIMPL;
724 static HRESULT WINAPI
725 fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2 * iface,
726 LPOLESTR lpwstrOld,
727 LPOLESTR lpwstrNew,
728 int fAllowEscAbort,
729 IAMCopyCaptureFileProgress *pCallback)
731 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
733 FIXME("(%p/%p)->(%s, %s, %i, %p) Stub!\n", This, iface,
734 debugstr_w(lpwstrOld), debugstr_w(lpwstrNew),
735 fAllowEscAbort, pCallback);
737 return E_NOTIMPL;
740 static HRESULT WINAPI
741 fnCaptureGraphBuilder2_FindPin(ICaptureGraphBuilder2 * iface,
742 IUnknown *pSource,
743 PIN_DIRECTION pindir,
744 const GUID *pCategory,
745 const GUID *pType,
746 BOOL fUnconnected,
747 INT num,
748 IPin **ppPin)
750 HRESULT hr;
751 IEnumPins *enumpins = NULL;
752 IPin *pin;
753 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
755 TRACE("(%p/%p)->(%p, %x, %s, %s, %d, %i, %p)\n", This, iface,
756 pSource, pindir, debugstr_guid(pCategory), debugstr_guid(pType),
757 fUnconnected, num, ppPin);
759 pin = NULL;
761 hr = IUnknown_QueryInterface(pSource, &IID_IPin, (void**)&pin);
762 if (hr == E_NOINTERFACE)
764 IBaseFilter *filter = NULL;
765 int numcurrent = 0;
767 hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&filter);
768 if (hr == E_NOINTERFACE)
770 WARN("Input not filter or pin?!\n");
771 return E_NOINTERFACE;
774 hr = IBaseFilter_EnumPins(filter, &enumpins);
775 if (FAILED(hr))
777 WARN("Could not enumerate\n");
778 IBaseFilter_Release(filter);
779 return hr;
782 while (1)
784 ULONG fetched;
786 hr = IEnumPins_Next(enumpins, 1, &pin, &fetched);
787 if (hr == VFW_E_ENUM_OUT_OF_SYNC)
789 numcurrent = 0;
790 IEnumPins_Reset(enumpins);
791 pin = NULL;
792 continue;
794 if (hr != S_OK)
795 break;
796 if (fetched != 1)
798 hr = E_FAIL;
799 break;
802 TRACE("Testing match\n");
803 if (pin_matches(pin, pindir, pCategory, pType, fUnconnected) && numcurrent++ == num)
804 break;
805 IPin_Release(pin);
806 pin = NULL;
808 IEnumPins_Release(enumpins);
809 IBaseFilter_Release(filter);
811 if (hr != S_OK)
813 WARN("Could not find %s pin # %d\n", (pindir == PINDIR_OUTPUT ? "output" : "input"), numcurrent);
814 return E_FAIL;
817 else if (!pin_matches(pin, pindir, pCategory, pType, fUnconnected))
819 IPin_Release(pin);
820 return E_FAIL;
823 *ppPin = pin;
824 return S_OK;
827 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl =
829 fnCaptureGraphBuilder2_QueryInterface,
830 fnCaptureGraphBuilder2_AddRef,
831 fnCaptureGraphBuilder2_Release,
832 fnCaptureGraphBuilder2_SetFilterGraph,
833 fnCaptureGraphBuilder2_GetFilterGraph,
834 fnCaptureGraphBuilder2_SetOutputFileName,
835 fnCaptureGraphBuilder2_FindInterface,
836 fnCaptureGraphBuilder2_RenderStream,
837 fnCaptureGraphBuilder2_ControlStream,
838 fnCaptureGraphBuilder2_AllocCapFile,
839 fnCaptureGraphBuilder2_CopyCaptureFile,
840 fnCaptureGraphBuilder2_FindPin
844 static HRESULT WINAPI
845 fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface,
846 REFIID riid, LPVOID * ppv)
848 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
849 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
850 return ICaptureGraphBuilder2_QueryInterface(&This->ICaptureGraphBuilder2_iface, riid, ppv);
853 static ULONG WINAPI
854 fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
856 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
857 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
858 return ICaptureGraphBuilder2_AddRef(&This->ICaptureGraphBuilder2_iface);
861 static ULONG WINAPI
862 fnCaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
864 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
865 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
866 return ICaptureGraphBuilder2_Release(&This->ICaptureGraphBuilder2_iface);
869 static HRESULT WINAPI
870 fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder * iface,
871 IGraphBuilder *pfg)
873 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
874 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
875 return ICaptureGraphBuilder2_SetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
878 static HRESULT WINAPI
879 fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder * iface,
880 IGraphBuilder **pfg)
882 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
883 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
884 return ICaptureGraphBuilder2_GetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
887 static HRESULT WINAPI
888 fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface,
889 const GUID *pType, LPCOLESTR lpstrFile,
890 IBaseFilter **ppf, IFileSinkFilter **ppSink)
892 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
893 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
894 return ICaptureGraphBuilder2_SetOutputFileName(&This->ICaptureGraphBuilder2_iface, pType,
895 lpstrFile, ppf, ppSink);
898 static HRESULT WINAPI
899 fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface,
900 const GUID *pCategory, IBaseFilter *pf,
901 REFIID riid, void **ppint)
903 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
904 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
905 return ICaptureGraphBuilder2_FindInterface(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
906 pf, riid, ppint);
909 static HRESULT WINAPI
910 fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface,
911 const GUID *pCategory, IUnknown *pSource,
912 IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
914 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
915 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
916 return ICaptureGraphBuilder2_RenderStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
917 pSource, pfCompressor, pfRenderer);
920 static HRESULT WINAPI
921 fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface,
922 const GUID *pCategory, IBaseFilter *pFilter,
923 REFERENCE_TIME *pstart, REFERENCE_TIME *pstop,
924 WORD wStartCookie, WORD wStopCookie)
926 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
927 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
928 return ICaptureGraphBuilder2_ControlStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
929 pFilter, pstart, pstop, wStartCookie, wStopCookie);
932 static HRESULT WINAPI
933 fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface,
934 LPCOLESTR lpstr, DWORDLONG dwlSize)
936 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
937 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
938 return ICaptureGraphBuilder2_AllocCapFile(&This->ICaptureGraphBuilder2_iface, lpstr, dwlSize);
941 static HRESULT WINAPI
942 fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface,
943 LPOLESTR lpwstrOld, LPOLESTR lpwstrNew,
944 int fAllowEscAbort,
945 IAMCopyCaptureFileProgress *pCallback)
947 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
948 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
949 return ICaptureGraphBuilder2_CopyCaptureFile(&This->ICaptureGraphBuilder2_iface, lpwstrOld,
950 lpwstrNew, fAllowEscAbort, pCallback);
953 static const ICaptureGraphBuilderVtbl builder_Vtbl =
955 fnCaptureGraphBuilder_QueryInterface,
956 fnCaptureGraphBuilder_AddRef,
957 fnCaptureGraphBuilder_Release,
958 fnCaptureGraphBuilder_SetFiltergraph,
959 fnCaptureGraphBuilder_GetFiltergraph,
960 fnCaptureGraphBuilder_SetOutputFileName,
961 fnCaptureGraphBuilder_FindInterface,
962 fnCaptureGraphBuilder_RenderStream,
963 fnCaptureGraphBuilder_ControlStream,
964 fnCaptureGraphBuilder_AllocCapFile,
965 fnCaptureGraphBuilder_CopyCaptureFile