msvcirt: Add implementation of streambuf::sputbackc.
[wine.git] / dlls / qcap / capturegraph.c
blob372e16f91ee7908e7e7a946d77404340060c02c7
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;
364 static HRESULT WINAPI
365 fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
366 const GUID *pCategory,
367 const GUID *pType,
368 IUnknown *pSource,
369 IBaseFilter *pfCompressor,
370 IBaseFilter *pfRenderer)
372 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
373 IPin *source_out = NULL, *renderer_in;
374 BOOL rendererNeedsRelease = FALSE;
375 BOOL usedSmartTeePreviewPin = FALSE;
376 HRESULT hr;
378 FIXME("(%p/%p)->(%s, %s, %p, %p, %p) semi-stub!\n", This, iface,
379 debugstr_guid(pCategory), debugstr_guid(pType),
380 pSource, pfCompressor, pfRenderer);
382 if (!This->mygraph)
384 FIXME("Need a capture graph\n");
385 return E_UNEXPECTED;
388 if (pCategory && IsEqualIID(pCategory, &PIN_CATEGORY_VBI)) {
389 FIXME("Tee/Sink-to-Sink filter not supported\n");
390 return E_NOTIMPL;
391 } else if (pCategory && (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) || IsEqualIID(pCategory, &PIN_CATEGORY_PREVIEW))){
392 IBaseFilter *sourceFilter = NULL;
393 hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&sourceFilter);
394 if (SUCCEEDED(hr)) {
395 hr = match_smart_tee_pin(This, pCategory, pType, pSource, &source_out);
396 if (hr == VFW_S_NOPREVIEWPIN)
397 usedSmartTeePreviewPin = TRUE;
398 IBaseFilter_Release(sourceFilter);
399 } else {
400 hr = ICaptureGraphBuilder2_FindPin(iface, pSource, PINDIR_OUTPUT, pCategory, pType, TRUE, 0, &source_out);
402 if (FAILED(hr))
403 return E_INVALIDARG;
404 } else {
405 hr = ICaptureGraphBuilder2_FindPin(iface, pSource, PINDIR_OUTPUT, pCategory, pType, TRUE, 0, &source_out);
406 if (FAILED(hr))
407 return E_INVALIDARG;
410 if (!pfRenderer)
412 IEnumMediaTypes *enumMedia = NULL;
413 hr = IPin_EnumMediaTypes(source_out, &enumMedia);
414 if (SUCCEEDED(hr)) {
415 AM_MEDIA_TYPE *mediaType;
416 hr = IEnumMediaTypes_Next(enumMedia, 1, &mediaType, NULL);
417 if (SUCCEEDED(hr)) {
418 if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Video)) {
419 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
420 &IID_IBaseFilter, (void**)&pfRenderer);
421 } else if (IsEqualIID(&mediaType->majortype, &MEDIATYPE_Audio)) {
422 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
423 &IID_IBaseFilter, (void**)&pfRenderer);
424 } else {
425 FIXME("cannot automatically load renderer for majortype %s\n", debugstr_guid(&mediaType->majortype));
426 hr = E_FAIL;
428 if (SUCCEEDED(hr)) {
429 rendererNeedsRelease = TRUE;
430 hr = IGraphBuilder_AddFilter(This->mygraph, pfRenderer, NULL);
432 DeleteMediaType(mediaType);
434 IEnumMediaTypes_Release(enumMedia);
436 if (FAILED(hr)) {
437 if (rendererNeedsRelease)
438 IBaseFilter_Release(pfRenderer);
439 IPin_Release(source_out);
440 return hr;
444 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, &renderer_in);
445 if (FAILED(hr))
447 if (rendererNeedsRelease)
448 IBaseFilter_Release(pfRenderer);
449 IPin_Release(source_out);
450 return hr;
453 if (!pfCompressor)
454 hr = IGraphBuilder_Connect(This->mygraph, source_out, renderer_in);
455 else
457 IPin *compressor_in, *compressor_out;
459 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
460 PINDIR_INPUT, NULL, NULL, TRUE, 0, &compressor_in);
461 if (SUCCEEDED(hr))
463 hr = IGraphBuilder_Connect(This->mygraph, source_out, compressor_in);
464 IPin_Release(compressor_in);
467 if (SUCCEEDED(hr))
469 hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
470 PINDIR_OUTPUT, NULL, NULL, TRUE, 0, &compressor_out);
471 if (SUCCEEDED(hr))
473 hr = IGraphBuilder_Connect(This->mygraph, compressor_out, renderer_in);
474 IPin_Release(compressor_out);
479 IPin_Release(source_out);
480 IPin_Release(renderer_in);
481 if (rendererNeedsRelease)
482 IBaseFilter_Release(pfRenderer);
483 if (SUCCEEDED(hr) && usedSmartTeePreviewPin)
484 hr = VFW_S_NOPREVIEWPIN;
485 return hr;
488 static HRESULT WINAPI
489 fnCaptureGraphBuilder2_ControlStream(ICaptureGraphBuilder2 * iface,
490 const GUID *pCategory,
491 const GUID *pType,
492 IBaseFilter *pFilter,
493 REFERENCE_TIME *pstart,
494 REFERENCE_TIME *pstop,
495 WORD wStartCookie,
496 WORD wStopCookie)
498 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
500 FIXME("(%p/%p)->(%s, %s, %p, %p, %p, %i, %i) Stub!\n", This, iface,
501 debugstr_guid(pCategory), debugstr_guid(pType),
502 pFilter, pstart, pstop, wStartCookie, wStopCookie);
504 return E_NOTIMPL;
507 static HRESULT WINAPI
508 fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2 * iface,
509 LPCOLESTR lpwstr,
510 DWORDLONG dwlSize)
512 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
514 FIXME("(%p/%p)->(%s, 0x%s) Stub!\n", This, iface,
515 debugstr_w(lpwstr), wine_dbgstr_longlong(dwlSize));
517 return E_NOTIMPL;
520 static HRESULT WINAPI
521 fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2 * iface,
522 LPOLESTR lpwstrOld,
523 LPOLESTR lpwstrNew,
524 int fAllowEscAbort,
525 IAMCopyCaptureFileProgress *pCallback)
527 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
529 FIXME("(%p/%p)->(%s, %s, %i, %p) Stub!\n", This, iface,
530 debugstr_w(lpwstrOld), debugstr_w(lpwstrNew),
531 fAllowEscAbort, pCallback);
533 return E_NOTIMPL;
536 static HRESULT pin_matches(IPin *pin, PIN_DIRECTION direction, const GUID *cat, const GUID *type, BOOL unconnected)
538 IPin *partner;
539 PIN_DIRECTION pindir;
540 HRESULT hr;
542 hr = IPin_QueryDirection(pin, &pindir);
544 if (unconnected && IPin_ConnectedTo(pin, &partner) == S_OK && partner!=NULL)
546 IPin_Release(partner);
547 TRACE("No match, %p already connected to %p\n", pin, partner);
548 return FAILED(hr) ? hr : S_FALSE;
551 if (FAILED(hr))
552 return hr;
553 if (SUCCEEDED(hr) && pindir != direction)
554 return S_FALSE;
556 if (cat)
558 IKsPropertySet *props;
559 GUID category;
560 DWORD fetched;
562 hr = IPin_QueryInterface(pin, &IID_IKsPropertySet, (void**)&props);
563 if (FAILED(hr))
564 return S_FALSE;
566 hr = IKsPropertySet_Get(props, &AMPROPSETID_Pin, 0, NULL,
567 0, &category, sizeof(category), &fetched);
568 IKsPropertySet_Release(props);
569 if (FAILED(hr) || !IsEqualIID(&category, cat))
570 return S_FALSE;
573 if (type)
575 IEnumMediaTypes *types;
576 AM_MEDIA_TYPE *media_type;
577 ULONG fetched;
579 hr = IPin_EnumMediaTypes(pin, &types);
580 if (FAILED(hr))
581 return S_FALSE;
583 IEnumMediaTypes_Reset(types);
584 while (1) {
585 if (IEnumMediaTypes_Next(types, 1, &media_type, &fetched) != S_OK || fetched != 1)
587 IEnumMediaTypes_Release(types);
588 return S_FALSE;
591 if (IsEqualIID(&media_type->majortype, type))
593 DeleteMediaType(media_type);
594 break;
596 DeleteMediaType(media_type);
598 IEnumMediaTypes_Release(types);
601 TRACE("Pin matched\n");
602 return S_OK;
605 static HRESULT WINAPI
606 fnCaptureGraphBuilder2_FindPin(ICaptureGraphBuilder2 * iface,
607 IUnknown *pSource,
608 PIN_DIRECTION pindir,
609 const GUID *pCategory,
610 const GUID *pType,
611 BOOL fUnconnected,
612 INT num,
613 IPin **ppPin)
615 HRESULT hr;
616 IEnumPins *enumpins = NULL;
617 IPin *pin;
618 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
620 TRACE("(%p/%p)->(%p, %x, %s, %s, %d, %i, %p)\n", This, iface,
621 pSource, pindir, debugstr_guid(pCategory), debugstr_guid(pType),
622 fUnconnected, num, ppPin);
624 pin = NULL;
626 hr = IUnknown_QueryInterface(pSource, &IID_IPin, (void**)&pin);
627 if (hr == E_NOINTERFACE)
629 IBaseFilter *filter = NULL;
630 int numcurrent = 0;
632 hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&filter);
633 if (hr == E_NOINTERFACE)
635 WARN("Input not filter or pin?!\n");
636 return E_NOINTERFACE;
639 hr = IBaseFilter_EnumPins(filter, &enumpins);
640 if (FAILED(hr))
642 WARN("Could not enumerate\n");
643 return hr;
646 while (1)
648 ULONG fetched;
650 hr = IEnumPins_Next(enumpins, 1, &pin, &fetched);
651 if (hr == VFW_E_ENUM_OUT_OF_SYNC)
653 numcurrent = 0;
654 IEnumPins_Reset(enumpins);
655 pin = NULL;
656 continue;
658 if (hr != S_OK)
659 break;
660 if (fetched != 1)
662 hr = E_FAIL;
663 break;
666 TRACE("Testing match\n");
667 hr = pin_matches(pin, pindir, pCategory, pType, fUnconnected);
668 if (hr == S_OK && numcurrent++ == num)
669 break;
670 IPin_Release(pin);
671 pin = NULL;
672 if (FAILED(hr))
673 break;
675 IEnumPins_Release(enumpins);
677 if (hr != S_OK)
679 WARN("Could not find %s pin # %d\n", (pindir == PINDIR_OUTPUT ? "output" : "input"), numcurrent);
680 return E_FAIL;
683 else if (pin_matches(pin, pindir, pCategory, pType, fUnconnected) != S_OK)
685 IPin_Release(pin);
686 return E_FAIL;
689 *ppPin = pin;
690 return S_OK;
693 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl =
695 fnCaptureGraphBuilder2_QueryInterface,
696 fnCaptureGraphBuilder2_AddRef,
697 fnCaptureGraphBuilder2_Release,
698 fnCaptureGraphBuilder2_SetFilterGraph,
699 fnCaptureGraphBuilder2_GetFilterGraph,
700 fnCaptureGraphBuilder2_SetOutputFileName,
701 fnCaptureGraphBuilder2_FindInterface,
702 fnCaptureGraphBuilder2_RenderStream,
703 fnCaptureGraphBuilder2_ControlStream,
704 fnCaptureGraphBuilder2_AllocCapFile,
705 fnCaptureGraphBuilder2_CopyCaptureFile,
706 fnCaptureGraphBuilder2_FindPin
710 static HRESULT WINAPI
711 fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface,
712 REFIID riid, LPVOID * ppv)
714 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
715 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
716 return ICaptureGraphBuilder2_QueryInterface(&This->ICaptureGraphBuilder2_iface, riid, ppv);
719 static ULONG WINAPI
720 fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
722 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
723 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
724 return ICaptureGraphBuilder2_AddRef(&This->ICaptureGraphBuilder2_iface);
727 static ULONG WINAPI
728 fnCaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
730 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
731 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
732 return ICaptureGraphBuilder2_Release(&This->ICaptureGraphBuilder2_iface);
735 static HRESULT WINAPI
736 fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder * iface,
737 IGraphBuilder *pfg)
739 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
740 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
741 return ICaptureGraphBuilder2_SetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
744 static HRESULT WINAPI
745 fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder * iface,
746 IGraphBuilder **pfg)
748 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
749 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
750 return ICaptureGraphBuilder2_GetFiltergraph(&This->ICaptureGraphBuilder2_iface, pfg);
753 static HRESULT WINAPI
754 fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface,
755 const GUID *pType, LPCOLESTR lpstrFile,
756 IBaseFilter **ppf, IFileSinkFilter **ppSink)
758 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
759 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
760 return ICaptureGraphBuilder2_SetOutputFileName(&This->ICaptureGraphBuilder2_iface, pType,
761 lpstrFile, ppf, ppSink);
764 static HRESULT WINAPI
765 fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface,
766 const GUID *pCategory, IBaseFilter *pf,
767 REFIID riid, void **ppint)
769 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
770 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
771 return ICaptureGraphBuilder2_FindInterface(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
772 pf, riid, ppint);
775 static HRESULT WINAPI
776 fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface,
777 const GUID *pCategory, IUnknown *pSource,
778 IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
780 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
781 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
782 return ICaptureGraphBuilder2_RenderStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
783 pSource, pfCompressor, pfRenderer);
786 static HRESULT WINAPI
787 fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface,
788 const GUID *pCategory, IBaseFilter *pFilter,
789 REFERENCE_TIME *pstart, REFERENCE_TIME *pstop,
790 WORD wStartCookie, WORD wStopCookie)
792 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
793 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
794 return ICaptureGraphBuilder2_ControlStream(&This->ICaptureGraphBuilder2_iface, pCategory, NULL,
795 pFilter, pstart, pstop, wStartCookie, wStopCookie);
798 static HRESULT WINAPI
799 fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface,
800 LPCOLESTR lpstr, DWORDLONG dwlSize)
802 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
803 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
804 return ICaptureGraphBuilder2_AllocCapFile(&This->ICaptureGraphBuilder2_iface, lpstr, dwlSize);
807 static HRESULT WINAPI
808 fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface,
809 LPOLESTR lpwstrOld, LPOLESTR lpwstrNew,
810 int fAllowEscAbort,
811 IAMCopyCaptureFileProgress *pCallback)
813 CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
814 TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
815 return ICaptureGraphBuilder2_CopyCaptureFile(&This->ICaptureGraphBuilder2_iface, lpwstrOld,
816 lpwstrNew, fAllowEscAbort, pCallback);
819 static const ICaptureGraphBuilderVtbl builder_Vtbl =
821 fnCaptureGraphBuilder_QueryInterface,
822 fnCaptureGraphBuilder_AddRef,
823 fnCaptureGraphBuilder_Release,
824 fnCaptureGraphBuilder_SetFiltergraph,
825 fnCaptureGraphBuilder_GetFiltergraph,
826 fnCaptureGraphBuilder_SetOutputFileName,
827 fnCaptureGraphBuilder_FindInterface,
828 fnCaptureGraphBuilder_RenderStream,
829 fnCaptureGraphBuilder_ControlStream,
830 fnCaptureGraphBuilder_AllocCapFile,
831 fnCaptureGraphBuilder_CopyCaptureFile