00001
00002
00003
00004
00005
00006 #include <streams.h>
00007 #include <mmsystem.h>
00008 #include <limits.h>
00009 #include <measure.h>
00010
00011 #pragma warning(disable:4355)
00012
00013 int inline TimeDiff(REFERENCE_TIME rt)
00014 {
00015 if (rt < - (50 * UNITS)) {
00016 return -(50 * UNITS);
00017 } else
00018 if (rt > 50 * UNITS) {
00019 return 50 * UNITS;
00020 } else return (int)rt;
00021 }
00022
00023 CBaseRenderer::CBaseRenderer(REFCLSID RenderClass,
00024 TCHAR *pName,
00025 LPUNKNOWN pUnk,
00026 HRESULT *phr) :
00027
00028 CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass),
00029 m_evComplete(TRUE),
00030 m_bAbort(FALSE),
00031 m_pPosition(NULL),
00032 m_ThreadSignal(TRUE),
00033 m_bStreaming(FALSE),
00034 m_bEOS(FALSE),
00035 m_bEOSDelivered(FALSE),
00036 m_pMediaSample(NULL),
00037 m_dwAdvise(0),
00038 m_pQSink(NULL),
00039 m_pInputPin(NULL),
00040 m_bRepaintStatus(TRUE),
00041 m_SignalTime(0),
00042 m_bInReceive(FALSE),
00043 m_EndOfStreamTimer(0)
00044 {
00045 Ready();
00046 #ifdef PERF
00047 m_idBaseStamp = MSR_REGISTER("BaseRenderer: sample time stamp");
00048 m_idBaseRenderTime = MSR_REGISTER("BaseRenderer: draw time (msec)");
00049 m_idBaseAccuracy = MSR_REGISTER("BaseRenderer: Accuracy (msec)");
00050 #endif
00051 }
00052
00053 CBaseRenderer::~CBaseRenderer()
00054 {
00055 ASSERT(m_bStreaming == FALSE);
00056 ASSERT(m_EndOfStreamTimer == 0);
00057 StopStreaming();
00058 ClearPendingSample();
00059
00060
00061
00062 if (m_pPosition) {
00063 delete m_pPosition;
00064 m_pPosition = NULL;
00065 }
00066
00067
00068
00069 if (m_pInputPin) {
00070 delete m_pInputPin;
00071 m_pInputPin = NULL;
00072 }
00073
00074
00075
00076 ASSERT(m_pQSink == NULL);
00077 }
00078
00079 HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid,void **ppv)
00080 {
00081 CAutoLock cRendererLock(&m_InterfaceLock);
00082 if (m_pPosition) {
00083 return m_pPosition->NonDelegatingQueryInterface(riid,ppv);
00084 }
00085
00086 HRESULT hr = NOERROR;
00087
00088
00089
00090
00091
00092
00093 m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"),
00094 CBaseFilter::GetOwner(),
00095 (HRESULT *) &hr,
00096 GetPin(0));
00097 if (m_pPosition == NULL) {
00098 return E_OUTOFMEMORY;
00099 }
00100
00101 if (FAILED(hr)) {
00102 delete m_pPosition;
00103 m_pPosition = NULL;
00104 return E_NOINTERFACE;
00105 }
00106 return GetMediaPositionInterface(riid,ppv);
00107 }
00108
00109 STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid,void **ppv)
00110 {
00111
00112
00113 if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) {
00114 return GetMediaPositionInterface(riid,ppv);
00115 } else {
00116 return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
00117 }
00118 }
00119
00120 HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait)
00121 {
00122 if (bCanWait == TRUE) {
00123 m_ThreadSignal.Reset();
00124 } else {
00125 m_ThreadSignal.Set();
00126 }
00127 return NOERROR;
00128 }
00129
00130 #ifdef DEBUG
00131
00132 void CBaseRenderer::DisplayRendererState()
00133 {
00134 DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime")));
00135
00136
00137
00138 BOOL bSignalled = m_ThreadSignal.Check();
00139 DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled));
00140
00141
00142
00143 DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State));
00144
00145 DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort));
00146
00147 DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming));
00148
00149 DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise));
00150
00151 DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample));
00152
00153 DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS));
00154
00155 DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered));
00156
00157 DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus));
00158
00159
00160
00161 DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer));
00162
00163 DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime)));
00164
00165
00166
00167 BOOL bFlushing = m_pInputPin->IsFlushing();
00168 DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing));
00169
00170
00171 DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time)));
00172
00173
00174 if (m_pClock == NULL) return;
00175
00176
00177
00178 CRefTime CurrentTime,StartTime,EndTime;
00179 m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime);
00180 CRefTime Offset = CurrentTime - m_tStart;
00181
00182
00183
00184 DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time)));
00185
00186 DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs()));
00187
00188
00189 if (m_pMediaSample == NULL) return;
00190
00191 m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime);
00192 DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"),
00193 StartTime.Millisecs(),EndTime.Millisecs()));
00194
00195
00196 CRefTime Wait = (m_tStart + StartTime) - CurrentTime;
00197 DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs()));
00198 }
00199 #endif
00200
00201 #define RENDER_TIMEOUT 10000
00202
00203 HRESULT CBaseRenderer::WaitForRenderTime()
00204 {
00205 HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent };
00206 DWORD Result = WAIT_TIMEOUT;
00207
00208
00209
00210 OnWaitStart();
00211 while (Result == WAIT_TIMEOUT) {
00212 Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT);
00213
00214 #ifdef DEBUG
00215 if (Result == WAIT_TIMEOUT) DisplayRendererState();
00216 #endif
00217
00218 }
00219 OnWaitEnd();
00220
00221
00222
00223 if (Result == WAIT_OBJECT_0) {
00224 return VFW_E_STATE_CHANGED;
00225 }
00226
00227 SignalTimerFired();
00228 return NOERROR;
00229 }
00230
00231 void CBaseRenderer::WaitForReceiveToComplete()
00232 {
00233 for (;;) {
00234 if (!m_bInReceive) {
00235 break;
00236 }
00237
00238 MSG msg;
00239
00240 PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE);
00241
00242 Sleep(1);
00243 }
00244
00245
00246
00247
00248
00249 if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) {
00250
00251 PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
00252 }
00253 }
00254
00255 FILTER_STATE CBaseRenderer::GetRealState() {
00256 return m_State;
00257 }
00258
00259 STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State)
00260 {
00261 CheckPointer(State,E_POINTER);
00262
00263 if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) {
00264 *State = m_State;
00265 return VFW_S_STATE_INTERMEDIATE;
00266 }
00267 *State = m_State;
00268 return NOERROR;
00269 }
00270
00271 HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState)
00272 {
00273
00274
00275 if (m_pInputPin->IsConnected() == FALSE) {
00276 Ready();
00277 return S_OK;
00278 }
00279
00280
00281
00282 if (IsEndOfStream() == TRUE) {
00283 Ready();
00284 return S_OK;
00285 }
00286
00287
00288
00289 if (HaveCurrentSample() == TRUE) {
00290 if (OldState != State_Stopped) {
00291 Ready();
00292 return S_OK;
00293 }
00294 }
00295 NotReady();
00296 return S_FALSE;
00297 }
00298
00299 STDMETHODIMP CBaseRenderer::Stop()
00300 {
00301 CAutoLock cRendererLock(&m_InterfaceLock);
00302
00303
00304
00305 if (m_State == State_Stopped) {
00306 return NOERROR;
00307 }
00308
00309
00310
00311 if (m_pInputPin->IsConnected() == FALSE) {
00312 NOTE("Input pin is not connected");
00313 m_State = State_Stopped;
00314 return NOERROR;
00315 }
00316
00317 CBaseFilter::Stop();
00318
00319
00320
00321
00322
00323 if (m_pInputPin->Allocator()) {
00324 m_pInputPin->Allocator()->Decommit();
00325 }
00326
00327
00328
00329 SetRepaintStatus(TRUE);
00330 StopStreaming();
00331 SourceThreadCanWait(FALSE);
00332 ResetEndOfStream();
00333 CancelNotification();
00334
00335
00336 ASSERT(CancelNotification() == S_FALSE);
00337 ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
00338 ASSERT(m_EndOfStreamTimer == 0);
00339
00340 Ready();
00341 WaitForReceiveToComplete();
00342 m_bAbort = FALSE;
00343 return NOERROR;
00344 }
00345
00346 STDMETHODIMP CBaseRenderer::Pause()
00347 {
00348 CAutoLock cRendererLock(&m_InterfaceLock);
00349 FILTER_STATE OldState = m_State;
00350 ASSERT(m_pInputPin->IsFlushing() == FALSE);
00351
00352
00353
00354 if (m_State == State_Paused) {
00355 return CompleteStateChange(State_Paused);
00356 }
00357
00358
00359
00360 if (m_pInputPin->IsConnected() == FALSE) {
00361 NOTE("Input pin is not connected");
00362 m_State = State_Paused;
00363 return CompleteStateChange(State_Paused);
00364 }
00365
00366
00367
00368 HRESULT hr = CBaseFilter::Pause();
00369 if (FAILED(hr)) {
00370 NOTE("Pause failed");
00371 return hr;
00372 }
00373
00374
00375
00376 SetRepaintStatus(TRUE);
00377 StopStreaming();
00378 SourceThreadCanWait(TRUE);
00379 CancelNotification();
00380 ResetEndOfStreamTimer();
00381
00382
00383
00384
00385
00386 if (m_pInputPin->Allocator()) {
00387 m_pInputPin->Allocator()->Commit();
00388 }
00389
00390
00391 ASSERT(CancelNotification() == S_FALSE);
00392 ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
00393 ASSERT(m_EndOfStreamTimer == 0);
00394 ASSERT(m_pInputPin->IsFlushing() == FALSE);
00395
00396
00397
00398
00399
00400
00401
00402 if (OldState == State_Stopped) {
00403 m_bAbort = FALSE;
00404 ClearPendingSample();
00405 }
00406 return CompleteStateChange(OldState);
00407 }
00408
00409 STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime)
00410 {
00411 CAutoLock cRendererLock(&m_InterfaceLock);
00412 FILTER_STATE OldState = m_State;
00413
00414
00415
00416 if (m_State == State_Running) {
00417 return NOERROR;
00418 }
00419
00420
00421
00422 if (m_pInputPin->IsConnected() == FALSE) {
00423 NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this);
00424 m_State = State_Running;
00425 return NOERROR;
00426 }
00427
00428 Ready();
00429
00430
00431
00432 HRESULT hr = CBaseFilter::Run(StartTime);
00433 if (FAILED(hr)) {
00434 NOTE("Run failed");
00435 return hr;
00436 }
00437
00438
00439 ASSERT(m_pInputPin->IsFlushing() == FALSE);
00440 SourceThreadCanWait(TRUE);
00441 SetRepaintStatus(FALSE);
00442
00443
00444 ASSERT(CancelNotification() == S_FALSE);
00445 ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
00446 ASSERT(m_EndOfStreamTimer == 0);
00447 ASSERT(m_pInputPin->IsFlushing() == FALSE);
00448
00449
00450
00451
00452
00453 if (m_pInputPin->Allocator()) {
00454 m_pInputPin->Allocator()->Commit();
00455 }
00456
00457
00458
00459
00460
00461
00462
00463 if (OldState == State_Stopped) {
00464 m_bAbort = FALSE;
00465 ClearPendingSample();
00466 }
00467 return StartStreaming();
00468 }
00469
00470 int CBaseRenderer::GetPinCount()
00471 {
00472 return 1;
00473 }
00474
00475 CBasePin *CBaseRenderer::GetPin(int n)
00476 {
00477 CAutoLock cRendererLock(&m_InterfaceLock);
00478 HRESULT hr = NOERROR;
00479 ASSERT(n == 0);
00480
00481
00482
00483 if (n != 0) {
00484 return NULL;
00485 }
00486
00487
00488
00489 if (m_pInputPin == NULL) {
00490 m_pInputPin = new CRendererInputPin(this,&hr,L"In");
00491 }
00492 return m_pInputPin;
00493 }
00494
00495 STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, IPin **ppPin)
00496 {
00497 CheckPointer(ppPin,E_POINTER);
00498
00499 if (0==lstrcmpW(Id,L"In")) {
00500 *ppPin = GetPin(0);
00501 ASSERT(*ppPin);
00502 (*ppPin)->AddRef();
00503 } else {
00504 *ppPin = NULL;
00505 return VFW_E_NOT_FOUND;
00506 }
00507 return NOERROR;
00508 }
00509
00510 HRESULT CBaseRenderer::EndOfStream()
00511 {
00512
00513
00514 if (m_State == State_Stopped) {
00515 return NOERROR;
00516 }
00517
00518
00519
00520 m_bEOS = TRUE;
00521 if (m_pMediaSample) {
00522 return NOERROR;
00523 }
00524
00525
00526
00527
00528
00529 Ready();
00530
00531
00532
00533
00534
00535 if (m_bStreaming) {
00536 SendEndOfStream();
00537 }
00538 return NOERROR;
00539 }
00540
00541 HRESULT CBaseRenderer::BeginFlush()
00542 {
00543
00544
00545 if (m_State == State_Paused) {
00546 NotReady();
00547 }
00548
00549 SourceThreadCanWait(FALSE);
00550 CancelNotification();
00551 ClearPendingSample();
00552
00553 WaitForReceiveToComplete();
00554 return NOERROR;
00555 }
00556
00557 HRESULT CBaseRenderer::EndFlush()
00558 {
00559
00560 if (m_pPosition) m_pPosition->ResetMediaTime();
00561
00562
00563
00564 ASSERT(CancelNotification() == S_FALSE);
00565 SourceThreadCanWait(TRUE);
00566 return NOERROR;
00567 }
00568
00569 HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin)
00570 {
00571 SetRepaintStatus(TRUE);
00572 m_bAbort = FALSE;
00573 return NOERROR;
00574 }
00575
00576 HRESULT CBaseRenderer::Active()
00577 {
00578 return NOERROR;
00579 }
00580
00581 HRESULT CBaseRenderer::Inactive()
00582 {
00583 if (m_pPosition) {
00584 m_pPosition->ResetMediaTime();
00585 }
00586
00587
00588 ClearPendingSample();
00589 return NOERROR;
00590 }
00591
00592 HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt)
00593 {
00594 return NOERROR;
00595 }
00596
00597 HRESULT CBaseRenderer::BreakConnect()
00598 {
00599
00600
00601 if (m_pQSink) {
00602 m_pQSink->Release();
00603 m_pQSink = NULL;
00604 }
00605
00606
00607
00608 if (m_pInputPin->IsConnected() == FALSE) {
00609 return S_FALSE;
00610 }
00611
00612
00613 if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) {
00614 return VFW_E_NOT_STOPPED;
00615 }
00616
00617 SetRepaintStatus(FALSE);
00618 ResetEndOfStream();
00619 ClearPendingSample();
00620 m_bAbort = FALSE;
00621 return NOERROR;
00622 }
00623
00624 HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample,
00625 REFERENCE_TIME *pStartTime,
00626 REFERENCE_TIME *pEndTime)
00627 {
00628 ASSERT(m_dwAdvise == 0);
00629 ASSERT(pMediaSample);
00630
00631
00632
00633
00634
00635 if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) {
00636 if (*pEndTime < *pStartTime) {
00637 return VFW_E_START_TIME_AFTER_END;
00638 }
00639 } else {
00640
00641 return S_OK;
00642 }
00643
00644
00645
00646
00647
00648 if (m_pClock == NULL) {
00649 return S_OK;
00650 }
00651 return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime);
00652 }
00653
00654 HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample,
00655 REFERENCE_TIME *ptrStart,
00656 REFERENCE_TIME *ptrEnd)
00657 {
00658 return S_FALSE;
00659 }
00660
00661 void CBaseRenderer::SignalTimerFired()
00662 {
00663 m_dwAdvise = 0;
00664 }
00665
00666 HRESULT CBaseRenderer::CancelNotification()
00667 {
00668 ASSERT(m_dwAdvise == 0 || m_pClock);
00669 DWORD_PTR dwAdvise = m_dwAdvise;
00670
00671
00672
00673 if (m_dwAdvise) {
00674 m_pClock->Unadvise(m_dwAdvise);
00675 SignalTimerFired();
00676 ASSERT(m_dwAdvise == 0);
00677 }
00678
00679
00680
00681 m_RenderEvent.Reset();
00682 return (dwAdvise ? S_OK : S_FALSE);
00683 }
00684
00685 BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample)
00686 {
00687 REFERENCE_TIME StartSample, EndSample;
00688
00689
00690
00691 if (pMediaSample == NULL) {
00692 return FALSE;
00693 }
00694
00695
00696
00697
00698
00699
00700 HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample);
00701 if (FAILED(hr)) {
00702 return FALSE;
00703 }
00704
00705
00706
00707
00708
00709 if (hr == S_OK) {
00710 EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent));
00711 return TRUE;
00712 }
00713
00714 ASSERT(m_dwAdvise == 0);
00715 ASSERT(m_pClock);
00716 ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
00717
00718
00719
00720
00721
00722
00723 hr = m_pClock->AdviseTime(
00724 (REFERENCE_TIME) m_tStart,
00725 StartSample,
00726 (HEVENT)(HANDLE) m_RenderEvent,
00727 &m_dwAdvise);
00728
00729 if (SUCCEEDED(hr)) {
00730 return TRUE;
00731 }
00732
00733
00734
00735
00736
00737 ASSERT(m_dwAdvise == 0);
00738 return FALSE;
00739 }
00740
00741 HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample)
00742 {
00743
00744
00745
00746
00747 if (pMediaSample == NULL) {
00748 return S_FALSE;
00749 }
00750
00751
00752
00753
00754
00755 if (m_bStreaming == FALSE) {
00756 return S_FALSE;
00757 }
00758
00759
00760
00761 OnRenderStart(pMediaSample);
00762 DoRenderSample(pMediaSample);
00763 OnRenderEnd(pMediaSample);
00764
00765 return NOERROR;
00766 }
00767
00768 BOOL CBaseRenderer::HaveCurrentSample()
00769 {
00770 CAutoLock cRendererLock(&m_RendererLock);
00771 return (m_pMediaSample == NULL ? FALSE : TRUE);
00772 }
00773
00774 IMediaSample *CBaseRenderer::GetCurrentSample()
00775 {
00776 CAutoLock cRendererLock(&m_RendererLock);
00777 if (m_pMediaSample) {
00778 m_pMediaSample->AddRef();
00779 }
00780 return m_pMediaSample;
00781 }
00782
00783 HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample)
00784 {
00785 CAutoLock cRendererLock(&m_InterfaceLock);
00786 m_bInReceive = TRUE;
00787
00788
00789
00790 HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample);
00791
00792 if (hr != NOERROR) {
00793 m_bInReceive = FALSE;
00794 return E_FAIL;
00795 }
00796
00797
00798
00799
00800
00801
00802
00803 if (m_pInputPin->SampleProps()->pMediaType) {
00804 m_pInputPin->SetMediaType(
00805 (CMediaType *)m_pInputPin->SampleProps()->pMediaType);
00806 }
00807
00808 CAutoLock cSampleLock(&m_RendererLock);
00809
00810 ASSERT(IsActive() == TRUE);
00811 ASSERT(m_pInputPin->IsFlushing() == FALSE);
00812 ASSERT(m_pInputPin->IsConnected() == TRUE);
00813 ASSERT(m_pMediaSample == NULL);
00814
00815
00816
00817
00818
00819 if (m_pMediaSample || m_bEOS || m_bAbort) {
00820 Ready();
00821 m_bInReceive = FALSE;
00822 return E_UNEXPECTED;
00823 }
00824
00825
00826 if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample);
00827
00828
00829
00830 if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) {
00831 ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
00832 ASSERT(CancelNotification() == S_FALSE);
00833 m_bInReceive = FALSE;
00834 return VFW_E_SAMPLE_REJECTED;
00835 }
00836
00837
00838 m_SignalTime = m_pInputPin->SampleProps()->tStop;
00839
00840
00841
00842
00843
00844
00845
00846 m_pMediaSample = pMediaSample;
00847 m_pMediaSample->AddRef();
00848
00849 if (m_bStreaming == FALSE) {
00850 SetRepaintStatus(TRUE);
00851 }
00852 return NOERROR;
00853 }
00854
00855 HRESULT CBaseRenderer::Receive(IMediaSample *pSample)
00856 {
00857 ASSERT(pSample);
00858
00859
00860
00861 HRESULT hr = PrepareReceive(pSample);
00862 ASSERT(m_bInReceive == SUCCEEDED(hr));
00863 if (FAILED(hr)) {
00864 if (hr == VFW_E_SAMPLE_REJECTED) {
00865 return NOERROR;
00866 }
00867 return hr;
00868 }
00869
00870
00871
00872 if (m_State == State_Paused) {
00873 PrepareRender();
00874
00875 m_bInReceive = FALSE;
00876 {
00877
00878 CAutoLock cRendererLock(&m_InterfaceLock);
00879 if (m_State == State_Stopped)
00880 return NOERROR;
00881 m_bInReceive = TRUE;
00882 CAutoLock cSampleLock(&m_RendererLock);
00883 OnReceiveFirstSample(pSample);
00884 }
00885 Ready();
00886 }
00887
00888
00889
00890
00891 hr = WaitForRenderTime();
00892 if (FAILED(hr)) {
00893 m_bInReceive = FALSE;
00894 return NOERROR;
00895 }
00896
00897 PrepareRender();
00898
00899
00900
00901
00902
00903 m_bInReceive = FALSE;
00904
00905
00906 CAutoLock cRendererLock(&m_InterfaceLock);
00907
00908
00909
00910 if (m_State == State_Stopped)
00911 return NOERROR;
00912
00913 CAutoLock cSampleLock(&m_RendererLock);
00914
00915
00916
00917 Render(m_pMediaSample);
00918 ClearPendingSample();
00919 SendEndOfStream();
00920 CancelNotification();
00921 return NOERROR;
00922 }
00923
00924 HRESULT CBaseRenderer::ClearPendingSample()
00925 {
00926 CAutoLock cRendererLock(&m_RendererLock);
00927 if (m_pMediaSample) {
00928 m_pMediaSample->Release();
00929 m_pMediaSample = NULL;
00930 }
00931 return NOERROR;
00932 }
00933
00934 void CALLBACK EndOfStreamTimer(UINT uID,
00935 UINT uMsg,
00936 DWORD_PTR dwUser,
00937 DWORD_PTR dw1,
00938 DWORD_PTR dw2)
00939 {
00940 CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser;
00941 NOTE1("EndOfStreamTimer called (%d)",uID);
00942 pRenderer->TimerCallback();
00943 }
00944
00945 void CBaseRenderer::TimerCallback()
00946 {
00947
00948
00949 CAutoLock cRendererLock(&m_RendererLock);
00950
00951
00952
00953 if (m_EndOfStreamTimer) {
00954 m_EndOfStreamTimer = 0;
00955 SendEndOfStream();
00956 }
00957 }
00958
00959 #define TIMEOUT_DELIVERYWAIT 50
00960 #define TIMEOUT_RESOLUTION 10
00961
00962 HRESULT CBaseRenderer::SendEndOfStream()
00963 {
00964 ASSERT(CritCheckIn(&m_RendererLock));
00965 if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) {
00966 return NOERROR;
00967 }
00968
00969
00970 if (m_pClock == NULL) {
00971 return NotifyEndOfStream();
00972 }
00973
00974
00975
00976 REFERENCE_TIME Signal = m_tStart + m_SignalTime;
00977 REFERENCE_TIME CurrentTime;
00978 m_pClock->GetTime(&CurrentTime);
00979 LONG Delay = LONG((Signal - CurrentTime) / 10000);
00980
00981
00982
00983 NOTE1("Delay until end of stream delivery %d",Delay);
00984 NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime));
00985 NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal));
00986
00987
00988
00989 if (Delay < TIMEOUT_DELIVERYWAIT) {
00990 return NotifyEndOfStream();
00991 }
00992
00993
00994
00995 m_EndOfStreamTimer = timeSetEvent((UINT) Delay,
00996 TIMEOUT_RESOLUTION,
00997 EndOfStreamTimer,
00998 DWORD_PTR(this),
00999 TIME_ONESHOT);
01000 if (m_EndOfStreamTimer == 0) {
01001 return NotifyEndOfStream();
01002 }
01003 return NOERROR;
01004 }
01005
01006 HRESULT CBaseRenderer::NotifyEndOfStream()
01007 {
01008 CAutoLock cRendererLock(&m_RendererLock);
01009 ASSERT(m_bEOS == TRUE);
01010 ASSERT(m_bEOSDelivered == FALSE);
01011 ASSERT(m_EndOfStreamTimer == 0);
01012
01013
01014
01015 if (m_bStreaming == FALSE) {
01016 ASSERT(m_EndOfStreamTimer == 0);
01017 return NOERROR;
01018 }
01019
01020
01021 m_EndOfStreamTimer = 0;
01022
01023
01024
01025
01026
01027
01028 if (m_pPosition) m_pPosition->EOS();
01029 m_bEOSDelivered = TRUE;
01030 NOTE("Sending EC_COMPLETE...");
01031 return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this);
01032 }
01033
01034 HRESULT CBaseRenderer::ResetEndOfStream()
01035 {
01036 ResetEndOfStreamTimer();
01037 CAutoLock cRendererLock(&m_RendererLock);
01038
01039 m_bEOS = FALSE;
01040 m_bEOSDelivered = FALSE;
01041 m_SignalTime = 0;
01042
01043 return NOERROR;
01044 }
01045
01046 void CBaseRenderer::ResetEndOfStreamTimer()
01047 {
01048 ASSERT(CritCheckOut(&m_RendererLock));
01049 if (m_EndOfStreamTimer) {
01050 timeKillEvent(m_EndOfStreamTimer);
01051 m_EndOfStreamTimer = 0;
01052 }
01053 }
01054
01055 HRESULT CBaseRenderer::StartStreaming()
01056 {
01057 CAutoLock cRendererLock(&m_RendererLock);
01058 if (m_bStreaming == TRUE) {
01059 return NOERROR;
01060 }
01061
01062
01063
01064 m_bStreaming = TRUE;
01065 timeBeginPeriod(1);
01066 OnStartStreaming();
01067
01068
01069 ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
01070 ASSERT(CancelNotification() == S_FALSE);
01071
01072
01073
01074 if (m_pMediaSample == NULL) {
01075 return SendEndOfStream();
01076 }
01077
01078
01079
01080 ASSERT(m_pMediaSample);
01081 if (!ScheduleSample(m_pMediaSample))
01082 m_RenderEvent.Set();
01083
01084 return NOERROR;
01085 }
01086
01087 HRESULT CBaseRenderer::StopStreaming()
01088 {
01089 CAutoLock cRendererLock(&m_RendererLock);
01090 m_bEOSDelivered = FALSE;
01091
01092 if (m_bStreaming == TRUE) {
01093 m_bStreaming = FALSE;
01094 OnStopStreaming();
01095 timeEndPeriod(1);
01096 }
01097 return NOERROR;
01098 }
01099
01100 void CBaseRenderer::SetRepaintStatus(BOOL bRepaint)
01101 {
01102 CAutoLock cSampleLock(&m_RendererLock);
01103 m_bRepaintStatus = bRepaint;
01104 }
01105
01106 void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd)
01107 {
01108 IMediaEventSink *pSink;
01109
01110
01111 HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink);
01112 if (SUCCEEDED(hr)) {
01113 pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0);
01114 pSink->Release();
01115 }
01116 NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0);
01117 }
01118
01119 #define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_)));
01120
01121 void CBaseRenderer::SendRepaint()
01122 {
01123 CAutoLock cSampleLock(&m_RendererLock);
01124 ASSERT(m_pInputPin);
01125
01126
01127
01128
01129
01130
01131
01132
01133 if (m_bAbort == FALSE) {
01134 if (m_pInputPin->IsConnected() == TRUE) {
01135 if (m_pInputPin->IsFlushing() == FALSE) {
01136 if (IsEndOfStream() == FALSE) {
01137 if (m_bRepaintStatus == TRUE) {
01138 IPin *pPin = (IPin *) m_pInputPin;
01139 NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0);
01140 SetRepaintStatus(FALSE);
01141 RLOG("Sending repaint");
01142 }
01143 }
01144 }
01145 }
01146 }
01147 }
01148
01149 BOOL CBaseRenderer::OnDisplayChange()
01150 {
01151
01152
01153 CAutoLock cSampleLock(&m_RendererLock);
01154 if (m_pInputPin->IsConnected() == FALSE) {
01155 return FALSE;
01156 }
01157
01158 RLOG("Notification of EC_DISPLAY_CHANGE");
01159
01160
01161
01162 IPin *pPin = (IPin *) m_pInputPin;
01163 m_pInputPin->AddRef();
01164 NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0);
01165 SetAbortSignal(TRUE);
01166 ClearPendingSample();
01167 m_pInputPin->Release();
01168
01169 return TRUE;
01170 }
01171
01172 void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample)
01173 {
01174 #ifdef PERF
01175 REFERENCE_TIME trStart, trEnd;
01176 pMediaSample->GetTime(&trStart, &trEnd);
01177
01178 MSR_INTEGER(m_idBaseStamp, (int)trStart);
01179
01180 m_pClock->GetTime(&m_trRenderStart);
01181 MSR_INTEGER(0, (int)m_trRenderStart);
01182 REFERENCE_TIME trStream;
01183 trStream = m_trRenderStart-m_tStart;
01184 MSR_INTEGER(0,(int)trStream);
01185
01186 const int trLate = (int)(trStream - trStart);
01187 MSR_INTEGER(m_idBaseAccuracy, trLate/10000);
01188 #endif
01189
01190 }
01191
01192 void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample)
01193 {
01194 #ifdef PERF
01195 REFERENCE_TIME trNow;
01196 m_pClock->GetTime(&trNow);
01197 MSR_INTEGER(0,(int)trNow);
01198 int t = (int)((trNow - m_trRenderStart)/10000);
01199 MSR_INTEGER(m_idBaseRenderTime, t);
01200 #endif
01201 }
01202
01203 CRendererInputPin::CRendererInputPin(CBaseRenderer *pRenderer,
01204 HRESULT *phr,
01205 LPCWSTR pPinName) :
01206 CBaseInputPin(NAME("Renderer pin"),
01207 pRenderer,
01208 &pRenderer->m_InterfaceLock,
01209 (HRESULT *) phr,
01210 pPinName)
01211 {
01212 m_pRenderer = pRenderer;
01213 ASSERT(m_pRenderer);
01214 }
01215
01216 STDMETHODIMP CRendererInputPin::EndOfStream()
01217 {
01218 CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
01219 CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
01220
01221
01222
01223 HRESULT hr = CheckStreaming();
01224 if (hr != NOERROR) {
01225 return hr;
01226 }
01227
01228
01229
01230 hr = m_pRenderer->EndOfStream();
01231 if (SUCCEEDED(hr)) {
01232 hr = CBaseInputPin::EndOfStream();
01233 }
01234 return hr;
01235 }
01236
01237 STDMETHODIMP CRendererInputPin::BeginFlush()
01238 {
01239 CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
01240 {
01241 CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
01242 CBaseInputPin::BeginFlush();
01243 m_pRenderer->BeginFlush();
01244 }
01245 return m_pRenderer->ResetEndOfStream();
01246 }
01247
01248 STDMETHODIMP CRendererInputPin::EndFlush()
01249 {
01250 CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
01251 CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
01252
01253 HRESULT hr = m_pRenderer->EndFlush();
01254 if (SUCCEEDED(hr)) {
01255 hr = CBaseInputPin::EndFlush();
01256 }
01257 return hr;
01258 }
01259
01260 STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample)
01261 {
01262 return m_pRenderer->Receive(pSample);
01263 }
01264
01265 HRESULT CRendererInputPin::BreakConnect()
01266 {
01267 HRESULT hr = m_pRenderer->BreakConnect();
01268 if (FAILED(hr)) {
01269 return hr;
01270 }
01271 return CBaseInputPin::BreakConnect();
01272 }
01273
01274 HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin)
01275 {
01276 HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin);
01277 if (FAILED(hr)) {
01278 return hr;
01279 }
01280 return CBaseInputPin::CompleteConnect(pReceivePin);
01281 }
01282
01283 STDMETHODIMP CRendererInputPin::QueryId(LPWSTR *Id)
01284 {
01285 CheckPointer(Id,E_POINTER);
01286
01287 *Id = (LPWSTR)CoTaskMemAlloc(8);
01288 if (*Id == NULL) {
01289 return E_OUTOFMEMORY;
01290 }
01291 lstrcpyW(*Id, L"In");
01292 return NOERROR;
01293 }
01294
01295 HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt)
01296 {
01297 return m_pRenderer->CheckMediaType(pmt);
01298 }
01299
01300 HRESULT CRendererInputPin::Active()
01301 {
01302 return m_pRenderer->Active();
01303 }
01304
01305 HRESULT CRendererInputPin::Inactive()
01306 {
01307 return m_pRenderer->Inactive();
01308 }
01309
01310 HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt)
01311 {
01312 HRESULT hr = CBaseInputPin::SetMediaType(pmt);
01313 if (FAILED(hr)) {
01314 return hr;
01315 }
01316 return m_pRenderer->SetMediaType(pmt);
01317 }
01318
01319 const TCHAR AMQUALITY[] = TEXT("ActiveMovie");
01320 const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames");
01321
01322 CBaseVideoRenderer::CBaseVideoRenderer(
01323 REFCLSID RenderClass,
01324 TCHAR *pName,
01325 LPUNKNOWN pUnk,
01326 HRESULT *phr) :
01327
01328 CBaseRenderer(RenderClass,pName,pUnk,phr),
01329 m_cFramesDropped(0),
01330 m_cFramesDrawn(0),
01331 m_bSupplierHandlingQuality(FALSE)
01332 {
01333 ResetStreamingTimes();
01334
01335 #ifdef PERF
01336 m_idTimeStamp = MSR_REGISTER("Frame time stamp");
01337 m_idEarliness = MSR_REGISTER("Earliness fudge");
01338 m_idTarget = MSR_REGISTER("Target (mSec)");
01339 m_idSchLateTime = MSR_REGISTER("mSec late when scheduled");
01340 m_idDecision = MSR_REGISTER("Scheduler decision code");
01341 m_idQualityRate = MSR_REGISTER("Quality rate sent");
01342 m_idQualityTime = MSR_REGISTER("Quality time sent");
01343 m_idWaitReal = MSR_REGISTER("Render wait");
01344
01345 m_idFrameAccuracy = MSR_REGISTER("Frame accuracy (msecs)");
01346 m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE);
01347
01348
01349 m_idRenderAvg = MSR_REGISTER("Render draw time Avg");
01350 m_idFrameAvg = MSR_REGISTER("FrameAvg");
01351 m_idWaitAvg = MSR_REGISTER("WaitAvg");
01352 m_idDuration = MSR_REGISTER("Duration");
01353 m_idThrottle = MSR_REGISTER("Audio-video throttle wait");
01354
01355 #endif
01356 }
01357
01358 CBaseVideoRenderer::~CBaseVideoRenderer()
01359 {
01360 ASSERT(m_dwAdvise == 0);
01361 }
01362
01363 HRESULT CBaseVideoRenderer::ResetStreamingTimes()
01364 {
01365 m_trLastDraw = -1000;
01366 m_tStreamingStart = timeGetTime();
01367 m_trRenderAvg = 0;
01368 m_trFrameAvg = -1;
01369 m_trDuration = 0;
01370 m_trRenderLast = 0;
01371 m_trWaitAvg = 0;
01372 m_tRenderStart = 0;
01373 m_cFramesDrawn = 0;
01374 m_cFramesDropped = 0;
01375 m_iTotAcc = 0;
01376 m_iSumSqAcc = 0;
01377 m_iSumSqFrameTime = 0;
01378 m_trFrame = 0;
01379 m_trLate = 0;
01380 m_iSumFrameTime = 0;
01381 m_nNormal = 0;
01382 m_trEarliness = 0;
01383 m_trTarget = -300000;
01384 m_trThrottle = 0;
01385 m_trRememberStampForPerf = 0;
01386
01387 #ifdef PERF
01388 m_trRememberFrameForPerf = 0;
01389 #endif
01390
01391 return NOERROR;
01392 }
01393
01394 HRESULT CBaseVideoRenderer::OnStartStreaming()
01395 {
01396 ResetStreamingTimes();
01397 return NOERROR;
01398 }
01399
01400 HRESULT CBaseVideoRenderer::OnStopStreaming()
01401 {
01402 m_tStreamingStart = timeGetTime()-m_tStreamingStart;
01403 return NOERROR;
01404 }
01405
01406 void CBaseVideoRenderer::OnWaitStart()
01407 {
01408 MSR_START(m_idWaitReal);
01409 }
01410
01411 void CBaseVideoRenderer::OnWaitEnd()
01412 {
01413 #ifdef PERF
01414 MSR_STOP(m_idWaitReal);
01415
01416
01417
01418 REFERENCE_TIME trRealStream;
01419 #if 0
01420 m_pClock->GetTime(&trRealStream);
01421 #else
01422
01423
01424
01425 REFERENCE_TIME tr = timeGetTime()*10000;
01426 trRealStream = tr + m_llTimeOffset;
01427 #endif
01428 trRealStream -= m_tStart;
01429
01430 if (m_trRememberStampForPerf==0) {
01431
01432
01433
01434
01435 PreparePerformanceData(0, 0);
01436 } else {
01437 int trLate = (int)(trRealStream - m_trRememberStampForPerf);
01438 int trFrame = (int)(tr - m_trRememberFrameForPerf);
01439 PreparePerformanceData(trLate, trFrame);
01440 }
01441 m_trRememberFrameForPerf = tr;
01442 #endif
01443 }
01444
01445 void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame)
01446 {
01447 m_trLate = trLate;
01448 m_trFrame = trFrame;
01449 }
01450
01451 void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame)
01452 {
01453
01454 int tLate = trLate/10000;
01455
01456
01457
01458
01459
01460 MSR_INTEGER( m_idFrameAccuracy, tLate );
01461
01462
01463
01464
01465 if (tLate>1000 || tLate<-1000) {
01466 if (m_cFramesDrawn<=1) {
01467 tLate = 0;
01468 } else if (tLate>0) {
01469 tLate = 1000;
01470 } else {
01471 tLate = -1000;
01472 }
01473 }
01474
01475
01476 if (m_cFramesDrawn>1) {
01477 m_iTotAcc += tLate;
01478 m_iSumSqAcc += (tLate*tLate);
01479 }
01480
01481
01482
01483 if (m_cFramesDrawn>2) {
01484 int tFrame = trFrame/10000;
01485
01486
01487
01488
01489 if (tFrame>1000||tFrame<0) tFrame = 1000;
01490 m_iSumSqFrameTime += tFrame*tFrame;
01491 ASSERT(m_iSumSqFrameTime>=0);
01492 m_iSumFrameTime += tFrame;
01493 }
01494 ++m_cFramesDrawn;
01495
01496 }
01497
01498 void CBaseVideoRenderer::ThrottleWait()
01499 {
01500 if (m_trThrottle>0) {
01501 int iThrottle = m_trThrottle/10000;
01502 MSR_INTEGER( m_idThrottle, iThrottle);
01503 DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle));
01504 Sleep(iThrottle);
01505 } else {
01506 Sleep(0);
01507 }
01508 }
01509
01510 void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample)
01511 {
01512 int time = 0;
01513 m_trRenderAvg = 0;
01514 m_trRenderLast = 5000000;
01515
01516
01517
01518 RecordFrameLateness(m_trLate, m_trFrame);
01519 ThrottleWait();
01520 }
01521
01522 void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample)
01523 {
01524
01525 RecordFrameLateness(m_trLate, m_trFrame);
01526 m_tRenderStart = timeGetTime();
01527 }
01528
01529 void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample)
01530 {
01531
01532
01533
01534
01535
01536 int tr = (timeGetTime() - m_tRenderStart)*10000;
01537 if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) {
01538
01539 m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD;
01540 }
01541 m_trRenderLast = tr;
01542 ThrottleWait();
01543 }
01544
01545 STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc)
01546 {
01547
01548 m_pQSink = piqc;
01549
01550 return NOERROR;
01551 }
01552
01553 STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q)
01554 {
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590 if (q.Proportion>=1000) { m_trThrottle = 0; }
01591 else {
01592
01593
01594 m_trThrottle = -330000 + (388880000/(q.Proportion+167));
01595 }
01596 return NOERROR;
01597 }
01598
01599 HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate,
01600 REFERENCE_TIME trRealStream)
01601 {
01602 Quality q;
01603 HRESULT hr;
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617 q.TimeStamp = (REFERENCE_TIME)trRealStream;
01618
01619 if (m_trFrameAvg<0) {
01620 q.Type = Famine;
01621 }
01622
01623 else if (m_trFrameAvg > 2*m_trRenderAvg) {
01624 q.Type = Famine;
01625 } else {
01626 q.Type = Flood;
01627 }
01628
01629 q.Proportion = 1000;
01630
01631 if (m_trFrameAvg<0) {
01632
01633 }
01634 else if ( trLate> 0 ) {
01635
01636
01637
01638
01639 q.Proportion = 1000 - (int)((trLate)/(UNITS/1000));
01640 if (q.Proportion<500) {
01641 q.Proportion = 500;
01642 } else {
01643 }
01644
01645 } else if ( m_trWaitAvg>20000
01646 && trLate<-20000
01647 ){
01648
01649 if (m_trWaitAvg>=m_trFrameAvg) {
01650
01651
01652
01653
01654 q.Proportion = 2000;
01655 } else {
01656 if (m_trFrameAvg+20000 > m_trWaitAvg) {
01657 q.Proportion
01658 = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg));
01659 } else {
01660
01661
01662
01663
01664 q.Proportion = 2000;
01665 }
01666 }
01667
01668 if (q.Proportion>2000) {
01669 q.Proportion = 2000;
01670 }
01671 }
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686 q.Late = trLate + m_trRenderAvg/2;
01687
01688
01689 MSR_INTEGER(m_idQualityRate, q.Proportion);
01690 MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 );
01691
01692
01693
01694 if (m_pQSink==NULL) {
01695
01696
01697
01698
01699 IQualityControl *pQC = NULL;
01700 IPin *pOutputPin = m_pInputPin->GetConnected();
01701 ASSERT(pOutputPin != NULL);
01702
01703
01704
01705 hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC);
01706 if (SUCCEEDED(hr)) {
01707 m_pQSink = pQC;
01708 }
01709 }
01710 if (m_pQSink) {
01711 return m_pQSink->Notify(this,q);
01712 }
01713
01714 return S_FALSE;
01715
01716 }
01717
01718 HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample,
01719 REFERENCE_TIME *ptrStart,
01720 REFERENCE_TIME *ptrEnd)
01721 {
01722
01723
01724 ASSERT(m_pClock);
01725
01726 MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32));
01727 MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart));
01728
01729
01730
01731
01732
01733
01734 if (*ptrStart>=80000) {
01735 *ptrStart -= 80000;
01736 *ptrEnd -= 80000;
01737 }
01738
01739
01740
01741 m_trRememberStampForPerf = *ptrStart;
01742
01743
01744 REFERENCE_TIME trRealStream;
01745 m_pClock->GetTime(&trRealStream);
01746 #ifdef PERF
01747
01748
01749
01750
01751 m_llTimeOffset = trRealStream-timeGetTime()*10000;
01752 #endif
01753 trRealStream -= m_tStart;
01754
01755
01756
01757
01758
01759
01760
01761
01762 const int trTrueLate = TimeDiff(trRealStream - *ptrStart);
01763 const int trLate = trTrueLate;
01764
01765 MSR_INTEGER(m_idSchLateTime, trTrueLate/10000);
01766
01767
01768 HRESULT hr = SendQuality(trLate, trRealStream);
01769
01770 m_bSupplierHandlingQuality = (hr==S_OK);
01771
01772
01773
01774 const int trDuration = (int)(*ptrEnd - *ptrStart);
01775 {
01776
01777
01778
01779
01780
01781 int t = m_trDuration/32;
01782 if ( trDuration > m_trDuration+t
01783 || trDuration < m_trDuration-t
01784 ) {
01785
01786
01787
01788 m_trFrameAvg = trDuration;
01789 m_trDuration = trDuration;
01790 }
01791 }
01792
01793 MSR_INTEGER(m_idEarliness, m_trEarliness/10000);
01794 MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000);
01795 MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000);
01796 MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000);
01797 MSR_INTEGER(m_idDuration, trDuration/10000);
01798
01799 #ifdef PERF
01800 if (S_OK==pMediaSample->IsDiscontinuity()) {
01801 MSR_INTEGER(m_idDecision, 9000);
01802 }
01803 #endif
01804
01805
01806
01807
01808
01809
01810 BOOL bJustDroppedFrame
01811 = ( m_bSupplierHandlingQuality
01812
01813
01814 && (S_OK == pMediaSample->IsDiscontinuity())
01815 )
01816 || (m_nNormal==-1);
01817
01818
01819 if (trLate>0) {
01820 m_trEarliness = 0;
01821 } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) {
01822 m_trEarliness = trLate;
01823 } else {
01824 m_trEarliness = m_trEarliness - m_trEarliness/8;
01825 }
01826
01827
01828
01829 int trWaitAvg;
01830 {
01831
01832
01833 int trL = trLate<0 ? -trLate : 0;
01834 trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD;
01835 }
01836
01837 int trFrame;
01838 {
01839 REFERENCE_TIME tr = trRealStream - m_trLastDraw;
01840 if (tr>10000000) {
01841 tr = 10000000;
01842 }
01843 trFrame = int(tr);
01844 }
01845
01846
01847 if (
01848
01849
01850 (3*m_trRenderAvg <= m_trFrameAvg)
01851
01852
01853
01854
01855 || ( m_bSupplierHandlingQuality
01856 ? (trLate <= trDuration*4)
01857 : (trLate+trLate < trDuration)
01858 )
01859
01860
01861
01862 || (m_trWaitAvg > 80000)
01863
01864
01865
01866
01867 || ((trRealStream - m_trLastDraw) > UNITS)
01868
01869 ) {
01870 HRESULT Result;
01871
01872
01873
01874
01875
01876
01877
01878 BOOL bPlayASAP = FALSE;
01879
01880
01881
01882
01883 if ( bJustDroppedFrame) {
01884 bPlayASAP = TRUE;
01885 MSR_INTEGER(m_idDecision, 9001);
01886 }
01887
01888
01889
01890
01891 else if ( (m_trFrameAvg > trDuration + trDuration/16)
01892
01893
01894
01895
01896 && (trLate > - trDuration*10)
01897 ){
01898 bPlayASAP = TRUE;
01899 MSR_INTEGER(m_idDecision, 9002);
01900 }
01901 #if 0
01902
01903 else if ( (trLate + trDuration > 0)
01904 && (m_trWaitAvg<=20000)
01905 ) {
01906 bPlayASAP = TRUE;
01907 MSR_INTEGER(m_idDecision, 9003);
01908 }
01909 #endif
01910
01911
01912
01913
01914 if (trLate<-9000000) {
01915 bPlayASAP = FALSE;
01916 }
01917
01918 if (bPlayASAP) {
01919
01920 m_nNormal = 0;
01921 MSR_INTEGER(m_idDecision, 0);
01922
01923
01924
01925
01926
01927 m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD;
01928
01929
01930 m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD;
01931 #ifndef PERF
01932
01933
01934
01935
01936
01937
01938 PreparePerformanceData(trTrueLate, trFrame);
01939 #endif
01940 m_trLastDraw = trRealStream;
01941 if (m_trEarliness > trLate) {
01942 m_trEarliness = trLate;
01943 }
01944 Result = S_OK;
01945
01946 } else {
01947 ++m_nNormal;
01948
01949
01950
01951
01952
01953
01954 m_trFrameAvg = trDuration;
01955 MSR_INTEGER(m_idDecision, 1);
01956
01957
01958
01959 {
01960 int trE = m_trEarliness;
01961 if (trE < -m_trFrameAvg) {
01962 trE = -m_trFrameAvg;
01963 }
01964 *ptrStart += trE;
01965 }
01966
01967 int Delay = -trTrueLate;
01968 Result = Delay<=0 ? S_OK : S_FALSE;
01969
01970 m_trWaitAvg = trWaitAvg;
01971
01972
01973
01974 if (Result==S_FALSE) {
01975 trFrame = TimeDiff(*ptrStart-m_trLastDraw);
01976 m_trLastDraw = *ptrStart;
01977 } else {
01978
01979 m_trLastDraw = trRealStream;
01980 }
01981 #ifndef PERF
01982 int iAccuracy;
01983 if (Delay>0) {
01984
01985 iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf);
01986 } else {
01987
01988 iAccuracy = trTrueLate;
01989 }
01990 PreparePerformanceData(iAccuracy, trFrame);
01991 #endif
01992 }
01993 return Result;
01994 }
01995
01996
01997
01998
01999
02000 m_trWaitAvg = trWaitAvg;
02001
02002 #ifdef PERF
02003
02004 if (m_bDrawLateFrames) {
02005 return S_OK;
02006 }
02007 #endif
02008
02009
02010
02011
02012
02013 MSR_INTEGER(m_idDecision, 2);
02014 m_nNormal = -1;
02015 return E_FAIL;
02016
02017 }
02018
02019 BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample)
02020 {
02021
02022
02023 BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample);
02024 if (bDrawImage == FALSE) {
02025
02026 ++m_cFramesDropped;
02027 return FALSE;
02028 }
02029
02030
02031
02032 return TRUE;
02033 }
02034
02035 STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(int *pcFramesDropped)
02036 {
02037 CheckPointer(pcFramesDropped,E_POINTER);
02038 CAutoLock cVideoLock(&m_InterfaceLock);
02039 *pcFramesDropped = m_cFramesDropped;
02040 return NOERROR;
02041 }
02042
02043 STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn)
02044 {
02045 CheckPointer(pcFramesDrawn,E_POINTER);
02046 CAutoLock cVideoLock(&m_InterfaceLock);
02047 *pcFramesDrawn = m_cFramesDrawn;
02048 return NOERROR;
02049 }
02050
02051 STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate)
02052 {
02053 CheckPointer(piAvgFrameRate,E_POINTER);
02054 CAutoLock cVideoLock(&m_InterfaceLock);
02055
02056 int t;
02057 if (m_bStreaming) {
02058 t = timeGetTime()-m_tStreamingStart;
02059 } else {
02060 t = m_tStreamingStart;
02061 }
02062
02063 if (t<=0) {
02064 *piAvgFrameRate = 0;
02065 ASSERT(m_cFramesDrawn == 0);
02066 } else {
02067
02068 *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t);
02069 }
02070 return NOERROR;
02071 }
02072
02073 STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset( int *piAvg)
02074 {
02075 CheckPointer(piAvg,E_POINTER);
02076 CAutoLock cVideoLock(&m_InterfaceLock);
02077
02078 if (NULL==m_pClock) {
02079 *piAvg = 0;
02080 return NOERROR;
02081 }
02082
02083
02084
02085 if (m_cFramesDrawn<=1) {
02086 *piAvg = 0;
02087 } else {
02088 *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1));
02089 }
02090 return NOERROR;
02091 }
02092
02093 int isqrt(int x)
02094 {
02095 int s = 1;
02096
02097 if (x > 0x40000000) {
02098 s = 0x8000;
02099 } else {
02100 while (s*s<x) {
02101 s = 2*s;
02102 }
02103
02104 if (x==0) {
02105 s= 0;
02106
02107 } else {
02108 s = (s*s+x)/(2*s);
02109 if (s>=0) s = (s*s+x)/(2*s);
02110 if (s>=0) s = (s*s+x)/(2*s);
02111 }
02112 }
02113 return s;
02114 }
02115
02116 HRESULT CBaseVideoRenderer::GetStdDev(
02117 int nSamples,
02118 int *piResult,
02119 LONGLONG llSumSq,
02120 LONGLONG iTot
02121 )
02122 {
02123 CheckPointer(piResult,E_POINTER);
02124 CAutoLock cVideoLock(&m_InterfaceLock);
02125
02126 if (NULL==m_pClock) {
02127 *piResult = 0;
02128 return NOERROR;
02129 }
02130
02131
02132
02133
02134
02135
02136 if (nSamples<=1) {
02137 *piResult = 0;
02138 } else {
02139 LONGLONG x;
02140
02141
02142
02143
02144 x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0);
02145 x = x / (nSamples-1);
02146 ASSERT(x>=0);
02147 *piResult = isqrt((LONG)x);
02148 }
02149 return NOERROR;
02150 }
02151
02152 STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset( int *piDev)
02153 {
02154
02155
02156 return GetStdDev(m_cFramesDrawn - 1,
02157 piDev,
02158 m_iSumSqAcc,
02159 m_iTotAcc);
02160 }
02161
02162 STDMETHODIMP CBaseVideoRenderer::get_Jitter( int *piJitter)
02163 {
02164
02165
02166
02167 return GetStdDev(m_cFramesDrawn - 2,
02168 piJitter,
02169 m_iSumSqFrameTime,
02170 m_iSumFrameTime);
02171 }
02172
02173 STDMETHODIMP
02174 CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,VOID **ppv)
02175 {
02176
02177
02178 if (riid == IID_IQualProp) {
02179 return GetInterface( (IQualProp *)this, ppv);
02180 } else if (riid == IID_IQualityControl) {
02181 return GetInterface( (IQualityControl *)this, ppv);
02182 }
02183 return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv);
02184 }
02185
02186 STDMETHODIMP
02187 CBaseVideoRenderer::JoinFilterGraph(IFilterGraph *pGraph,LPCWSTR pName)
02188 {
02189
02190
02191
02192 if (!pGraph && m_pGraph) {
02193
02194
02195
02196 IBaseFilter* pFilter;
02197 QueryInterface(IID_IBaseFilter,(void **) &pFilter);
02198 NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0);
02199 pFilter->Release();
02200 }
02201 return CBaseFilter::JoinFilterGraph(pGraph, pName);
02202 }
02203
02204 #pragma warning(disable: 4514)
02205