comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / qcap / capturegraph.c
blob45cef802ba2dc94cf3793604b376fcd748de39d6
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(quartz);
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 = calloc(1, 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 *out = (IUnknown *)&object->ICaptureGraphBuilder_iface;
70 return S_OK;
73 static HRESULT WINAPI
74 fnCaptureGraphBuilder2_QueryInterface(ICaptureGraphBuilder2 * iface,
75 REFIID riid,
76 LPVOID * ppv)
78 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
80 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
82 *ppv = NULL;
83 if (IsEqualIID(riid, &IID_IUnknown))
84 *ppv = &This->ICaptureGraphBuilder2_iface;
85 else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder))
86 *ppv = &This->ICaptureGraphBuilder_iface;
87 else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder2))
88 *ppv = &This->ICaptureGraphBuilder2_iface;
90 if (*ppv)
92 IUnknown_AddRef((IUnknown *)(*ppv));
93 TRACE ("-- Interface = %p\n", *ppv);
94 return S_OK;
97 TRACE ("-- Interface: E_NOINTERFACE\n");
98 return E_NOINTERFACE;
101 static ULONG WINAPI
102 fnCaptureGraphBuilder2_AddRef(ICaptureGraphBuilder2 * iface)
104 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
105 DWORD ref = InterlockedIncrement(&This->ref);
107 TRACE("%p increasing refcount to %lu.\n", This, ref);
109 return ref;
112 static ULONG WINAPI fnCaptureGraphBuilder2_Release(ICaptureGraphBuilder2 * iface)
114 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
115 ULONG ref = InterlockedDecrement(&This->ref);
117 TRACE("%p decreasing refcount to %lu.\n", This, ref);
119 if (!ref)
121 This->csFilter.DebugInfo->Spare[0] = 0;
122 DeleteCriticalSection(&This->csFilter);
123 if (This->mygraph)
124 IGraphBuilder_Release(This->mygraph);
125 free(This);
127 return ref;
130 static HRESULT WINAPI
131 fnCaptureGraphBuilder2_SetFilterGraph(ICaptureGraphBuilder2 * iface,
132 IGraphBuilder *pfg)
134 /* The graph builder will automatically create a filter graph if you don't call
135 this method. If you call this method after the graph builder has created its
136 own filter graph, the call will fail. */
137 IMediaEvent *pmev;
138 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
140 TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
142 if (This->mygraph)
143 return E_UNEXPECTED;
145 if (!pfg)
146 return E_POINTER;
148 This->mygraph = pfg;
149 IGraphBuilder_AddRef(This->mygraph);
150 if (SUCCEEDED(IGraphBuilder_QueryInterface(This->mygraph,
151 &IID_IMediaEvent, (LPVOID *)&pmev)))
153 IMediaEvent_CancelDefaultHandling(pmev, EC_REPAINT);
154 IMediaEvent_Release(pmev);
156 return S_OK;
159 static HRESULT WINAPI
160 fnCaptureGraphBuilder2_GetFilterGraph(ICaptureGraphBuilder2 * iface,
161 IGraphBuilder **pfg)
163 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
165 TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
167 if (!pfg)
168 return E_POINTER;
170 *pfg = This->mygraph;
171 if (!This->mygraph)
173 TRACE("(%p) Getting NULL filtergraph\n", iface);
174 return E_UNEXPECTED;
177 IGraphBuilder_AddRef(This->mygraph);
179 TRACE("(%p) return filtergraph %p\n", iface, *pfg);
180 return S_OK;
183 static HRESULT WINAPI
184 fnCaptureGraphBuilder2_SetOutputFileName(ICaptureGraphBuilder2 * iface,
185 const GUID *pType,
186 LPCOLESTR lpstrFile,
187 IBaseFilter **ppf,
188 IFileSinkFilter **ppSink)
190 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
192 FIXME("(%p/%p)->(%s, %s, %p, %p) Stub!\n", This, iface,
193 debugstr_guid(pType), debugstr_w(lpstrFile), ppf, ppSink);
195 return E_NOTIMPL;
198 static BOOL pin_has_majortype(IPin *pin, const GUID *majortype)
200 IEnumMediaTypes *enummt;
201 AM_MEDIA_TYPE *mt;
203 if (FAILED(IPin_EnumMediaTypes(pin, &enummt)))
204 return FALSE;
206 while (IEnumMediaTypes_Next(enummt, 1, &mt, NULL) == S_OK)
208 if (IsEqualGUID(&mt->majortype, majortype))
210 DeleteMediaType(mt);
211 IEnumMediaTypes_Release(enummt);
212 return TRUE;
214 DeleteMediaType(mt);
216 IEnumMediaTypes_Release(enummt);
217 return FALSE;
220 static BOOL pin_matches(IPin *pin, PIN_DIRECTION dir, const GUID *category,
221 const GUID *majortype, BOOL unconnected)
223 PIN_DIRECTION candidate_dir;
224 HRESULT hr;
225 IPin *peer;
227 if (FAILED(hr = IPin_QueryDirection(pin, &candidate_dir)))
228 ERR("Failed to query direction, hr %#lx.\n", hr);
230 if (dir != candidate_dir)
231 return FALSE;
233 if (unconnected && IPin_ConnectedTo(pin, &peer) == S_OK && peer)
235 IPin_Release(peer);
236 return FALSE;
239 if (category)
241 IKsPropertySet *set;
242 GUID property;
243 DWORD size;
245 if (FAILED(IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **)&set)))
246 return FALSE;
248 hr = IKsPropertySet_Get(set, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
249 NULL, 0, &property, sizeof(property), &size);
250 IKsPropertySet_Release(set);
251 if (FAILED(hr) || !IsEqualGUID(&property, category))
252 return FALSE;
255 if (majortype && !pin_has_majortype(pin, majortype))
256 return FALSE;
258 return TRUE;
261 static HRESULT find_interface_recurse(PIN_DIRECTION dir, const GUID *category,
262 const GUID *majortype, IBaseFilter *filter, REFIID iid, void **out)
264 BOOL found_category = FALSE;
265 IEnumPins *enumpins;
266 IPin *pin, *peer;
267 PIN_INFO info;
268 HRESULT hr;
270 TRACE("Looking for %s pins, category %s, majortype %s from filter %p.\n",
271 dir == PINDIR_INPUT ? "sink" : "source", debugstr_guid(category),
272 debugstr_guid(majortype), filter);
274 if (FAILED(hr = IBaseFilter_EnumPins(filter, &enumpins)))
276 ERR("Failed to enumerate pins, hr %#lx.\n", hr);
277 return hr;
280 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
282 if (!pin_matches(pin, dir, category, majortype, FALSE))
284 IPin_Release(pin);
285 continue;
288 if (category)
289 found_category = TRUE;
291 if (IPin_QueryInterface(pin, iid, out) == S_OK)
293 IPin_Release(pin);
294 IEnumPins_Release(enumpins);
295 return S_OK;
298 hr = IPin_ConnectedTo(pin, &peer);
299 IPin_Release(pin);
300 if (hr == S_OK)
302 if (IPin_QueryInterface(peer, iid, out) == S_OK)
304 IPin_Release(peer);
305 IEnumPins_Release(enumpins);
306 return S_OK;
309 IPin_QueryPinInfo(peer, &info);
310 IPin_Release(peer);
312 if (IBaseFilter_QueryInterface(info.pFilter, iid, out) == S_OK)
314 IBaseFilter_Release(info.pFilter);
315 IEnumPins_Release(enumpins);
316 return S_OK;
319 hr = find_interface_recurse(dir, NULL, NULL, info.pFilter, iid, out);
320 IBaseFilter_Release(info.pFilter);
321 if (hr == S_OK)
323 IEnumPins_Release(enumpins);
324 return S_OK;
328 IEnumPins_Release(enumpins);
330 if (category && !found_category)
331 return E_NOINTERFACE;
333 return E_FAIL;
336 static HRESULT WINAPI fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2 *iface,
337 const GUID *category, const GUID *majortype, IBaseFilter *filter, REFIID iid, void **out)
339 CaptureGraphImpl *graph = impl_from_ICaptureGraphBuilder2(iface);
340 HRESULT hr;
342 TRACE("graph %p, category %s, majortype %s, filter %p, iid %s, out %p.\n",
343 graph, debugstr_guid(category), debugstr_guid(majortype), filter, debugstr_guid(iid), out);
345 if (!filter)
346 return E_POINTER;
348 if (category && IsEqualGUID(category, &LOOK_DOWNSTREAM_ONLY))
349 return find_interface_recurse(PINDIR_OUTPUT, NULL, NULL, filter, iid, out);
351 if (category && IsEqualGUID(category, &LOOK_UPSTREAM_ONLY))
352 return find_interface_recurse(PINDIR_INPUT, NULL, NULL, filter, iid, out);
354 if (IBaseFilter_QueryInterface(filter, iid, out) == S_OK)
355 return S_OK;
357 if (!category)
358 majortype = NULL;
360 hr = find_interface_recurse(PINDIR_OUTPUT, category, majortype, filter, iid, out);
361 if (hr == S_OK || hr == E_NOINTERFACE)
362 return hr;
364 return find_interface_recurse(PINDIR_INPUT, NULL, NULL, filter, iid, out);
367 static HRESULT match_smart_tee_pin(CaptureGraphImpl *This,
368 const GUID *pCategory,
369 const GUID *pType,
370 IUnknown *pSource,
371 IPin **source_out)
373 IPin *capture = NULL;
374 IPin *preview = NULL;
375 IPin *peer = NULL;
376 IBaseFilter *smartTee = NULL;
377 BOOL needSmartTee = FALSE;
378 HRESULT hr;
380 TRACE("(%p, %s, %s, %p, %p)\n", This, debugstr_guid(pCategory), debugstr_guid(pType), pSource, source_out);
381 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
382 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, pType, FALSE, 0, &capture);
383 if (SUCCEEDED(hr)) {
384 hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource,
385 PINDIR_OUTPUT, &PIN_CATEGORY_PREVIEW, pType, FALSE, 0, &preview);
386 if (FAILED(hr))
387 needSmartTee = TRUE;
388 } else {
389 hr = E_INVALIDARG;
390 goto end;
392 if (!needSmartTee) {
393 if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE)) {
394 hr = IPin_ConnectedTo(capture, &peer);
395 if (hr == VFW_E_NOT_CONNECTED) {
396 *source_out = capture;
397 IPin_AddRef(*source_out);
398 hr = S_OK;
399 } else
400 hr = E_INVALIDARG;
401 } else {
402 hr = IPin_ConnectedTo(preview, &peer);
403 if (hr == VFW_E_NOT_CONNECTED) {
404 *source_out = preview;
405 IPin_AddRef(*source_out);
406 hr = S_OK;
407 } else
408 hr = E_INVALIDARG;
410 goto end;
412 hr = IPin_ConnectedTo(capture, &peer);
413 if (SUCCEEDED(hr)) {
414 PIN_INFO pinInfo;
415 GUID classID;
416 hr = IPin_QueryPinInfo(peer, &pinInfo);
417 if (SUCCEEDED(hr)) {
418 hr = IBaseFilter_GetClassID(pinInfo.pFilter, &classID);
419 if (SUCCEEDED(hr)) {
420 if (IsEqualIID(&classID, &CLSID_SmartTee)) {
421 smartTee = pinInfo.pFilter;
422 IBaseFilter_AddRef(smartTee);
425 IBaseFilter_Release(pinInfo.pFilter);
427 if (!smartTee) {
428 hr = E_INVALIDARG;
429 goto end;
431 } else if (hr == VFW_E_NOT_CONNECTED) {
432 hr = CoCreateInstance(&CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER,
433 &IID_IBaseFilter, (LPVOID*)&smartTee);
434 if (SUCCEEDED(hr)) {
435 hr = IGraphBuilder_AddFilter(This->mygraph, smartTee, NULL);
436 if (SUCCEEDED(hr)) {
437 IPin *smartTeeInput = NULL;
438 hr = IBaseFilter_FindPin(smartTee, L"Input", &smartTeeInput);
439 if (SUCCEEDED(hr)) {
440 hr = IGraphBuilder_ConnectDirect(This->mygraph, capture, smartTeeInput, NULL);
441 IPin_Release(smartTeeInput);
445 if (FAILED(hr)) {
446 TRACE("adding SmartTee failed with hr=0x%08lx\n", hr);
447 hr = E_INVALIDARG;
448 goto end;
450 } else {
451 hr = E_INVALIDARG;
452 goto end;
454 if (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE))
455 hr = IBaseFilter_FindPin(smartTee, L"Capture", source_out);
456 else {
457 hr = IBaseFilter_FindPin(smartTee, L"Preview", source_out);
458 if (SUCCEEDED(hr))
459 hr = VFW_S_NOPREVIEWPIN;
462 end:
463 if (capture)
464 IPin_Release(capture);
465 if (preview)
466 IPin_Release(preview);
467 if (peer)
468 IPin_Release(peer);
469 if (smartTee)
470 IBaseFilter_Release(smartTee);
471 TRACE("for %s returning hr=0x%08lx, *source_out=%p\n", IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) ? "capture" : "preview", hr, source_out ? *source_out : 0);
472 return hr;
475 static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_graph,
476 const GUID *category, const GUID *majortype, IBaseFilter *filter, IPin **ret);
478 static HRESULT find_unconnected_source_from_pin(CaptureGraphImpl *capture_graph,
479 const GUID *category, const GUID *majortype, IPin *pin, IPin **ret)
481 PIN_DIRECTION dir;
482 PIN_INFO info;
483 HRESULT hr;
484 IPin *peer;
486 IPin_QueryDirection(pin, &dir);
487 if (dir != PINDIR_OUTPUT)
488 return VFW_E_INVALID_DIRECTION;
490 if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE)
491 || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW)))
493 if (FAILED(hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)pin, &pin)))
494 return hr;
496 if (FAILED(IPin_ConnectedTo(pin, &peer)))
498 *ret = pin;
499 return S_OK;
502 else
504 if (FAILED(IPin_ConnectedTo(pin, &peer)))
506 if (!pin_matches(pin, PINDIR_OUTPUT, category, majortype, FALSE))
507 return E_FAIL;
509 IPin_AddRef(*ret = pin);
510 return S_OK;
512 IPin_AddRef(pin);
515 IPin_QueryPinInfo(peer, &info);
516 hr = find_unconnected_source_from_filter(capture_graph, category, majortype, info.pFilter, ret);
517 IBaseFilter_Release(info.pFilter);
518 IPin_Release(peer);
519 IPin_Release(pin);
520 return hr;
523 static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_graph,
524 const GUID *category, const GUID *majortype, IBaseFilter *filter, IPin **ret)
526 IEnumPins *enumpins;
527 IPin *pin, *peer;
528 HRESULT hr;
530 if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE)
531 || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW)))
533 if (FAILED(hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)filter, &pin)))
534 return hr;
536 if (FAILED(IPin_ConnectedTo(pin, &peer)))
538 *ret = pin;
539 return hr;
542 IPin_Release(peer);
543 IPin_Release(pin);
544 return E_INVALIDARG;
547 if (FAILED(hr = IBaseFilter_EnumPins(filter, &enumpins)))
548 return hr;
550 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
552 if (SUCCEEDED(hr = find_unconnected_source_from_pin(capture_graph, category, majortype, pin, ret)))
554 IEnumPins_Release(enumpins);
555 IPin_Release(pin);
556 return hr;
558 IPin_Release(pin);
560 IEnumPins_Release(enumpins);
562 return E_INVALIDARG;
565 static HRESULT WINAPI fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 *iface,
566 const GUID *category, const GUID *majortype, IUnknown *source,
567 IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
569 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
570 IPin *source_out = NULL, *renderer_in;
571 BOOL rendererNeedsRelease = FALSE;
572 HRESULT hr, return_hr = S_OK;
573 IBaseFilter *filter;
574 IPin *pin;
576 TRACE("graph %p, category %s, majortype %s, source %p, intermediate %p, sink %p.\n",
577 This, debugstr_guid(category), debugstr_guid(majortype), source, pfCompressor, pfRenderer);
579 if (!This->mygraph)
581 FIXME("Need a capture graph\n");
582 return E_UNEXPECTED;
585 if (category && IsEqualGUID(category, &PIN_CATEGORY_VBI))
587 FIXME("Tee/Sink-to-Sink filter not supported\n");
588 return E_NOTIMPL;
591 if (IUnknown_QueryInterface(source, &IID_IPin, (void **)&pin) == S_OK)
593 hr = find_unconnected_source_from_pin(This, category, majortype, pin, &source_out);
594 IPin_Release(pin);
596 else if (IUnknown_QueryInterface(source, &IID_IBaseFilter, (void **)&filter) == S_OK)
598 hr = find_unconnected_source_from_filter(This, category, majortype, filter, &source_out);
599 IBaseFilter_Release(filter);
601 else
603 WARN("Source object does not expose IBaseFilter or IPin.\n");
604 return E_INVALIDARG;
606 if (FAILED(hr))
607 return hr;
608 return_hr = hr;
610 if (!pfRenderer)
612 IEnumMediaTypes *enumMedia = NULL;
613 hr = IPin_EnumMediaTypes(source_out, &enumMedia);
614 if (SUCCEEDED(hr)) {
615 AM_MEDIA_TYPE *mediaType;
616 hr = IEnumMediaTypes_Next(enumMedia, 1, &mediaType, NULL);
617 if (SUCCEEDED(hr)) {
618 if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Video)) {
619 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
620 &IID_IBaseFilter, (void**)&pfRenderer);
621 } else if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Audio)) {
622 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
623 &IID_IBaseFilter, (void**)&pfRenderer);
624 } else {
625 FIXME("cannot automatically load renderer for majortype %s\n", debugstr_guid(&mediaType->majortype));
626 hr = E_FAIL;
628 if (SUCCEEDED(hr)) {
629 rendererNeedsRelease = TRUE;
630 hr = IGraphBuilder_AddFilter(This->mygraph, pfRenderer, NULL);
632 DeleteMediaType(mediaType);
634 IEnumMediaTypes_Release(enumMedia);
636 if (FAILED(hr)) {
637 if (rendererNeedsRelease)
638 IBaseFilter_Release(pfRenderer);
639 IPin_Release(source_out);
640 return hr;
644 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, &renderer_in);
645 if (FAILED(hr))
647 if (rendererNeedsRelease)
648 IBaseFilter_Release(pfRenderer);
649 IPin_Release(source_out);
650 return hr;
653 if (!pfCompressor)
654 hr = IGraphBuilder_Connect(This->mygraph, source_out, renderer_in);
655 else
657 IPin *compressor_in, *compressor_out;
659 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
660 PINDIR_INPUT, NULL, NULL, TRUE, 0, &compressor_in);
661 if (SUCCEEDED(hr))
663 hr = IGraphBuilder_Connect(This->mygraph, source_out, compressor_in);
664 IPin_Release(compressor_in);
667 if (SUCCEEDED(hr))
669 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
670 PINDIR_OUTPUT, NULL, NULL, TRUE, 0, &compressor_out);
671 if (SUCCEEDED(hr))
673 hr = IGraphBuilder_Connect(This->mygraph, compressor_out, renderer_in);
674 IPin_Release(compressor_out);
679 IPin_Release(source_out);
680 IPin_Release(renderer_in);
681 if (rendererNeedsRelease)
682 IBaseFilter_Release(pfRenderer);
683 if (SUCCEEDED(hr))
684 return return_hr;
685 return hr;
688 static HRESULT WINAPI
689 fnCaptureGraphBuilder2_ControlStream(ICaptureGraphBuilder2 * iface,
690 const GUID *pCategory,
691 const GUID *pType,
692 IBaseFilter *pFilter,
693 REFERENCE_TIME *pstart,
694 REFERENCE_TIME *pstop,
695 WORD wStartCookie,
696 WORD wStopCookie)
698 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
700 FIXME("(%p/%p)->(%s, %s, %p, %p, %p, %i, %i) Stub!\n", This, iface,
701 debugstr_guid(pCategory), debugstr_guid(pType),
702 pFilter, pstart, pstop, wStartCookie, wStopCookie);
704 return E_NOTIMPL;
707 static HRESULT WINAPI
708 fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2 * iface,
709 LPCOLESTR lpwstr,
710 DWORDLONG dwlSize)
712 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
714 FIXME("(%p/%p)->(%s, 0x%s) Stub!\n", This, iface,
715 debugstr_w(lpwstr), wine_dbgstr_longlong(dwlSize));
717 return E_NOTIMPL;
720 static HRESULT WINAPI
721 fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2 * iface,
722 LPOLESTR lpwstrOld,
723 LPOLESTR lpwstrNew,
724 int fAllowEscAbort,
725 IAMCopyCaptureFileProgress *pCallback)
727 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
729 FIXME("(%p/%p)->(%s, %s, %i, %p) Stub!\n", This, iface,
730 debugstr_w(lpwstrOld), debugstr_w(lpwstrNew),
731 fAllowEscAbort, pCallback);
733 return E_NOTIMPL;
736 static HRESULT WINAPI
737 fnCaptureGraphBuilder2_FindPin(ICaptureGraphBuilder2 * iface,
738 IUnknown *pSource,
739 PIN_DIRECTION pindir,
740 const GUID *pCategory,
741 const GUID *pType,
742 BOOL fUnconnected,
743 INT num,
744 IPin **ppPin)
746 HRESULT hr;
747 IEnumPins *enumpins = NULL;
748 IPin *pin;
749 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
751 TRACE("(%p/%p)->(%p, %x, %s, %s, %d, %i, %p)\n", This, iface,
752 pSource, pindir, debugstr_guid(pCategory), debugstr_guid(pType),
753 fUnconnected, num, ppPin);
755 pin = NULL;
757 hr = IUnknown_QueryInterface(pSource, &IID_IPin, (void**)&pin);
758 if (hr == E_NOINTERFACE)
760 IBaseFilter *filter = NULL;
761 int numcurrent = 0;
763 hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&filter);
764 if (hr == E_NOINTERFACE)
766 WARN("Input not filter or pin?!\n");
767 return E_NOINTERFACE;
770 hr = IBaseFilter_EnumPins(filter, &enumpins);
771 if (FAILED(hr))
773 WARN("Could not enumerate\n");
774 IBaseFilter_Release(filter);
775 return hr;
778 while (1)
780 ULONG fetched;
782 hr = IEnumPins_Next(enumpins, 1, &pin, &fetched);
783 if (hr == VFW_E_ENUM_OUT_OF_SYNC)
785 numcurrent = 0;
786 IEnumPins_Reset(enumpins);
787 pin = NULL;
788 continue;
790 if (hr != S_OK)
791 break;
792 if (fetched != 1)
794 hr = E_FAIL;
795 break;
798 TRACE("Testing match\n");
799 if (pin_matches(pin, pindir, pCategory, pType, fUnconnected) && numcurrent++ == num)
800 break;
801 IPin_Release(pin);
802 pin = NULL;
804 IEnumPins_Release(enumpins);
805 IBaseFilter_Release(filter);
807 if (hr != S_OK)
809 WARN("Could not find %s pin # %d\n", (pindir == PINDIR_OUTPUT ? "output" : "input"), numcurrent);
810 return E_FAIL;
813 else if (!pin_matches(pin, pindir, pCategory, pType, fUnconnected))
815 IPin_Release(pin);
816 return E_FAIL;
819 *ppPin = pin;
820 return S_OK;
823 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl =
825 fnCaptureGraphBuilder2_QueryInterface,
826 fnCaptureGraphBuilder2_AddRef,
827 fnCaptureGraphBuilder2_Release,
828 fnCaptureGraphBuilder2_SetFilterGraph,
829 fnCaptureGraphBuilder2_GetFilterGraph,
830 fnCaptureGraphBuilder2_SetOutputFileName,
831 fnCaptureGraphBuilder2_FindInterface,
832 fnCaptureGraphBuilder2_RenderStream,
833 fnCaptureGraphBuilder2_ControlStream,
834 fnCaptureGraphBuilder2_AllocCapFile,
835 fnCaptureGraphBuilder2_CopyCaptureFile,
836 fnCaptureGraphBuilder2_FindPin
840 static HRESULT WINAPI
841 fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface,
842 REFIID riid, LPVOID * ppv)
844 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
845 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
846 return ICaptureGraphBuilder2_QueryInterface(&This->ICaptureGraphBuilder2_iface, riid, ppv);
849 static ULONG WINAPI
850 fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
852 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
853 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
854 return ICaptureGraphBuilder2_AddRef(&This->ICaptureGraphBuilder2_iface);
857 static ULONG WINAPI
858 fnCaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
860 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
861 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
862 return ICaptureGraphBuilder2_Release(&This->ICaptureGraphBuilder2_iface);
865 static HRESULT WINAPI
866 fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder * iface,
867 IGraphBuilder *pfg)
869 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
870 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
871 return ICaptureGraphBuilder2_SetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
874 static HRESULT WINAPI
875 fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder * iface,
876 IGraphBuilder **pfg)
878 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
879 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
880 return ICaptureGraphBuilder2_GetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
883 static HRESULT WINAPI
884 fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface,
885 const GUID *pType, LPCOLESTR lpstrFile,
886 IBaseFilter **ppf, IFileSinkFilter **ppSink)
888 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
889 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
890 return ICaptureGraphBuilder2_SetOutputFileName(&This->ICaptureGraphBuilder2_iface, pType,
891 lpstrFile, ppf, ppSink);
894 static HRESULT WINAPI
895 fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface,
896 const GUID *pCategory, IBaseFilter *pf,
897 REFIID riid, void **ppint)
899 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
900 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
901 return ICaptureGraphBuilder2_FindInterface(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
902 pf, riid, ppint);
905 static HRESULT WINAPI
906 fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface,
907 const GUID *pCategory, IUnknown *pSource,
908 IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
910 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
911 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
912 return ICaptureGraphBuilder2_RenderStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
913 pSource, pfCompressor, pfRenderer);
916 static HRESULT WINAPI
917 fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface,
918 const GUID *pCategory, IBaseFilter *pFilter,
919 REFERENCE_TIME *pstart, REFERENCE_TIME *pstop,
920 WORD wStartCookie, WORD wStopCookie)
922 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
923 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
924 return ICaptureGraphBuilder2_ControlStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
925 pFilter, pstart, pstop, wStartCookie, wStopCookie);
928 static HRESULT WINAPI
929 fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface,
930 LPCOLESTR lpstr, DWORDLONG dwlSize)
932 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
933 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
934 return ICaptureGraphBuilder2_AllocCapFile(&This->ICaptureGraphBuilder2_iface, lpstr, dwlSize);
937 static HRESULT WINAPI
938 fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface,
939 LPOLESTR lpwstrOld, LPOLESTR lpwstrNew,
940 int fAllowEscAbort,
941 IAMCopyCaptureFileProgress *pCallback)
943 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
944 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
945 return ICaptureGraphBuilder2_CopyCaptureFile(&This->ICaptureGraphBuilder2_iface, lpwstrOld,
946 lpwstrNew, fAllowEscAbort, pCallback);
949 static const ICaptureGraphBuilderVtbl builder_Vtbl =
951 fnCaptureGraphBuilder_QueryInterface,
952 fnCaptureGraphBuilder_AddRef,
953 fnCaptureGraphBuilder_Release,
954 fnCaptureGraphBuilder_SetFiltergraph,
955 fnCaptureGraphBuilder_GetFiltergraph,
956 fnCaptureGraphBuilder_SetOutputFileName,
957 fnCaptureGraphBuilder_FindInterface,
958 fnCaptureGraphBuilder_RenderStream,
959 fnCaptureGraphBuilder_ControlStream,
960 fnCaptureGraphBuilder_AllocCapFile,
961 fnCaptureGraphBuilder_CopyCaptureFile