webrtc jitter中緩存最近一段時(shí)間內(nèi)的視頻數(shù)據(jù)包,供解碼線程取出解碼顯示积蜻。
本文以h264視頻為例講解緩存機(jī)制,webrtc先將接收到的rtp包組裝成幀數(shù)據(jù)(vcmframe)
1彻消,h264 rtp傳輸格式
h264在rtp包中的封裝格式如下浅侨,以下為借用網(wǎng)絡(luò)圖片
上圖的左邊的打包流程對(duì)應(yīng)的場(chǎng)景是“NALU的長度 <= MTU”,直接將NALU的header拷貝到H264 RTP?Payload Header上证膨,將NALU的RBSP拷貝到H264 RTP Payload Content上如输。
上圖右邊的打包流程對(duì)應(yīng)的場(chǎng)景是“NALU的長度 > MTU”,要將NALU的RBSP進(jìn)行分片央勒,以保證打包后的RTP報(bào)文長度不大于MTU不见,H264 RTP Payload Header由FU-identity + FU Header組成;FU-identity字段和NALU header字段的格式一樣(如果不一樣的話崔步,接收端就搞不清這是一個(gè)NALU分片還是一整個(gè)NALU了)稳吮,其最低的5bits表示payload的類型;FU payload就是NALU的RBSP(一部分)井濒;另外灶似,屬于同一H264幀的所有RTP頭的時(shí)間戳都要打成相同的,接收端根據(jù)時(shí)間戳來判斷哪些包是屬于同一個(gè)H264幀的瑞你。
webrtc中在RtpDepacketizerH264::Parse中解析rtp包
將fua格式的第一個(gè)包解析成single包組織方式酪惭,其他包去掉2byte頭
對(duì)于single和stap格式,每個(gè)rtp包的marker設(shè)置為1者甲。 fua格式春感,一幀最后一個(gè)包的marker設(shè)置為1,其他為0
if (is_first_packet_in_frame() && markerBit) { //single
? ? completeNALU = kNaluComplete;
? } else if (is_first_packet_in_frame()) { //fua第一個(gè)包
? ? completeNALU = kNaluStart;
? } else if (markerBit) { //fua最后一個(gè)包
? ? completeNALU = kNaluEnd;
? } else {? //fua中間包
? ? completeNALU = kNaluIncomplete;
2虏缸,jitterbuffer存儲(chǔ)格式
webrtc中VideoCodingModuleImpl是jitter總的接口
vcmpacket對(duì)應(yīng)rtp包鲫懒,vcmframe對(duì)應(yīng)一個(gè)完整的幀(fua格式需要將多個(gè)rtppacket合并,這通過sessioninfo完成)
VCMSessionInfo 將rtp packet組裝成可解碼的frame
VCMFrameBuffer? 封裝VCMSessionInfo方法
VCMDecodingState 記錄當(dāng)前已經(jīng)解碼幀的最后seq和tiemstamp等信息
frame在jitter中的存儲(chǔ)分為decodable_frames_刽辙、incomplete_frames_窥岩、free_frames_。下面為借用網(wǎng)絡(luò)上圖片
詳細(xì)可參閱文章http://www.reibang.com/p/bd10d60cebcd
其中decodable_frames_存儲(chǔ)可以解碼的幀(比如關(guān)鍵幀或者前序完整的P幀)宰缤;
incomplete_frames_存儲(chǔ)暫時(shí)不能解碼的幀:(1)本身rtp包不完整的幀(2)依賴的參考幀不完整的幀
為了更便于理解jitter的存儲(chǔ)機(jī)制颂翼,用以下的邏輯存儲(chǔ)格式來描述
每個(gè)方格為一幀數(shù)據(jù)vcmframe。
綠色表示可解碼幀(圖中1撵溃、2)疚鲤,存儲(chǔ)在decodable_frames_
紅漸變色表示rtp包不完整的幀(圖中3锥累、4)缘挑,存儲(chǔ)在incomplete_frames_
紅色表示rtp包完整,但是依賴的參考幀不完整(圖中5桶略、6)语淘,存儲(chǔ)在incomplete_frames_
白色表示還未接收到的包(圖中7)诲宇,存儲(chǔ)在missing_sequence_numbers_
每個(gè)gop都是以關(guān)鍵幀起始,如果關(guān)鍵幀不完整惶翻,那整個(gè)gop都不可解嗎姑蓝,必然都是存儲(chǔ)在incomplete_frames_中
在一個(gè)gop中,可解碼幀都是以關(guān)鍵幀起始吕粗,然后連續(xù)存儲(chǔ)在一起的纺荧。中間只要有間隔的不完整包或者丟失包,后面都是存儲(chǔ)在incomplete_frames_中颅筋。如圖中的5本身rtp包是完整的宙暇,但因?yàn)橐蕾噮⒄諑?、4不完整议泵,本身也不能解碼占贫,連鎖導(dǎo)致6也不能解碼。同樣圖中12由于依賴參考幀未接收到先口,暫時(shí)也不能解碼
decode_state記錄當(dāng)前解碼到哪一幀型奥,如圖中已解碼到9,那之前未解碼的幀(3~7)都丟棄碉京,未接收到的rtp也不再發(fā)送nack請(qǐng)求厢汹。
從圖中可以看出,未接收到包的重要程度是不同的谐宙,11的重要程度大于14坑匠,11的不完整影響了12和13的解碼。因此在網(wǎng)絡(luò)擁塞時(shí)卧惜,可以根據(jù)未接收到包的重要程度來優(yōu)先發(fā)送nack請(qǐng)求厘灼,盡可能使靠近關(guān)鍵幀的包接收完整。必要情況下可以丟棄重要程度低的nack請(qǐng)求咽瓷。