HRESULT SMPortOutputQueue::Flush(SMThread& Thread, DWORD dwTimeout /*= DEFAULT_FLUSH_TIMEOUT*/) { HRESULT hr = S_OK; // Verify that the queue has been initialized CHECK_INITIALIZED(Flush); SMTimer Timer; bool bDone = false; while (!bDone && Thread.IsPermittedToRun() && m_Port.IsOpen()) { // Need atomic access to queue SMSingleLock SingleLock(&m_QueueMutex); SingleLock.Lock(); bDone = m_Queue.empty(); SingleLock.Unlock(); // Sleep for a while, even if the queue is now empty (in order to allow // for the last message removed to be fully transmitted). ::Sleep(100); if (!bDone && (Timer.ElapsedSeconds() >= dwTimeout)) { bDone = true; hr = E_FAIL; SM_LOG_NAME(hr, 1, "SMPortOutputQueue::Flush(): Timed-out waiting for queue to become empty!"); } } return hr; }
void CVideoReferenceClock::RefreshChanged() { CSingleLock SingleLock(m_CritSection); if (m_pVideoSync) { m_pVideoSync->RefreshChanged(); } }
void CVideoReferenceClock::UpdateRefreshrate() { CSingleLock SingleLock(m_CritSection); m_RefreshRate = m_pVideoSync->GetFps(); m_ClockSpeed = 1.0; CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %.3f hertz", m_RefreshRate); }
void CVideoReferenceClock::Process() { bool SetupSuccess = false; int64_t Now; while(!m_bStop) { m_pVideoSync = g_Windowing.GetVideoSync(this); if (m_pVideoSync) { SetupSuccess = m_pVideoSync->Setup(CBUpdateClock); UpdateRefreshrate(); } CSingleLock SingleLock(m_CritSection); Now = CurrentHostCounter(); m_CurrTime = Now + m_ClockOffset; //add the clock offset from the previous time we stopped m_LastIntTime = m_CurrTime; m_CurrTimeFract = 0.0; m_ClockSpeed = 1.0; m_TotalMissedVblanks = 0; m_MissedVblanks = 0; if (SetupSuccess) { m_UseVblank = true; //tell other threads we're using vblank as clock m_VblankTime = Now; //initialize the timestamp of the last vblank SingleLock.Leave(); //run the clock m_pVideoSync->Run(m_bStop); } else { SingleLock.Leave(); CLog::Log(LOGDEBUG, "CVideoReferenceClock: Setup failed, falling back to CurrentHostCounter()"); } SingleLock.Enter(); m_UseVblank = false; //we're back to using the systemclock Now = CurrentHostCounter(); //set the clockoffset between the vblank clock and systemclock m_ClockOffset = m_CurrTime - Now; SingleLock.Leave(); //clean up the vblank clock if (m_pVideoSync) { m_pVideoSync->Cleanup(); m_pVideoSync.reset(); } if (!SetupSuccess) break; } }
double CVideoReferenceClock::GetSpeed() { CSingleLock SingleLock(m_CritSection); //dvdplayer needs to know the speed for the resampler if (m_UseVblank) return m_ClockSpeed; else return 1.0; }
void CVideoReferenceClock::Process() { bool SetupSuccess = false; int64_t Now; while(!m_bStop) { m_pVideoSync = CServiceBroker::GetWinSystem()->GetVideoSync(this); if (m_pVideoSync) { SetupSuccess = m_pVideoSync->Setup(CBUpdateClock); UpdateRefreshrate(); } CSingleLock SingleLock(m_CritSection); Now = CurrentHostCounter(); m_CurrTime = Now; m_LastIntTime = m_CurrTime; m_CurrTimeFract = 0.0; m_ClockSpeed = 1.0; m_TotalMissedVblanks = 0; m_MissedVblanks = 0; if (SetupSuccess) { m_UseVblank = true; //tell other threads we're using vblank as clock m_VblankTime = Now; //initialize the timestamp of the last vblank SingleLock.Leave(); m_vsyncStopEvent.Reset(); //run the clock m_pVideoSync->Run(m_vsyncStopEvent); } else { SingleLock.Leave(); CLog::Log(LOGDEBUG, "CVideoReferenceClock: Setup failed, falling back to CurrentHostCounter()"); } SingleLock.Enter(); m_UseVblank = false; //we're back to using the systemclock SingleLock.Leave(); //clean up the vblank clock if (m_pVideoSync) { m_pVideoSync->Cleanup(); m_pVideoSync.reset(); } if (!SetupSuccess) break; } }
//this is called from CDVDClock::WaitAbsoluteClock, which is called from CXBMCRenderManager::WaitPresentTime //it waits until a certain timestamp has passed, used for displaying videoframes at the correct moment int64_t CVideoReferenceClock::Wait(int64_t Target) { int64_t Now; int SleepTime; CSingleLock SingleLock(m_CritSection); if (m_UseVblank) //when true the vblank is used as clock source { while (m_CurrTime < Target) { //calculate how long to sleep before we should have gotten a signal that a vblank happened Now = CurrentHostCounter(); int64_t NextVblank = TimeOfNextVblank(); SleepTime = (int)((NextVblank - Now) * 1000 / m_SystemFrequency); int64_t CurrTime = m_CurrTime; //save current value of the clock bool Late = false; if (SleepTime <= 0) //if sleeptime is 0 or lower, the vblank clock is already late in updating { Late = true; } else { m_VblankEvent.Reset(); SingleLock.Leave(); if (!m_VblankEvent.WaitMSec(SleepTime)) //if this returns false, it means the vblank event was not set within Late = true; //the required time SingleLock.Enter(); } //if the vblank clock was late with its update, we update the clock ourselves if (Late && CurrTime == m_CurrTime) UpdateClock(1, false); //update the clock by 1 vblank } return m_CurrTime; } else { int64_t ClockOffset = m_ClockOffset; SingleLock.Leave(); Now = CurrentHostCounter(); //sleep until the timestamp has passed SleepTime = (int)((Target - (Now + ClockOffset)) * 1000 / m_SystemFrequency); if (SleepTime > 0) Sleep(SleepTime); Now = CurrentHostCounter(); return Now + ClockOffset; } }
void CVideoReferenceClock::SetSpeed(double Speed) { CSingleLock SingleLock(m_CritSection); //dvdplayer can change the speed to fit the rereshrate if (m_UseVblank) { if (Speed != m_ClockSpeed) { m_ClockSpeed = Speed; CLog::Log(LOGDEBUG, "CVideoReferenceClock: Clock speed %f%%", GetSpeed() * 100.0); } } }
//for the codec information screen bool CVideoReferenceClock::GetClockInfo(int& MissedVblanks, double& ClockSpeed, double& RefreshRate) const { CSingleLock SingleLock(m_CritSection); if (m_UseVblank) { MissedVblanks = m_TotalMissedVblanks; ClockSpeed = m_ClockSpeed; RefreshRate = m_RefreshRate; return true; } return false; }
//dvdplayer needs to know the refreshrate for matching the fps of the video playing to it double CVideoReferenceClock::GetRefreshRate(double* interval /*= NULL*/) { CSingleLock SingleLock(m_CritSection); if (m_UseVblank) { if (interval) *interval = m_ClockSpeed / m_RefreshRate; return m_RefreshRate; } else return -1; }
//called from dvdclock to get the time int64_t CVideoReferenceClock::GetTime(bool interpolated /* = true*/) { CSingleLock SingleLock(m_CritSection); //when using vblank, get the time from that, otherwise use the systemclock if (m_UseVblank) { int64_t NextVblank; int64_t Now; Now = CurrentHostCounter(); //get current system time NextVblank = TimeOfNextVblank(); //get time when the next vblank should happen while(Now >= NextVblank) //keep looping until the next vblank is in the future { UpdateClock(1, false); //update clock when next vblank should have happened already NextVblank = TimeOfNextVblank(); //get time when the next vblank should happen } if (interpolated) { //interpolate from the last time the clock was updated double elapsed = (double)(Now - m_VblankTime) * m_ClockSpeed * m_fineadjust; //don't interpolate more than 2 vblank periods elapsed = std::min(elapsed, UpdateInterval() * 2.0); //make sure the clock doesn't go backwards int64_t intTime = m_CurrTime + (int64_t)elapsed; if (intTime > m_LastIntTime) m_LastIntTime = intTime; return m_LastIntTime; } else { return m_CurrTime; } } else { return CurrentHostCounter() + m_ClockOffset; } }
HRESULT SMPortOutputQueue::Push(SMString& Data) { HRESULT hr = S_OK; // Verify that the queue has been initialized CHECK_INITIALIZED(Push); // Trace message if enabled if (m_bMessageTrace) { SM_LOG_NAME(S_OK, 1, "SMPortOutputQueue::Push(): " << Data.Data()); } // Protect access to the queue from multiple threads SMSingleLock SingleLock(&m_QueueMutex, true); // Push a copy of the object into the output queue m_Queue.push(new SMString(Data)); // Signal write thread that we added to the queue m_AddedToQueue.Set(); return hr; }
HRESULT SMPortOutputQueue::Thread(SMThread& Thread) { SM_LOG(S_OK, 1, "SMPortOutputQueue::Thread(): thread running..."); HRESULT hr = S_OK; // While thread is alive, receive data from port, push message onto queue // and signal that data has been made available. while (Thread.IsPermittedToRun() && m_Port.IsOpen()) { SM_TRY // Wait for event signaling that data is available to publish SMMultiLock MultiLock(&m_AddedToQueue, &Thread.GetStopEvent()); MultiLock.Lock(); bool bQueueEmpty = false; while(Thread.IsPermittedToRun() && !bQueueEmpty) { // Need atomic access to queue SMSingleLock SingleLock(&m_QueueMutex); SingleLock.Lock(); if (!m_Queue.empty()) { bQueueEmpty = false; SMString* pData = m_Queue.front(); m_Queue.pop(); SingleLock.Unlock(); if (pData != NULL) { hr = m_Port.Send(pData->Data(), pData->GetLength()); if (hr == 0x8007006d || hr == 0x800700e8) // broken pipe { SM_LOG(hr, 1, "Broken pipe, stop output queue thread"); m_Port.Close(); m_bInitialized = false; break; // get out of while (bQueueEmpty) } // Trace message if enabled if (m_bMessageTrace) { SM_LOG_NAME(S_OK, 1, "SMPortOutputQueue::Pop(): " << pData->Data()); } } // Delete the message if (pData != NULL) delete pData; } else { SingleLock.Unlock(); bQueueEmpty = true; // Delay on errors, incoming data to avoid consuming too much CPU Thread.Sleep(100); } } // Catch any exceptions here so we can try to continue running SM_CATCH_ALL_DEFAULT_NO_HR } SM_LOG_NAME(S_OK, 1, "SMPortOutputQueue::Thread(): Write thread exiting..."); return S_OK; }
void CVideoReferenceClock::Process() { bool SetupSuccess = false; int64_t Now; while(!m_bStop) { //set up the vblank clock #if defined(HAVE_X11) std::string gpuvendor = g_Windowing.GetRenderVendor(); std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower); if ((gpuvendor.compare(0, 5, "intel") == 0 || gpuvendor.compare(0, 5, "x.org") == 0)) // AMD m_pVideoSync = new CVideoSyncDRM(); #if defined(HAS_GLX) else m_pVideoSync = new CVideoSyncGLX(); #endif #elif defined(TARGET_DARWIN_OSX) m_pVideoSync = new CVideoSyncOsx(); #elif defined(TARGET_DARWIN_IOS) m_pVideoSync = new CVideoSyncIos(); #elif defined(TARGET_RASPBERRY_PI) m_pVideoSync = new CVideoSyncPi(); #elif defined(TARGET_ANDROID) m_pVideoSync = new CVideoSyncAndroid(); #endif if (m_pVideoSync) { SetupSuccess = m_pVideoSync->Setup(CBUpdateClock); UpdateRefreshrate(); } CSingleLock SingleLock(m_CritSection); Now = CurrentHostCounter(); m_CurrTime = Now + m_ClockOffset; //add the clock offset from the previous time we stopped m_LastIntTime = m_CurrTime; m_CurrTimeFract = 0.0; m_ClockSpeed = 1.0; m_TotalMissedVblanks = 0; m_fineadjust = 1.0; m_MissedVblanks = 0; if (SetupSuccess) { m_UseVblank = true; //tell other threads we're using vblank as clock m_VblankTime = Now; //initialize the timestamp of the last vblank SingleLock.Leave(); //run the clock m_pVideoSync->Run(m_bStop); } else { SingleLock.Leave(); CLog::Log(LOGDEBUG, "CVideoReferenceClock: Setup failed, falling back to CurrentHostCounter()"); } SingleLock.Enter(); m_UseVblank = false; //we're back to using the systemclock Now = CurrentHostCounter(); //set the clockoffset between the vblank clock and systemclock m_ClockOffset = m_CurrTime - Now; SingleLock.Leave(); //clean up the vblank clock if (m_pVideoSync) { m_pVideoSync->Cleanup(); delete m_pVideoSync; m_pVideoSync = NULL; } if (!SetupSuccess) break; } }
void CVideoReferenceClock::SetFineAdjust(double fineadjust) { CSingleLock SingleLock(m_CritSection); m_fineadjust = fineadjust; }
BOOL DownLoad(LPCSTR URL, LPCSTR Path, BOOL& quit, CSocketList& list, CMutex& mutex) { try{ CHttpSocket HttpSocket; CFile DownloadFile; CString strServer,strObject; unsigned short nPort; DWORD dwServiceType; long nLength; const char *pRequestHeader = NULL; SOCKET tmpS = 0; if(!AfxParseURL(URL,dwServiceType,strServer,strObject,nPort)) { return FALSE; } try{ pRequestHeader = HttpSocket.FormatRequestHeader((LPTSTR)(LPCTSTR)strServer,(LPTSTR)(LPCTSTR)strObject,nLength, nPort); if(!HttpSocket.Socket()) throw 0; tmpS = HttpSocket.GetSocket(); CSingleLock SingleLock(&mutex); SingleLock.Lock(); if(SingleLock.IsLocked()) list.AddTail(tmpS); SingleLock.Unlock(); if(quit){ return FALSE; } // HttpSocket.SetTimeout(20000,0); if(!HttpSocket.Connect((LPTSTR)(LPCTSTR)strServer,nPort)) throw 1; if(quit) return FALSE; if(!HttpSocket.SendRequest()) throw 1; if(quit) return FALSE; int nLineSize = 0; char szLine[256]; while(nLineSize != -1){ nLineSize = HttpSocket.GetResponseLine(szLine,256); if(quit) return FALSE; } char szValue[30]; BOOL bContLen = TRUE; int nFileSize = -1; if(HttpSocket.GetField("Content-Length",szValue,30)==-1) bContLen = FALSE; else nFileSize = atoi(szValue); if(quit) return FALSE; int nCompletedSize = 0; if(!DownloadFile.Open(Path, CFile::modeCreate|CFile::modeWrite)) throw 2; char pData[1024]; int nReceSize = 0; BOOL first = TRUE; while(!quit){ nReceSize = HttpSocket.Receive(pData,1024); if(quit) return FALSE; if(nReceSize == 0) break; if(nReceSize == -1) throw 3; if(first&&!bContLen){ char* temp = strstr(pData,"\r\n"); if(!temp) throw 3; DownloadFile.Write(temp+2,nReceSize-(temp+2-pData)); } else DownloadFile.Write(pData,nReceSize); nCompletedSize += nReceSize; first = FALSE; if(bContLen && nCompletedSize>=nFileSize) break; } if(!bContLen && !quit){ long len =(long) DownloadFile.GetLength(); DownloadFile.SetLength(len-7); } DownloadFile.Close(); SingleLock.Lock(); if(SingleLock.IsLocked()){ POSITION pos = list.Find(tmpS); if(pos) list.RemoveAt(pos); } SingleLock.Unlock(); HttpSocket.CloseSocket(); } catch(int err){ POSITION pos; CSingleLock SingleLock(&mutex); switch(err){ case 3: DownloadFile.Close(); case 2: case 1: SingleLock.Lock(); if(SingleLock.IsLocked()){ pos = list.Find(tmpS); if(pos) list.RemoveAt(pos); } SingleLock.Unlock(); HttpSocket.CloseSocket(); break; } return FALSE; } return !quit; } catch(...){ #ifdef _DEBUG Tips("BOOL DownLoad(LPCSTR URL, LPCSTR Path, BOOL& quit, CSocketList& list)"); #endif } return FALSE; }