1 /* 2 * Parser (Base for parsers and splitters) 3 * 4 * Copyright 2003 Robert Shearman 5 * Copyright 2004-2005 Christian Costa 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 "quartz_private.h" 23 #include "pin.h" 24 25 #include "vfwmsgs.h" 26 #include "amvideo.h" 27 28 #include "wine/unicode.h" 29 #include "wine/debug.h" 30 31 #include <math.h> 32 #include <assert.h> 33 34 #include "parser.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(quartz); 37 38 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; 39 static const IMediaSeekingVtbl Parser_Seeking_Vtbl; 40 static const IPinVtbl Parser_OutputPin_Vtbl; 41 static const IPinVtbl Parser_InputPin_Vtbl; 42 43 static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface); 44 static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface); 45 static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface); 46 static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); 47 static HRESULT WINAPI Parser_OutputPin_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE *pmt); 48 static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt); 49 static HRESULT WINAPI Parser_OutputPin_DecideAllocator(BaseOutputPin *This, IMemInputPin *pPin, IMemAllocator **pAlloc); 50 static HRESULT WINAPI Parser_OutputPin_BreakConnect(BaseOutputPin *This); 51 52 static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) 53 { 54 return CONTAINING_RECORD(iface, ParserImpl, sourceSeeking.IMediaSeeking_iface); 55 } 56 57 static inline ParserImpl *impl_from_IBaseFilter( IBaseFilter *iface ) 58 { 59 return CONTAINING_RECORD(iface, ParserImpl, filter.IBaseFilter_iface); 60 } 61 62 static inline ParserImpl *impl_from_BaseFilter( BaseFilter *iface ) 63 { 64 return CONTAINING_RECORD(iface, ParserImpl, filter); 65 } 66 67 /* FIXME: WRONG */ 68 static IPin* WINAPI Parser_GetPin(BaseFilter *iface, int pos) 69 { 70 ParserImpl *This = impl_from_BaseFilter(iface); 71 72 TRACE("%p->(%x)\n", This, pos); 73 74 /* Input pin also has a pin, hence the > and not >= */ 75 if (pos > This->cStreams || pos < 0) 76 return NULL; 77 78 IPin_AddRef(This->ppPins[pos]); 79 return This->ppPins[pos]; 80 } 81 82 static LONG WINAPI Parser_GetPinCount(BaseFilter *iface) 83 { 84 ParserImpl *This = impl_from_BaseFilter(iface); 85 86 TRACE("%p->()\n", This); 87 88 return This->cStreams; 89 } 90 91 static const BaseFilterFuncTable BaseFuncTable = { 92 Parser_GetPin, 93 Parser_GetPinCount 94 }; 95 96 HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, STOPPROCESSPROC fnDone, SourceSeeking_ChangeStop stop, SourceSeeking_ChangeStart start, SourceSeeking_ChangeRate rate) 97 { 98 HRESULT hr; 99 PIN_INFO piInput; 100 101 /* pTransformFilter is already allocated */ 102 BaseFilter_Init(&pParser->filter, Parser_Vtbl, pClsid, (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter"), &BaseFuncTable); 103 104 pParser->fnDisconnect = fnDisconnect; 105 106 pParser->cStreams = 0; 107 pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *)); 108 109 /* construct input pin */ 110 piInput.dir = PINDIR_INPUT; 111 piInput.pFilter = &pParser->filter.IBaseFilter_iface; 112 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); 113 114 if (!start) 115 start = Parser_ChangeStart; 116 117 if (!stop) 118 stop = Parser_ChangeStop; 119 120 if (!rate) 121 rate = Parser_ChangeRate; 122 123 SourceSeeking_Init(&pParser->sourceSeeking, &Parser_Seeking_Vtbl, stop, start, rate, &pParser->filter.csFilter); 124 125 hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, fnDone, &pParser->filter.csFilter, (IPin **)&pParser->pInputPin); 126 127 if (SUCCEEDED(hr)) 128 { 129 pParser->ppPins[0] = &pParser->pInputPin->pin.IPin_iface; 130 pParser->pInputPin->fnPreConnect = fnPreConnect; 131 } 132 else 133 { 134 CoTaskMemFree(pParser->ppPins); 135 BaseFilterImpl_Release(&pParser->filter.IBaseFilter_iface); 136 CoTaskMemFree(pParser); 137 } 138 139 return hr; 140 } 141 142 HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) 143 { 144 ParserImpl *This = impl_from_IBaseFilter(iface); 145 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); 146 147 *ppv = NULL; 148 149 if ( IsEqualIID(riid, &IID_IUnknown) 150 || IsEqualIID(riid, &IID_IPersist) 151 || IsEqualIID(riid, &IID_IMediaFilter) 152 || IsEqualIID(riid, &IID_IBaseFilter) ) 153 *ppv = &This->filter.IBaseFilter_iface; 154 155 if (*ppv) 156 { 157 IUnknown_AddRef((IUnknown *)*ppv); 158 return S_OK; 159 } 160 161 if (!IsEqualIID(riid, &IID_IPin) && 162 !IsEqualIID(riid, &IID_IVideoWindow) && 163 !IsEqualIID(riid, &IID_IAMFilterMiscFlags)) 164 { 165 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 166 } 167 168 return E_NOINTERFACE; 169 } 170 171 ULONG WINAPI Parser_AddRef(IBaseFilter * iface) 172 { 173 return BaseFilterImpl_AddRef(iface); 174 } 175 176 void Parser_Destroy(ParserImpl *This) 177 { 178 IPin *connected = NULL; 179 ULONG pinref; 180 HRESULT hr; 181 182 assert(!This->filter.refCount); 183 PullPin_WaitForStateChange(This->pInputPin, INFINITE); 184 185 /* Don't need to clean up output pins, freeing input pin will do that */ 186 IPin_ConnectedTo(&This->pInputPin->pin.IPin_iface, &connected); 187 if (connected) 188 { 189 hr = IPin_Disconnect(connected); 190 assert(hr == S_OK); 191 IPin_Release(connected); 192 hr = IPin_Disconnect(&This->pInputPin->pin.IPin_iface); 193 assert(hr == S_OK); 194 } 195 pinref = IPin_Release(&This->pInputPin->pin.IPin_iface); 196 if (pinref) 197 { 198 /* Valgrind could find this, if I kill it here */ 199 ERR("pinref should be null, is %u, destroying anyway\n", pinref); 200 assert((LONG)pinref > 0); 201 202 while (pinref) 203 pinref = IPin_Release(&This->pInputPin->pin.IPin_iface); 204 } 205 206 CoTaskMemFree(This->ppPins); 207 BaseFilter_Destroy(&This->filter); 208 209 TRACE("Destroying parser\n"); 210 CoTaskMemFree(This); 211 } 212 213 ULONG WINAPI Parser_Release(IBaseFilter * iface) 214 { 215 ParserImpl *This = impl_from_IBaseFilter(iface); 216 ULONG refCount = InterlockedDecrement(&This->filter.refCount); 217 218 TRACE("(%p)->() Release from %d\n", This, refCount + 1); 219 220 if (!refCount) 221 Parser_Destroy(This); 222 223 return refCount; 224 } 225 226 /** IPersist methods **/ 227 228 HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid) 229 { 230 ParserImpl *This = impl_from_IBaseFilter(iface); 231 232 TRACE("%p->(%p)\n", This, pClsid); 233 234 *pClsid = This->filter.clsid; 235 236 return S_OK; 237 } 238 239 /** IMediaFilter methods **/ 240 241 HRESULT WINAPI Parser_Stop(IBaseFilter * iface) 242 { 243 ParserImpl *This = impl_from_IBaseFilter(iface); 244 PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); 245 ULONG i; 246 247 TRACE("%p->()\n", This); 248 249 EnterCriticalSection(&pin->thread_lock); 250 251 IAsyncReader_BeginFlush(This->pInputPin->pReader); 252 EnterCriticalSection(&This->filter.csFilter); 253 254 if (This->filter.state == State_Stopped) 255 { 256 LeaveCriticalSection(&This->filter.csFilter); 257 IAsyncReader_EndFlush(This->pInputPin->pReader); 258 LeaveCriticalSection(&pin->thread_lock); 259 return S_OK; 260 } 261 262 This->filter.state = State_Stopped; 263 264 for (i = 1; i < (This->cStreams + 1); i++) 265 { 266 BaseOutputPinImpl_Inactive((BaseOutputPin *)This->ppPins[i]); 267 } 268 269 LeaveCriticalSection(&This->filter.csFilter); 270 271 PullPin_PauseProcessing(This->pInputPin); 272 PullPin_WaitForStateChange(This->pInputPin, INFINITE); 273 IAsyncReader_EndFlush(This->pInputPin->pReader); 274 275 LeaveCriticalSection(&pin->thread_lock); 276 return S_OK; 277 } 278 279 HRESULT WINAPI Parser_Pause(IBaseFilter * iface) 280 { 281 HRESULT hr = S_OK; 282 ParserImpl *This = impl_from_IBaseFilter(iface); 283 PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); 284 285 TRACE("%p->()\n", This); 286 287 EnterCriticalSection(&pin->thread_lock); 288 EnterCriticalSection(&This->filter.csFilter); 289 290 if (This->filter.state == State_Paused) 291 { 292 LeaveCriticalSection(&This->filter.csFilter); 293 LeaveCriticalSection(&pin->thread_lock); 294 return S_OK; 295 } 296 297 if (This->filter.state == State_Stopped) 298 { 299 LeaveCriticalSection(&This->filter.csFilter); 300 hr = IBaseFilter_Run(iface, -1); 301 EnterCriticalSection(&This->filter.csFilter); 302 } 303 304 if (SUCCEEDED(hr)) 305 This->filter.state = State_Paused; 306 307 LeaveCriticalSection(&This->filter.csFilter); 308 LeaveCriticalSection(&pin->thread_lock); 309 310 return hr; 311 } 312 313 HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) 314 { 315 HRESULT hr = S_OK; 316 ParserImpl *This = impl_from_IBaseFilter(iface); 317 PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); 318 319 ULONG i; 320 321 TRACE("%p->(%s)\n", This, wine_dbgstr_longlong(tStart)); 322 323 EnterCriticalSection(&pin->thread_lock); 324 EnterCriticalSection(&This->filter.csFilter); 325 { 326 HRESULT hr_any = VFW_E_NOT_CONNECTED; 327 328 This->filter.rtStreamStart = tStart; 329 if (This->filter.state == State_Running || This->filter.state == State_Paused) 330 { 331 This->filter.state = State_Running; 332 LeaveCriticalSection(&This->filter.csFilter); 333 LeaveCriticalSection(&pin->thread_lock); 334 return S_OK; 335 } 336 337 for (i = 1; i < (This->cStreams + 1); i++) 338 { 339 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[i]); 340 if (SUCCEEDED(hr)) 341 hr_any = hr; 342 } 343 344 hr = hr_any; 345 if (SUCCEEDED(hr)) 346 { 347 LeaveCriticalSection(&This->filter.csFilter); 348 hr = PullPin_StartProcessing(This->pInputPin); 349 EnterCriticalSection(&This->filter.csFilter); 350 } 351 352 if (SUCCEEDED(hr)) 353 This->filter.state = State_Running; 354 } 355 LeaveCriticalSection(&This->filter.csFilter); 356 LeaveCriticalSection(&pin->thread_lock); 357 358 return hr; 359 } 360 361 HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) 362 { 363 ParserImpl *This = impl_from_IBaseFilter(iface); 364 PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); 365 HRESULT hr = S_OK; 366 367 TRACE("%p->(%d, %p)\n", This, dwMilliSecsTimeout, pState); 368 369 EnterCriticalSection(&pin->thread_lock); 370 EnterCriticalSection(&This->filter.csFilter); 371 { 372 *pState = This->filter.state; 373 } 374 LeaveCriticalSection(&This->filter.csFilter); 375 376 if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE)) 377 hr = VFW_S_STATE_INTERMEDIATE; 378 LeaveCriticalSection(&pin->thread_lock); 379 380 return hr; 381 } 382 383 HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) 384 { 385 ParserImpl *This = impl_from_IBaseFilter(iface); 386 PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); 387 388 TRACE("%p->(%p)\n", This, pClock); 389 390 EnterCriticalSection(&pin->thread_lock); 391 BaseFilterImpl_SetSyncSource(iface,pClock); 392 LeaveCriticalSection(&pin->thread_lock); 393 394 return S_OK; 395 } 396 397 HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) 398 { 399 return BaseFilterImpl_GetSyncSource(iface, ppClock); 400 } 401 402 /** IBaseFilter implementation **/ 403 404 HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) 405 { 406 return BaseFilterImpl_EnumPins(iface,ppEnum); 407 } 408 409 HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) 410 { 411 ParserImpl *This = impl_from_IBaseFilter(iface); 412 FIXME("(%p)->(%s,%p)\n", This, debugstr_w(Id), ppPin); 413 414 /* FIXME: critical section */ 415 416 return E_NOTIMPL; 417 } 418 419 HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) 420 { 421 return BaseFilterImpl_QueryFilterInfo(iface, pInfo); 422 } 423 424 HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) 425 { 426 return BaseFilterImpl_JoinFilterGraph(iface, pGraph, pName); 427 } 428 429 HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) 430 { 431 return BaseFilterImpl_QueryVendorInfo(iface, pVendorInfo); 432 } 433 434 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = { 435 { 436 Parser_OutputPin_CheckMediaType, 437 BaseOutputPinImpl_AttemptConnection, 438 BasePinImpl_GetMediaTypeVersion, 439 Parser_OutputPin_GetMediaType 440 }, 441 Parser_OutputPin_DecideBufferSize, 442 Parser_OutputPin_DecideAllocator, 443 Parser_OutputPin_BreakConnect 444 }; 445 446 HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt) 447 { 448 IPin ** ppOldPins; 449 HRESULT hr; 450 451 ppOldPins = This->ppPins; 452 453 This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *)); 454 memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *)); 455 456 hr = BaseOutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, &output_BaseOutputFuncTable, &This->filter.csFilter, This->ppPins + (This->cStreams + 1)); 457 458 if (SUCCEEDED(hr)) 459 { 460 IPin *pPin = This->ppPins[This->cStreams + 1]; 461 Parser_OutputPin *pin = unsafe_impl_Parser_OutputPin_from_IPin(pPin); 462 pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); 463 CopyMediaType(pin->pmt, amt); 464 pin->dwSamplesProcessed = 0; 465 466 pin->pin.pin.pinInfo.pFilter = &This->filter.IBaseFilter_iface; 467 pin->allocProps = *props; 468 This->cStreams++; 469 BaseFilterImpl_IncrementPinVersion(&This->filter); 470 CoTaskMemFree(ppOldPins); 471 } 472 else 473 { 474 CoTaskMemFree(This->ppPins); 475 This->ppPins = ppOldPins; 476 ERR("Failed with error %x\n", hr); 477 } 478 479 return hr; 480 } 481 482 static HRESULT Parser_RemoveOutputPins(ParserImpl * This) 483 { 484 /* NOTE: should be in critical section when calling this function */ 485 HRESULT hr; 486 ULONG i; 487 IPin ** ppOldPins = This->ppPins; 488 489 TRACE("(%p)\n", This); 490 491 /* reduce the pin array down to 1 (just our input pin) */ 492 This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1); 493 memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1); 494 495 for (i = 0; i < This->cStreams; i++) 496 { 497 hr = ((BaseOutputPin *)ppOldPins[i + 1])->pFuncsTable->pfnBreakConnect((BaseOutputPin *)ppOldPins[i + 1]); 498 TRACE("Disconnect: %08x\n", hr); 499 IPin_Release(ppOldPins[i + 1]); 500 } 501 502 BaseFilterImpl_IncrementPinVersion(&This->filter); 503 This->cStreams = 0; 504 CoTaskMemFree(ppOldPins); 505 506 return S_OK; 507 } 508 509 static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface) 510 { 511 FIXME("(%p) filter hasn't implemented start position change!\n", iface); 512 return S_OK; 513 } 514 515 static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface) 516 { 517 FIXME("(%p) filter hasn't implemented stop position change!\n", iface); 518 return S_OK; 519 } 520 521 static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface) 522 { 523 FIXME("(%p) filter hasn't implemented rate change!\n", iface); 524 return S_OK; 525 } 526 527 528 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) 529 { 530 ParserImpl *This = impl_from_IMediaSeeking(iface); 531 532 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); 533 } 534 535 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface) 536 { 537 ParserImpl *This = impl_from_IMediaSeeking(iface); 538 539 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 540 } 541 542 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface) 543 { 544 ParserImpl *This = impl_from_IMediaSeeking(iface); 545 546 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 547 } 548 549 static const IMediaSeekingVtbl Parser_Seeking_Vtbl = 550 { 551 Parser_Seeking_QueryInterface, 552 Parser_Seeking_AddRef, 553 Parser_Seeking_Release, 554 SourceSeekingImpl_GetCapabilities, 555 SourceSeekingImpl_CheckCapabilities, 556 SourceSeekingImpl_IsFormatSupported, 557 SourceSeekingImpl_QueryPreferredFormat, 558 SourceSeekingImpl_GetTimeFormat, 559 SourceSeekingImpl_IsUsingTimeFormat, 560 SourceSeekingImpl_SetTimeFormat, 561 SourceSeekingImpl_GetDuration, 562 SourceSeekingImpl_GetStopPosition, 563 SourceSeekingImpl_GetCurrentPosition, 564 SourceSeekingImpl_ConvertTimeFormat, 565 SourceSeekingImpl_SetPositions, 566 SourceSeekingImpl_GetPositions, 567 SourceSeekingImpl_GetAvailable, 568 SourceSeekingImpl_SetRate, 569 SourceSeekingImpl_GetRate, 570 SourceSeekingImpl_GetPreroll 571 }; 572 573 static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) 574 { 575 Parser_OutputPin *This = (Parser_OutputPin*)iface; 576 ALLOCATOR_PROPERTIES actual; 577 578 if (ppropInputRequest->cbAlign && ppropInputRequest->cbAlign != This->allocProps.cbAlign) 579 FIXME("Requested Buffer cbAlign mismatch %i,%i\n",This->allocProps.cbAlign, ppropInputRequest->cbAlign); 580 if (ppropInputRequest->cbPrefix) 581 FIXME("Requested Buffer cbPrefix mismatch %i,%i\n",This->allocProps.cbPrefix, ppropInputRequest->cbPrefix); 582 if (ppropInputRequest->cbBuffer) 583 FIXME("Requested Buffer cbBuffer mismatch %i,%i\n",This->allocProps.cbBuffer, ppropInputRequest->cbBuffer); 584 if (ppropInputRequest->cBuffers) 585 FIXME("Requested Buffer cBuffers mismatch %i,%i\n",This->allocProps.cBuffers, ppropInputRequest->cBuffers); 586 587 return IMemAllocator_SetProperties(pAlloc, &This->allocProps, &actual); 588 } 589 590 static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt) 591 { 592 Parser_OutputPin *This = (Parser_OutputPin*)iface; 593 if (iPosition < 0) 594 return E_INVALIDARG; 595 if (iPosition > 0) 596 return VFW_S_NO_MORE_ITEMS; 597 CopyMediaType(pmt, This->pmt); 598 return S_OK; 599 } 600 601 static HRESULT WINAPI Parser_OutputPin_DecideAllocator(BaseOutputPin *iface, IMemInputPin *pPin, IMemAllocator **pAlloc) 602 { 603 Parser_OutputPin *This = (Parser_OutputPin*)iface; 604 HRESULT hr; 605 606 *pAlloc = NULL; 607 608 if (This->alloc) 609 { 610 hr = IMemInputPin_NotifyAllocator(pPin, This->alloc, This->readonly); 611 if (SUCCEEDED(hr)) 612 { 613 *pAlloc = This->alloc; 614 IMemAllocator_AddRef(*pAlloc); 615 } 616 } 617 else 618 hr = VFW_E_NO_ALLOCATOR; 619 620 return hr; 621 } 622 623 static HRESULT WINAPI Parser_OutputPin_BreakConnect(BaseOutputPin *This) 624 { 625 HRESULT hr; 626 627 TRACE("(%p)->()\n", This); 628 629 EnterCriticalSection(This->pin.pCritSec); 630 if (!This->pin.pConnectedTo || !This->pMemInputPin) 631 hr = VFW_E_NOT_CONNECTED; 632 else 633 { 634 hr = IPin_Disconnect(This->pin.pConnectedTo); 635 IPin_Disconnect(&This->pin.IPin_iface); 636 } 637 LeaveCriticalSection(This->pin.pCritSec); 638 639 return hr; 640 } 641 642 643 static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 644 { 645 Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); 646 647 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); 648 649 *ppv = NULL; 650 651 if (IsEqualIID(riid, &IID_IUnknown)) 652 *ppv = iface; 653 else if (IsEqualIID(riid, &IID_IPin)) 654 *ppv = iface; 655 /* The Parser filter does not support querying IMediaSeeking, return it directly */ 656 else if (IsEqualIID(riid, &IID_IMediaSeeking)) 657 *ppv = &impl_from_IBaseFilter(This->pin.pin.pinInfo.pFilter)->sourceSeeking; 658 659 if (*ppv) 660 { 661 IUnknown_AddRef((IUnknown *)(*ppv)); 662 return S_OK; 663 } 664 665 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 666 667 return E_NOINTERFACE; 668 } 669 670 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface) 671 { 672 Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); 673 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount); 674 675 TRACE("(%p)->() Release from %d\n", iface, refCount + 1); 676 677 if (!refCount) 678 { 679 FreeMediaType(This->pmt); 680 CoTaskMemFree(This->pmt); 681 FreeMediaType(&This->pin.pin.mtCurrent); 682 if (This->pin.pAllocator) 683 IMemAllocator_Release(This->pin.pAllocator); 684 CoTaskMemFree(This); 685 return 0; 686 } 687 return refCount; 688 } 689 690 static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 691 { 692 Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); 693 ParserImpl *parser = impl_from_IBaseFilter(This->pin.pin.pinInfo.pFilter); 694 695 /* Set the allocator to our input pin's */ 696 EnterCriticalSection(This->pin.pin.pCritSec); 697 This->alloc = parser->pInputPin->pAlloc; 698 LeaveCriticalSection(This->pin.pin.pCritSec); 699 700 return BaseOutputPinImpl_Connect(iface, pReceivePin, pmt); 701 } 702 703 static HRESULT WINAPI Parser_OutputPin_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE *pmt) 704 { 705 Parser_OutputPin *This = (Parser_OutputPin *)pin; 706 707 dump_AM_MEDIA_TYPE(pmt); 708 709 return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0); 710 } 711 712 static const IPinVtbl Parser_OutputPin_Vtbl = 713 { 714 Parser_OutputPin_QueryInterface, 715 BasePinImpl_AddRef, 716 Parser_OutputPin_Release, 717 Parser_OutputPin_Connect, 718 BaseOutputPinImpl_ReceiveConnection, 719 BaseOutputPinImpl_Disconnect, 720 BasePinImpl_ConnectedTo, 721 BasePinImpl_ConnectionMediaType, 722 BasePinImpl_QueryPinInfo, 723 BasePinImpl_QueryDirection, 724 BasePinImpl_QueryId, 725 BasePinImpl_QueryAccept, 726 BasePinImpl_EnumMediaTypes, 727 BasePinImpl_QueryInternalConnections, 728 BaseOutputPinImpl_EndOfStream, 729 BaseOutputPinImpl_BeginFlush, 730 BaseOutputPinImpl_EndFlush, 731 BasePinImpl_NewSegment 732 }; 733 734 static HRESULT WINAPI Parser_PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 735 { 736 PullPin *This = impl_PullPin_from_IPin(iface); 737 738 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); 739 740 *ppv = NULL; 741 742 /* 743 * It is important to capture the request for the IMediaSeeking interface before it is passed 744 * on to PullPin_QueryInterface, this is necessary since the Parser filter does not support 745 * querying IMediaSeeking 746 */ 747 if (IsEqualIID(riid, &IID_IMediaSeeking)) 748 *ppv = &impl_from_IBaseFilter(This->pin.pinInfo.pFilter)->sourceSeeking; 749 750 if (*ppv) 751 { 752 IUnknown_AddRef((IUnknown *)(*ppv)); 753 return S_OK; 754 } 755 756 return PullPin_QueryInterface(iface, riid, ppv); 757 } 758 759 static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface) 760 { 761 HRESULT hr; 762 PullPin *This = impl_PullPin_from_IPin(iface); 763 764 TRACE("()\n"); 765 766 EnterCriticalSection(&This->thread_lock); 767 EnterCriticalSection(This->pin.pCritSec); 768 { 769 if (This->pin.pConnectedTo) 770 { 771 FILTER_STATE state; 772 ParserImpl *Parser = impl_from_IBaseFilter(This->pin.pinInfo.pFilter); 773 774 LeaveCriticalSection(This->pin.pCritSec); 775 hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state); 776 EnterCriticalSection(This->pin.pCritSec); 777 778 if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser))) 779 { 780 LeaveCriticalSection(This->pin.pCritSec); 781 PullPin_Disconnect(iface); 782 EnterCriticalSection(This->pin.pCritSec); 783 hr = Parser_RemoveOutputPins(impl_from_IBaseFilter(This->pin.pinInfo.pFilter)); 784 } 785 else 786 hr = VFW_E_NOT_STOPPED; 787 } 788 else 789 hr = S_FALSE; 790 } 791 LeaveCriticalSection(This->pin.pCritSec); 792 LeaveCriticalSection(&This->thread_lock); 793 794 return hr; 795 } 796 797 static HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 798 { 799 HRESULT hr; 800 801 TRACE("()\n"); 802 803 hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt); 804 if (FAILED(hr)) 805 { 806 BasePin *This = (BasePin *)iface; 807 808 EnterCriticalSection(This->pCritSec); 809 Parser_RemoveOutputPins(impl_from_IBaseFilter(This->pinInfo.pFilter)); 810 LeaveCriticalSection(This->pCritSec); 811 } 812 813 return hr; 814 } 815 816 static HRESULT WINAPI Parser_PullPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) 817 { 818 BasePin *This = (BasePin *)iface; 819 820 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); 821 822 return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum); 823 } 824 825 static const IPinVtbl Parser_InputPin_Vtbl = 826 { 827 Parser_PullPin_QueryInterface, 828 BasePinImpl_AddRef, 829 PullPin_Release, 830 BaseInputPinImpl_Connect, 831 Parser_PullPin_ReceiveConnection, 832 Parser_PullPin_Disconnect, 833 BasePinImpl_ConnectedTo, 834 BasePinImpl_ConnectionMediaType, 835 BasePinImpl_QueryPinInfo, 836 BasePinImpl_QueryDirection, 837 BasePinImpl_QueryId, 838 PullPin_QueryAccept, 839 Parser_PullPin_EnumMediaTypes, 840 BasePinImpl_QueryInternalConnections, 841 PullPin_EndOfStream, 842 PullPin_BeginFlush, 843 PullPin_EndFlush, 844 PullPin_NewSegment 845 }; 846