同步问题
因为ffmpeg解码出来的纹理需要传递给engine渲染,如果在play的时候就开始进行ffmpeg解码,生成的texture传递给engine进行渲染,这样也没啥问题
但是如果要符合视频的正常速率,就需要我们在合适的时机进行ffmpeg解码,然后再和engine进行同步,否则的话,就会造成渲染的视频播放速率和实际的视频播放速率不太一致
要解决这个同步问题,有很多办法
如果ffmpeg解码是在另外一个线程解码,的确可以缓解OpenGL线程卡顿的问题,但是需要注意ffmpeg的解码时机,如果ffmpeg的解码跟时间无关,
void thread(){ while(ffmpeg->decode()){ results->push(ffmpeg->currentFrame()); } }
如上的代码,在这个线程开始执行的时候,ffmpeg的解码结果就会不停的产生,那么你就得注意缓存ffmpeg的解码结果,否则OpenGL要真正渲染当前时间的画面时,就拿不到了
视频帧率和游戏帧率不一致导致的同步问题
因为游戏引擎一般的帧率都是每秒60帧,有些情况下,出于性能考虑,会将帧率锁定在30左右, FFMpeg解码视频也需要花费时间,如果视频的帧率比游戏的帧率还要高,那么游戏引擎在渲染视频时,必定会发生丢帧现象。
举个例子:
▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ | time | 0s | 0.1s | 0.2s | 0.3s | 0.4s | 0.5s | 0.6s | 0.7s | 0.8s | 0.9s | 1s | -------------------------------------------------------------------------------------- |video | f0 | f1 | f2 | f3 | f4 | f5 | f6 | f7 | f8 | f9 | f10| |game | f0 | | f1 | | f2 | | f3 | | f4 | | f5 | ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
如上所示例,游戏引擎的fps是每秒5帧,视频的fps是每秒10帧。
当游戏的帧率走到f1
时,时间已经过去了0.2s,此时的0.2s对应的是视频的f2
,也就是说,视频的f1帧就是解码出来了,游戏引擎在渲染的时候,因为时间同步的原因也会抛弃掉。
因此,视频的帧率不建议比游戏的帧率高,这样会浪费好多解码的视频帧,产生无效帧的同时还增加了CPU的负担,但是我们在处理音频时,还需要处理好这种情况,主动将落后时间过多的视频帧丢弃掉。
如果视频的帧率过高,还会导致解码的速度跟不上播放的速度,比如当前时间已经流逝到第1s,但是解码的视频帧还在第0.5s,通常的处理办法就是画面卡在解码出来的视频最后一帧,这样循环往复下去,视频的播放速率是比正常要慢的,原因就出在解码速度跟不上。
只有游戏引擎的帧率高于视频的帧率,渲染出来的视频效果才能表现出更多的细节,因为这种情况下,播放视频时不会发生丢帧现象。
视频帧过于提前当前时间,导致播放节奏变快
还有一种情况,就是我们也要校验当前的视频帧,是否提前于当前时间,如果过于视频帧过于提前,我们需要等待下当前时间,也就是说我们播放的视频帧时间和当前时间的关系如下:
当前时间-offset1
<=视频帧时间
<=当前时间+offset2
一般来说:
- offset1(我设置的是40)要大一点,因为丢帧是为了追赶当前时间
- offset2(我设置的是20)要小一点,因为等待时间到来时,当前是有画面的,稍微停留一下是感知不出来的