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 66 static inline CaptureGraphImpl *impl_from_ICaptureGraphBuilder(ICaptureGraphBuilder *iface) 67 { 68 return CONTAINING_RECORD(iface, CaptureGraphImpl, ICaptureGraphBuilder_iface); 69 } 70 71 static inline CaptureGraphImpl *impl_from_ICaptureGraphBuilder2(ICaptureGraphBuilder2 *iface) 72 { 73 return CONTAINING_RECORD(iface, CaptureGraphImpl, ICaptureGraphBuilder2_iface); 74 } 75 76 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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