Frame Rate
幀率代表的是每一秒所播放的視頻圖像數目。通常,視頻都會有固定的幀率,具體點地說是每一幀的時間間隔都是一樣的,這種情況簡稱為CFR(Constant Frame Rate);另外一種情況就是每一幀的時間間隔不一定相同,即可變幀率,簡稱為VFR(Variable Frame Rate),現在也有些錄像設備支持錄制VFR視頻了,在錄制具有大量靜止場景的視頻時,采用VFR能降低錄制出來的視頻的容量大小。
PTS
通過上文對幀率的描述,我們知道在進行視頻播放時,每一幀都應該有自己的播放時刻。不過視頻文件中不會直接存放幀的播放時刻,為了保證精度以及節省存儲空間,文件中會存儲每一幀的PTS(Presentation Time Stamp)以及一個名為time base的參數,PTS是整數,而time base是小數,通過PTS與time base相乘,就能得到視頻的播放時刻,單位為秒。大部分的視頻格式都支持存放幀的PTS,而在播放的時候,通過對PTS進行計算就能使得視頻的每一幀都在合適的時間顯示。通常,第一幀的PTS為0。
同步流程
視頻幀有固定的輸出時間的話,意味着在解碼完成一幀之后,需要進行等待,等到合適的時間才能進行幀的顯示。
上圖為一個視頻幀的解碼、顯示循環。在解碼完成一幀后,需要獲得當前時間以及當前幀的顯示時間,兩者的時間差就是需要睡眠的時長。
不過由於我們常用的操作系統為非實時系統,因此如果希望執行短時間的休眠,調用sleep通常不會得到非常滿意的結果。解決方法就是通過多次休眠更短的時間段,並在被喚醒過后檢查是否已經超時,超時即可進行視頻幀的輸出。
//Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if(frameFinished){
memcpy(Display.YPlane, pFrame->data[0], bufsize);
memcpy(Display.UPlane, pFrame->data[1], bufsize/4);
memcpy(Display.VPlane, pFrame->data[2], bufsize/4);
vs.frame_last_pts = vs.frame_cur_pts;
vs.frame_cur_pts = pFrame->pts * time_base * 1000000;
pts_delay = vs.frame_cur_pts - vs.frame_last_pts;
vs.cur_display_time = vs.last_display_time + pts_delay;
//vs.last_frame_displayed = 0;
if(!vs.is_first_frame){
time = av_gettime_relative();
delay = vs.cur_display_time - time;
while(delay > 0){
if(delay > 10000)
vs.sleep_time = 10000;
else
vs.sleep_time = delay;
av_usleep(vs.sleep_time);
time = av_gettime_relative();
delay = vs.cur_display_time - time;
}
vs.last_display_time = time;
DisplayFrame(&Display);
//vs.last_frame_displayed = 1;
}else{
vs.last_display_time = av_gettime_relative();
DisplayFrame(&Display);
vs.is_first_frame = 0;
//vs.last_frame_displated = 1;
}
SDL_PumpEvents();
}



