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