REFERENCE_TIME CSubPicQueue::UpdateQueue() { CAutoLock cQueueLock(&m_csQueueLock); REFERENCE_TIME rtNow = m_rtNow; REFERENCE_TIME rtNowCompare = rtNow; if (rtNow < m_rtNowLast) { m_Queue.RemoveAll(); m_rtNowLast = rtNow; } else { m_rtNowLast = rtNow; m_rtQueueMin = LONGLONG_MAX; m_rtQueueMax = LONGLONG_ERROR; POSITION SavePos = 0; { POSITION Iter = m_Queue.GetHeadPosition(); REFERENCE_TIME rtBestStop = LONGLONG_MAX; while (Iter) { POSITION ThisPos = Iter; ISubPic* pSubPic = m_Queue.GetNext(Iter); REFERENCE_TIME rtStart = pSubPic->GetStart(); REFERENCE_TIME rtStop = pSubPic->GetStop(); REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); if (rtNow >= rtStart && rtNow < rtSegmentStop) { REFERENCE_TIME Diff = rtNow - rtStop; if (Diff < rtBestStop) { rtBestStop = Diff; SavePos = ThisPos; } } } } #if SUBPIC_TRACE_LEVEL > 3 if (SavePos) { ISubPic* pSubPic = m_Queue.GetAt(SavePos); REFERENCE_TIME rtStart = pSubPic->GetStart(); REFERENCE_TIME rtStop = pSubPic->GetStop(); TRACE(_T("Save: %f->%f\n"), double(rtStart) / 10000000.0, double(rtStop) / 10000000.0); } #endif { POSITION Iter = m_Queue.GetHeadPosition(); while (Iter) { POSITION ThisPos = Iter; ISubPic* pSubPic = m_Queue.GetNext(Iter); REFERENCE_TIME rtStart = pSubPic->GetStart(); REFERENCE_TIME rtStop = pSubPic->GetStop(); if (rtStop <= rtNowCompare && ThisPos != SavePos) { #if SUBPIC_TRACE_LEVEL > 0 TRACE(_T("Remove: %f->%f\n"), double(rtStart) / 10000000.0, double(rtStop) / 10000000.0); #endif m_Queue.RemoveAt(ThisPos); continue; } if (rtStop > rtNow) { rtNow = rtStop; } m_rtQueueMin = std::min(m_rtQueueMin, rtStart); m_rtQueueMax = std::max(m_rtQueueMax, rtStop); } } } return rtNow; }
DWORD CSubPicQueue::ThreadProc() { BOOL bDisableAnim = m_bDisableAnim; SetThreadName(DWORD(-1), "Subtitle Renderer Thread"); SetThreadPriority(m_hThread, bDisableAnim ? THREAD_PRIORITY_LOWEST : THREAD_PRIORITY_ABOVE_NORMAL); bool bAgain = true; for (;;) { DWORD Ret = WaitForMultipleObjects(EVENT_COUNT, m_ThreadEvents, FALSE, bAgain ? 0 : INFINITE); bAgain = false; if (Ret == WAIT_TIMEOUT) { ; } else if ((Ret - WAIT_OBJECT_0) != EVENT_TIME) { break; } double fps = m_fps; REFERENCE_TIME rtTimePerFrame = (REFERENCE_TIME)(10000000.0 / fps); REFERENCE_TIME rtNow = UpdateQueue(); int nMaxSubPic = m_nMaxSubPic; CComPtr<ISubPicProvider> pSubPicProvider; if (SUCCEEDED(GetSubPicProvider(&pSubPicProvider)) && pSubPicProvider && SUCCEEDED(pSubPicProvider->Lock())) { for (POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps); pos && !m_fBreakBuffering && GetQueueCount() < nMaxSubPic; pos = pSubPicProvider->GetNext(pos)) { REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); if (m_rtNow >= rtStart) { if (m_rtNow >= rtStop) { continue; } } if (rtStart >= m_rtNow + 60 * 10000000i64) { // we are already one minute ahead, this should be enough break; } if (rtNow < rtStop) { REFERENCE_TIME rtCurrent = std::max(rtNow, rtStart); bool bIsAnimated = pSubPicProvider->IsAnimated(pos) && !bDisableAnim; while (rtCurrent < rtStop) { SIZE MaxTextureSize, VirtualSize; POINT VirtualTopLeft; HRESULT hr2; if (SUCCEEDED(hr2 = pSubPicProvider->GetTextureSize(pos, MaxTextureSize, VirtualSize, VirtualTopLeft))) { m_pAllocator->SetMaxTextureSize(MaxTextureSize); } CComPtr<ISubPic> pStatic; if (FAILED(m_pAllocator->GetStatic(&pStatic))) { break; } HRESULT hr; if (bIsAnimated) { REFERENCE_TIME rtEndThis = std::min(rtCurrent + rtTimePerFrame, rtStop); hr = RenderTo(pStatic, rtCurrent, rtEndThis, fps, bIsAnimated); pStatic->SetSegmentStart(rtStart); pStatic->SetSegmentStop(rtStop); #if SUBPIC_TRACE_LEVEL > 0 CRect r; pStatic->GetDirtyRect(&r); TRACE(_T("Render: %f->%f %f->%f %dx%d\n"), double(rtCurrent) / 10000000.0, double(rtEndThis) / 10000000.0, double(rtStart) / 10000000.0, double(rtStop) / 10000000.0, r.Width(), r.Height()); #endif rtCurrent = rtEndThis; } else { hr = RenderTo(pStatic, rtStart, rtStop, fps, bIsAnimated); // Non-animated subtitles aren't part of a segment pStatic->SetSegmentStart(0); pStatic->SetSegmentStop(0); rtCurrent = rtStop; } #if SUBPIC_TRACE_LEVEL > 0 if (m_rtNow > rtCurrent) { TRACE(_T("BEHIND\n")); } #endif if (FAILED(hr)) { break; } if (S_OK != hr) { // subpic was probably empty continue; } CComPtr<ISubPic> pDynamic; if (FAILED(m_pAllocator->AllocDynamic(&pDynamic)) || FAILED(pStatic->CopyTo(pDynamic))) { break; } if (SUCCEEDED(hr2)) { pDynamic->SetVirtualTextureSize(VirtualSize, VirtualTopLeft); } RelativeTo relativeTo; if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { pDynamic->SetRelativeTo(relativeTo); } AppendQueue(pDynamic); bAgain = true; if (GetQueueCount() >= nMaxSubPic) { break; } } } } pSubPicProvider->Unlock(); } if (m_fBreakBuffering) { bAgain = true; CAutoLock cQueueLock(&m_csQueueLock); REFERENCE_TIME rtInvalidate = m_rtInvalidate; POSITION Iter = m_Queue.GetHeadPosition(); while (Iter) { POSITION ThisPos = Iter; ISubPic* pSubPic = m_Queue.GetNext(Iter); REFERENCE_TIME rtStart = pSubPic->GetStart(); REFERENCE_TIME rtStop = pSubPic->GetStop(); REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); if (rtSegmentStop > rtInvalidate) { #if SUBPIC_TRACE_LEVEL >= 0 TRACE(_T("Removed subtitle because of invalidation: %f -> %f (%f)\n"), double(rtStart) / 10000000.0, double(rtStop) / 10000000.0, double(rtSegmentStop) / 10000000.0); #endif m_Queue.RemoveAt(ThisPos); continue; } } /* while (GetCount() && GetTail()->GetStop() > rtInvalidate) { if (GetTail()->GetStart() < rtInvalidate) GetTail()->SetStop(rtInvalidate); else { RemoveTail(); } } */ m_fBreakBuffering = false; } } return 0; }
REFERENCE_TIME CSubPicQueue::UpdateQueue() { CAutoLock cQueueLock(&m_csQueueLock); REFERENCE_TIME rtNow = m_rtNow; REFERENCE_TIME rtNowCompare = rtNow; if (rtNow < m_rtNowLast) { m_Queue.RemoveAll(); m_rtNowLast = rtNow; } else { m_rtNowLast = rtNow; m_rtQueueMin = 0x7fffffffffffffffi64; m_rtQueueMax = 0xffffffffffffffffi64; REFERENCE_TIME rtBestStop = 0x7fffffffffffffffi64; POSITION SavePos = 0; { POSITION Iter = m_Queue.GetHeadPosition(); while(Iter) { POSITION ThisPos = Iter; ISubPic *pSubPic = m_Queue.GetNext(Iter); REFERENCE_TIME rtStart = pSubPic->GetStart(); REFERENCE_TIME rtStop = pSubPic->GetStop(); REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); if(rtNow >= rtStart && rtNow < rtSegmentStop) { REFERENCE_TIME Diff = rtNow - rtStop; if (Diff < rtBestStop) { rtBestStop = Diff; SavePos = ThisPos; } } } } #if DSubPicTraceLevel > 3 if (SavePos) { ISubPic *pSubPic = GetAt(SavePos); REFERENCE_TIME rtStart = pSubPic->GetStart(); REFERENCE_TIME rtStop = pSubPic->GetStop(); TRACE("Save: %f->%f\n", double(rtStart) / 10000000.0, double(rtStop) / 10000000.0); } #endif { POSITION Iter = m_Queue.GetHeadPosition(); while(Iter) { POSITION ThisPos = Iter; ISubPic *pSubPic = m_Queue.GetNext(Iter); REFERENCE_TIME rtStart = pSubPic->GetStart(); REFERENCE_TIME rtStop = pSubPic->GetStop(); if (rtStop <= rtNowCompare && ThisPos != SavePos) { #if DSubPicTraceLevel > 0 TRACE("Remove: %f %f->%f\n",double(rtNowCompare) / 10000000.0, double(rtStart) / 10000000.0, double(rtStop) / 10000000.0); #endif m_Queue.RemoveAt(ThisPos); continue; } if (rtStop > rtNow) rtNow = rtStop; m_rtQueueMin = min(m_rtQueueMin, rtStart); m_rtQueueMax = max(m_rtQueueMax, rtStop); } } } return(rtNow); }