1 /* 2 * Generic Implementation of IPin Interface 3 * 4 * Copyright 2003 Robert Shearman 5 * Copyright 2010 Aric Stewart, CodeWeavers 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "strmbase_private.h" 23 24 static const IMemInputPinVtbl MemInputPin_Vtbl; 25 26 typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg ); 27 28 static inline BasePin *impl_from_IPin( IPin *iface ) 29 { 30 return CONTAINING_RECORD(iface, BasePin, IPin_iface); 31 } 32 33 /** Helper function, there are a lot of places where the error code is inherited 34 * The following rules apply: 35 * 36 * Return the first received error code (E_NOTIMPL is ignored) 37 * If no errors occur: return the first received non-error-code that isn't S_OK 38 */ 39 static HRESULT updatehres( HRESULT original, HRESULT new ) 40 { 41 if (FAILED( original ) || new == E_NOTIMPL) 42 return original; 43 44 if (FAILED( new ) || original == S_OK) 45 return new; 46 47 return original; 48 } 49 50 /** Sends a message from a pin further to other, similar pins 51 * fnMiddle is called on each pin found further on the stream. 52 * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source) 53 * 54 * If the pin given is an input pin, the message will be sent downstream to other input pins 55 * If the pin given is an output pin, the message will be sent upstream to other output pins 56 */ 57 static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd ) 58 { 59 PIN_INFO pin_info; 60 ULONG amount = 0; 61 HRESULT hr = S_OK; 62 HRESULT hr_return = S_OK; 63 IEnumPins *enumpins = NULL; 64 BOOL foundend = TRUE; 65 PIN_DIRECTION from_dir; 66 67 IPin_QueryDirection( from, &from_dir ); 68 69 hr = IPin_QueryInternalConnections( from, NULL, &amount ); 70 if (hr != E_NOTIMPL && amount) 71 FIXME("Use QueryInternalConnections!\n"); 72 73 pin_info.pFilter = NULL; 74 hr = IPin_QueryPinInfo( from, &pin_info ); 75 if (FAILED(hr)) 76 goto out; 77 78 hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins ); 79 if (FAILED(hr)) 80 goto out; 81 82 hr = IEnumPins_Reset( enumpins ); 83 while (hr == S_OK) { 84 IPin *pin = NULL; 85 hr = IEnumPins_Next( enumpins, 1, &pin, NULL ); 86 if (hr == VFW_E_ENUM_OUT_OF_SYNC) 87 { 88 hr = IEnumPins_Reset( enumpins ); 89 continue; 90 } 91 if (pin) 92 { 93 PIN_DIRECTION dir; 94 95 IPin_QueryDirection( pin, &dir ); 96 if (dir != from_dir) 97 { 98 IPin *connected = NULL; 99 100 foundend = FALSE; 101 IPin_ConnectedTo( pin, &connected ); 102 if (connected) 103 { 104 HRESULT hr_local; 105 106 hr_local = fnMiddle( connected, arg ); 107 hr_return = updatehres( hr_return, hr_local ); 108 IPin_Release(connected); 109 } 110 } 111 IPin_Release( pin ); 112 } 113 else 114 { 115 hr = S_OK; 116 break; 117 } 118 } 119 120 if (!foundend) 121 hr = hr_return; 122 else if (fnEnd) { 123 HRESULT hr_local; 124 125 hr_local = fnEnd( from, arg ); 126 hr_return = updatehres( hr_return, hr_local ); 127 } 128 IEnumPins_Release(enumpins); 129 130 out: 131 if (pin_info.pFilter) 132 IBaseFilter_Release( pin_info.pFilter ); 133 return hr; 134 } 135 136 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) 137 { 138 /* Tempting to just do a memcpy, but the name field is 139 128 characters long! We will probably never exceed 10 140 most of the time, so we are better off copying 141 each field manually */ 142 strcpyW(pDest->achName, pSrc->achName); 143 pDest->dir = pSrc->dir; 144 pDest->pFilter = pSrc->pFilter; 145 } 146 147 static void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt) 148 { 149 if (!pmt) 150 return; 151 TRACE("\t%s\n\t%s\n\t...\n\t%s\n", debugstr_guid(&pmt->majortype), debugstr_guid(&pmt->subtype), debugstr_guid(&pmt->formattype)); 152 } 153 154 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards) 155 { 156 TRACE("pmt1: "); 157 dump_AM_MEDIA_TYPE(pmt1); 158 TRACE("pmt2: "); 159 dump_AM_MEDIA_TYPE(pmt2); 160 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) && 161 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype))); 162 } 163 164 /*** Common Base Pin function */ 165 HRESULT WINAPI BasePinImpl_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt) 166 { 167 if (iPosition < 0) 168 return E_INVALIDARG; 169 return VFW_S_NO_MORE_ITEMS; 170 } 171 172 LONG WINAPI BasePinImpl_GetMediaTypeVersion(BasePin *iface) 173 { 174 return 1; 175 } 176 177 ULONG WINAPI BasePinImpl_AddRef(IPin * iface) 178 { 179 BasePin *This = impl_from_IPin(iface); 180 ULONG refCount = InterlockedIncrement(&This->refCount); 181 182 TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1); 183 184 return refCount; 185 } 186 187 HRESULT WINAPI BasePinImpl_Disconnect(IPin * iface) 188 { 189 HRESULT hr; 190 BasePin *This = impl_from_IPin(iface); 191 192 TRACE("()\n"); 193 194 EnterCriticalSection(This->pCritSec); 195 { 196 if (This->pConnectedTo) 197 { 198 IPin_Release(This->pConnectedTo); 199 This->pConnectedTo = NULL; 200 FreeMediaType(&This->mtCurrent); 201 ZeroMemory(&This->mtCurrent, sizeof(This->mtCurrent)); 202 hr = S_OK; 203 } 204 else 205 hr = S_FALSE; 206 } 207 LeaveCriticalSection(This->pCritSec); 208 209 return hr; 210 } 211 212 HRESULT WINAPI BasePinImpl_ConnectedTo(IPin * iface, IPin ** ppPin) 213 { 214 HRESULT hr; 215 BasePin *This = impl_from_IPin(iface); 216 217 TRACE("(%p)\n", ppPin); 218 219 EnterCriticalSection(This->pCritSec); 220 { 221 if (This->pConnectedTo) 222 { 223 *ppPin = This->pConnectedTo; 224 IPin_AddRef(*ppPin); 225 hr = S_OK; 226 } 227 else 228 { 229 hr = VFW_E_NOT_CONNECTED; 230 *ppPin = NULL; 231 } 232 } 233 LeaveCriticalSection(This->pCritSec); 234 235 return hr; 236 } 237 238 HRESULT WINAPI BasePinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt) 239 { 240 HRESULT hr; 241 BasePin *This = impl_from_IPin(iface); 242 243 TRACE("(%p/%p)->(%p)\n", This, iface, pmt); 244 245 EnterCriticalSection(This->pCritSec); 246 { 247 if (This->pConnectedTo) 248 { 249 CopyMediaType(pmt, &This->mtCurrent); 250 hr = S_OK; 251 } 252 else 253 { 254 ZeroMemory(pmt, sizeof(*pmt)); 255 hr = VFW_E_NOT_CONNECTED; 256 } 257 } 258 LeaveCriticalSection(This->pCritSec); 259 260 return hr; 261 } 262 263 HRESULT WINAPI BasePinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo) 264 { 265 BasePin *This = impl_from_IPin(iface); 266 267 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo); 268 269 Copy_PinInfo(pInfo, &This->pinInfo); 270 IBaseFilter_AddRef(pInfo->pFilter); 271 272 return S_OK; 273 } 274 275 HRESULT WINAPI BasePinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir) 276 { 277 BasePin *This = impl_from_IPin(iface); 278 279 TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir); 280 281 *pPinDir = This->pinInfo.dir; 282 283 return S_OK; 284 } 285 286 HRESULT WINAPI BasePinImpl_QueryId(IPin * iface, LPWSTR * Id) 287 { 288 BasePin *This = impl_from_IPin(iface); 289 290 TRACE("(%p/%p)->(%p)\n", This, iface, Id); 291 292 *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR)); 293 if (!*Id) 294 return E_OUTOFMEMORY; 295 296 strcpyW(*Id, This->pinInfo.achName); 297 298 return S_OK; 299 } 300 301 HRESULT WINAPI BasePinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) 302 { 303 TRACE("(%p)->(%p)\n", iface, pmt); 304 305 return S_OK; 306 } 307 308 HRESULT WINAPI BasePinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) 309 { 310 BasePin *This = impl_from_IPin(iface); 311 312 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); 313 314 /* override this method to allow enumeration of your types */ 315 316 return EnumMediaTypes_Construct(This, This->pFuncsTable->pfnGetMediaType, This->pFuncsTable->pfnGetMediaTypeVersion , ppEnum); 317 } 318 319 HRESULT WINAPI BasePinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) 320 { 321 BasePin *This = impl_from_IPin(iface); 322 323 TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin); 324 325 return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */ 326 } 327 328 HRESULT WINAPI BasePinImpl_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) 329 { 330 BasePin *This = impl_from_IPin(iface); 331 332 TRACE("(%s, %s, %e)\n", wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); 333 334 This->tStart = tStart; 335 This->tStop = tStop; 336 This->dRate = dRate; 337 338 return S_OK; 339 } 340 341 /*** OutputPin implementation ***/ 342 343 static inline BaseOutputPin *impl_BaseOutputPin_from_IPin( IPin *iface ) 344 { 345 return CONTAINING_RECORD(iface, BaseOutputPin, pin.IPin_iface); 346 } 347 348 static inline BaseOutputPin *impl_BaseOutputPin_from_BasePin( BasePin *iface ) 349 { 350 return CONTAINING_RECORD(iface, BaseOutputPin, pin); 351 } 352 353 HRESULT WINAPI BaseOutputPinImpl_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 354 { 355 BaseOutputPin *This = impl_BaseOutputPin_from_IPin(iface); 356 357 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv); 358 359 *ppv = NULL; 360 361 if (IsEqualIID(riid, &IID_IUnknown)) 362 *ppv = iface; 363 else if (IsEqualIID(riid, &IID_IPin)) 364 *ppv = iface; 365 else if (IsEqualIID(riid, &IID_IMediaSeeking) || 366 IsEqualIID(riid, &IID_IQualityControl)) 367 { 368 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, riid, ppv); 369 } 370 371 if (*ppv) 372 { 373 IUnknown_AddRef((IUnknown *)(*ppv)); 374 return S_OK; 375 } 376 377 FIXME("No interface for %s!\n", debugstr_guid(riid)); 378 379 return E_NOINTERFACE; 380 } 381 382 ULONG WINAPI BaseOutputPinImpl_Release(IPin * iface) 383 { 384 BaseOutputPin *This = impl_BaseOutputPin_from_IPin(iface); 385 ULONG refCount = InterlockedDecrement(&This->pin.refCount); 386 387 TRACE("(%p)->() Release from %d\n", iface, refCount + 1); 388 389 if (!refCount) 390 BaseOutputPin_Destroy(This); 391 392 return refCount; 393 } 394 395 HRESULT WINAPI BaseOutputPinImpl_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 396 { 397 HRESULT hr; 398 BaseOutputPin *This = impl_BaseOutputPin_from_IPin(iface); 399 400 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); 401 dump_AM_MEDIA_TYPE(pmt); 402 403 if (!pReceivePin) 404 return E_POINTER; 405 406 /* If we try to connect to ourselves, we will definitely deadlock. 407 * There are other cases where we could deadlock too, but this 408 * catches the obvious case */ 409 assert(pReceivePin != iface); 410 411 EnterCriticalSection(This->pin.pCritSec); 412 { 413 /* if we have been a specific type to connect with, then we can either connect 414 * with that or fail. We cannot choose different AM_MEDIA_TYPE */ 415 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) 416 hr = This->pin.pFuncsTable->pfnAttemptConnection(&This->pin, pReceivePin, pmt); 417 else 418 { 419 /* negotiate media type */ 420 421 IEnumMediaTypes * pEnumCandidates; 422 AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */ 423 424 if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates))) 425 { 426 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ 427 428 /* try this filter's media types first */ 429 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) 430 { 431 assert(pmtCandidate); 432 dump_AM_MEDIA_TYPE(pmtCandidate); 433 if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) 434 && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) 435 assert(pmtCandidate->pbFormat); 436 if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 437 (This->pin.pFuncsTable->pfnAttemptConnection(&This->pin, pReceivePin, pmtCandidate) == S_OK)) 438 { 439 hr = S_OK; 440 DeleteMediaType(pmtCandidate); 441 break; 442 } 443 DeleteMediaType(pmtCandidate); 444 pmtCandidate = NULL; 445 } 446 IEnumMediaTypes_Release(pEnumCandidates); 447 } 448 449 /* then try receiver filter's media types */ 450 if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */ 451 { 452 ULONG fetched; 453 454 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ 455 456 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, &fetched)) 457 { 458 assert(pmtCandidate); 459 dump_AM_MEDIA_TYPE(pmtCandidate); 460 if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 461 (This->pin.pFuncsTable->pfnAttemptConnection(&This->pin, pReceivePin, pmtCandidate) == S_OK)) 462 { 463 hr = S_OK; 464 DeleteMediaType(pmtCandidate); 465 break; 466 } 467 DeleteMediaType(pmtCandidate); 468 pmtCandidate = NULL; 469 } /* while */ 470 IEnumMediaTypes_Release(pEnumCandidates); 471 } /* if not found */ 472 } /* if negotiate media type */ 473 } /* if succeeded */ 474 LeaveCriticalSection(This->pin.pCritSec); 475 476 TRACE(" -- %x\n", hr); 477 return hr; 478 } 479 480 HRESULT WINAPI BaseOutputPinImpl_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 481 { 482 ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt); 483 484 return E_UNEXPECTED; 485 } 486 487 HRESULT WINAPI BaseOutputPinImpl_Disconnect(IPin * iface) 488 { 489 HRESULT hr; 490 BaseOutputPin *This = impl_BaseOutputPin_from_IPin(iface); 491 492 TRACE("()\n"); 493 494 EnterCriticalSection(This->pin.pCritSec); 495 { 496 if (This->pMemInputPin) 497 { 498 IMemInputPin_Release(This->pMemInputPin); 499 This->pMemInputPin = NULL; 500 } 501 if (This->pin.pConnectedTo) 502 { 503 IPin_Release(This->pin.pConnectedTo); 504 This->pin.pConnectedTo = NULL; 505 FreeMediaType(&This->pin.mtCurrent); 506 ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); 507 hr = S_OK; 508 } 509 else 510 hr = S_FALSE; 511 } 512 LeaveCriticalSection(This->pin.pCritSec); 513 514 return hr; 515 } 516 517 HRESULT WINAPI BaseOutputPinImpl_EndOfStream(IPin * iface) 518 { 519 TRACE("()\n"); 520 521 /* not supposed to do anything in an output pin */ 522 523 return E_UNEXPECTED; 524 } 525 526 HRESULT WINAPI BaseOutputPinImpl_BeginFlush(IPin * iface) 527 { 528 TRACE("(%p)->()\n", iface); 529 530 /* not supposed to do anything in an output pin */ 531 532 return E_UNEXPECTED; 533 } 534 535 HRESULT WINAPI BaseOutputPinImpl_EndFlush(IPin * iface) 536 { 537 TRACE("(%p)->()\n", iface); 538 539 /* not supposed to do anything in an output pin */ 540 541 return E_UNEXPECTED; 542 } 543 544 HRESULT WINAPI BaseOutputPinImpl_GetDeliveryBuffer(BaseOutputPin *This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags) 545 { 546 HRESULT hr; 547 548 TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags); 549 550 if (!This->pin.pConnectedTo) 551 hr = VFW_E_NOT_CONNECTED; 552 else 553 { 554 hr = IMemAllocator_GetBuffer(This->pAllocator, ppSample, tStart, tStop, dwFlags); 555 556 if (SUCCEEDED(hr)) 557 hr = IMediaSample_SetTime(*ppSample, tStart, tStop); 558 } 559 560 return hr; 561 } 562 563 /* replaces OutputPin_SendSample */ 564 HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin *This, IMediaSample * pSample) 565 { 566 IMemInputPin * pMemConnected = NULL; 567 PIN_INFO pinInfo; 568 HRESULT hr; 569 570 EnterCriticalSection(This->pin.pCritSec); 571 { 572 if (!This->pin.pConnectedTo || !This->pMemInputPin) 573 hr = VFW_E_NOT_CONNECTED; 574 else 575 { 576 /* we don't have the lock held when using This->pMemInputPin, 577 * so we need to AddRef it to stop it being deleted while we are 578 * using it. Same with its filter. */ 579 pMemConnected = This->pMemInputPin; 580 IMemInputPin_AddRef(pMemConnected); 581 hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo); 582 } 583 } 584 LeaveCriticalSection(This->pin.pCritSec); 585 586 if (SUCCEEDED(hr)) 587 { 588 /* NOTE: if we are in a critical section when Receive is called 589 * then it causes some problems (most notably with the native Video 590 * Renderer) if we are re-entered for whatever reason */ 591 hr = IMemInputPin_Receive(pMemConnected, pSample); 592 593 /* If the filter's destroyed, tell upstream to stop sending data */ 594 if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr)) 595 hr = S_FALSE; 596 } 597 if (pMemConnected) 598 IMemInputPin_Release(pMemConnected); 599 600 return hr; 601 } 602 603 /* replaces OutputPin_CommitAllocator */ 604 HRESULT WINAPI BaseOutputPinImpl_Active(BaseOutputPin *This) 605 { 606 HRESULT hr; 607 608 TRACE("(%p)->()\n", This); 609 610 EnterCriticalSection(This->pin.pCritSec); 611 { 612 if (!This->pin.pConnectedTo || !This->pMemInputPin) 613 hr = VFW_E_NOT_CONNECTED; 614 else 615 hr = IMemAllocator_Commit(This->pAllocator); 616 } 617 LeaveCriticalSection(This->pin.pCritSec); 618 619 TRACE("--> %08x\n", hr); 620 return hr; 621 } 622 623 /* replaces OutputPin_DecommitAllocator */ 624 HRESULT WINAPI BaseOutputPinImpl_Inactive(BaseOutputPin *This) 625 { 626 HRESULT hr; 627 628 TRACE("(%p)->()\n", This); 629 630 EnterCriticalSection(This->pin.pCritSec); 631 { 632 if (!This->pin.pConnectedTo || !This->pMemInputPin) 633 hr = VFW_E_NOT_CONNECTED; 634 else 635 hr = IMemAllocator_Decommit(This->pAllocator); 636 } 637 LeaveCriticalSection(This->pin.pCritSec); 638 639 TRACE("--> %08x\n", hr); 640 return hr; 641 } 642 643 /* replaces OutputPin_DeliverDisconnect */ 644 HRESULT WINAPI BaseOutputPinImpl_BreakConnect(BaseOutputPin *This) 645 { 646 HRESULT hr; 647 648 TRACE("(%p)->()\n", This); 649 650 EnterCriticalSection(This->pin.pCritSec); 651 { 652 if (!This->pin.pConnectedTo || !This->pMemInputPin) 653 hr = VFW_E_NOT_CONNECTED; 654 else 655 { 656 hr = IMemAllocator_Decommit(This->pAllocator); 657 658 if (SUCCEEDED(hr)) 659 hr = IPin_Disconnect(This->pin.pConnectedTo); 660 } 661 IPin_Disconnect(&This->pin.IPin_iface); 662 } 663 LeaveCriticalSection(This->pin.pCritSec); 664 665 return hr; 666 } 667 668 HRESULT WINAPI BaseOutputPinImpl_InitAllocator(BaseOutputPin *This, IMemAllocator **pMemAlloc) 669 { 670 return CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)pMemAlloc); 671 } 672 673 HRESULT WINAPI BaseOutputPinImpl_DecideAllocator(BaseOutputPin *This, IMemInputPin *pPin, IMemAllocator **pAlloc) 674 { 675 HRESULT hr; 676 677 hr = IMemInputPin_GetAllocator(pPin, pAlloc); 678 679 if (hr == VFW_E_NO_ALLOCATOR) 680 /* Input pin provides no allocator, use standard memory allocator */ 681 hr = BaseOutputPinImpl_InitAllocator(This, pAlloc); 682 683 if (SUCCEEDED(hr)) 684 { 685 ALLOCATOR_PROPERTIES rProps; 686 ZeroMemory(&rProps, sizeof(ALLOCATOR_PROPERTIES)); 687 688 IMemInputPin_GetAllocatorRequirements(pPin, &rProps); 689 hr = This->pFuncsTable->pfnDecideBufferSize(This, *pAlloc, &rProps); 690 } 691 692 if (SUCCEEDED(hr)) 693 hr = IMemInputPin_NotifyAllocator(pPin, *pAlloc, FALSE); 694 695 return hr; 696 } 697 698 /*** The Construct functions ***/ 699 700 /* Function called as a helper to IPin_Connect */ 701 /* specific AM_MEDIA_TYPE - it cannot be NULL */ 702 HRESULT WINAPI BaseOutputPinImpl_AttemptConnection(BasePin* iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 703 { 704 BaseOutputPin *This = impl_BaseOutputPin_from_BasePin(iface); 705 HRESULT hr; 706 IMemAllocator * pMemAlloc = NULL; 707 708 TRACE("(%p, %p)\n", pReceivePin, pmt); 709 dump_AM_MEDIA_TYPE(pmt); 710 711 /* FIXME: call queryacceptproc */ 712 713 This->pin.pConnectedTo = pReceivePin; 714 IPin_AddRef(pReceivePin); 715 CopyMediaType(&This->pin.mtCurrent, pmt); 716 717 hr = IPin_ReceiveConnection(pReceivePin, &iface->IPin_iface, pmt); 718 719 /* get the IMemInputPin interface we will use to deliver samples to the 720 * connected pin */ 721 if (SUCCEEDED(hr)) 722 { 723 This->pMemInputPin = NULL; 724 hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin); 725 726 if (SUCCEEDED(hr)) 727 { 728 hr = This->pFuncsTable->pfnDecideAllocator(This, This->pMemInputPin, &pMemAlloc); 729 if (SUCCEEDED(hr)) 730 This->pAllocator = pMemAlloc; 731 else if (pMemAlloc) 732 IMemAllocator_Release(pMemAlloc); 733 } 734 735 /* break connection if we couldn't get the allocator */ 736 if (FAILED(hr)) 737 { 738 if (This->pMemInputPin) 739 IMemInputPin_Release(This->pMemInputPin); 740 This->pMemInputPin = NULL; 741 742 IPin_Disconnect(pReceivePin); 743 } 744 } 745 746 if (FAILED(hr)) 747 { 748 IPin_Release(This->pin.pConnectedTo); 749 This->pin.pConnectedTo = NULL; 750 FreeMediaType(&This->pin.mtCurrent); 751 } 752 753 TRACE(" -- %x\n", hr); 754 return hr; 755 } 756 757 static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const BaseOutputPinFuncTable* vtbl, LPCRITICAL_SECTION pCritSec, BaseOutputPin * pPinImpl) 758 { 759 TRACE("\n"); 760 761 /* Common attributes */ 762 pPinImpl->pin.IPin_iface.lpVtbl = OutputPin_Vtbl; 763 pPinImpl->pin.refCount = 1; 764 pPinImpl->pin.pConnectedTo = NULL; 765 pPinImpl->pin.pCritSec = pCritSec; 766 pPinImpl->pin.tStart = 0; 767 pPinImpl->pin.tStop = 0; 768 pPinImpl->pin.dRate = 1.0; 769 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); 770 pPinImpl->pin.pFuncsTable = &vtbl->base; 771 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); 772 773 /* Output pin attributes */ 774 pPinImpl->pMemInputPin = NULL; 775 pPinImpl->pAllocator = NULL; 776 pPinImpl->pFuncsTable = vtbl; 777 778 return S_OK; 779 } 780 781 HRESULT WINAPI BaseOutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, LONG outputpin_size, const PIN_INFO * pPinInfo, const BaseOutputPinFuncTable* vtbl, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) 782 { 783 BaseOutputPin * pPinImpl; 784 785 *ppPin = NULL; 786 787 if (pPinInfo->dir != PINDIR_OUTPUT) 788 { 789 ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir); 790 return E_INVALIDARG; 791 } 792 793 assert(outputpin_size >= sizeof(BaseOutputPin)); 794 assert(vtbl->base.pfnAttemptConnection); 795 796 pPinImpl = CoTaskMemAlloc(outputpin_size); 797 798 if (!pPinImpl) 799 return E_OUTOFMEMORY; 800 801 if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, vtbl, pCritSec, pPinImpl))) 802 { 803 *ppPin = &pPinImpl->pin.IPin_iface; 804 return S_OK; 805 } 806 807 CoTaskMemFree(pPinImpl); 808 return E_FAIL; 809 } 810 811 HRESULT WINAPI BaseOutputPin_Destroy(BaseOutputPin *This) 812 { 813 FreeMediaType(&This->pin.mtCurrent); 814 if (This->pAllocator) 815 IMemAllocator_Release(This->pAllocator); 816 This->pAllocator = NULL; 817 CoTaskMemFree(This); 818 return S_OK; 819 } 820 821 /*** Input Pin implementation ***/ 822 823 static inline BaseInputPin *impl_BaseInputPin_from_IPin( IPin *iface ) 824 { 825 return CONTAINING_RECORD(iface, BaseInputPin, pin.IPin_iface); 826 } 827 828 HRESULT WINAPI BaseInputPinImpl_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 829 { 830 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 831 832 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); 833 834 *ppv = NULL; 835 836 if (IsEqualIID(riid, &IID_IUnknown)) 837 *ppv = iface; 838 else if (IsEqualIID(riid, &IID_IPin)) 839 *ppv = iface; 840 else if (IsEqualIID(riid, &IID_IMemInputPin)) 841 *ppv = &This->IMemInputPin_iface; 842 else if (IsEqualIID(riid, &IID_IMediaSeeking)) 843 { 844 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); 845 } 846 847 if (*ppv) 848 { 849 IUnknown_AddRef((IUnknown *)(*ppv)); 850 return S_OK; 851 } 852 853 FIXME("No interface for %s!\n", debugstr_guid(riid)); 854 855 return E_NOINTERFACE; 856 } 857 858 ULONG WINAPI BaseInputPinImpl_Release(IPin * iface) 859 { 860 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 861 ULONG refCount = InterlockedDecrement(&This->pin.refCount); 862 863 TRACE("(%p)->() Release from %d\n", iface, refCount + 1); 864 865 if (!refCount) 866 BaseInputPin_Destroy(This); 867 868 return refCount; 869 } 870 871 HRESULT WINAPI BaseInputPinImpl_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt) 872 { 873 ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt); 874 875 return E_UNEXPECTED; 876 } 877 878 879 HRESULT WINAPI BaseInputPinImpl_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 880 { 881 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 882 PIN_DIRECTION pindirReceive; 883 HRESULT hr = S_OK; 884 885 TRACE("(%p, %p)\n", pReceivePin, pmt); 886 dump_AM_MEDIA_TYPE(pmt); 887 888 EnterCriticalSection(This->pin.pCritSec); 889 { 890 if (This->pin.pConnectedTo) 891 hr = VFW_E_ALREADY_CONNECTED; 892 893 if (SUCCEEDED(hr) && This->pin.pFuncsTable->pfnCheckMediaType(&This->pin, pmt) != S_OK) 894 hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 895 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ 896 897 if (SUCCEEDED(hr)) 898 { 899 IPin_QueryDirection(pReceivePin, &pindirReceive); 900 901 if (pindirReceive != PINDIR_OUTPUT) 902 { 903 ERR("Can't connect from non-output pin\n"); 904 hr = VFW_E_INVALID_DIRECTION; 905 } 906 } 907 908 if (SUCCEEDED(hr)) 909 { 910 CopyMediaType(&This->pin.mtCurrent, pmt); 911 This->pin.pConnectedTo = pReceivePin; 912 IPin_AddRef(pReceivePin); 913 } 914 } 915 LeaveCriticalSection(This->pin.pCritSec); 916 917 return hr; 918 } 919 920 static HRESULT deliver_endofstream(IPin* pin, LPVOID unused) 921 { 922 return IPin_EndOfStream( pin ); 923 } 924 925 HRESULT WINAPI BaseInputPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) 926 { 927 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 928 929 TRACE("(%p/%p)->(%p)\n", This, iface, pmt); 930 931 return (This->pin.pFuncsTable->pfnCheckMediaType(&This->pin, pmt) == S_OK ? S_OK : S_FALSE); 932 } 933 934 HRESULT WINAPI BaseInputPinImpl_EndOfStream(IPin * iface) 935 { 936 HRESULT hr = S_OK; 937 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 938 939 TRACE("(%p)\n", This); 940 941 EnterCriticalSection(This->pin.pCritSec); 942 if (This->flushing) 943 hr = S_FALSE; 944 else 945 This->end_of_stream = TRUE; 946 LeaveCriticalSection(This->pin.pCritSec); 947 948 if (hr == S_OK) 949 hr = SendFurther( iface, deliver_endofstream, NULL, NULL ); 950 return hr; 951 } 952 953 static HRESULT deliver_beginflush(IPin* pin, LPVOID unused) 954 { 955 return IPin_BeginFlush( pin ); 956 } 957 958 HRESULT WINAPI BaseInputPinImpl_BeginFlush(IPin * iface) 959 { 960 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 961 HRESULT hr; 962 TRACE("() semi-stub\n"); 963 964 EnterCriticalSection(This->pin.pCritSec); 965 This->flushing = TRUE; 966 967 hr = SendFurther( iface, deliver_beginflush, NULL, NULL ); 968 LeaveCriticalSection(This->pin.pCritSec); 969 970 return hr; 971 } 972 973 static HRESULT deliver_endflush(IPin* pin, LPVOID unused) 974 { 975 return IPin_EndFlush( pin ); 976 } 977 978 HRESULT WINAPI BaseInputPinImpl_EndFlush(IPin * iface) 979 { 980 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 981 HRESULT hr; 982 TRACE("(%p)\n", This); 983 984 EnterCriticalSection(This->pin.pCritSec); 985 This->flushing = This->end_of_stream = FALSE; 986 987 hr = SendFurther( iface, deliver_endflush, NULL, NULL ); 988 LeaveCriticalSection(This->pin.pCritSec); 989 990 return hr; 991 } 992 993 typedef struct newsegmentargs 994 { 995 REFERENCE_TIME tStart, tStop; 996 double rate; 997 } newsegmentargs; 998 999 static HRESULT deliver_newsegment(IPin *pin, LPVOID data) 1000 { 1001 newsegmentargs *args = data; 1002 return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate); 1003 } 1004 1005 HRESULT WINAPI BaseInputPinImpl_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) 1006 { 1007 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 1008 newsegmentargs args; 1009 1010 TRACE("(%s, %s, %e)\n", wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); 1011 1012 args.tStart = This->pin.tStart = tStart; 1013 args.tStop = This->pin.tStop = tStop; 1014 args.rate = This->pin.dRate = dRate; 1015 1016 return SendFurther( iface, deliver_newsegment, &args, NULL ); 1017 } 1018 1019 /*** IMemInputPin implementation ***/ 1020 1021 static inline BaseInputPin *impl_from_IMemInputPin( IMemInputPin *iface ) 1022 { 1023 return CONTAINING_RECORD(iface, BaseInputPin, IMemInputPin_iface); 1024 } 1025 1026 static HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv) 1027 { 1028 BaseInputPin *This = impl_from_IMemInputPin(iface); 1029 1030 return IPin_QueryInterface(&This->pin.IPin_iface, riid, ppv); 1031 } 1032 1033 static ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface) 1034 { 1035 BaseInputPin *This = impl_from_IMemInputPin(iface); 1036 1037 return IPin_AddRef(&This->pin.IPin_iface); 1038 } 1039 1040 static ULONG WINAPI MemInputPin_Release(IMemInputPin * iface) 1041 { 1042 BaseInputPin *This = impl_from_IMemInputPin(iface); 1043 1044 return IPin_Release(&This->pin.IPin_iface); 1045 } 1046 1047 static HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator) 1048 { 1049 BaseInputPin *This = impl_from_IMemInputPin(iface); 1050 1051 TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator); 1052 1053 *ppAllocator = This->pAllocator; 1054 if (*ppAllocator) 1055 IMemAllocator_AddRef(*ppAllocator); 1056 1057 return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR; 1058 } 1059 1060 static HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly) 1061 { 1062 BaseInputPin *This = impl_from_IMemInputPin(iface); 1063 1064 TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly); 1065 1066 if (bReadOnly) 1067 FIXME("Read only flag not handled yet!\n"); 1068 1069 /* FIXME: Should we release the allocator on disconnection? */ 1070 if (!pAllocator) 1071 { 1072 WARN("Null allocator\n"); 1073 return E_POINTER; 1074 } 1075 1076 if (This->preferred_allocator && pAllocator != This->preferred_allocator) 1077 return E_FAIL; 1078 1079 if (This->pAllocator) 1080 IMemAllocator_Release(This->pAllocator); 1081 This->pAllocator = pAllocator; 1082 if (This->pAllocator) 1083 IMemAllocator_AddRef(This->pAllocator); 1084 1085 return S_OK; 1086 } 1087 1088 static HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps) 1089 { 1090 BaseInputPin *This = impl_from_IMemInputPin(iface); 1091 1092 TRACE("(%p/%p)->(%p)\n", This, iface, pProps); 1093 1094 /* override this method if you have any specific requirements */ 1095 1096 return E_NOTIMPL; 1097 } 1098 1099 static HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample) 1100 { 1101 BaseInputPin *This = impl_from_IMemInputPin(iface); 1102 HRESULT hr = S_FALSE; 1103 1104 /* this trace commented out for performance reasons */ 1105 /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/ 1106 if (This->pFuncsTable->pfnReceive) 1107 hr = This->pFuncsTable->pfnReceive(This, pSample); 1108 return hr; 1109 } 1110 1111 static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, LONG nSamples, LONG *nSamplesProcessed) 1112 { 1113 HRESULT hr = S_OK; 1114 BaseInputPin *This = impl_from_IMemInputPin(iface); 1115 1116 TRACE("(%p/%p)->(%p, %d, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed); 1117 1118 for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++) 1119 { 1120 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]); 1121 if (hr != S_OK) 1122 break; 1123 } 1124 1125 return hr; 1126 } 1127 1128 static HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface) 1129 { 1130 BaseInputPin *This = impl_from_IMemInputPin(iface); 1131 1132 TRACE("(%p/%p)->()\n", This, iface); 1133 1134 return S_OK; 1135 } 1136 1137 static const IMemInputPinVtbl MemInputPin_Vtbl = 1138 { 1139 MemInputPin_QueryInterface, 1140 MemInputPin_AddRef, 1141 MemInputPin_Release, 1142 MemInputPin_GetAllocator, 1143 MemInputPin_NotifyAllocator, 1144 MemInputPin_GetAllocatorRequirements, 1145 MemInputPin_Receive, 1146 MemInputPin_ReceiveMultiple, 1147 MemInputPin_ReceiveCanBlock 1148 }; 1149 1150 static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, 1151 const BaseInputPinFuncTable* vtbl, 1152 LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, BaseInputPin * pPinImpl) 1153 { 1154 TRACE("\n"); 1155 1156 /* Common attributes */ 1157 pPinImpl->pin.refCount = 1; 1158 pPinImpl->pin.pConnectedTo = NULL; 1159 pPinImpl->pin.pCritSec = pCritSec; 1160 pPinImpl->pin.tStart = 0; 1161 pPinImpl->pin.tStop = 0; 1162 pPinImpl->pin.dRate = 1.0; 1163 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); 1164 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); 1165 pPinImpl->pin.pFuncsTable = &vtbl->base; 1166 1167 /* Input pin attributes */ 1168 pPinImpl->pFuncsTable = vtbl; 1169 pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator; 1170 if (pPinImpl->preferred_allocator) 1171 IMemAllocator_AddRef(pPinImpl->preferred_allocator); 1172 pPinImpl->pin.IPin_iface.lpVtbl = InputPin_Vtbl; 1173 pPinImpl->IMemInputPin_iface.lpVtbl = &MemInputPin_Vtbl; 1174 pPinImpl->flushing = pPinImpl->end_of_stream = FALSE; 1175 1176 return S_OK; 1177 } 1178 1179 HRESULT BaseInputPin_Construct(const IPinVtbl *InputPin_Vtbl, LONG inputpin_size, const PIN_INFO * pPinInfo, 1180 const BaseInputPinFuncTable* vtbl, 1181 LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin) 1182 { 1183 BaseInputPin * pPinImpl; 1184 1185 *ppPin = NULL; 1186 1187 assert(inputpin_size >= sizeof(BaseInputPin)); 1188 assert(vtbl->base.pfnCheckMediaType); 1189 1190 if (pPinInfo->dir != PINDIR_INPUT) 1191 { 1192 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir); 1193 return E_INVALIDARG; 1194 } 1195 1196 pPinImpl = CoTaskMemAlloc(inputpin_size); 1197 1198 if (!pPinImpl) 1199 return E_OUTOFMEMORY; 1200 1201 if (SUCCEEDED(InputPin_Init(InputPin_Vtbl, pPinInfo, vtbl, pCritSec, allocator, pPinImpl))) 1202 { 1203 *ppPin = &pPinImpl->pin.IPin_iface; 1204 return S_OK; 1205 } 1206 1207 CoTaskMemFree(pPinImpl); 1208 return E_FAIL; 1209 } 1210 1211 HRESULT WINAPI BaseInputPin_Destroy(BaseInputPin *This) 1212 { 1213 FreeMediaType(&This->pin.mtCurrent); 1214 if (This->pAllocator) 1215 IMemAllocator_Release(This->pAllocator); 1216 This->pAllocator = NULL; 1217 This->pin.IPin_iface.lpVtbl = NULL; 1218 CoTaskMemFree(This); 1219 return S_OK; 1220 } 1221