1. 程式人生 > >-------------別人解決的, rtmp中音訊和視訊資料不對稱導致的卡頓的情況-----------------

-------------別人解決的, rtmp中音訊和視訊資料不對稱導致的卡頓的情況-----------------

轉自:http://www.cnweblog.com/fly2700/archive/2011/12/06/318916.html

(原創) 
花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快。
 事情是這樣的,前面跟外地一家公司,開發一個二路RTSP音視訊合成一路RTMP音視訊的裝置。裝置在公司內執行是好好的,可到了現場,出現直播流暢,錄製後點播卡頓的問題。由於裝置在外地,除錯不方便。只能這邊寫日誌列印程式碼,那邊燒程式除錯,於是遠端除錯的惡夢開始了。遠端操作畫面卡不說,關鍵是慢,本來一個幾分鐘的事情,遠端要搞幾十分鐘。長達5天的遠端除錯,真是對人的耐性的一種考驗。
 首先我懷疑的是時間戳不均勻。於是我將傳送端的時間戳,接收端的時間戳分別日誌成檔案,統計,沒有發現過大或過小的時間戳。也沒有發現累計時間戳和累計到達時間偏差很大。這樣能排除時間戳的問題。


 其次我懷疑是資料格式的問題。我們這邊RTSP的資料來源裝置和現場的不一樣。於是我又寫程式碼,將RTSP下拉的資料儲存檔案,去掉RTP頭,新增SPS、PPS,儲存為裸H264檔案。資料用VLC播放這個裸H.264檔案,結果可以流暢播放,說明視訊資料是完整的。再寫程式碼將H264檔案分幀並用RTMP協議打包傳送直播,FP能流暢直播,錄製依然是卡的。開始懷疑我的分幀傳送程式碼是否有問題,於是將我以前錄製好的H.264檔案拿來,用同樣的方法測試,結果直播流暢,錄製流暢。同樣的程式碼不同H264檔案有不同效果,那麼可能是H264檔案格式的不同。於是分析h264檔案的NAL。NAL等於5的就是關鍵幀。錄製流暢的h264每個關鍵幀之間的間隔是固定的32,而錄製卡頓的H264檔案,十幾個關鍵幀連在一起。根據以往經驗,這是變位元速率的H264資料。我的RTMP協議棧並沒用支援這種格式。於是開始分析這種變位元速率的h264格式,在我自己的電腦裡面搭建環境除錯改寫協議棧,輕車熟路,沒過多久,我的RTMP協議棧能支援傳送這種變位元速率的H264資料直播了。直播流暢,錄製流暢。好像問題攻克了。於是帶著高興的心情,將程式更新到我的遠端裝置,執行。一看效果,剛開始直播和錄製流暢,沒過多久就開始卡頓了。和之前卡頓不同的是,卡頓頻率降低了,而且FP會反覆列印日誌NetStream.Buffer.Empty。剛才高興的心情一下子彷彿回到瞭解放前。

 根據經驗,這種情況一般是網路頻寬不足,播放端快取不足,或時間戳過小導致。於是我讓在現場的工作的人員測試播放,結果他們在區域網看效果仍然卡頓,排除了頻寬不足的問題。然後我增加播放器快取到5秒,播放依然卡頓,又排除了快取不足的問題。再然後我將傳送端時間戳,接收端時間戳日誌到檔案,終於發現問題了。傳送端時間戳正常,而接收端時間戳出現4000以上的大時間戳。按道理髮送30幀每秒的視訊,平滑處理後的時間戳應該是33-34。如果是FMS將我的時間戳修改增加了,那麼會導致累計時間戳比累計時間大,但結果統計這二個值相差不大。我也沒有發現有過小時間戳來中和這個大時間戳,那麼累計時間戳是如何保持不變的呢,有一種可能性,丟包了。我將統計的幀數除以時間打印出來發現接收端只有20幀每秒。傳送端列印的是30幀每秒。恩,可能是丟包了。我想看看是哪些資料丟了,於是將傳送端的資料記錄到檔案,接收端接收的資料也儲存到檔案,對比,竟然發現數據總大小一模一樣,說明沒有丟包。於是我逐幀地對比傳送端和接收端的資料,發現接收端有一包裡面包含十多個幀的現象。而這種現象出現在接收到一個大關鍵幀的後面。FMS為什麼會將大關鍵幀幀後面的小參考幀連起來做為一幀呢?這個問題我想了很久,也做了各種各樣的實驗。修改了多種打時間戳的方法和平滑時間戳的方法,也沒有效果。最後,我猜測是否因為音訊資料不足導致。因為我知道音訊和視訊播放不一樣,它不會因為時間戳打得快就快放,它按照自己的頻率計算時間勻速播放。如果音訊資料不足或丟失,那麼本來應該和它一起播放的視訊幀會快進或跳過。於是我將傳送音訊部分的日誌打印出來,果然發現存放問題,音訊資料的環形快取區滿了,導致音訊丟包。我為了防止重入,傳送視訊包的時候,音訊不能傳送。而且我們是1080P 的視訊,視訊關鍵幀有上百KB。我的音訊環形快取長度設定的10個。瞬間導致音訊快取滿,然後就是音訊資料丟失。於是我將音訊環形緩衝長度改為30,日誌顯示環形緩衝最大不超過20個。小心地將最新的程式更新到裝置,看效果,直播依然卡頓。我明明解決了一個BUG,竟然沒有效果。神啊,救救我吧,我已經花了4天時間了,早已身心疲憊。

 當然,神是不會理我的,這BUG還是要我們程式設計師自己解決。FP還是列印日誌NetStream.Buffer.Empty。於是又來分析時間戳,統計,沒有發現過大或過小的時間戳。也沒有發現累計時間戳和累計到達時間偏差很大。但是發現累計時間和累計到達時間相比戳抖動比較大。說明時間戳沒問題,只是有些包來晚了,然後後來又補上了。這樣子好像是遠端直播頻寬不穩定導致。於是讓在現場的工作人員測試直播,效果流暢。再讓他們測測錄製,也是流暢的。反覆測試沒出現卡頓,問題終於解決了。心情愉悅。

總結,1,找BUG需要沉下心來,找不到問題不要灰心,一定要充滿鬥志,否則容易中途放棄不前。 2,判斷問題需要準確定位,在一個錯誤方向上努力完全是浪費時間。3,多做實驗,寫日誌,用資料說話,不要憑空猜測。4,寫程式碼的時候,日誌不要多,但處理嚴重錯誤的時候還是需要日誌一下,方便日後排除錯誤。不要像我緩衝滿了也不printf一下。

評論

# re: 花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快  回覆  更多評論   

寫的太好了,受益匪淺 2012-02-16 09:56 | wxg0130

# re: 花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快  回覆  更多評論   

傳送端時間戳正常,而接收端時間戳出現4000以上的大時間戳。按道理髮送30幀每秒的視訊,平滑處理後的時間戳應該是33-34。如果是FMS將我的時間戳修改增加了,那麼會導致累計時間戳比累計時間大,但結果統計這二個值相差不大 

這個時間戳是H264的IBP幀的時間戳還是RTMP包的時間戳呢?如果是264的時間戳不是連續增加的嗎?33-34是rtmp包的相對時間戳嗎?rtmp包的時間戳有什麼作用呢,接觸不多,請賜教 2012-02-16 10:19 | wxg0130

# 回覆:wxg0130   回覆  更多評論   

1我指的是RTMP包的時間戳。 
2傳送的rtmp包時間戳是相對時間戳。 
3rtmp時間戳是用來做音視訊同步的。 2012-02-23 14:47 | ZhangEF

# re: 花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快  回覆  更多評論   

寫的很好,給我們程式設計師很大的啟發。有一個問題想請教一下博主。我做的也是獲取到視訊,經過X264編碼,通過RTMP協議傳送到RED5,可是傳送的視訊用flash播放器出現黑屏,但是時間正常走著。除了flash 播放器外,其他的播放器都可以播放,請賜教一下,這是怎麼回事 2012-10-31 11:12 | 阿日月

# re: 花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快  回覆  更多評論   

你好,我將dm368編碼的h264視訊裸流儲存成檔案,但是vlc開啟後發現播放速度是原來的兩倍,請問知道是為什麼嗎? 2013-01-09 10:35 | AMAM

# re: 花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快[未登入]  回覆  更多評論   

@AMAN
編碼的時候,輸入正確幀率就可以了。如果不輸入幀率,編碼後的裸H264 檔案VLC會用預設幀率播放,預設好像是25還是30的。如果你實際壓縮是15幀每秒,按照預設幀率播放就會快放了。 2013-02-11 17:39 | ZhangEF

# re: 花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快  回覆  更多評論   

請問大神,我寫的實現流播放器。在開發工具下直接執行,畫畫是不卡的,但是當我打包出來,安裝播放, 畫畫就變得一卡一卡的?這是為什麼啊? 2013-08-13 11:04 | 黑熊

# re: 花了5天時間,終於解決了一個bug,心情非常愉快,憋了這麼久,不吐不快  回覆  更多評論   

請教一下,如何新增SPS、PPS,將資料儲存為裸H264檔案?如能告知,萬分感謝! 2013-08-16 09:56 | lxdlut