1. 程式人生 > >av_seek_frame() 定位為什麽不準呢?

av_seek_frame() 定位為什麽不準呢?

art 位置 back 情況 nbsp flags 顯示 電腦 發現

初次學習和使用ffmpeg,電腦系統有點老,沒辦法使用最新版的ffmpeg 3.3,只能從別處下載了一個2.8版的用用,官網提供的歷史版本都沒有我電腦可用的版本。

花了兩天時間學習並寫了一個簡單的處理視頻的程序,實現視頻的截屏保存為jpg圖片。

本來想用SDL寫個播放器,但寫著寫著,感覺實現視頻、音頻同步什麽的有點難,有點累,就沒再繼續。

今天在研究視頻定位(seek)的時候,在測試代碼時發現問題:

我測試了不同格式的視頻: mp4,flv,mov,3gp,wmv,mkv,avi

定位,我用的是 av_seek_frame(),如果定位:wmv,avi,3gp 等,我只需簡單的使用:

int64_t seekTime_us = 8 * AV_TIME_BASE; //單位: 微秒
av_seek_frame(pFormatCtx, -1 , seekTime_us, AVSEEK_FLAG_BACKWARD); // AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY | AVSEEK_FLAG_FRAME

結果:定位很準確。

但上面的代碼用來定位:mp4,flv,mov,mkv等,經常會遇到定位不準的情況,誤差在[0-5秒]左右。

在網上搜索了半天,找到下面另一種計算方法,經測試和上面的效果其實是一樣的,誤差在[0-5秒]左右,還不如上面的簡單。

int startSecond = 8;
int64_t seekTime_us = startSecond * AV_TIME_BASE; //單位: 微秒
int64_t targetFrame = av_rescale_q(seekTime_us, AV_TIME_BASE_Q, pFormatCtx->streams[videoStream]->time_base);

int64_t seekStreamDuration = pFormatCtx->streams[videoStream]->duration;
int flags = AVSEEK_FLAG_BACKWARD; //默認使用
if(targetFrame > 0 && targetFrame < seekStreamDuration)
{
// H.264 I frames don‘t always register as "keyframes" in FFmpeg
flags |= AVSEEK_FLAG_ANY; //加了這個,有時定位更不準
}

av_seek_frame(pFormatCtx, videoStream, targetFrame, flags);
avcodec_flush_buffers(pCodecCtx);

我又換了個方式:先計算視頻的總幀數(frameCount),然後通過fps計算出8秒位置的frame_index, 不用av_seek_frame,直接通過while(av_read_frame()),跳過frame_index,來實現seek,這個方法定位非常準,但不科學。因為如果要定位到60秒,我用的電腦光是花費在while(av_read_frame())上的時間就將近4秒,效率太低了,只適合定位開頭幾十秒內。

誰能告訴我,怎樣用 av_seek_frame 來定位 mp4,flv 格式的視頻精準一點,不要定位到8秒,顯示的是5秒時的內容。

av_seek_frame() 定位為什麽不準呢?