xref: /reactos/dll/directx/wine/qcap/capturegraph.c (revision 56aa5137)
1 /* Capture Graph Builder, Minimal edition
2  *
3  * Copyright 2005 Maarten Lankhorst
4  * Copyright 2005 Rolf Kalbermatter
5  *
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.
10  *
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.
15  *
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
19  */
20 #include "config.h"
21 
22 #include <stdio.h>
23 #include <stdarg.h>
24 
25 #define COBJMACROS
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winerror.h"
31 #include "objbase.h"
32 
33 #include "evcode.h"
34 #include "strmif.h"
35 #include "control.h"
36 #include "vfwmsgs.h"
37 /*
38  *#include "amvideo.h"
39  *#include "mmreg.h"
40  *#include "dshow.h"
41  *#include "ddraw.h"
42  */
43 #include "uuids.h"
44 #include "qcap_main.h"
45 
46 #include "wine/unicode.h"
47 #include "wine/debug.h"
48 
49 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
50 
51 /***********************************************************************
52 *   ICaptureGraphBuilder & ICaptureGraphBuilder2 implementation
53 */
54 typedef struct CaptureGraphImpl
55 {
56     ICaptureGraphBuilder2 ICaptureGraphBuilder2_iface;
57     ICaptureGraphBuilder ICaptureGraphBuilder_iface;
58     LONG ref;
59     IGraphBuilder *mygraph;
60     CRITICAL_SECTION csFilter;
61 } CaptureGraphImpl;
62 
63 static const ICaptureGraphBuilderVtbl builder_Vtbl;
64 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl;
65 
impl_from_ICaptureGraphBuilder(ICaptureGraphBuilder * iface)66 static inline CaptureGraphImpl *impl_from_ICaptureGraphBuilder(ICaptureGraphBuilder *iface)
67 {
68     return CONTAINING_RECORD(iface, CaptureGraphImpl, ICaptureGraphBuilder_iface);
69 }
70 
impl_from_ICaptureGraphBuilder2(ICaptureGraphBuilder2 * iface)71 static inline CaptureGraphImpl *impl_from_ICaptureGraphBuilder2(ICaptureGraphBuilder2 *iface)
72 {
73     return CONTAINING_RECORD(iface, CaptureGraphImpl, ICaptureGraphBuilder2_iface);
74 }
75 
76 
QCAP_createCaptureGraphBuilder2(IUnknown * pUnkOuter,HRESULT * phr)77 IUnknown * CALLBACK QCAP_createCaptureGraphBuilder2(IUnknown *pUnkOuter,
78                                                     HRESULT *phr)
79 {
80     CaptureGraphImpl * pCapture = NULL;
81 
82     TRACE("(%p, %p)\n", pUnkOuter, phr);
83 
84     *phr = CLASS_E_NOAGGREGATION;
85     if (pUnkOuter)
86     {
87         return NULL;
88     }
89     *phr = E_OUTOFMEMORY;
90 
91     pCapture = CoTaskMemAlloc(sizeof(CaptureGraphImpl));
92     if (pCapture)
93     {
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);
102     }
103     return (IUnknown *)&pCapture->ICaptureGraphBuilder_iface;
104 }
105 
106 static HRESULT WINAPI
fnCaptureGraphBuilder2_QueryInterface(ICaptureGraphBuilder2 * iface,REFIID riid,LPVOID * ppv)107 fnCaptureGraphBuilder2_QueryInterface(ICaptureGraphBuilder2 * iface,
108                                       REFIID riid,
109                                       LPVOID * ppv)
110 {
111     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
112 
113     TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
114 
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;
122 
123     if (*ppv)
124     {
125         IUnknown_AddRef((IUnknown *)(*ppv));
126         TRACE ("-- Interface = %p\n", *ppv);
127         return S_OK;
128     }
129 
130     TRACE ("-- Interface: E_NOINTERFACE\n");
131     return E_NOINTERFACE;
132 }
133 
134 static ULONG WINAPI
fnCaptureGraphBuilder2_AddRef(ICaptureGraphBuilder2 * iface)135 fnCaptureGraphBuilder2_AddRef(ICaptureGraphBuilder2 * iface)
136 {
137     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
138     DWORD ref = InterlockedIncrement(&This->ref);
139 
140     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, ref - 1);
141     return ref;
142 }
143 
fnCaptureGraphBuilder2_Release(ICaptureGraphBuilder2 * iface)144 static ULONG WINAPI fnCaptureGraphBuilder2_Release(ICaptureGraphBuilder2 * iface)
145 {
146     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
147     DWORD ref = InterlockedDecrement(&This->ref);
148 
149     TRACE("(%p/%p)->() Release from %d\n", This, iface, ref + 1);
150 
151     if (!ref)
152     {
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);
159     }
160     return ref;
161 }
162 
163 static HRESULT WINAPI
fnCaptureGraphBuilder2_SetFilterGraph(ICaptureGraphBuilder2 * iface,IGraphBuilder * pfg)164 fnCaptureGraphBuilder2_SetFilterGraph(ICaptureGraphBuilder2 * iface,
165                                       IGraphBuilder *pfg)
166 {
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);
172 
173     TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
174 
175     if (This->mygraph)
176         return E_UNEXPECTED;
177 
178     if (!pfg)
179         return E_POINTER;
180 
181     This->mygraph = pfg;
182     IGraphBuilder_AddRef(This->mygraph);
183     if (SUCCEEDED(IGraphBuilder_QueryInterface(This->mygraph,
184                                           &IID_IMediaEvent, (LPVOID *)&pmev)))
185     {
186         IMediaEvent_CancelDefaultHandling(pmev, EC_REPAINT);
187         IMediaEvent_Release(pmev);
188     }
189     return S_OK;
190 }
191 
192 static HRESULT WINAPI
fnCaptureGraphBuilder2_GetFilterGraph(ICaptureGraphBuilder2 * iface,IGraphBuilder ** pfg)193 fnCaptureGraphBuilder2_GetFilterGraph(ICaptureGraphBuilder2 * iface,
194                                       IGraphBuilder **pfg)
195 {
196     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
197 
198     TRACE("(%p/%p)->(%p)\n", This, iface, pfg);
199 
200     if (!pfg)
201         return E_POINTER;
202 
203     *pfg = This->mygraph;
204     if (!This->mygraph)
205     {
206         TRACE("(%p) Getting NULL filtergraph\n", iface);
207         return E_UNEXPECTED;
208     }
209 
210     IGraphBuilder_AddRef(This->mygraph);
211 
212     TRACE("(%p) return filtergraph %p\n", iface, *pfg);
213     return S_OK;
214 }
215 
216 static HRESULT WINAPI
fnCaptureGraphBuilder2_SetOutputFileName(ICaptureGraphBuilder2 * iface,const GUID * pType,LPCOLESTR lpstrFile,IBaseFilter ** ppf,IFileSinkFilter ** ppSink)217 fnCaptureGraphBuilder2_SetOutputFileName(ICaptureGraphBuilder2 * iface,
218                                          const GUID *pType,
219                                          LPCOLESTR lpstrFile,
220                                          IBaseFilter **ppf,
221                                          IFileSinkFilter **ppSink)
222 {
223     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
224 
225     FIXME("(%p/%p)->(%s, %s, %p, %p) Stub!\n", This, iface,
226           debugstr_guid(pType), debugstr_w(lpstrFile), ppf, ppSink);
227 
228     return E_NOTIMPL;
229 }
230 
231 static HRESULT WINAPI
fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2 * iface,const GUID * pCategory,const GUID * pType,IBaseFilter * pf,REFIID riid,void ** ppint)232 fnCaptureGraphBuilder2_FindInterface(ICaptureGraphBuilder2 * iface,
233                                      const GUID *pCategory,
234                                      const GUID *pType,
235                                      IBaseFilter *pf,
236                                      REFIID riid,
237                                      void **ppint)
238 {
239     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
240 
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);
244 
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.
249      */
250 }
251 
match_smart_tee_pin(CaptureGraphImpl * This,const GUID * pCategory,const GUID * pType,IUnknown * pSource,IPin ** source_out)252 static HRESULT match_smart_tee_pin(CaptureGraphImpl *This,
253                                    const GUID *pCategory,
254                                    const GUID *pType,
255                                    IUnknown *pSource,
256                                    IPin **source_out)
257 {
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;
267 
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;
279     }
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;
297         }
298         goto end;
299     }
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);
311                 }
312             }
313             IBaseFilter_Release(pinInfo.pFilter);
314         }
315         if (!smartTee) {
316             hr = E_INVALIDARG;
317             goto end;
318         }
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);
330                 }
331             }
332         }
333         if (FAILED(hr)) {
334             TRACE("adding SmartTee failed with hr=0x%08x\n", hr);
335             hr = E_INVALIDARG;
336             goto end;
337         }
338     } else {
339         hr = E_INVALIDARG;
340         goto end;
341     }
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;
348     }
349 
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;
361 }
362 
find_unconnected_pin(CaptureGraphImpl * This,const GUID * pCategory,const GUID * pType,IUnknown * pSource,IPin ** out_pin)363 static HRESULT find_unconnected_pin(CaptureGraphImpl *This,
364         const GUID *pCategory, const GUID *pType, IUnknown *pSource, IPin **out_pin)
365 {
366     int index = 0;
367     IPin *source_out;
368     HRESULT hr;
369     BOOL usedSmartTeePreviewPin = FALSE;
370 
371     /* depth-first search the graph for the first unconnected pin that matches
372      * the given category and type */
373     for(;;){
374         IPin *nextpin;
375 
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);
386             }
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;
393         }
394 
395         hr = IPin_ConnectedTo(source_out, &nextpin);
396         if(SUCCEEDED(hr)){
397             PIN_INFO info;
398 
399             IPin_Release(source_out);
400 
401             hr = IPin_QueryPinInfo(nextpin, &info);
402             if(FAILED(hr) || !info.pFilter){
403                 WARN("QueryPinInfo failed: %08x\n", hr);
404                 return hr;
405             }
406 
407             hr = find_unconnected_pin(This, pCategory, pType, (IUnknown*)info.pFilter, out_pin);
408 
409             IBaseFilter_Release(info.pFilter);
410 
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;
418         }
419 
420         index++;
421     }
422 }
423 
424 static HRESULT WINAPI
fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,const GUID * pCategory,const GUID * pType,IUnknown * pSource,IBaseFilter * pfCompressor,IBaseFilter * pfRenderer)425 fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface,
426                                     const GUID *pCategory,
427                                     const GUID *pType,
428                                     IUnknown *pSource,
429                                     IBaseFilter *pfCompressor,
430                                     IBaseFilter *pfRenderer)
431 {
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;
436 
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);
440 
441     if (!This->mygraph)
442     {
443         FIXME("Need a capture graph\n");
444         return E_UNEXPECTED;
445     }
446 
447     if (pCategory && IsEqualIID(pCategory, &PIN_CATEGORY_VBI)) {
448         FIXME("Tee/Sink-to-Sink filter not supported\n");
449         return E_NOTIMPL;
450     }
451 
452     hr = find_unconnected_pin(This, pCategory, pType, pSource, &source_out);
453     if (FAILED(hr))
454         return hr;
455     return_hr = hr;
456 
457     if (!pfRenderer)
458     {
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;
474                 }
475                 if (SUCCEEDED(hr)) {
476                     rendererNeedsRelease = TRUE;
477                     hr = IGraphBuilder_AddFilter(This->mygraph, pfRenderer, NULL);
478                 }
479                 DeleteMediaType(mediaType);
480             }
481             IEnumMediaTypes_Release(enumMedia);
482         }
483         if (FAILED(hr)) {
484             if (rendererNeedsRelease)
485                 IBaseFilter_Release(pfRenderer);
486             IPin_Release(source_out);
487             return hr;
488         }
489     }
490 
491     hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, &renderer_in);
492     if (FAILED(hr))
493     {
494         if (rendererNeedsRelease)
495             IBaseFilter_Release(pfRenderer);
496         IPin_Release(source_out);
497         return hr;
498     }
499 
500     if (!pfCompressor)
501         hr = IGraphBuilder_Connect(This->mygraph, source_out, renderer_in);
502     else
503     {
504         IPin *compressor_in, *compressor_out;
505 
506         hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
507                 PINDIR_INPUT, NULL, NULL, TRUE, 0, &compressor_in);
508         if (SUCCEEDED(hr))
509         {
510             hr = IGraphBuilder_Connect(This->mygraph, source_out, compressor_in);
511             IPin_Release(compressor_in);
512         }
513 
514         if (SUCCEEDED(hr))
515         {
516             hr = ICaptureGraphBuilder2_FindPin(iface, (IUnknown*)pfCompressor,
517                     PINDIR_OUTPUT, NULL, NULL, TRUE, 0, &compressor_out);
518             if (SUCCEEDED(hr))
519             {
520                 hr = IGraphBuilder_Connect(This->mygraph, compressor_out, renderer_in);
521                 IPin_Release(compressor_out);
522             }
523         }
524     }
525 
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;
533 }
534 
535 static HRESULT WINAPI
fnCaptureGraphBuilder2_ControlStream(ICaptureGraphBuilder2 * iface,const GUID * pCategory,const GUID * pType,IBaseFilter * pFilter,REFERENCE_TIME * pstart,REFERENCE_TIME * pstop,WORD wStartCookie,WORD wStopCookie)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)
544 {
545     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
546 
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);
550 
551     return E_NOTIMPL;
552 }
553 
554 static HRESULT WINAPI
fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2 * iface,LPCOLESTR lpwstr,DWORDLONG dwlSize)555 fnCaptureGraphBuilder2_AllocCapFile(ICaptureGraphBuilder2 * iface,
556                                     LPCOLESTR lpwstr,
557                                     DWORDLONG dwlSize)
558 {
559     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
560 
561     FIXME("(%p/%p)->(%s, 0x%s) Stub!\n", This, iface,
562           debugstr_w(lpwstr), wine_dbgstr_longlong(dwlSize));
563 
564     return E_NOTIMPL;
565 }
566 
567 static HRESULT WINAPI
fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2 * iface,LPOLESTR lpwstrOld,LPOLESTR lpwstrNew,int fAllowEscAbort,IAMCopyCaptureFileProgress * pCallback)568 fnCaptureGraphBuilder2_CopyCaptureFile(ICaptureGraphBuilder2 * iface,
569                                        LPOLESTR lpwstrOld,
570                                        LPOLESTR lpwstrNew,
571                                        int fAllowEscAbort,
572                                        IAMCopyCaptureFileProgress *pCallback)
573 {
574     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
575 
576     FIXME("(%p/%p)->(%s, %s, %i, %p) Stub!\n", This, iface,
577           debugstr_w(lpwstrOld), debugstr_w(lpwstrNew),
578           fAllowEscAbort, pCallback);
579 
580     return E_NOTIMPL;
581 }
582 
pin_matches(IPin * pin,PIN_DIRECTION direction,const GUID * cat,const GUID * type,BOOL unconnected)583 static HRESULT pin_matches(IPin *pin, PIN_DIRECTION direction, const GUID *cat, const GUID *type, BOOL unconnected)
584 {
585     IPin *partner;
586     PIN_DIRECTION pindir;
587     HRESULT hr;
588 
589     hr = IPin_QueryDirection(pin, &pindir);
590 
591     if (unconnected && IPin_ConnectedTo(pin, &partner) == S_OK && partner!=NULL)
592     {
593         IPin_Release(partner);
594         TRACE("No match, %p already connected to %p\n", pin, partner);
595         return FAILED(hr) ? hr : S_FALSE;
596     }
597 
598     if (FAILED(hr))
599         return hr;
600     if (SUCCEEDED(hr) && pindir != direction)
601         return S_FALSE;
602 
603     if (cat)
604     {
605         IKsPropertySet *props;
606         GUID category;
607         DWORD fetched;
608 
609         hr = IPin_QueryInterface(pin, &IID_IKsPropertySet, (void**)&props);
610         if (FAILED(hr))
611             return S_FALSE;
612 
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;
618     }
619 
620     if (type)
621     {
622         IEnumMediaTypes *types;
623         AM_MEDIA_TYPE *media_type;
624         ULONG fetched;
625 
626         hr = IPin_EnumMediaTypes(pin, &types);
627         if (FAILED(hr))
628             return S_FALSE;
629 
630         IEnumMediaTypes_Reset(types);
631         while (1) {
632             if (IEnumMediaTypes_Next(types, 1, &media_type, &fetched) != S_OK || fetched != 1)
633             {
634                 IEnumMediaTypes_Release(types);
635                 return S_FALSE;
636             }
637 
638             if (IsEqualIID(&media_type->majortype, type))
639             {
640                 DeleteMediaType(media_type);
641                 break;
642             }
643             DeleteMediaType(media_type);
644         }
645         IEnumMediaTypes_Release(types);
646     }
647 
648     TRACE("Pin matched\n");
649     return S_OK;
650 }
651 
652 static HRESULT WINAPI
fnCaptureGraphBuilder2_FindPin(ICaptureGraphBuilder2 * iface,IUnknown * pSource,PIN_DIRECTION pindir,const GUID * pCategory,const GUID * pType,BOOL fUnconnected,INT num,IPin ** ppPin)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)
661 {
662     HRESULT hr;
663     IEnumPins *enumpins = NULL;
664     IPin *pin;
665     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface);
666 
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);
670 
671     pin = NULL;
672 
673     hr = IUnknown_QueryInterface(pSource, &IID_IPin, (void**)&pin);
674     if (hr == E_NOINTERFACE)
675     {
676         IBaseFilter *filter = NULL;
677         int numcurrent = 0;
678 
679         hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&filter);
680         if (hr == E_NOINTERFACE)
681         {
682             WARN("Input not filter or pin?!\n");
683             return E_NOINTERFACE;
684         }
685 
686         hr = IBaseFilter_EnumPins(filter, &enumpins);
687         if (FAILED(hr))
688         {
689             WARN("Could not enumerate\n");
690             IBaseFilter_Release(filter);
691             return hr;
692         }
693 
694         while (1)
695         {
696             ULONG fetched;
697 
698             hr = IEnumPins_Next(enumpins, 1, &pin, &fetched);
699             if (hr == VFW_E_ENUM_OUT_OF_SYNC)
700             {
701                 numcurrent = 0;
702                 IEnumPins_Reset(enumpins);
703                 pin = NULL;
704                 continue;
705             }
706             if (hr != S_OK)
707                 break;
708             if (fetched != 1)
709             {
710                 hr = E_FAIL;
711                 break;
712             }
713 
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;
722         }
723         IEnumPins_Release(enumpins);
724         IBaseFilter_Release(filter);
725 
726         if (hr != S_OK)
727         {
728             WARN("Could not find %s pin # %d\n", (pindir == PINDIR_OUTPUT ? "output" : "input"), numcurrent);
729             return E_FAIL;
730         }
731     }
732     else if (pin_matches(pin, pindir, pCategory, pType, fUnconnected) != S_OK)
733     {
734         IPin_Release(pin);
735         return E_FAIL;
736     }
737 
738     *ppPin = pin;
739     return S_OK;
740 }
741 
742 static const ICaptureGraphBuilder2Vtbl builder2_Vtbl =
743 {
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
756 };
757 
758 
759 static HRESULT WINAPI
fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface,REFIID riid,LPVOID * ppv)760 fnCaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface,
761                                      REFIID riid, LPVOID * ppv)
762 {
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);
766 }
767 
768 static ULONG WINAPI
fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)769 fnCaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
770 {
771     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
772     TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
773     return ICaptureGraphBuilder2_AddRef(&This->ICaptureGraphBuilder2_iface);
774 }
775 
776 static ULONG WINAPI
fnCaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)777 fnCaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
778 {
779     CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder(iface);
780     TRACE("%p --> Forwarding to v2 (%p)\n", iface, This);
781     return ICaptureGraphBuilder2_Release(&This->ICaptureGraphBuilder2_iface);
782 }
783 
784 static HRESULT WINAPI
fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder * iface,IGraphBuilder * pfg)785 fnCaptureGraphBuilder_SetFiltergraph(ICaptureGraphBuilder * iface,
786                                      IGraphBuilder *pfg)
787 {
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);
791 }
792 
793 static HRESULT WINAPI
fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder * iface,IGraphBuilder ** pfg)794 fnCaptureGraphBuilder_GetFiltergraph(ICaptureGraphBuilder * iface,
795                                      IGraphBuilder **pfg)
796 {
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);
800 }
801 
802 static HRESULT WINAPI
fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface,const GUID * pType,LPCOLESTR lpstrFile,IBaseFilter ** ppf,IFileSinkFilter ** ppSink)803 fnCaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface,
804                                         const GUID *pType, LPCOLESTR lpstrFile,
805                                         IBaseFilter **ppf, IFileSinkFilter **ppSink)
806 {
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);
811 }
812 
813 static HRESULT WINAPI
fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface,const GUID * pCategory,IBaseFilter * pf,REFIID riid,void ** ppint)814 fnCaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface,
815                                     const GUID *pCategory, IBaseFilter *pf,
816                                     REFIID riid, void **ppint)
817 {
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);
822 }
823 
824 static HRESULT WINAPI
fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface,const GUID * pCategory,IUnknown * pSource,IBaseFilter * pfCompressor,IBaseFilter * pfRenderer)825 fnCaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface,
826                                    const GUID *pCategory, IUnknown *pSource,
827                                    IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
828 {
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);
833 }
834 
835 static HRESULT WINAPI
fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface,const GUID * pCategory,IBaseFilter * pFilter,REFERENCE_TIME * pstart,REFERENCE_TIME * pstop,WORD wStartCookie,WORD wStopCookie)836 fnCaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface,
837                                     const GUID *pCategory, IBaseFilter *pFilter,
838                                     REFERENCE_TIME *pstart, REFERENCE_TIME *pstop,
839                                     WORD wStartCookie, WORD wStopCookie)
840 {
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);
845 }
846 
847 static HRESULT WINAPI
fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface,LPCOLESTR lpstr,DWORDLONG dwlSize)848 fnCaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface,
849                                    LPCOLESTR lpstr, DWORDLONG dwlSize)
850 {
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);
854 }
855 
856 static HRESULT WINAPI
fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface,LPOLESTR lpwstrOld,LPOLESTR lpwstrNew,int fAllowEscAbort,IAMCopyCaptureFileProgress * pCallback)857 fnCaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface,
858                                       LPOLESTR lpwstrOld, LPOLESTR lpwstrNew,
859                                       int fAllowEscAbort,
860                                       IAMCopyCaptureFileProgress *pCallback)
861 {
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);
866 }
867 
868 static const ICaptureGraphBuilderVtbl builder_Vtbl =
869 {
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
881 };
882