時間戳 音視頻同步【】【】【非常好】


http://6352513.blog.51cto.com/6342513/1180742

http://blog.csdn.net/happydeer/article/details/206765

http://blog.csdn.net/sidumqz/article/details/53102623

 

對pts、dts、duration的處理主要集中在兩大函數里面 
1、process_input()讀入數據並處理,放到濾鏡里面 
2、reap_filters()從濾鏡讀出數據,處理后寫入文件

 

媒體內容在播放時,最令人頭痛的就是音視頻不同步。從技術上來說,解決音視頻同步問題的最佳方案就是時間戳:

首先選擇一個參考時鍾(要求參考時鍾上的時間是線性遞增的);

生成數據流時依據參考時鍾上的時間給每個數據塊都打上時間戳(一般包括開始時間和結束時間);

在播放時,讀取數據塊上的時間戳,同時參考當前參考時鍾上的時間來安排播放(如果數據塊的開始時間大於當前參考時鍾上的時間,則不急於播放該數據塊,直到參考時鍾達到數據塊的開始時間;如果數據塊的開始時間小於當前參考時鍾上的時間,則“盡快”播放這塊數據或者索性將這塊數據“丟棄”,以使播放進度追上參考時鍾)。

 

 

 

 

圖2.8 解決音視頻同步問題的時間戳方案

 

可見,避免音視頻不同步現象有兩個關鍵——

一是在生成數據流時要打上正確的時間戳。如果數據塊上打的時間戳本身就有問題,那么播放時再怎么調整也於事無補。

如圖2.8,視頻流內容是從0s開始的,假設10s時有人開始說話,要求配上音頻流,那么音頻流的起始時間應該是10s,如果時間戳從0s或其它時間開始打,則這個混合的音視頻流在時間同步上本身就出了問題。

打時間戳時,視頻流和音頻流都是參考參考時鍾的時間,而數據流之間不會發生參考關系;也就是說,視頻流和音頻流是通過一個中立的第三方(也就是參考時鍾)來實現同步的。

第二個關鍵的地方,就是在播放時基於時間戳對數據流的控制,也就是對數據塊早到或晚到采取不同的處理方法

圖2.8中,參考時鍾時間在0-10s內播放視頻流內容過程中,即使收到了音頻流數據塊也不能立即播放它,而必須等到參考時鍾的時間達到10s之后才可以,否則就會引起音視頻不同步問題

基於時間戳的播放過程中,僅僅對早到的或晚到的數據塊進行等待或快速處理,有時候是不夠的。

如果想要更加主動並且有效地調節播放性能,需要引入一個反饋機制,也就是要將當前數據流速度太快或太慢的狀態反饋給“源”,讓源去放慢或加快數據流的速度

熟悉DirectShow的讀者一定知道,DirectShow中的質量控制(Quality Control)就是這么一個反饋機制。DirectShow對於音視頻同步的解決方案是相當出色的。但WMF SDK在播放時只負責將ASF數據流讀出並解碼,而並不負責音視頻內容的最終呈現,所以它也缺少這樣的一個反饋機制。

為了更好地理解基於時間戳的音視頻同步方案,下面舉一個生活中的例子。假設你和你的一個朋友約好了今天18:00在滬上廣場見面,然后一起吃飯,再去打游戲。實際上,這個18:00就是你和你朋友保持同步的一個時間點。結果你17:50就到了滬上廣場,那么你必須等你的朋友。10分鍾過后,你的朋友還沒有到,這時他打來電話說有事耽擱了,要晚一點才能到。你沒辦法,因為你已經在旁邊的餐廳預訂了位置,如果不馬上趕過去,預訂就會被取消,於是你告訴你的朋友直接到餐廳碰頭吧,要他加快點。於是在餐廳將來的某個時間點就成為你和你朋友的又一個同步點。雖然具體時間不定(要看你朋友趕過來的速度),但這樣努力的方向是對的,你和你朋友肯定能在餐廳見到面。結果呢?你朋友終於在18:30趕過來了,你們最終“同步”了。吃完飯19:30了,你臨時有事要處理一下,於是跟你朋友再約好了20:00在附近的一家游戲廳碰頭。你們又不同步了,但在游戲廳將來的某個時間點你們還是會再次同步的。

悟出什么道理了沒有?其實,同步是一個動態的過程,是一個有人等待、有人追趕的過程。同步只是暫時的,而不同步才是常態。人們總是在同步的水平線上振盪波動,但不會偏離這條基線太遠

 
 
====================================http://www.cnblogs.com/NerdWill/p/6744432.html

在對音視頻重新編碼並需要進行同步的場景中,需要遵守幾項基本原則(否則音視頻就會卡頓,不流暢。以音頻aac編碼頻率44.1k,視頻h264編碼25幀幀率為例):

1. 保證輸入端的音視頻幀到達間隔基本精確。音頻aac每幀時長是23.2ms(1000*1024/44100),視頻每幀時長是40ms(1000/25)。所以,用於編碼的原始音頻samples的到達頻率(或從buffer中獲取的頻率)應該為441 samples/per channel/ per 10ms(每個樣本假設16bits,即882字節/通道/10ms,如果原始音頻采樣率不是44.1k,編碼前需要重新采樣);原始視頻幀到達頻率(或從buffer中獲取的頻率)應該為1幀/per 40ms(視頻幀率可能需要重新采樣)。如果輸出的音視頻流不流暢,可先檢查輸入端音視頻流的輸入間隔情況。

2.保證輸出端的音視頻流時間戳使用同一參考系。比如音視頻流都使用當前系統時間作為同一時間參考系,但音視頻流可以有不同的系統時間起始點。比如音頻流先開始於1492764087000 ms,視頻稍后700ms開始於1492764087700ms。比如rtmp里面使用32位時間戳,則音視頻流只能使用相對時間戳,接上例,音頻時間戳增長到700ms的時候視頻流才從0開始,表示視頻流是從音頻流的700ms處開始的,這樣才能達到同步的效果。 另外一種時間戳方案是每個音視頻幀按固定間隔增長,比如音視頻時間戳都從0開始,音頻每個aac幀增加23.2ms,每個視頻幀增長40ms。正常情況下,音視頻流是同時從0開始按相應各自間隔發送幀的,但也有視頻流晚於音頻流或音頻流晚於視頻流的情況。這種情況需要做時間戳同步,稍晚的流起始時間要根據超前的流的時間來設置。


3.保證交叉輸出時音視頻間隔基本精確。這里的輸出端就完全等同於一個硬件編碼器,只有保證交叉輸出的音視頻幀間隔穩定,才能保證播放端的流暢。比如rtmp,每個aac音頻幀輸出間隔應該在23ms左右,每個視頻幀輸出間隔應該在40ms左右,而且音視頻幀是交叉輸出。換句話說,每23ms要發送一個aac音頻幀,每40ms發送一個視頻幀(可以使用兩個單獨的線程來分別發送音視頻流)。如果排除了上面的兩個問題還是不能流暢播放,可以檢查這個環節是否正常。

總之,重新編碼並同步的這個環節,必須建立在數學測量的基礎上。有錯誤或補充的地方,歡迎指出。

 

================

http://www.cnblogs.com/my_life/articles/6944054.html

視頻中幀就是一個圖片采樣。音頻中一幀一般包含多個樣本,如AAC格式會包含1024個樣本。

http://blog.sina.com.cn/s/blog_6b87c7eb010182hs.html

http://www.jianshu.com/p/030288800a61

采樣頻率是指將模擬聲音波形進行數字化時,每秒鍾抽取聲波幅度樣本的次數。

正常人聽覺的頻率范圍大約在20Hz~20kHz之間,根據奈奎斯特采樣理論,為了保證聲音不失真,采樣頻率應該在40kHz左右。常用的音頻采樣頻率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采樣頻率,還可以達到DVD的音質。

 

音頻

在數字音頻領域,常用的采樣率有:

  • 8,000 Hz - 電話所用采樣率, 對於人的說話已經足夠
  • 11,025 Hz
  • 22,050 Hz - 無線電廣播所用采樣率
  • 32,000 Hz - miniDV 數碼視頻 camcorder、DAT (LP mode)所用采樣率
  • 44,100 Hz - 音頻CD, 也常用於MPEG-1 音頻(VCD, SVCD, MP3)所用采樣率
  • 47,250 Hz - Nippon Columbia (Denon)開發的世界上第一個商用 PCM 錄音機所用采樣率
  • 48,000 Hz - miniDV、數字電視、DVD、DAT、電影和專業音頻所用的數字聲音所用采樣率
  • 50,000 Hz - 二十世紀七十年代后期出現的3M 和Soundstream 開發的第一款商用數字錄音機所用采樣率
  • 50,400 Hz - 三菱 X-80 數字錄音機所用所用采樣率
  • 96,000 或者 192,000 Hz - DVD-Audio、一些 LPCM DVD 音軌、BD-ROM(藍光盤)音軌、和 HD-DVD (高清晰度 DVD)音軌所用所用采樣率
  • 2.8224 MHz - SACD、索尼 和 飛利浦 聯合開發的稱為Direct Stream Digital的1位sigma-delta modulation 過程所用采樣率。

采樣頻率定義了每秒從連續信號中提取並組成離散信號的采樣個數,采樣頻率的倒數是采樣周期或者叫作采樣時間,它是采樣之間的時間間隔

44100已是CD音質, 超過48000或96000的采樣對人耳已經沒有意義。這和電影的每秒 24 幀圖片的道理差不多。

AAC一幀可以解析出的音頻時長

  1. 一個AAC原始幀包含一段時間內1024個采樣及相關數據
  2. 音頻幀的播放時間=一個AAC幀對應的采樣樣本的個數/采樣頻率(單位為s)
  3. 一幀 1024個 sample。采樣率 Samplerate 44100KHz,每秒44100個sample, 所以 根據公式 音頻幀的播放時間=一個AAC幀對應的采樣樣本的個數/采樣頻率
  4. 當前AAC一幀的播放時間是= 1024*1000000/44100= 22.32ms(單位為ms)

(一個aac幀是由1024個樣本組成的,一秒內aac的采樣次數是44.1k次,所以一個aac幀的時長是1*1024/44.1k, 單位為秒)

對采樣率為44.1kHz的AAC音頻進行解碼時,一幀的解碼時間須控制在23.22毫秒內。

MP3一幀可以解析出的音頻時長

  1. mp3 每幀均為1152個字節 (樣本), 則:
  2. frame_duration = 1152 * 1000000 / sample_rate
  3. sample_rate = 44100HZ時, 計算出的時長為26.122ms,這就是經常聽到的mp3每幀播放時間固定為26ms的由來。

H264 視頻
視頻的一個幀的播放時間跟幀率有關:

frame_duration = 1000/幀率(fps) 

例如:fps = 25.00 ,計算出來的時常為40ms,這就是同行所說的40ms一幀視頻數據

 

================

http://blog.csdn.net/aoshilang2249/article/details/38469051

http://blog.csdn.net/ownWell/article/details/8114121

【采樣位數】

 
采樣值或取樣值(就是將采樣樣本幅度量化)。它是用來衡量聲音波動變化的一個參數,也可以說是聲卡的分辨率。它的數值越大,分辨率也就越高,所發出聲音的能力越強。
 
每個采樣數據記錄的是振幅, 采樣精度取決於采樣位數的大小:
  • 1 字節(也就是8bit) 只能記錄 256 個數, 也就是只能將振幅划分成 256 個等級;
  • 2 字節(也就是16bit) 可以細到 65536 個數, 這已是 CD 標准了;
  • 4 字節(也就是32bit) 能把振幅細分到 4294967296 個等級, 實在是沒必要了.

 

【交錯模式】

http://www.cnblogs.com/my_life/articles/6841859.html
數字音頻信號存儲的方式。數據以 連續幀的方式存放,即首先記錄幀1的左聲道樣本和右聲道樣本,再開始幀2的記錄...

【非交錯模式】

首先記錄的是一個周期內所有幀的左聲道樣本,再記錄所有右聲道樣本。

 

 

 

 ==================
http://blog.sina.com.cn/s/blog_864ca0b60101p7zn.html
音頻中經常會提到兩個概念:采樣率、比特率(碼率)。實際上當我們在播放MP3時,這兩個信息有些播放器會顯示:例如:采樣率44.1KHz,比特率192Kbps。
    采樣率是指每秒從連續信號中提取並組成離散信號的采樣個數,用赫茲(Hz)來表示。
1、編碼前比特率
  比特率是指經過 編碼后 的音頻數據每秒鍾需要用多少個比特來表示,但是這里的編碼需要注意不是指MP3,WMA等編碼概念,是指 模擬信號到數字信號的編碼即(PCM數據) ,與它們密切相關的是表示每個PCM樣點的bit位數。比如8bit,16bit
  以網上的例子來說:
   以電話為例,每秒3000次取樣,每個取樣是7比特,那么電話的比特率是21000。而CD是每秒44100次取樣,兩個聲道,每個取樣是13位PCM編碼,所以CD的比特率是44100*2*13=1146600,也就是說CD每秒的數據量大約是144KB,而一張CD的容量是74分等於4440秒,就是639360KB=640MB。
    
  通過上面的原理說明,就很容易解釋,為什么有些音頻文件采樣率一樣,但是比特率不一樣,或者是比特率一樣,采樣率不一樣的問題。當然,在實際的應用中,為了同一輸出,可能會將解碼后的PCM數據進行上采樣或者下采樣統一到48K,最后輸出。由於這個限制,對於采樣文件本身為96K的高保真文件就無法有效播放。需要更加高端的播放硬件。
2、編碼后比特率
  比特率是指經過 編碼后 的音頻數據每秒鍾需要用多少個比特來表示,但是這里的編碼需要注意 是指 MP3,WMA等編碼概念, 不是 模擬信號到數字信號的編碼即(PCM數據) ,與它們密切相關的是表示每個PCM樣點的bit位數。比如8bit,16bit
       編碼的時候設置比特率(wav --->aac--->wav),例如為64Kbps,也就是說音樂播放時每秒讀取的編碼文件的大小是64KBytes,因此假如一個12m的音樂片段,它的文件大小應該是64*12 /8=96Kb,以上數據都是指AAC文件的大小。至於aac編碼得到的文件wav大小,它與aac壓縮說法的壓縮比有關。
     aac--->wav的原理,aac 文件中需要包含信道個數信息,采樣率信息,幀大小。解碼的時候是一幀一幀的解碼得到480或者是512PCM數據。做仿真時存放到wav文件中。如果是實時播放,則需要考慮DAC的采樣率問題,一般它的采樣率是一定的,我們的平台是按48K輸出。即每秒鍾48000個PCM數據輸入到 DAC處處理。這里需要注意區分比特率概念。如果是做仿真保存到wav文件,則可以看到相應的信息.

 

=====================================
http://developer.t-firefly.com/thread-5731-1-1.html
http://www.cnblogs.com/my_life/articles/6274692.html
 
PCR(Program Clock Reference)同步在非硬件精確時鍾源的情況還是謹慎使用,我起初采用PCR同步就會出現,隨着時間的推移,軟件模擬的時鍾不精確會導致視頻出現延時或者音視頻不同步。
最近研究了FFMPEG的同步技巧,覺得其精妙絕倫,完全不用擔心隨着時間的推移會發生如上問題!下面簡述下FFMPEG下如何進行音視頻同步的吧!
FFMPEG有三種同步方式,視頻同步音頻,音頻同步視頻,同步到外部時鍾
第三種,同步到外部始終也就是PCR同步和我原來說的那中同步方式,一樣!
用的最多的還是,視頻同步音頻,為什么呢?
音頻的采樣率是固定的,若音頻稍有卡頓,都會很明顯的聽出來,反則視頻則不如此,雖然表面上說的是30P(每秒30幀),不一定每一幀的間隔就必須精確到33.33ms(所以每幀間隔大約33.33ms),
因為人肉眼是觀察不出來的,所以視頻的幀率可以是動態的,並不是嚴格標准的!
廢話少說了!用視頻同步音頻,做法很簡單!
首先,音頻線程只管自己獨立解碼播放。視頻線程在顯示之前只需要檢測視頻PTS是否大於音頻PTS,若大,則等待音頻PTS>=視頻PTS,若小,則直接播放,小太多則可以直接丟棄(跳幀)。做法就如此簡單!但前提是你編碼器一定要打好正確的PTS,若沒有則只有自己偽造PTS了
 
音視頻同步和幀率控制其實是一個東西。 我們先不管音視頻同步是什么,我們先來看看如何進行幀率控制。明白了幀率控制,音視頻同步那些都一通百通。一些基本的音視頻術語我就不介紹了,大家自己百度吧!
1、幀率控制
幀率控制的方法有千萬種,最2的方法無非是每解碼/顯示一幀就進行延時,為了方便我們在進行幀率控制的同時能夠理解音視頻同步,我在此采用PCR同步的方式來進行幀率控制。網上關於PCR同步的原理講了一大堆,有些很是難懂,一點兒也不通俗,我這里來給大家把晦澀的理論以最通俗的方式表達出來。還希望大家多多指教!

拿1280x720@30p的視頻源來做理解。30P也就是說每秒鍾30幀,也就是每一幀需要1/30*1000ms大概也就是每隔33.33ms就必須顯示一幀。

要想知道如何正確的進行解碼,就必須先了解編碼端是如何工作的!
一般編碼器會以27MHZ的時鍾來進行編碼,這些都不重要,重要的就是,編碼器一般默認會每隔30ms會發送一次PCR信息,這里的PCR信息就很重要了,
他是我們在解碼端解碼進行幀率控制的時間基點,同時也是我們以后在進行同步校准的校准基點。

說了這么多,那么我就那個PCR信息來給大家分析分析。PCR信息是33bit組成的一個INT64_T的數據,從解復用器里面出來我們可以得到一個很龐大的數字,看這個我們當然看不太懂!但是如果知道這個數字如何生成的那就好理解多了!

PCR信息說白了就是給視頻的時間戳信息,比如一部電影是從  (00:01:23:033)時 : 分 : 秒 : 毫秒 開始,那么這個時間基點生成的PCR信息就是  (((00*60+1)*60+23.033)*90K)%2^33。90K為27M,300分頻的結果。 剛剛說了PCR會每30ms更新一次,那么PCR每次遞增的數值就為0.030*90K=2700,這和PTS的值原理是相同的,這里先提一下,其實這個增量也不重要。我們需要的知識第一個PCR值就OK,但是如果考慮到后期校准,還是要用到以后的PCR值的。這里先不管校准的問題!

說了PCR,還有個值是我們需要的,那就是PTS。其實對於硬解碼器來說DTS信息我們根本就不需要管他,我們只需要一幀一幀的把數據送進去,順便把每一幀的PTS信息送進去,解碼器送出來的就是排列好了PTS信息的幀了,其他解碼器不知道至少RK3288是這樣的。大家可以試着把解復用后的每一幀的PTS打印出來,你會發現在解復用后一般是這樣排列的9000 3000 6000 18000 12000 15000.......這種是AVC編碼的使用的是預測編碼決定的,先不管他,你只管這樣把沒一幀依次送入解碼器,解碼器解碼輸出后自然就排列成3000 6000 9000 12000 15000 18000這才是我們需要的PTS! 至於什么是PTS,實際上和PCR原理差不多,但是有個關鍵的地方PTS的增量值可不是默認的30ms了,他是由視頻的幀率來決定的!說道重要的地方了哈!根據上面PCR的原理,如果是30p的視頻那么每一幀就是1/30這么多的增量,再乘90K=3000。

說透了,我們這里就是利用這個PTS值來進行同步順便進行幀率控制!
關鍵的地方來了!
如果視頻流現在來了,我們先獲取到第一個PCR值為1230000,我們現在馬上在解碼器端重建一個90K的時鍾!這就是關鍵所在,至於如何重建90K的時鍾,說白了就是開一個定時器,定時時間為1/90K(11.11us),每隔11.11us我們就把PCR計數值+1,同時這時候解碼器也在工作,試想一下,如果是30P的視頻,也就是33.33ms顯示一次,那么當過了33.33ms后,PCR的數值加到好多了呢?沒錯就是33.33ms/11.11us=3000,這個增量不是和PTS的增量一摸一樣!這時候你只需要在解碼線程里判斷當前幀的PTS是不是和這個PCR相等,如果相等就顯示,如果PCR大可以丟棄當前幀,也就是說的跳幀,如果PCR小說明解碼快了,這個時候就可以等待定時器線程到PCR==PTS。
這樣就很巧妙的解決了幀率控制的問題了!同理,音視頻同步也可以這樣!你可以讓音頻的PTS去和PCR對比!其實大多數情況下都是以視頻同步音頻,音頻解碼不用管它,直接解碼播放就OK了,你只需要進行幀率控制就OK了!同時注意隨着時間的推移有可能出現延時,那么這個時候就需要重新來獲取PCR來更新定時器線程里面的PCR基值了!

 =====================

http://www.cnblogs.com/NerdWill/p/6744432.html

在對音視頻重新編碼並需要進行同步的場景中,需要遵守幾項基本原則(否則音視頻就會卡頓,不流暢。以音頻aac編碼頻率44.1k,視頻h264編碼25幀幀率為例):

1. 保證輸入端的音視頻幀到達間隔基本精確。音頻aac每幀時長是23.2ms(1000*1024/44100),視頻每幀時長是40ms(1000/25)。所以,用於編碼的原始音頻samples的到達頻率(或從buffer中獲取的頻率)應該為441 samples/per channel/ per 10ms(每個樣本假設16bits,即882字節/通道/10ms,如果原始音頻采樣率不是44.1k,編碼前需要重新采樣);原始視頻幀到達頻率(或從buffer中獲取的頻率)應該為1幀/per 40ms(視頻幀率可能需要重新采樣)。如果輸出的音視頻流不流暢,可先檢查輸入端音視頻流的輸入間隔情況。

2.保證輸出端的音視頻流時間戳使用同一參考系。比如音視頻流都使用當前系統時間作為同一時間參考系,但音視頻流可以有不同的系統時間起始點。比如音頻流先開始於1492764087000 ms,視頻稍后700ms開始於1492764087700ms。比如rtmp里面使用32位時間戳,則音視頻流只能使用相對時間戳,接上例,音頻時間戳增長到700ms的時候視頻流才從0開始,表示視頻流是從音頻流的700ms處開始的,這樣才能達到同步的效果。 另外一種時間戳方案是每個音視頻幀按固定間隔增長,比如音視頻時間戳都從0開始,音頻每個aac幀增加23.2ms,每個視頻幀增長40ms。正常情況下,音視頻流是同時從0開始按相應各自間隔發送幀的,但也有視頻流晚於音頻流或音頻流晚於視頻流的情況。這種情況需要做時間戳同步,稍晚的流起始時間要根據超前的流的時間來設置。


3.保證交叉輸出時音視頻間隔基本精確。這里的輸出端就完全等同於一個硬件編碼器,只有保證交叉輸出的音視頻幀間隔穩定,才能保證播放端的流暢。比如rtmp,每個aac音頻幀輸出間隔應該在23ms左右,每個視頻幀輸出間隔應該在40ms左右,而且音視頻幀是交叉輸出。換句話說,每23ms要發送一個aac音頻幀,每40ms發送一個視頻幀(可以使用兩個單獨的線程來分別發送音視頻流)。如果排除了上面的兩個問題還是不能流暢播放,可以檢查這個環節是否正常。

總之,重新編碼並同步的這個環節,必須建立在數學測量的基礎上。有錯誤或補充的地方,歡迎指出。

 ======================

http://www.xuebuyuan.com/1400936.html

視頻、音頻打時間戳的方法

 

http://blog.csdn.net/wfqxx/article/details/5497138

 

AVCodecContext *m_VCtx;

一 固定幀率

1. 視頻時間戳

     pts = inc++ *(1000/fps);  其中inc是一個靜態的,初始值為0,每次打完時間戳inc加1.

    在ffmpeg,中的代碼

    pkt.pts= m_nVideoTimeStamp++ * (m_VCtx->time_base.num * 1000 / m_VCtx->time_base.den);

 

注:見AVCodecContext 的代碼注釋:

對於固定幀率, timebase == 1/framerate

framerate = fps

2. 音頻時間戳

    pts = inc++ * (frame_size * 1000 / sample_rate)

   在ffmpeg中的代碼為

   pkt.pts= m_nAudioTimeStamp++ * (m_ACtx->frame_size * 1000 / m_ACtx->sample_rate);

注: frame_size: Number of samples per channel in an audio frame.  每個音頻幀的 sample 個數.

 

采樣頻率是指將模擬聲音波形進行數字化時,每秒鍾抽取聲波幅度樣本的次數。

正常人聽覺的頻率范圍大約在20Hz~20kHz之間,根據奈奎斯特采樣理論,為了保證聲音不失真,采樣頻率應該在40kHz左右。常用的音頻采樣頻率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采樣頻率,還可以達到DVD的音質

對采樣率為44.1kHz的AAC音頻進行解碼時,一幀的解碼時間須控制在23.22毫秒內。

背景知識:

(一個AAC原始幀包含一段時間內1024個采樣及相關數據)

(一個MP3原始幀包含一段時間內1152個采樣及相關數據)

分析:

1 AAC

音頻幀的播放時間=一個AAC幀對應的采樣樣本的個數/采樣頻率(單位為s)

一幀 1024個 sample。采樣率 Samplerate 44100KHz,每秒44100個sample, 所以 根據公式   音頻幀的播放時間=一個AAC幀對應的采樣樣本的個數/采樣頻率

當前AAC一幀的播放時間是= 1024*1000000/44100= 22.32ms(單位為ms)

 

2 MP3 

mp3 每幀均為1152個字節, 則:

frame_duration = 1152 * 1000000 / sample_rate

例如:sample_rate = 44100HZ時, 計算出的時長為26.122ms,這就是經常聽到的mp3每幀播放時間固定為26ms的由來。

 

二 可變幀率

 

有很多的采集卡,攝像頭,在做采集的時候,明明設置的25FPS,但實際采集數據回調過來,發現並不是40毫秒(1s=1000ms; 1000ms / 25 = 40 ms)的間隔,而是50,60,甚至100不等的時間間隔。這就給編碼后打時間戳帶來很大的困難

 

在libav里,我們的默認編碼參數都是:

ptAvEncoder->ptAvStreamVideo->codec->time_base.den = s32Fps;   //s32Fps是幀率

ptAvEncoder->ptAvStreamVideo->codec->time_base.num = 1;

這樣在編碼后的時間戳以1遞增,只適合於固定幀率。

 

我們來改一下:

ptAvEncoder->ptAvStreamVideo->codec->time_base.den = s32Fps * 1000;

ptAvEncoder->ptAvStreamVideo->codec->time_base.num = 1* 1000;

這樣就把時間戳的scale變成了毫秒,就可以以毫秒為單位進行計算了,如下:

tAvPacket.pts = ((s64)u32TimeStamp * (s64)s32Fps);

u32TimeStamp是從開始記錄的時間差值,以毫秒為單位;s32Fps是幀率

 

對於音頻,mp4文件默認是采樣率為tick的,時間戳計算為:

tAvPacket.pts = (AvEncoderAudioInSizeGet(hHandle) * ( (s64)(u32TimeStamp)) / (AvEncoderAudioInSizeGet(hHandle) * 1000 / ptAvEncoder->ptAvStreamAudio->codec->sample_rate);

AvEncoderAudioInSizeGet(hHandle) 每次編碼器需要的PCM數據長度。

u32TimeStamp是從開始記錄的時間差值,以毫秒為單位。

ptAvEncoder->ptAvStreamAudio->codec->sample_rate PCM采樣率,代表一秒的數據量。

因為乘以了1000,所以也化成了毫秒單位。

 

=============示例AVInputFormat mio===========

音頻基本信息初始化(read_header):

st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
st->codecpar->sample_rate = 48000;
st->codecpar->channels = 2;
avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE); /* 64 bits pts in us */
// to assume AAC encode
md->a_frame_duration = AV_TIME_BASE * 1024 / st->codecpar->sample_rate;   //每個音頻幀的時長

 

給音頻幀打時間戳(read_packet):

int64_t ats = 0;

av_init_packet(&pkt);
pkt.pts = (ats += a_frame_duration);    //計算方式其實跟上面    pts = inc++ * (frame_size * 1000 / sample_rate)一樣
pkt.dts = pkt.pts;
pkt.data = (uint8_t *)abuf;
pkt.size = rtval;
pkt.stream_index = audio_index;

 

====視頻基本信息的初始化==

st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
st->codecpar->width = vhcnt;
st->codecpar->height = vvcnt;
st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
st->codecpar->format = AV_PIX_FMT_UYVY422;
st->codecpar->codec_tag = MKTAG('U', 'Y', 'V', 'Y');
st->time_base = av_make_q(1, 25);                //25: 幀率
st->avg_frame_rate = av_inv_q(st->time_base);
md->v_frame_duration = av_q2d(st->time_base)  * AV_TIME_BASE;   //每個視頻幀的時長
avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE); /* 64 bits pts in use */

 

給視頻幀打時間戳(read_packet):

int64_t vts = 0;

av_init_packet(&pkt);
pkt.pts = (vts += v_frame_duration);
pkt.dts = pkt.pts;
pkt.data = (uint8_t *)vbuf;
pkt.size = rtval;
pkt.stream_index = video_index;


免責聲明!

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



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