📄 timer.h
字号:
/* * Copyright (C) 2005-2007 gulikoza * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* $Id$ */#ifndef TIMER_H#define TIMER_H#include <math.h>#define MODULE "Timer"#define NO_WAIT 0xffffffffclass HPTimer { private: MUTEX * tm_mutex; SDL_semaphore * sem; SDL_TimerID timer; // Current time in ms double time; double advance; double lastupdate, tick; // When to exit unsigned int waittime; const int DELAY; // Difference between current time and pts int ticksdiff; void WaitMS(unsigned int ms) { if(ms) { MUTEX_LOCK(tm_mutex); waittime = (unsigned int)lrint(time) + ms; MUTEX_UNLOCK(tm_mutex); // Wait for semaphore#ifdef SEM_SILENT SDL_SemWait(sem);#else while(SDL_SemWaitTimeout(sem, 1000) == SDL_MUTEX_TIMEDOUT) { ERROR_MSG("Semaphore timeout expired, line: %d, thread: %u", __LINE__, SDL_ThreadID()); }#endif DEBUG_MSG("Sleep complete"); } } public: // File playback has to provide own clock bool unlocked; HPTimer(int d):time(0.0),advance(0.0),lastupdate(0.0),tick(0.0),ticksdiff(0),unlocked(false),DELAY(d) { tm_mutex = MUTEX_CREATE(); if(tm_mutex == NULL) throw "Timer: Failed to create mutex"; sem = SDL_CreateSemaphore(0); if(sem == NULL) { MUTEX_DESTROY(tm_mutex); throw "Timer: Failed to create semaphore"; } // Add 1 ms timer timer = SDL_AddTimer(1, Callback, (void*)this); waittime = SDL_GetTicks(); if(SDL_SemWaitTimeout(sem, 500) == SDL_MUTEX_TIMEDOUT) throw "Timer: Failed to create timer!"; ERROR_MSG("Created timer with delay %d in thread %u", DELAY, SDL_ThreadID()); } static Uint32 Callback(Uint32 interval, void *param) { HPTimer *tm = (HPTimer*)param; MUTEX_LOCK(tm->tm_mutex); if(tm->tick > 0.0) { tm->time += tm->advance; if(lrint(tm->time) > tm->waittime) { tm->waittime = NO_WAIT; SDL_SemPost(tm->sem); } DEBUG_MSG("Time set to %.2f, PTS: %d", tm->time, (unsigned int)tm->time+tm->ticksdiff); MUTEX_UNLOCK(tm->tm_mutex); return interval; } tm->time += 1.0; // Calibrate starting interval if(tm->time > 25.0) { tm->tick = (double)(SDL_GetTicks()-tm->waittime)/tm->time; tm->advance = tm->time = tm->tick; tm->waittime = NO_WAIT; SDL_SemPost(tm->sem); LOG_MSG("Timer calibrated, tick set to %.2f", tm->tick); } MUTEX_UNLOCK(tm->tm_mutex); return interval; } unsigned int GetPTS(void) { MUTEX_LOCK(tm_mutex); unsigned int ret = (unsigned int)lrint(time+ticksdiff); MUTEX_UNLOCK(tm_mutex); return ret; } void SetPTS(unsigned int pts) { MUTEX_LOCK(tm_mutex); double curPTS = time+ticksdiff; LOG_MSG("Cur PTS: %.2f, has to be %.2f", curPTS, (double)pts-DELAY); if(lastupdate == 0.0f) { curPTS = pts-DELAY; ticksdiff = pts-(int)lrint(time)-DELAY; LOG_MSG("PTS set to %.2f (%d)", curPTS, (pts-(time+ticksdiff))); } else if(unlocked) { // Do some rate limiting if(pts-(DELAY<<1) > (unsigned int)lrint(curPTS)) { MUTEX_UNLOCK(tm_mutex); int delay = (pts-DELAY-(unsigned int)lrint(curPTS)); if(delay > 1000) delay = 1000; SDL_Delay(delay); MUTEX_LOCK(tm_mutex); } } else if(fabs(lastupdate-curPTS) > 4) { // Allow at least 5 ms between updates double realPTS = (double)pts-DELAY; LOG_MSG("%.2f PTS difference, last update @%.2f", realPTS-curPTS, lastupdate); realPTS = tick + (realPTS-curPTS)/((curPTS-lastupdate)*10); // Do not allow more than 20% differnce) if(fabs(realPTS-tick) < 0.20) { advance = realPTS; LOG_MSG("Advance set to %lf", advance); } else { LOG_MSG("Weird PTS sample, ignored"); } } lastupdate = curPTS; MUTEX_UNLOCK(tm_mutex); } bool SleepPTS(unsigned int pts) { MUTEX_LOCK(tm_mutex); unsigned int curPTS = (unsigned int)lrint(time+ticksdiff); MUTEX_UNLOCK(tm_mutex); if(curPTS > pts) { // Only 10ms late, don't sleep just return if(curPTS-pts < 10) return false; // Sorry, too late LOG_MSG("%d ms late (%d > %d)", curPTS-pts, curPTS, pts); return true; } // If sleep lasts more than a sec, it's probably an error if((pts - curPTS) > 5000) { LOG_MSG("Sleep to long (%u ms), current time: %u", pts-curPTS, curPTS); return true; } WaitMS(pts - curPTS); return false; } void Reset(void) { MUTEX_LOCK(tm_mutex); time = 0.0; waittime = 0; advance = tick; ticksdiff = 0; lastupdate = 0.0; MUTEX_UNLOCK(tm_mutex); } ~HPTimer() { SDL_RemoveTimer(timer); SDL_Delay(10); MUTEX_LOCK(tm_mutex); SDL_SemPost(sem); SDL_DestroySemaphore(sem); MUTEX_UNLOCK(tm_mutex); MUTEX_DESTROY(tm_mutex); ERROR_MSG("Destroyed timer in thread %u", SDL_ThreadID()); }};// Make timer globalextern HPTimer * timer;#undef MODULE#endif // TIMER_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -