1 /* Video For Windows Steering structure 2 * 3 * Copyright 2005 Maarten Lankhorst 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 * 19 */ 20 21 #define COBJMACROS 22 23 #include "config.h" 24 #include <stdarg.h> 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "wtypes.h" 29 #include "wingdi.h" 30 #include "winuser.h" 31 #include "dshow.h" 32 33 #include "qcap_main.h" 34 #include "wine/debug.h" 35 36 #include "capture.h" 37 #include "uuids.h" 38 #include "vfwmsgs.h" 39 #include "amvideo.h" 40 #include "strmif.h" 41 #include "ddraw.h" 42 #include "ocidl.h" 43 #include "oleauto.h" 44 45 WINE_DEFAULT_DEBUG_CHANNEL(qcap); 46 47 static const IBaseFilterVtbl VfwCapture_Vtbl; 48 static const IAMStreamConfigVtbl IAMStreamConfig_VTable; 49 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable; 50 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable; 51 static const IPinVtbl VfwPin_Vtbl; 52 53 static HRESULT VfwPin_Construct( IBaseFilter *, LPCRITICAL_SECTION, IPin ** ); 54 55 typedef struct VfwCapture 56 { 57 IUnknown IUnknown_inner; 58 BaseFilter filter; 59 IAMStreamConfig IAMStreamConfig_iface; 60 IAMVideoProcAmp IAMVideoProcAmp_iface; 61 IPersistPropertyBag IPersistPropertyBag_iface; 62 IUnknown *outer_unk; 63 BOOL init; 64 Capture *driver_info; 65 66 IPin * pOutputPin; 67 } VfwCapture; 68 69 static inline VfwCapture *impl_from_IUnknown(IUnknown *iface) 70 { 71 return CONTAINING_RECORD(iface, VfwCapture, IUnknown_inner); 72 } 73 74 static inline VfwCapture *impl_from_BaseFilter(BaseFilter *iface) 75 { 76 return CONTAINING_RECORD(iface, VfwCapture, filter); 77 } 78 79 static inline VfwCapture *impl_from_IBaseFilter(IBaseFilter *iface) 80 { 81 return CONTAINING_RECORD(iface, VfwCapture, filter.IBaseFilter_iface); 82 } 83 84 static inline VfwCapture *impl_from_IAMStreamConfig(IAMStreamConfig *iface) 85 { 86 return CONTAINING_RECORD(iface, VfwCapture, IAMStreamConfig_iface); 87 } 88 89 static inline VfwCapture *impl_from_IAMVideoProcAmp(IAMVideoProcAmp *iface) 90 { 91 return CONTAINING_RECORD(iface, VfwCapture, IAMVideoProcAmp_iface); 92 } 93 94 static inline VfwCapture *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface) 95 { 96 return CONTAINING_RECORD(iface, VfwCapture, IPersistPropertyBag_iface); 97 } 98 99 /* VfwPin implementation */ 100 typedef struct VfwPinImpl 101 { 102 BaseOutputPin pin; 103 IKsPropertySet IKsPropertySet_iface; 104 VfwCapture *parent; 105 } VfwPinImpl; 106 107 108 /* VfwCapture inner IUnknown */ 109 static HRESULT WINAPI unknown_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ret_iface) 110 { 111 VfwCapture *This = impl_from_IUnknown(iface); 112 113 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ret_iface); 114 115 *ret_iface = NULL; 116 117 if (IsEqualIID(riid, &IID_IUnknown)) 118 *ret_iface = &This->IUnknown_inner; 119 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) || 120 IsEqualIID(riid, &IID_IBaseFilter)) 121 *ret_iface = &This->filter.IBaseFilter_iface; 122 else if (IsEqualIID(riid, &IID_IPersistPropertyBag)) 123 *ret_iface = &This->IPersistPropertyBag_iface; 124 else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags)) 125 FIXME("IAMFilterMiscFlags not supported yet!\n"); 126 else if (IsEqualIID(riid, &IID_ISpecifyPropertyPages)) 127 FIXME("ISpecifyPropertyPages not supported yet!\n"); 128 else if (IsEqualIID(riid, &IID_IAMVfwCaptureDialogs)) 129 FIXME("IAMVfwCaptureDialogs not supported yet!\n"); 130 else if (IsEqualIID(riid, &IID_IAMStreamConfig)) 131 *ret_iface = &This->IAMStreamConfig_iface; 132 else if (IsEqualIID(riid, &IID_IAMVideoProcAmp)) 133 *ret_iface = &This->IAMVideoProcAmp_iface; 134 else 135 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ret_iface); 136 137 if (!*ret_iface) 138 return E_NOINTERFACE; 139 140 IUnknown_AddRef((IUnknown*)*ret_iface); 141 return S_OK; 142 } 143 144 static ULONG WINAPI unknown_inner_AddRef(IUnknown *iface) 145 { 146 VfwCapture *This = impl_from_IUnknown(iface); 147 ULONG ref = BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface); 148 149 TRACE("(%p) ref=%d\n", This, ref); 150 151 return ref; 152 } 153 154 static ULONG WINAPI unknown_inner_Release(IUnknown *iface) 155 { 156 VfwCapture *This = impl_from_IUnknown(iface); 157 ULONG ref = InterlockedDecrement(&This->filter.refCount); 158 159 TRACE("(%p) ref=%d\n", This, ref); 160 161 if (!ref) 162 { 163 IPin *conn = NULL; 164 165 TRACE("destroying everything\n"); 166 if (This->init) 167 { 168 if (This->filter.state != State_Stopped) 169 qcap_driver_stop(This->driver_info, &This->filter.state); 170 qcap_driver_destroy(This->driver_info); 171 } 172 IPin_ConnectedTo(This->pOutputPin, &conn); 173 if (conn) 174 { 175 IPin_Disconnect(conn); 176 IPin_Disconnect(This->pOutputPin); 177 IPin_Release(conn); 178 } 179 IPin_Release(This->pOutputPin); 180 BaseFilter_Destroy(&This->filter); 181 CoTaskMemFree(This); 182 ObjectRefCount(FALSE); 183 } 184 185 return ref; 186 } 187 188 static const IUnknownVtbl unknown_inner_vtbl = 189 { 190 unknown_inner_QueryInterface, 191 unknown_inner_AddRef, 192 unknown_inner_Release, 193 }; 194 195 static IPin* WINAPI VfwCapture_GetPin(BaseFilter *iface, int pos) 196 { 197 VfwCapture *This = impl_from_BaseFilter(iface); 198 199 if (pos >= 1 || pos < 0) 200 return NULL; 201 202 IPin_AddRef(This->pOutputPin); 203 return This->pOutputPin; 204 } 205 206 static LONG WINAPI VfwCapture_GetPinCount(BaseFilter *iface) 207 { 208 return 1; 209 } 210 211 static const BaseFilterFuncTable BaseFuncTable = { 212 VfwCapture_GetPin, 213 VfwCapture_GetPinCount 214 }; 215 216 IUnknown * WINAPI QCAP_createVFWCaptureFilter(IUnknown *pUnkOuter, HRESULT *phr) 217 { 218 VfwCapture *pVfwCapture; 219 HRESULT hr; 220 221 TRACE("%p - %p\n", pUnkOuter, phr); 222 223 *phr = E_OUTOFMEMORY; 224 pVfwCapture = CoTaskMemAlloc( sizeof(VfwCapture) ); 225 if (!pVfwCapture) 226 return NULL; 227 228 BaseFilter_Init(&pVfwCapture->filter, &VfwCapture_Vtbl, &CLSID_VfwCapture, (DWORD_PTR)(__FILE__ ": VfwCapture.csFilter"), &BaseFuncTable); 229 230 pVfwCapture->IUnknown_inner.lpVtbl = &unknown_inner_vtbl; 231 pVfwCapture->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable; 232 pVfwCapture->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable; 233 pVfwCapture->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable; 234 pVfwCapture->init = FALSE; 235 236 if (pUnkOuter) 237 pVfwCapture->outer_unk = pUnkOuter; 238 else 239 pVfwCapture->outer_unk = &pVfwCapture->IUnknown_inner; 240 241 hr = VfwPin_Construct(&pVfwCapture->filter.IBaseFilter_iface, 242 &pVfwCapture->filter.csFilter, &pVfwCapture->pOutputPin); 243 if (FAILED(hr)) 244 { 245 CoTaskMemFree(pVfwCapture); 246 return NULL; 247 } 248 TRACE("-- created at %p\n", pVfwCapture); 249 250 ObjectRefCount(TRUE); 251 *phr = S_OK; 252 return &pVfwCapture->IUnknown_inner; 253 } 254 255 static HRESULT WINAPI VfwCapture_QueryInterface(IBaseFilter *iface, REFIID riid, void **ret_iface) 256 { 257 VfwCapture *This = impl_from_IBaseFilter(iface); 258 259 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); 260 } 261 262 static ULONG WINAPI VfwCapture_AddRef(IBaseFilter *iface) 263 { 264 VfwCapture *This = impl_from_IBaseFilter(iface); 265 266 return IUnknown_AddRef(This->outer_unk); 267 } 268 269 static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface) 270 { 271 VfwCapture *This = impl_from_IBaseFilter(iface); 272 273 return IUnknown_Release(This->outer_unk); 274 } 275 276 /** IMediaFilter methods **/ 277 278 static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface) 279 { 280 VfwCapture *This = impl_from_IBaseFilter(iface); 281 282 TRACE("()\n"); 283 return qcap_driver_stop(This->driver_info, &This->filter.state); 284 } 285 286 static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface) 287 { 288 VfwCapture *This = impl_from_IBaseFilter(iface); 289 290 TRACE("()\n"); 291 return qcap_driver_pause(This->driver_info, &This->filter.state); 292 } 293 294 static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart) 295 { 296 VfwCapture *This = impl_from_IBaseFilter(iface); 297 TRACE("(%s)\n", wine_dbgstr_longlong(tStart)); 298 return qcap_driver_run(This->driver_info, &This->filter.state); 299 } 300 301 /** IBaseFilter methods **/ 302 static HRESULT WINAPI VfwCapture_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) 303 { 304 FIXME("(%s, %p) - stub\n", debugstr_w(Id), ppPin); 305 return E_NOTIMPL; 306 } 307 308 static const IBaseFilterVtbl VfwCapture_Vtbl = 309 { 310 VfwCapture_QueryInterface, 311 VfwCapture_AddRef, 312 VfwCapture_Release, 313 BaseFilterImpl_GetClassID, 314 VfwCapture_Stop, 315 VfwCapture_Pause, 316 VfwCapture_Run, 317 BaseFilterImpl_GetState, 318 BaseFilterImpl_SetSyncSource, 319 BaseFilterImpl_GetSyncSource, 320 BaseFilterImpl_EnumPins, 321 VfwCapture_FindPin, 322 BaseFilterImpl_QueryFilterInfo, 323 BaseFilterImpl_JoinFilterGraph, 324 BaseFilterImpl_QueryVendorInfo 325 }; 326 327 /* AMStreamConfig interface, we only need to implement {G,S}etFormat */ 328 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID riid, 329 void **ret_iface) 330 { 331 VfwCapture *This = impl_from_IAMStreamConfig(iface); 332 333 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); 334 } 335 336 static ULONG WINAPI AMStreamConfig_AddRef( IAMStreamConfig * iface ) 337 { 338 VfwCapture *This = impl_from_IAMStreamConfig(iface); 339 340 return IUnknown_AddRef(This->outer_unk); 341 } 342 343 static ULONG WINAPI AMStreamConfig_Release( IAMStreamConfig * iface ) 344 { 345 VfwCapture *This = impl_from_IAMStreamConfig(iface); 346 347 return IUnknown_Release(This->outer_unk); 348 } 349 350 static HRESULT WINAPI 351 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt) 352 { 353 HRESULT hr; 354 VfwCapture *This = impl_from_IAMStreamConfig(iface); 355 BasePin *pin; 356 357 TRACE("(%p): %p->%p\n", iface, pmt, pmt ? pmt->pbFormat : NULL); 358 359 if (This->filter.state != State_Stopped) 360 { 361 TRACE("Returning not stopped error\n"); 362 return VFW_E_NOT_STOPPED; 363 } 364 365 if (!pmt) 366 { 367 TRACE("pmt is NULL\n"); 368 return E_POINTER; 369 } 370 371 dump_AM_MEDIA_TYPE(pmt); 372 373 pin = (BasePin *)This->pOutputPin; 374 if (pin->pConnectedTo != NULL) 375 { 376 hr = IPin_QueryAccept(pin->pConnectedTo, pmt); 377 TRACE("Would accept: %d\n", hr); 378 if (hr == S_FALSE) 379 return VFW_E_INVALIDMEDIATYPE; 380 } 381 382 hr = qcap_driver_set_format(This->driver_info, pmt); 383 if (SUCCEEDED(hr) && This->filter.filterInfo.pGraph && pin->pConnectedTo ) 384 { 385 hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, This->pOutputPin); 386 if (SUCCEEDED(hr)) 387 TRACE("Reconnection completed, with new media format..\n"); 388 } 389 TRACE("Returning: %d\n", hr); 390 return hr; 391 } 392 393 static HRESULT WINAPI 394 AMStreamConfig_GetFormat( IAMStreamConfig *iface, AM_MEDIA_TYPE **pmt ) 395 { 396 VfwCapture *This = impl_from_IAMStreamConfig(iface); 397 398 TRACE("%p -> (%p)\n", iface, pmt); 399 return qcap_driver_get_format(This->driver_info, pmt); 400 } 401 402 static HRESULT WINAPI 403 AMStreamConfig_GetNumberOfCapabilities( IAMStreamConfig *iface, int *piCount, 404 int *piSize ) 405 { 406 FIXME("%p: %p %p - stub, intentional\n", iface, piCount, piSize); 407 *piCount = 0; 408 return E_NOTIMPL; /* Not implemented for this interface */ 409 } 410 411 static HRESULT WINAPI 412 AMStreamConfig_GetStreamCaps( IAMStreamConfig *iface, int iIndex, 413 AM_MEDIA_TYPE **pmt, BYTE *pSCC ) 414 { 415 FIXME("%p: %d %p %p - stub, intentional\n", iface, iIndex, pmt, pSCC); 416 return E_NOTIMPL; /* Not implemented for this interface */ 417 } 418 419 static const IAMStreamConfigVtbl IAMStreamConfig_VTable = 420 { 421 AMStreamConfig_QueryInterface, 422 AMStreamConfig_AddRef, 423 AMStreamConfig_Release, 424 AMStreamConfig_SetFormat, 425 AMStreamConfig_GetFormat, 426 AMStreamConfig_GetNumberOfCapabilities, 427 AMStreamConfig_GetStreamCaps 428 }; 429 430 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID riid, 431 void **ret_iface) 432 { 433 VfwCapture *This = impl_from_IAMVideoProcAmp(iface); 434 435 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); 436 } 437 438 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface) 439 { 440 VfwCapture *This = impl_from_IAMVideoProcAmp(iface); 441 442 return IUnknown_AddRef(This->outer_unk); 443 } 444 445 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface) 446 { 447 VfwCapture *This = impl_from_IAMVideoProcAmp(iface); 448 449 return IUnknown_Release(This->outer_unk); 450 } 451 452 static HRESULT WINAPI 453 AMVideoProcAmp_GetRange( IAMVideoProcAmp * iface, LONG Property, LONG *pMin, 454 LONG *pMax, LONG *pSteppingDelta, LONG *pDefault, LONG *pCapsFlags ) 455 { 456 VfwCapture *This = impl_from_IAMVideoProcAmp(iface); 457 458 return qcap_driver_get_prop_range( This->driver_info, Property, pMin, pMax, 459 pSteppingDelta, pDefault, pCapsFlags ); 460 } 461 462 static HRESULT WINAPI 463 AMVideoProcAmp_Set( IAMVideoProcAmp * iface, LONG Property, LONG lValue, 464 LONG Flags ) 465 { 466 VfwCapture *This = impl_from_IAMVideoProcAmp(iface); 467 468 return qcap_driver_set_prop(This->driver_info, Property, lValue, Flags); 469 } 470 471 static HRESULT WINAPI 472 AMVideoProcAmp_Get( IAMVideoProcAmp * iface, LONG Property, LONG *lValue, 473 LONG *Flags ) 474 { 475 VfwCapture *This = impl_from_IAMVideoProcAmp(iface); 476 477 return qcap_driver_get_prop(This->driver_info, Property, lValue, Flags); 478 } 479 480 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable = 481 { 482 AMVideoProcAmp_QueryInterface, 483 AMVideoProcAmp_AddRef, 484 AMVideoProcAmp_Release, 485 AMVideoProcAmp_GetRange, 486 AMVideoProcAmp_Set, 487 AMVideoProcAmp_Get, 488 }; 489 490 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID riid, void **ret_iface) 491 { 492 VfwCapture *This = impl_from_IPersistPropertyBag(iface); 493 494 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); 495 } 496 497 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface) 498 { 499 VfwCapture *This = impl_from_IPersistPropertyBag(iface); 500 501 return IUnknown_AddRef(This->outer_unk); 502 } 503 504 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface) 505 { 506 VfwCapture *This = impl_from_IPersistPropertyBag(iface); 507 508 return IUnknown_Release(This->outer_unk); 509 } 510 511 static HRESULT WINAPI 512 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID ) 513 { 514 VfwCapture *This = impl_from_IPersistPropertyBag(iface); 515 516 FIXME("%p - stub\n", This); 517 518 return E_NOTIMPL; 519 } 520 521 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface) 522 { 523 VfwCapture *This = impl_from_IPersistPropertyBag(iface); 524 525 FIXME("%p - stub\n", This); 526 527 return E_NOTIMPL; 528 } 529 530 static HRESULT WINAPI 531 PPB_Load( IPersistPropertyBag * iface, IPropertyBag *pPropBag, 532 IErrorLog *pErrorLog ) 533 { 534 VfwCapture *This = impl_from_IPersistPropertyBag(iface); 535 HRESULT hr; 536 VARIANT var; 537 const OLECHAR VFWIndex[] = {'V','F','W','I','n','d','e','x',0}; 538 539 TRACE("%p/%p-> (%p, %p)\n", iface, This, pPropBag, pErrorLog); 540 541 V_VT(&var) = VT_I4; 542 hr = IPropertyBag_Read(pPropBag, VFWIndex, &var, pErrorLog); 543 544 if (SUCCEEDED(hr)) 545 { 546 VfwPinImpl *pin; 547 548 This->driver_info = qcap_driver_init( This->pOutputPin, 549 var.__VARIANT_NAME_1.__VARIANT_NAME_2.__VARIANT_NAME_3.ulVal ); 550 if (This->driver_info) 551 { 552 pin = (VfwPinImpl *)This->pOutputPin; 553 pin->parent = This; 554 This->init = TRUE; 555 hr = S_OK; 556 } 557 else 558 hr = E_FAIL; 559 } 560 561 return hr; 562 } 563 564 static HRESULT WINAPI 565 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag, 566 BOOL fClearDirty, BOOL fSaveAllProperties ) 567 { 568 VfwCapture *This = impl_from_IPersistPropertyBag(iface); 569 FIXME("%p - stub\n", This); 570 return E_NOTIMPL; 571 } 572 573 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable = 574 { 575 PPB_QueryInterface, 576 PPB_AddRef, 577 PPB_Release, 578 PPB_GetClassID, 579 PPB_InitNew, 580 PPB_Load, 581 PPB_Save 582 }; 583 584 /* IKsPropertySet interface */ 585 static inline VfwPinImpl *impl_from_IKsPropertySet(IKsPropertySet *iface) 586 { 587 return CONTAINING_RECORD(iface, VfwPinImpl, IKsPropertySet_iface); 588 } 589 590 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet * iface, REFIID riid, void **ret_iface) 591 { 592 VfwPinImpl *This = impl_from_IKsPropertySet(iface); 593 594 return IPin_QueryInterface(&This->pin.pin.IPin_iface, riid, ret_iface); 595 } 596 597 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface) 598 { 599 VfwPinImpl *This = impl_from_IKsPropertySet(iface); 600 601 return IPin_AddRef(&This->pin.pin.IPin_iface); 602 } 603 604 static ULONG WINAPI KSP_Release(IKsPropertySet * iface) 605 { 606 VfwPinImpl *This = impl_from_IKsPropertySet(iface); 607 608 return IPin_Release(&This->pin.pin.IPin_iface); 609 } 610 611 static HRESULT WINAPI 612 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, 613 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, 614 DWORD cbPropData ) 615 { 616 FIXME("%p: stub\n", iface); 617 return E_NOTIMPL; 618 } 619 620 static HRESULT WINAPI 621 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, 622 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, 623 DWORD cbPropData, DWORD *pcbReturned ) 624 { 625 LPGUID pGuid; 626 627 TRACE("()\n"); 628 629 if (!IsEqualIID(guidPropSet, &ROPSETID_Pin)) 630 return E_PROP_SET_UNSUPPORTED; 631 if (pPropData == NULL && pcbReturned == NULL) 632 return E_POINTER; 633 if (pcbReturned) 634 *pcbReturned = sizeof(GUID); 635 if (pPropData == NULL) 636 return S_OK; 637 if (cbPropData < sizeof(GUID)) 638 return E_UNEXPECTED; 639 pGuid = pPropData; 640 *pGuid = PIN_CATEGORY_CAPTURE; 641 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n"); 642 return S_OK; 643 } 644 645 static HRESULT WINAPI 646 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet, 647 DWORD dwPropID, DWORD *pTypeSupport ) 648 { 649 FIXME("%p: stub\n", iface); 650 return E_NOTIMPL; 651 } 652 653 static const IKsPropertySetVtbl IKsPropertySet_VTable = 654 { 655 KSP_QueryInterface, 656 KSP_AddRef, 657 KSP_Release, 658 KSP_Set, 659 KSP_Get, 660 KSP_QuerySupported 661 }; 662 663 static inline VfwPinImpl *impl_from_BasePin(BasePin *pin) 664 { 665 return CONTAINING_RECORD(pin, VfwPinImpl, pin.pin); 666 } 667 668 static HRESULT WINAPI VfwPin_GetMediaType(BasePin *pin, int iPosition, AM_MEDIA_TYPE *pmt) 669 { 670 VfwPinImpl *This = impl_from_BasePin(pin); 671 AM_MEDIA_TYPE *vfw_pmt; 672 HRESULT hr; 673 674 if (iPosition < 0) 675 return E_INVALIDARG; 676 if (iPosition > 0) 677 return VFW_S_NO_MORE_ITEMS; 678 679 hr = qcap_driver_get_format(This->parent->driver_info, &vfw_pmt); 680 if (SUCCEEDED(hr)) { 681 CopyMediaType(pmt, vfw_pmt); 682 DeleteMediaType(vfw_pmt); 683 } 684 return hr; 685 } 686 687 static LONG WINAPI VfwPin_GetMediaTypeVersion(BasePin *iface) 688 { 689 return 1; 690 } 691 692 static HRESULT WINAPI VfwPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) 693 { 694 ALLOCATOR_PROPERTIES actual; 695 696 /* What we put here doesn't matter, the 697 driver function should override it then commit */ 698 if (!ppropInputRequest->cBuffers) 699 ppropInputRequest->cBuffers = 3; 700 if (!ppropInputRequest->cbBuffer) 701 ppropInputRequest->cbBuffer = 230400; 702 if (!ppropInputRequest->cbAlign) 703 ppropInputRequest->cbAlign = 1; 704 705 return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual); 706 } 707 708 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = { 709 { 710 NULL, 711 BaseOutputPinImpl_AttemptConnection, 712 VfwPin_GetMediaTypeVersion, 713 VfwPin_GetMediaType 714 }, 715 VfwPin_DecideBufferSize, 716 BaseOutputPinImpl_DecideAllocator, 717 BaseOutputPinImpl_BreakConnect 718 }; 719 720 static HRESULT 721 VfwPin_Construct( IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, 722 IPin ** ppPin ) 723 { 724 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 }; 725 PIN_INFO piOutput; 726 HRESULT hr; 727 728 *ppPin = NULL; 729 730 piOutput.dir = PINDIR_OUTPUT; 731 piOutput.pFilter = pBaseFilter; 732 lstrcpyW(piOutput.achName, wszOutputPinName); 733 734 hr = BaseOutputPin_Construct(&VfwPin_Vtbl, sizeof(VfwPinImpl), &piOutput, &output_BaseOutputFuncTable, pCritSec, ppPin); 735 736 if (SUCCEEDED(hr)) 737 { 738 VfwPinImpl *pPinImpl = (VfwPinImpl*)*ppPin; 739 pPinImpl->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable; 740 ObjectRefCount(TRUE); 741 } 742 743 return hr; 744 } 745 746 static inline VfwPinImpl *impl_from_IPin(IPin *iface) 747 { 748 return CONTAINING_RECORD(iface, VfwPinImpl, pin.pin.IPin_iface); 749 } 750 751 static HRESULT WINAPI VfwPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 752 { 753 VfwPinImpl *This = impl_from_IPin(iface); 754 755 TRACE("%s %p\n", debugstr_guid(riid), ppv); 756 757 *ppv = NULL; 758 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin)) 759 *ppv = This; 760 else if (IsEqualIID(riid, &IID_IKsPropertySet)) 761 *ppv = &This->IKsPropertySet_iface; 762 else if (IsEqualIID(riid, &IID_IAMStreamConfig)) 763 return IUnknown_QueryInterface((IUnknown *)This->parent, riid, ppv); 764 765 if (*ppv) 766 { 767 IUnknown_AddRef((IUnknown *)(*ppv)); 768 return S_OK; 769 } 770 771 FIXME("No interface for %s!\n", debugstr_guid(riid)); 772 return E_NOINTERFACE; 773 } 774 775 static ULONG WINAPI 776 VfwPin_Release(IPin * iface) 777 { 778 VfwPinImpl *This = impl_from_IPin(iface); 779 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount); 780 781 TRACE("() -> new refcount: %u\n", refCount); 782 783 if (!refCount) 784 { 785 BaseOutputPin_Destroy(&This->pin); 786 ObjectRefCount(FALSE); 787 } 788 return refCount; 789 } 790 791 static HRESULT WINAPI 792 VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) 793 { 794 VfwPinImpl *This = impl_from_IPin(iface); 795 AM_MEDIA_TYPE *pmt; 796 HRESULT hr; 797 798 hr = qcap_driver_get_format(This->parent->driver_info, &pmt); 799 if (SUCCEEDED(hr)) { 800 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum); 801 DeleteMediaType(pmt); 802 } 803 TRACE("%p -- %x\n", This, hr); 804 return hr; 805 } 806 807 static HRESULT WINAPI 808 VfwPin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) 809 { 810 TRACE("(%p)->(%p, %p)\n", iface, apPin, cPin); 811 return E_NOTIMPL; 812 } 813 814 static const IPinVtbl VfwPin_Vtbl = 815 { 816 VfwPin_QueryInterface, 817 BasePinImpl_AddRef, 818 VfwPin_Release, 819 BaseOutputPinImpl_Connect, 820 BaseOutputPinImpl_ReceiveConnection, 821 BaseOutputPinImpl_Disconnect, 822 BasePinImpl_ConnectedTo, 823 BasePinImpl_ConnectionMediaType, 824 BasePinImpl_QueryPinInfo, 825 BasePinImpl_QueryDirection, 826 BasePinImpl_QueryId, 827 BasePinImpl_QueryAccept, 828 VfwPin_EnumMediaTypes, 829 VfwPin_QueryInternalConnections, 830 BaseOutputPinImpl_EndOfStream, 831 BaseOutputPinImpl_BeginFlush, 832 BaseOutputPinImpl_EndFlush, 833 BasePinImpl_NewSegment 834 }; 835