现在用ffmpeg库写播放器,求帧率(12帧/s左右),计算出每帧时间,然后掐头去尾,sleep一个延时时间。
现在的问题是,sleep延时超级不准,误差在55MS左右,而我一帧延时也才五六十MS网上找精确延时的方法,基本上都是用while循环不停的取时间,没到点就继续循环,如下面这段代码:
while( (timeGetTime()- vstart) < (unsigned long)time_delay);
但是这样的一个问题就是CPU时间占满了不知道有什么办法可以做到精确的延时,同时又降低CPU的占用率的。或者有什么其他方法可以让我的视频同步播放的也欢迎回答,多谢!我有两个设想请高手论证下:
设想一:
就是我在A之外,再另外开一个线程B,作为唤醒线程,进入延时循环后A唤醒B,将自己挂起来,B在循环中唤醒A,然后将自己挂起来,这样子让两个线程反复的唤醒另外一个线程,来利用线程的切换实现延时,不知道这样理论上可行否。设想二:
还有一个设想是用高精度定时器,A进入循环后,生成一个高精度定时器,让定时器每个最小周期将自己唤醒,醒了后检查延时时间有没有完,如果完了就干掉定时器跳出延时循环执行后面的代码,如果还没完就自己挂起自己,等待下次再被唤醒。
现在的问题是,sleep延时超级不准,误差在55MS左右,而我一帧延时也才五六十MS网上找精确延时的方法,基本上都是用while循环不停的取时间,没到点就继续循环,如下面这段代码:
while( (timeGetTime()- vstart) < (unsigned long)time_delay);
但是这样的一个问题就是CPU时间占满了不知道有什么办法可以做到精确的延时,同时又降低CPU的占用率的。或者有什么其他方法可以让我的视频同步播放的也欢迎回答,多谢!我有两个设想请高手论证下:
设想一:
就是我在A之外,再另外开一个线程B,作为唤醒线程,进入延时循环后A唤醒B,将自己挂起来,B在循环中唤醒A,然后将自己挂起来,这样子让两个线程反复的唤醒另外一个线程,来利用线程的切换实现延时,不知道这样理论上可行否。设想二:
还有一个设想是用高精度定时器,A进入循环后,生成一个高精度定时器,让定时器每个最小周期将自己唤醒,醒了后检查延时时间有没有完,如果完了就干掉定时器跳出延时循环执行后面的代码,如果还没完就自己挂起自己,等待下次再被唤醒。
如果是改变帧率,ffmpeg应该有提供函数的
另外高精度的定时器,可以用QueryPerformanceFrequency,QueryPerformanceCounter;或者ftime
不是改变帧率,这个以后可能会用到,现在暂时还不考虑
QueryPerformanceFrequency,QueryPerformanceCounter;的延时代码我有,也是通过WHILE循环来延时的,同while( (timeGetTime()- vstart) < (unsigned long)time_delay);一样,不过精度更高一点而已,CPU会占满的
Sleep实现高精度定时,可以把显示线程提升为实时优先级.这里有一个定时类可以参考.http://blog.csdn.net/dengzikun/archive/2010/08/19/5824874.aspx
#include <windows.h>
#include <time.h>
#include <stdio.h>
ULONG GetTimeDis(struct tm first, struct tm second) //计算两次时间差
{
return abs((first.tm_hour * 3600 + first.tm_min * 60 + first.tm_sec)
- (second.tm_hour * 3600 + second.tm_min * 60 + second.tm_sec));
}void Delay(ULONG ulMicroSeconds)
{
LARGE_INTEGER timeStop;
LARGE_INTEGER timeStart;
LARGE_INTEGER Freq;
ULONG ulTimeToWait; if (!QueryPerformanceFrequency( &Freq ))
return; ulTimeToWait = Freq.QuadPart * ulMicroSeconds / 1000 / 1000; QueryPerformanceCounter ( &timeStart ); timeStop = timeStart; while( timeStop.QuadPart - timeStart.QuadPart < ulTimeToWait )
{
QueryPerformanceCounter( &timeStop );
}
}int main(void)
{
struct tm timeStart, timeEnd; _getsystime(&timeStart);// Delay(1000 * 1000 * 3); //3秒
_getsystime(&timeEnd); //
printf("用时:%d秒\n", GetTimeDis(timeStart, timeEnd));// return 0;
}
还是用的循环,一样占CPU,我现在已经找到近似的精确定时的方法了。代码贴出来,给其他人可以做个参考。/*
*在算法上进行改进,以前是以单独每帧计算延时,这样误差会累计。
*现在以1分钟为一个周期,进行整体延时。
*前面的误差会被后面的误差抵消掉,所以一分钟的误差就接近一个sleep的误差
*为了更加减小误差,这个周期数可以适当加大
*/
int vbegin,vstart,vfinish,time_delay;//注意这里一定要用int必须为有符号型的,不可用DWORD或者UINT
int frame_rate=12;//帧率
int ms_per_minite=60000;//每周期毫秒数
int frames_per_minite=frame_rate*60;//每周期帧数,
int count=0;//循环计数器,每周期清零一次vstart=timeGetTime();//每帧开始时间
while(//视频没播放完)
{
if(count%frames_per_minite==0)//计算是否到了一个周期接合点
{
vstart=timeGetTime();//每计时周期开始时间
count=0;//每周期开始将计时器清零
}
//解码
//显示;
vfinish=timeGetTime();//画图完成时间
time_delay=(count+1)*1000/frame_rate-(vfinish-vstart);
if (time_delay>0)
{
Sleep(time_delay);//延迟
}
count++;
}