1 /* 2 * Generic Implementation of strmbase Base Renderer classes 3 * 4 * Copyright 2012 Aric Stewart, CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "strmbase_private.h" 22 23 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; 24 static const WCHAR wcsAltInputPinName[] = {'I','n',0}; 25 26 static inline BaseInputPin *impl_BaseInputPin_from_IPin( IPin *iface ) 27 { 28 return CONTAINING_RECORD(iface, BaseInputPin, pin.IPin_iface); 29 } 30 31 static inline BaseRenderer *impl_from_IBaseFilter(IBaseFilter *iface) 32 { 33 return CONTAINING_RECORD(iface, BaseRenderer, filter.IBaseFilter_iface); 34 } 35 36 static inline BaseRenderer *impl_from_BaseFilter(BaseFilter *iface) 37 { 38 return CONTAINING_RECORD(iface, BaseRenderer, filter); 39 } 40 41 static const IQualityControlVtbl Renderer_QualityControl_Vtbl = { 42 QualityControlImpl_QueryInterface, 43 QualityControlImpl_AddRef, 44 QualityControlImpl_Release, 45 QualityControlImpl_Notify, 46 QualityControlImpl_SetSink 47 }; 48 49 static HRESULT WINAPI BaseRenderer_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 50 { 51 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 52 BaseRenderer *renderer = impl_from_IBaseFilter(This->pin.pinInfo.pFilter); 53 HRESULT hr; 54 55 TRACE("(%p/%p)->(%p, %p)\n", This, renderer, pReceivePin, pmt); 56 57 EnterCriticalSection(This->pin.pCritSec); 58 hr = BaseInputPinImpl_ReceiveConnection(iface, pReceivePin, pmt); 59 if (SUCCEEDED(hr)) 60 { 61 if (renderer->pFuncsTable->pfnCompleteConnect) 62 hr = renderer->pFuncsTable->pfnCompleteConnect(renderer, pReceivePin); 63 } 64 LeaveCriticalSection(This->pin.pCritSec); 65 66 return hr; 67 } 68 69 static HRESULT WINAPI BaseRenderer_InputPin_Disconnect(IPin * iface) 70 { 71 BaseInputPin *This = impl_BaseInputPin_from_IPin(iface); 72 BaseRenderer *renderer = impl_from_IBaseFilter(This->pin.pinInfo.pFilter); 73 HRESULT hr; 74 75 TRACE("(%p/%p)\n", This, renderer); 76 77 EnterCriticalSection(This->pin.pCritSec); 78 hr = BasePinImpl_Disconnect(iface); 79 if (SUCCEEDED(hr)) 80 { 81 if (renderer->pFuncsTable->pfnBreakConnect) 82 hr = renderer->pFuncsTable->pfnBreakConnect(renderer); 83 } 84 BaseRendererImpl_ClearPendingSample(renderer); 85 LeaveCriticalSection(This->pin.pCritSec); 86 87 return hr; 88 } 89 90 static HRESULT WINAPI BaseRenderer_InputPin_EndOfStream(IPin * iface) 91 { 92 HRESULT hr; 93 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface); 94 BaseRenderer *pFilter = impl_from_IBaseFilter(This->pin.pinInfo.pFilter); 95 96 TRACE("(%p/%p)->()\n", This, pFilter); 97 98 EnterCriticalSection(&pFilter->csRenderLock); 99 EnterCriticalSection(&pFilter->filter.csFilter); 100 hr = BaseInputPinImpl_EndOfStream(iface); 101 EnterCriticalSection(This->pin.pCritSec); 102 if (SUCCEEDED(hr)) 103 { 104 if (pFilter->pFuncsTable->pfnEndOfStream) 105 hr = pFilter->pFuncsTable->pfnEndOfStream(pFilter); 106 else 107 hr = BaseRendererImpl_EndOfStream(pFilter); 108 } 109 LeaveCriticalSection(This->pin.pCritSec); 110 LeaveCriticalSection(&pFilter->filter.csFilter); 111 LeaveCriticalSection(&pFilter->csRenderLock); 112 return hr; 113 } 114 115 static HRESULT WINAPI BaseRenderer_InputPin_BeginFlush(IPin * iface) 116 { 117 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface); 118 BaseRenderer *pFilter = impl_from_IBaseFilter(This->pin.pinInfo.pFilter); 119 HRESULT hr; 120 121 TRACE("(%p/%p)->()\n", This, iface); 122 123 EnterCriticalSection(&pFilter->csRenderLock); 124 EnterCriticalSection(&pFilter->filter.csFilter); 125 EnterCriticalSection(This->pin.pCritSec); 126 hr = BaseInputPinImpl_BeginFlush(iface); 127 if (SUCCEEDED(hr)) 128 { 129 if (pFilter->pFuncsTable->pfnBeginFlush) 130 hr = pFilter->pFuncsTable->pfnBeginFlush(pFilter); 131 else 132 hr = BaseRendererImpl_BeginFlush(pFilter); 133 } 134 LeaveCriticalSection(This->pin.pCritSec); 135 LeaveCriticalSection(&pFilter->filter.csFilter); 136 LeaveCriticalSection(&pFilter->csRenderLock); 137 return hr; 138 } 139 140 static HRESULT WINAPI BaseRenderer_InputPin_EndFlush(IPin * iface) 141 { 142 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface); 143 BaseRenderer *pFilter = impl_from_IBaseFilter(This->pin.pinInfo.pFilter); 144 HRESULT hr; 145 146 TRACE("(%p/%p)->()\n", This, pFilter); 147 148 EnterCriticalSection(&pFilter->csRenderLock); 149 EnterCriticalSection(&pFilter->filter.csFilter); 150 EnterCriticalSection(This->pin.pCritSec); 151 hr = BaseInputPinImpl_EndFlush(iface); 152 if (SUCCEEDED(hr)) 153 { 154 if (pFilter->pFuncsTable->pfnEndFlush) 155 hr = pFilter->pFuncsTable->pfnEndFlush(pFilter); 156 else 157 hr = BaseRendererImpl_EndFlush(pFilter); 158 } 159 LeaveCriticalSection(This->pin.pCritSec); 160 LeaveCriticalSection(&pFilter->filter.csFilter); 161 LeaveCriticalSection(&pFilter->csRenderLock); 162 return hr; 163 } 164 165 static const IPinVtbl BaseRenderer_InputPin_Vtbl = 166 { 167 BaseInputPinImpl_QueryInterface, 168 BasePinImpl_AddRef, 169 BaseInputPinImpl_Release, 170 BaseInputPinImpl_Connect, 171 BaseRenderer_InputPin_ReceiveConnection, 172 BaseRenderer_InputPin_Disconnect, 173 BasePinImpl_ConnectedTo, 174 BasePinImpl_ConnectionMediaType, 175 BasePinImpl_QueryPinInfo, 176 BasePinImpl_QueryDirection, 177 BasePinImpl_QueryId, 178 BaseInputPinImpl_QueryAccept, 179 BasePinImpl_EnumMediaTypes, 180 BasePinImpl_QueryInternalConnections, 181 BaseRenderer_InputPin_EndOfStream, 182 BaseRenderer_InputPin_BeginFlush, 183 BaseRenderer_InputPin_EndFlush, 184 BaseInputPinImpl_NewSegment 185 }; 186 187 static IPin* WINAPI BaseRenderer_GetPin(BaseFilter *iface, int pos) 188 { 189 BaseRenderer *This = impl_from_BaseFilter(iface); 190 191 if (pos >= 1 || pos < 0) 192 return NULL; 193 194 IPin_AddRef(&This->pInputPin->pin.IPin_iface); 195 return &This->pInputPin->pin.IPin_iface; 196 } 197 198 static LONG WINAPI BaseRenderer_GetPinCount(BaseFilter *iface) 199 { 200 return 1; 201 } 202 203 static HRESULT WINAPI BaseRenderer_Input_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE * pmt) 204 { 205 BaseRenderer *This = impl_from_IBaseFilter(pin->pinInfo.pFilter); 206 return This->pFuncsTable->pfnCheckMediaType(This, pmt); 207 } 208 209 static HRESULT WINAPI BaseRenderer_Receive(BaseInputPin *pin, IMediaSample * pSample) 210 { 211 BaseRenderer *This = impl_from_IBaseFilter(pin->pin.pinInfo.pFilter); 212 return BaseRendererImpl_Receive(This, pSample); 213 } 214 215 static const BaseFilterFuncTable RendererBaseFilterFuncTable = { 216 BaseRenderer_GetPin, 217 BaseRenderer_GetPinCount 218 }; 219 220 static const BaseInputPinFuncTable input_BaseInputFuncTable = { 221 { 222 BaseRenderer_Input_CheckMediaType, 223 NULL, 224 BasePinImpl_GetMediaTypeVersion, 225 BasePinImpl_GetMediaType 226 }, 227 BaseRenderer_Receive 228 }; 229 230 231 HRESULT WINAPI BaseRenderer_Init(BaseRenderer * This, const IBaseFilterVtbl *Vtbl, IUnknown *pUnkOuter, const CLSID *pClsid, 232 DWORD_PTR DebugInfo, const BaseRendererFuncTable* pBaseFuncsTable) 233 { 234 PIN_INFO piInput; 235 HRESULT hr; 236 237 BaseFilter_Init(&This->filter, Vtbl, pClsid, DebugInfo, &RendererBaseFilterFuncTable); 238 239 This->pFuncsTable = pBaseFuncsTable; 240 241 /* construct input pin */ 242 piInput.dir = PINDIR_INPUT; 243 piInput.pFilter = &This->filter.IBaseFilter_iface; 244 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); 245 246 hr = BaseInputPin_Construct(&BaseRenderer_InputPin_Vtbl, sizeof(BaseInputPin), &piInput, 247 &input_BaseInputFuncTable, &This->filter.csFilter, NULL, (IPin **)&This->pInputPin); 248 249 if (SUCCEEDED(hr)) 250 { 251 hr = CreatePosPassThru(pUnkOuter ? pUnkOuter: (IUnknown *)&This->filter.IBaseFilter_iface, TRUE, 252 &This->pInputPin->pin.IPin_iface, &This->pPosition); 253 if (FAILED(hr)) 254 return hr; 255 256 InitializeCriticalSection(&This->csRenderLock); 257 This->csRenderLock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": BaseRenderer.csRenderLock"); 258 This->evComplete = CreateEventW(NULL, TRUE, TRUE, NULL); 259 This->ThreadSignal = CreateEventW(NULL, TRUE, TRUE, NULL); 260 This->RenderEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 261 This->pMediaSample = NULL; 262 263 QualityControlImpl_Create(&This->pInputPin->pin.IPin_iface, &This->filter.IBaseFilter_iface, &This->qcimpl); 264 This->qcimpl->IQualityControl_iface.lpVtbl = &Renderer_QualityControl_Vtbl; 265 } 266 267 return hr; 268 } 269 270 HRESULT WINAPI BaseRendererImpl_QueryInterface(IBaseFilter* iface, REFIID riid, LPVOID * ppv) 271 { 272 BaseRenderer *This = impl_from_IBaseFilter(iface); 273 274 if (IsEqualIID(riid, &IID_IMediaSeeking) || IsEqualIID(riid, &IID_IMediaPosition)) 275 return IUnknown_QueryInterface(This->pPosition, riid, ppv); 276 else if (IsEqualIID(riid, &IID_IQualityControl)) 277 { 278 *ppv = &This->qcimpl->IQualityControl_iface; 279 IUnknown_AddRef((IUnknown *)(*ppv)); 280 return S_OK; 281 } 282 else 283 return BaseFilterImpl_QueryInterface(iface, riid, ppv); 284 } 285 286 ULONG WINAPI BaseRendererImpl_Release(IBaseFilter* iface) 287 { 288 BaseRenderer *This = impl_from_IBaseFilter(iface); 289 ULONG refCount = InterlockedDecrement(&This->filter.refCount); 290 291 if (!refCount) 292 { 293 IPin *pConnectedTo; 294 295 if (SUCCEEDED(IPin_ConnectedTo(&This->pInputPin->pin.IPin_iface, &pConnectedTo))) 296 { 297 IPin_Disconnect(pConnectedTo); 298 IPin_Release(pConnectedTo); 299 } 300 IPin_Disconnect(&This->pInputPin->pin.IPin_iface); 301 IPin_Release(&This->pInputPin->pin.IPin_iface); 302 303 if (This->pPosition) 304 IUnknown_Release(This->pPosition); 305 306 This->csRenderLock.DebugInfo->Spare[0] = 0; 307 DeleteCriticalSection(&This->csRenderLock); 308 309 BaseRendererImpl_ClearPendingSample(This); 310 CloseHandle(This->evComplete); 311 CloseHandle(This->ThreadSignal); 312 CloseHandle(This->RenderEvent); 313 QualityControlImpl_Destroy(This->qcimpl); 314 BaseFilter_Destroy(&This->filter); 315 } 316 return refCount; 317 } 318 319 HRESULT WINAPI BaseRendererImpl_Receive(BaseRenderer *This, IMediaSample * pSample) 320 { 321 HRESULT hr = S_OK; 322 REFERENCE_TIME start, stop; 323 AM_MEDIA_TYPE *pmt; 324 325 TRACE("(%p)->%p\n", This, pSample); 326 327 if (This->pInputPin->end_of_stream || This->pInputPin->flushing) 328 return S_FALSE; 329 330 if (This->filter.state == State_Stopped) 331 return VFW_E_WRONG_STATE; 332 333 if (IMediaSample_GetMediaType(pSample, &pmt) == S_OK) 334 { 335 if (FAILED(This->pFuncsTable->pfnCheckMediaType(This, pmt))) 336 { 337 return VFW_E_TYPE_NOT_ACCEPTED; 338 } 339 } 340 341 This->pMediaSample = pSample; 342 IMediaSample_AddRef(pSample); 343 344 if (This->pFuncsTable->pfnPrepareReceive) 345 hr = This->pFuncsTable->pfnPrepareReceive(This, pSample); 346 if (FAILED(hr)) 347 { 348 if (hr == VFW_E_SAMPLE_REJECTED) 349 return S_OK; 350 else 351 return hr; 352 } 353 354 if (This->pFuncsTable->pfnPrepareRender) 355 This->pFuncsTable->pfnPrepareRender(This); 356 357 EnterCriticalSection(&This->csRenderLock); 358 if ( This->filter.state == State_Paused ) 359 { 360 if (This->pFuncsTable->pfnOnReceiveFirstSample) 361 This->pFuncsTable->pfnOnReceiveFirstSample(This, pSample); 362 363 SetEvent(This->evComplete); 364 } 365 366 /* Wait for render Time */ 367 if (SUCCEEDED(IMediaSample_GetTime(pSample, &start, &stop))) 368 { 369 hr = S_FALSE; 370 RendererPosPassThru_RegisterMediaTime(This->pPosition, start); 371 if (This->pFuncsTable->pfnShouldDrawSampleNow) 372 hr = This->pFuncsTable->pfnShouldDrawSampleNow(This, pSample, &start, &stop); 373 374 if (hr == S_OK) 375 ;/* Do not wait: drop through */ 376 else if (hr == S_FALSE) 377 { 378 if (This->pFuncsTable->pfnOnWaitStart) 379 This->pFuncsTable->pfnOnWaitStart(This); 380 381 LeaveCriticalSection(&This->csRenderLock); 382 hr = QualityControlRender_WaitFor(This->qcimpl, pSample, This->RenderEvent); 383 EnterCriticalSection(&This->csRenderLock); 384 385 if (This->pFuncsTable->pfnOnWaitEnd) 386 This->pFuncsTable->pfnOnWaitEnd(This); 387 } 388 else 389 { 390 LeaveCriticalSection(&This->csRenderLock); 391 /* Drop Sample */ 392 return S_OK; 393 } 394 } 395 396 if (SUCCEEDED(hr)) 397 { 398 QualityControlRender_BeginRender(This->qcimpl); 399 hr = This->pFuncsTable->pfnDoRenderSample(This, pSample); 400 QualityControlRender_EndRender(This->qcimpl); 401 } 402 403 QualityControlRender_DoQOS(This->qcimpl); 404 405 BaseRendererImpl_ClearPendingSample(This); 406 LeaveCriticalSection(&This->csRenderLock); 407 408 return hr; 409 } 410 411 HRESULT WINAPI BaseRendererImpl_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) 412 { 413 BaseRenderer *This = impl_from_IBaseFilter(iface); 414 415 TRACE("(%p)->(%s,%p)\n", This, debugstr_w(Id), ppPin); 416 417 if (!Id || !ppPin) 418 return E_POINTER; 419 420 if (!lstrcmpiW(Id,wcsInputPinName) || !lstrcmpiW(Id,wcsAltInputPinName)) 421 { 422 *ppPin = &This->pInputPin->pin.IPin_iface; 423 IPin_AddRef(*ppPin); 424 return S_OK; 425 } 426 *ppPin = NULL; 427 return VFW_E_NOT_FOUND; 428 } 429 430 HRESULT WINAPI BaseRendererImpl_Stop(IBaseFilter * iface) 431 { 432 BaseRenderer *This = impl_from_IBaseFilter(iface); 433 434 TRACE("(%p)->()\n", This); 435 436 EnterCriticalSection(&This->csRenderLock); 437 { 438 RendererPosPassThru_ResetMediaTime(This->pPosition); 439 if (This->pFuncsTable->pfnOnStopStreaming) 440 This->pFuncsTable->pfnOnStopStreaming(This); 441 This->filter.state = State_Stopped; 442 SetEvent(This->evComplete); 443 SetEvent(This->ThreadSignal); 444 SetEvent(This->RenderEvent); 445 } 446 LeaveCriticalSection(&This->csRenderLock); 447 448 return S_OK; 449 } 450 451 HRESULT WINAPI BaseRendererImpl_Run(IBaseFilter * iface, REFERENCE_TIME tStart) 452 { 453 HRESULT hr = S_OK; 454 BaseRenderer *This = impl_from_IBaseFilter(iface); 455 TRACE("(%p)->(%s)\n", This, wine_dbgstr_longlong(tStart)); 456 457 EnterCriticalSection(&This->csRenderLock); 458 This->filter.rtStreamStart = tStart; 459 if (This->filter.state == State_Running) 460 goto out; 461 462 SetEvent(This->evComplete); 463 ResetEvent(This->ThreadSignal); 464 465 if (This->pInputPin->pin.pConnectedTo) 466 { 467 This->pInputPin->end_of_stream = FALSE; 468 } 469 else if (This->filter.filterInfo.pGraph) 470 { 471 IMediaEventSink *pEventSink; 472 hr = IFilterGraph_QueryInterface(This->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink); 473 if (SUCCEEDED(hr)) 474 { 475 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)This); 476 IMediaEventSink_Release(pEventSink); 477 } 478 hr = S_OK; 479 } 480 if (SUCCEEDED(hr)) 481 { 482 QualityControlRender_Start(This->qcimpl, This->filter.rtStreamStart); 483 if (This->pFuncsTable->pfnOnStartStreaming) 484 This->pFuncsTable->pfnOnStartStreaming(This); 485 if (This->filter.state == State_Stopped) 486 BaseRendererImpl_ClearPendingSample(This); 487 SetEvent(This->RenderEvent); 488 This->filter.state = State_Running; 489 } 490 out: 491 LeaveCriticalSection(&This->csRenderLock); 492 493 return hr; 494 } 495 496 HRESULT WINAPI BaseRendererImpl_Pause(IBaseFilter * iface) 497 { 498 BaseRenderer *This = impl_from_IBaseFilter(iface); 499 500 TRACE("(%p)->()\n", This); 501 502 EnterCriticalSection(&This->csRenderLock); 503 { 504 if (This->filter.state != State_Paused) 505 { 506 if (This->filter.state == State_Stopped) 507 { 508 if (This->pInputPin->pin.pConnectedTo) 509 ResetEvent(This->evComplete); 510 This->pInputPin->end_of_stream = FALSE; 511 } 512 else if (This->pFuncsTable->pfnOnStopStreaming) 513 This->pFuncsTable->pfnOnStopStreaming(This); 514 515 if (This->filter.state == State_Stopped) 516 BaseRendererImpl_ClearPendingSample(This); 517 ResetEvent(This->RenderEvent); 518 This->filter.state = State_Paused; 519 } 520 } 521 ResetEvent(This->ThreadSignal); 522 LeaveCriticalSection(&This->csRenderLock); 523 524 return S_OK; 525 } 526 527 HRESULT WINAPI BaseRendererImpl_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock) 528 { 529 BaseRenderer *This = impl_from_IBaseFilter(iface); 530 HRESULT hr; 531 532 EnterCriticalSection(&This->filter.csFilter); 533 QualityControlRender_SetClock(This->qcimpl, clock); 534 hr = BaseFilterImpl_SetSyncSource(iface, clock); 535 LeaveCriticalSection(&This->filter.csFilter); 536 return hr; 537 } 538 539 540 HRESULT WINAPI BaseRendererImpl_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) 541 { 542 HRESULT hr; 543 BaseRenderer *This = impl_from_IBaseFilter(iface); 544 545 TRACE("(%p)->(%d, %p)\n", This, dwMilliSecsTimeout, pState); 546 547 if (WaitForSingleObject(This->evComplete, dwMilliSecsTimeout) == WAIT_TIMEOUT) 548 hr = VFW_S_STATE_INTERMEDIATE; 549 else 550 hr = S_OK; 551 552 BaseFilterImpl_GetState(iface, dwMilliSecsTimeout, pState); 553 554 return hr; 555 } 556 557 HRESULT WINAPI BaseRendererImpl_EndOfStream(BaseRenderer* iface) 558 { 559 IMediaEventSink* pEventSink; 560 IFilterGraph *graph; 561 HRESULT hr = S_OK; 562 563 TRACE("(%p)\n", iface); 564 565 graph = iface->filter.filterInfo.pGraph; 566 if (graph) 567 { hr = IFilterGraph_QueryInterface(iface->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink); 568 if (SUCCEEDED(hr)) 569 { 570 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)iface); 571 IMediaEventSink_Release(pEventSink); 572 } 573 } 574 RendererPosPassThru_EOS(iface->pPosition); 575 SetEvent(iface->evComplete); 576 577 return hr; 578 } 579 580 HRESULT WINAPI BaseRendererImpl_BeginFlush(BaseRenderer* iface) 581 { 582 TRACE("(%p)\n", iface); 583 BaseRendererImpl_ClearPendingSample(iface); 584 SetEvent(iface->ThreadSignal); 585 SetEvent(iface->RenderEvent); 586 return S_OK; 587 } 588 589 HRESULT WINAPI BaseRendererImpl_EndFlush(BaseRenderer* iface) 590 { 591 TRACE("(%p)\n", iface); 592 QualityControlRender_Start(iface->qcimpl, iface->filter.rtStreamStart); 593 RendererPosPassThru_ResetMediaTime(iface->pPosition); 594 ResetEvent(iface->ThreadSignal); 595 ResetEvent(iface->RenderEvent); 596 return S_OK; 597 } 598 599 HRESULT WINAPI BaseRendererImpl_ClearPendingSample(BaseRenderer *iface) 600 { 601 if (iface->pMediaSample) 602 { 603 IMediaSample_Release(iface->pMediaSample); 604 iface->pMediaSample = NULL; 605 } 606 return S_OK; 607 } 608