音視頻同步及其他

這幾天搞文件回放,視頻格式是H264,音頻是PCM,使用FFMPEG來讀取音視頻,然後用ffmpeg來解碼顯示,所有的一切還算順利,但音視頻同步花了我很多時間,總也搞不清楚爲什麼會差很多。音視頻同步的原理當然是根據音頻的pts來控制視頻的播放,也就是說在視頻解碼一幀後,是否顯示以及顯示多長時間是通過該幀的PTS與同時正在播放的音頻的PTS比較而來的,如果音頻的PTS較大,則視頻顯示完畢準備下一幀的解碼顯示,否則等待。
        具體實現時遇到的問題一:沒辦法得到正在播放的音頻幀的PTS,因爲進行音頻播放使用的DirectSound,而對於DirectSound我只能得到當前拷入DirectSound的緩存的幀的PTS,而無法得到正在播放的PTS,如果得不到正在播放的幀的PTS的話,那同步肯定是不可能的了。在網上找資料好象也沒找到有用的,最後突然想到由於音頻幀的大小與時間成正比,那麼DirectSound的緩存中的數據所需要的播放時間就可以計算得出,再根據當前正在拷入的音頻幀的PTS,就可以得到正在播放的幀的PTS,再用這個就可以正確同步視頻幀的顯示了。
        問題二:根據上面的方法處理後還是出現不同步的現象,爲什麼這樣我也是百思不得其解,後來才發現是等待機制有問題,原來我是用Sleep()來做等待的,但實際上Sleep()的誤差很大的,網上有說有15MS,做音視頻同步肯定是不行的了,經過不斷的google,找到一份代碼:
void MySleep(int interval)
{
LARGE_INTEGER litmp; 
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim; 
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 獲得初始值

do
{
   QueryPerformanceCounter(&litmp);
   QPart2 = litmp.QuadPart;//獲得中止值
   dfMinus = (double)(QPart2-QPart1);
   dfTim = dfMinus / dfFreq;// 獲得對應的時間值,單位爲秒
}while(dfTim<0.001 * interval);
}
       可以達到精度比較高的等待,從效果看,也可以達到音視頻同步。
       本以爲問題到這就算結束了,但程序運行的時候怎麼發現機器這麼慢呀,看了下CPU佔用率,達到100%。很顯然使用這個做等待是不行的了。
       於是繼續google,網上有說timesetevent什麼的,我沒有試。感覺麻煩了些。後來想到以前看過的一篇用WaitForSingleObject來做定時讓某段代碼執行的,於是試了試,一試之下立即發現效果明顯,CPU佔用率一下子回到了個位數。更改後的代碼如下:
void MySleep(int interval)
{
HANDLE evt;
evt = CreateEvent(NULL, TRUE, FALSE, NULL);
WaitForSingleObject(evt, interval);
CloseHandle(evt);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章