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, &ROPSETID_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