音視頻的同步原理--記錄


1.   音視頻同步的原理

 2.  音視頻同步的較正方法

 3.  音視頻同步時遇到的問題

聲明:以下所有內容均為轉載

 1.原文轉自:http://bbs.chinavideo.org/viewthread.php?tid=1183&extra=page%3D1%26amp%3Bfilter%3Ddigest&page=1

下面貼出部分:

視頻同步這一塊,我一直不是很了解,很想嘗試一下,下面是在qq群上向諸位前人請教的會話記錄,因為對我這樣的初學者很有幫助,所以粘貼至此,以作備份,再次感謝熱心回答問題的人,尤其是(不做好人!)^_^;

2006-10-25 10:21:06  dophin
有人有實時編碼時對音視頻進行錄制時,音視頻如何同步的相關資料么?有相關網站也可以哈,我實在找不到相關資料了。。。
2006-10-25 10:25:42  dophin
或者具體一點的也行,比如音視頻到底是如何同步的,有書籍介紹也可以啊,先謝了哈。。。。
(人眾人)  2006-10-25 10:21:45
通過時間戳 
(人眾人)  2006-10-25 10:21:49
我也在研究這個問題 
( 新左派)  2006-10-25 10:21:56
音頻時間為主 
(人眾人)  2006-10-25 10:22:01
對 
(不做好人!)  2006-10-25 10:22:08
新左派講對了。 
(不做好人!)  2006-10-25 10:22:14
聲音圖象交錯發送。 
( 新左派)  2006-10-25 10:22:43
視頻解碼時,按當前播放時間找到對應的視頻幀 
(不做好人!)  2006-10-25 10:22:44
可以一個音頻包有N個圖象。就在這一個音頻包完成的過程中按幀率顯示圖象。 
(dophin)  2006-10-25 10:28:39
嗯,那么音頻又是以什么為主呢?畢竟,音頻的播放也是和時間有關系的,音頻在播放時就是只管自己播放就行么?
(不做好人!)  2006-10-25 10:24:05
聲卡有時間同步處理機制的。 
(不做好人!)  2006-10-25 10:24:32
我以前的電腦主板如果驅動沒有裝好。聲音就非常快。結果圖象也是一閃就過去了。 
( 新左派)  2006-10-25 10:24:47
聲音正常解碼與播放啊 
(不做好人!)  2006-10-25 10:25:05
是WINDOWS MEDIAPLAYER播放的。只有驅動裝好了。能正確驅動的時候聲卡有時鍾同步功能的。 
( 新左派)  2006-10-25 10:25:14
只是視頻的解碼需要參照當前的聲音的時間 
(不做好人!)  2006-10-25 10:25:16
所以聲音和圖象交錯, 
( 新左派)  2006-10-25 10:25:36
聲音播放時,是不用管什么的,就是單獨的聲音解碼 
(dophin)  2006-10-25 10:32:16
哦,我現在大腦中大致有點模型了,就是音頻只管自己播放就行,視頻根據自己本身帶的時間戳與但前系統時間和音頻時間進行比較,然后解碼播放,如此實現同步,這么理解對么?
(不做好人!)  2006-10-25 10:28:00
你是用什么系統? 
(dophin)  2006-10-25 10:33:26
聲音和圖像交錯是什么意思?這兩個不是開兩個線程完成的么?不存在交錯問題啊,即使存在,也是操作系統級的吧 ?
(不做好人!)  2006-10-25 10:28:35
AVVVVVVVVVVVVVVVAVVVVVVVVVVVVVVV 
(dophin)  2006-10-25 10:33:42
我得,Linux。。。
(不做好人!)  2006-10-25 10:28:52
當你放A的時候,直接交給聲卡。 
(不做好人!)  2006-10-25 10:29:30
中間的V就是前后兩個聲音包的相差時間,你就算出平均速度 
(dophin)  2006-10-25 10:35:35
算出 平均速度后,得出每sec放幾幀,然后播放v,是這樣么?
(不做好人!)  2006-10-25 10:30:54
對 
(不做好人!)  2006-10-25 10:31:01
你聲音有一個采樣率吧。 
(dophin)  2006-10-25 10:36:02
對,有,
(不做好人!)  2006-10-25 10:31:23
這就可以算出前后一個聲音的時間了對不? 
(不做好人!)  2006-10-25 10:31:36
比如44.1K/S 
(dophin)  2006-10-25 10:36:36
對,
(不做好人!)  2006-10-25 10:31:56
那你從DSP中讀取22.05K的數據是不是0.5? 
(dophin)  2006-10-25 10:37:05
是,
(不做好人!)  2006-10-25 10:32:29
那在這段0.5秒鍾的時間內你獲取了15幀的數據。那你是不是0.5/15=0.03333秒鍾就刷新一副圖。 
(dophin)  2006-10-25 10:37:49
沒錯。
(不做好人!)  2006-10-25 10:32:55
然后你再讀取下一個聲音和圖象包。再這樣搞。就可以了啦。不過前提條件你采集必須是同步的。 
(不做好人!)  2006-10-25 10:33:11
對了。你是用嵌入式的嗎? 
(不做好人!)  2006-10-25 10:33:25
這個是以聲音為基礎的。 
(不做好人!)  2006-10-25 10:34:04
還有一種是設置時鍾,計算你的幀率來設置前后幀的時間,中間有誤差就延時或者是跳躍一下。聲音就另外單獨管理。 
(不做好人!)  2006-10-25 10:34:21
看看ffmpeg 的fplay.c,里面的源程序講得很詳細了。 
(dophin)  2006-10-25 10:40:12
我的不是embedded
(dophin)  2006-10-25 10:40:24
就是普通pc機,
(不做好人!)  2006-10-25 10:36:08
哦。那你看fplay.c吧。里面很詳細的有聲音和圖象的同步。雖然簡單了一點。但麻雀雖小五臟俱全。 
(dophin)  2006-10-25 10:41:54
哦,太好了,采集這一塊,我基本明白了,播放我想也應該差不多,我自己試試看看,太感謝了你了哈。。。^_^
(不做好人!)  2006-10-25 10:37:14
別謝謝我。 
(不做好人!)  2006-10-25 10:37:24
不過我做的方法是按照fplay.c里面的做的。 
(dophin)  2006-10-25 10:42:23
好的,我馬上就看看fplay。c,以前沒有看是因為感覺他的播放效果不如mplayer,
(不做好人!)  2006-10-25 10:38:06
這個是簡化了的啦。當然比不上mplayer

2.
mplayer播放時的大循環過程為:
while(!mpctx->eof){
  fill_audio_out_buffers();//音頻stream的讀取,解碼,播放
  update_video(&blit_frame);//視頻stream的讀取,解碼,過濾處理
  sleep_until_update(&time_frame, &aq_sleep_time);//計算延遲時間並睡眠等待
  mpctx->video_out->flip_page();//視頻的播放
  adjust_sync_and_print_status(frame_time_remaining, time_frame);//根據音視頻的PTS做同步矯正處理
}

音視頻同步方法為
1)音頻播放playsize = mpctx->audio_out->play(sh_audio->a_out_buffer, playsize,  playflags);  后,根據數據大小算出時間並累計
mpctx->delay += playback_speed*playsize/(double)ao_data.bps;
2)視頻解碼前,用累計延遲時間剪掉本禎視頻的時間mpctx->delay -= frame_time;
3)計算聲音延遲時間*time_frame = delay - mpctx->delay / playback_speed;
其中float delay = mpctx->audio_out->get_delay();為距當前聲音OUTPUT BUF里數據被全部播放完為止所需的時間。
4)播放視頻同步完成,所以視頻的播放是完全根據聲卡最后的數據輸出來同步的。
5)計算出當前音視頻PTS差double AV_delay = a_pts - audio_delay - v_pts;再算出矯正值x = (AV_delay + timing_error * playback_speed) * 0.1f;最后把矯正的時間加到延遲累計中mpctx->delay+=x;。
3.

這幾天搞文件回放,視頻格式是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);
}

轉自:http://blog.csdn.net/allentangtg/article/details/6873681


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM