一種基于rudp的實(shí)時(shí)互動(dòng)視頻的高效可靠傳輸方案

注:本文已收錄專(zhuān)利公般,版權(quán)所有。另外择份,部分段落縮減了部分內(nèi)容扣孟。

1. 背景

當(dāng)下移動(dòng)互聯(lián)網(wǎng)視頻直播正處于如火如荼的井噴式發(fā)展當(dāng)中,不同的行業(yè)(比如教育缓淹、醫(yī)療哈打、旅游等)都涉足參與進(jìn)來(lái),企圖在這個(gè)市場(chǎng)上占有一席之地讯壶,爭(zhēng)當(dāng)獨(dú)角獸式的公司料仗。傳統(tǒng)的直播,大多數(shù)是單向型伏蚊,比如電視臺(tái)或者運(yùn)營(yíng)商直播立轧,用戶只需要打開(kāi)終端收看即可,對(duì)于實(shí)時(shí)性并沒(méi)有太大的要求躏吊。而移動(dòng)直播往往在功能上需要主播端和播放端有交互氛改,這種交互不限于文字的互動(dòng),視頻與語(yǔ)音的互動(dòng)也日趨成為基本的交互場(chǎng)景需求比伏,傳統(tǒng)的做法是主播端采集視頻數(shù)據(jù)并編碼成x264胜卤、采集音頻數(shù)據(jù)并編碼成aac,再合并打包后通過(guò)一定的Qos算法將音視頻流數(shù)據(jù)通過(guò)rtmp協(xié)議(基于TCP協(xié)議之上)推流到CDN服務(wù)器進(jìn)行分發(fā)赁项,用戶端從CDN服務(wù)器拉流解碼來(lái)播放葛躏,這種方式的延時(shí)表現(xiàn)在rtmp推流到CDN和播放器從CDN通過(guò)rtmp拉流緩存播放,整個(gè)網(wǎng)絡(luò)鏈路的延遲通常在1-3秒或者更差悠菜。在網(wǎng)絡(luò)不穩(wěn)定的情況下舰攒,通常提高用戶觀看體驗(yàn)的方式是通過(guò)在主播端和播放端設(shè)置Gop緩存,讓碼率均勻悔醋;另外可以在主播端通過(guò)Qos算法檢測(cè)變化的網(wǎng)絡(luò)來(lái)動(dòng)態(tài)改變碼率和幀率摩窃;還可以接入多個(gè)視頻云服務(wù)CDN提供商,這樣可以做推拉流線路互備芬骄,對(duì)推流后視頻服務(wù)集群再優(yōu)化并根據(jù)端點(diǎn)網(wǎng)絡(luò)狀況做實(shí)時(shí)線路切換猾愿。另外一種方式是通過(guò)http HLS的方式進(jìn)行傳輸鹦聪,這種切片式的直播方式延遲更大,不適合高互動(dòng)式的場(chǎng)景直播蒂秘。

所以本文提出了一種基于UDP方式的視頻傳輸方案(webrtc層外)椎麦,旨在服務(wù)于低延遲高實(shí)時(shí)互動(dòng)式的直播場(chǎng)景,這種方式能將延遲控制在800ms人眼可接收范圍內(nèi)材彪,在網(wǎng)絡(luò)帶寬比較差或者強(qiáng)丟包观挎、亂序的情況下,通過(guò)緩存機(jī)制段化、帶寬自適應(yīng)檢測(cè)機(jī)制實(shí)時(shí)匯報(bào)給編碼器降低碼率嘁捷、分辨率、幀率显熏,能可靠有效的將實(shí)時(shí)畫(huà)面完整的播放出來(lái)雄嚣,提高了用戶體驗(yàn)。

2 視頻傳輸流程

2.1 視頻傳輸時(shí)序圖

本方案采用基于udp協(xié)議的報(bào)文傳輸喘蟆,設(shè)計(jì)了一套私有的報(bào)文格式缓升,以使得整個(gè)報(bào)文在網(wǎng)絡(luò)鏈路中傳輸簡(jiǎn)單可靠并可控,相對(duì)于TCP傳輸?shù)姆绞皆坦欤蟠蟮慕档土藞?bào)文的大小與復(fù)雜度港谊,保證了整個(gè)傳輸過(guò)程的實(shí)時(shí)性。如下圖1為視頻傳輸?shù)臅r(shí)序圖橙弱。

圖1 視頻傳輸時(shí)序圖

2.2 關(guān)鍵技術(shù)

本方案視頻編碼采用h264的形式(也可以是h265歧寺,負(fù)載數(shù)據(jù)是不受傳輸模塊限制的,可以在兩端進(jìn)行適配和協(xié)調(diào))棘脐,因?yàn)锽幀是雙向預(yù)測(cè)幀斜筐,它需要根據(jù)后向視頻幀來(lái)預(yù)測(cè)編碼,一定程度上會(huì)增大編解碼延遲蛀缝,所以為了保證傳輸和播放的實(shí)時(shí)性顷链,本方案視頻壓縮丟棄B幀編碼。

2.2.1 發(fā)送端處理

2.2.1.1 視頻切片算法

當(dāng)編碼器編碼出一幀完整的h264視頻幀數(shù)據(jù)時(shí)送入發(fā)送端屈梁,對(duì)于高分辨率的視頻編碼幀嗤练,幀大小往往高于UDP網(wǎng)絡(luò)MTU,所以此時(shí)需要發(fā)送端對(duì)其進(jìn)行分片處理再發(fā)送俘闯,每次按照分片單位來(lái)發(fā)送幀塊數(shù)據(jù)潭苞。

視頻編碼幀的最大分片數(shù)SMAX為500忽冻,規(guī)定單個(gè)分片字節(jié)大小SEGS為800bytes (根據(jù)探測(cè)MTU可動(dòng)態(tài)計(jì)算調(diào)整)真朗。當(dāng)幀字節(jié)大小FS小于SEGS+50時(shí)只分為一個(gè)分片;否則僧诚,整數(shù)倍的分片數(shù)S為FS/SEGS遮婶,超出的最后字節(jié)數(shù)FS1為FS%SEGS蝗碎,如果FS1大于50,則再單獨(dú)分一個(gè)分片旗扑,此時(shí)總分片數(shù)為S+1蹦骑,否則如果FS1小于50并且大于0時(shí),將FS1字節(jié)累加放入最后一個(gè)分片中臀防,此時(shí)總分片數(shù)為S眠菇。如下圖2為視頻分片結(jié)構(gòu)與流程。

圖2 視頻分片結(jié)構(gòu)

2.2.1.2 發(fā)送端滑動(dòng)窗口

發(fā)送緩存區(qū)保存著所有正在發(fā)送且沒(méi)有收到接收方連續(xù)seq確認(rèn)acked的報(bào)文袱衷。當(dāng)收到peer端發(fā)來(lái)的分片的ack信息(攜帶一系列丟包的分片seq和已經(jīng)ack并連續(xù)處理到的seq)時(shí)捎废,發(fā)送端從發(fā)送緩存中獲取對(duì)應(yīng)的那些丟包seq并重發(fā)分片(如下圖的seq 10/12分片),同時(shí)從緩存中刪除區(qū)間[s1+1, s2]中的分片致燥,同時(shí)移動(dòng)滑動(dòng)窗口登疗。如下圖3為發(fā)送端滑動(dòng)窗口滑動(dòng)過(guò)程圖。

圖3 發(fā)送端滑動(dòng)窗口

2.2.1.3 發(fā)送端帶寬自適應(yīng)調(diào)整算法

對(duì)于網(wǎng)絡(luò)的不可預(yù)測(cè)性嫌蚤,可能出現(xiàn)抖動(dòng)辐益、擁塞或者很多的丟包,如果按照固定的碼率和參數(shù)來(lái)發(fā)送視頻幀脱吱,這會(huì)導(dǎo)致發(fā)送端與接收端的線路間更擁塞智政,從而使觀看端出現(xiàn)更多的播放延遲或者馬賽克。所以在發(fā)送端需要做帶寬的實(shí)時(shí)估算來(lái)探測(cè)網(wǎng)絡(luò)情況箱蝠,從而便于實(shí)時(shí)根據(jù)網(wǎng)絡(luò)帶寬來(lái)調(diào)整上層視頻編碼器的幀率或者碼率女仰。

在發(fā)送端設(shè)置了一個(gè)定時(shí)器,每10秒鐘(可配置)做一次帶寬統(tǒng)計(jì)抡锈。rtt修正值(網(wǎng)絡(luò)抖動(dòng)的時(shí)間差值)為rtt_var疾忍,期望目標(biāo)帶寬為dst_bw,當(dāng)前發(fā)送的幀分片時(shí)間為cur_ts,最后acked的幀分片時(shí)間為acked_ts床三,則

delay_ts_delta = cur_ts–acked_ts

當(dāng)前單位時(shí)間內(nèi)的acked帶寬為bw一罩,則帶寬抖動(dòng)修正值acked_bw為:

acked_bw = (acked_bw * 3 + bw) / 4

如果當(dāng)前有包在重發(fā),且 delay _ts_delta 大于 8 * MAX(rtt + rtt_var, 100)撇簿,則dst_bw = acked_bw聂渊,向下降低調(diào)整視頻編碼器的分辨率、幀率或碼率來(lái)保證播放的實(shí)時(shí)性和流暢性四瘫;否則如果acked_bw 大于0,則dst_bw = acked_bw * 9 / 8汉嗽,向上提高調(diào)整視頻編碼器的分辨率、幀率或碼率來(lái)恢復(fù)清晰度和提高播放體驗(yàn)找蜜。

2.2.1.4 過(guò)期幀丟棄策略

在網(wǎng)絡(luò)擁塞時(shí)可能發(fā)送窗口緩沖區(qū)中有很多正在發(fā)送中的分片報(bào)文饼暑,為了緩解擁塞和減少延遲會(huì)對(duì)整個(gè)緩沖區(qū)做檢查,如果有超過(guò)一定閾值時(shí)間的GOP 幀存在,則會(huì)將這個(gè) GOP 內(nèi)的所有幀的分片從窗口緩沖區(qū)移除弓叛,并將它的下一個(gè) GOP 的 I 幀 fid和分片seq 通過(guò) syn 協(xié)議同步到各個(gè)接收端上彰居,接收端接收到此協(xié)議,會(huì)將最新連續(xù) seq 設(shè)置成同步過(guò)來(lái)的 seq撰筷。如果頻繁出現(xiàn)過(guò)期幀丟棄處理則會(huì)造成一定程度上的播放卡頓陈惰,此時(shí)說(shuō)明當(dāng)前網(wǎng)絡(luò)不適合傳輸高分辨率或高幀率的視頻,可以通知上層視頻編碼器設(shè)置為更小的分辨率或幀率毕籽。

2.2.2 接收端處理

2.2.2.1 接收端收包處理

接收端收到服務(wù)器中轉(zhuǎn)過(guò)來(lái)的syn消息(攜帶用戶uid抬闯、開(kāi)始分片序列號(hào)start_seq、幀率)后关筒,根據(jù)uid查找(或分配)對(duì)應(yīng)的發(fā)送者并激活画髓,同時(shí)根據(jù)start_seq更新已經(jīng)連續(xù)接收到的分片序列號(hào)base_seq和當(dāng)前接收到的分片最大序列號(hào)max_seq。

圖4 接收者存儲(chǔ)表

接收端第一幀必須是關(guān)鍵幀(即一個(gè)完整GOP的開(kāi)始)平委,如果是其他幀則丟棄奈虾,直到出現(xiàn)關(guān)鍵幀為止,因?yàn)槿绻谝粠荘幀將出現(xiàn)花屏現(xiàn)象廉赔。

每收到一個(gè)分片肉微,如果此分片的seq小于base_seq或者幀fid小于已經(jīng)接收到的最小幀min_fid(已經(jīng)接收過(guò)了)或者分片的seq大于max_seq+2000(太大的跳變導(dǎo)致丟包緩存太大),則丟棄蜡塌;否則碉纳,當(dāng)收到第一個(gè)關(guān)鍵幀的第一個(gè)片段時(shí),記下此時(shí)max_seq和base_seq馏艾,將此分片放入對(duì)應(yīng)幀fid的分片緩存區(qū)劳曹,同時(shí)計(jì)算單位時(shí)間內(nèi)的幀間隔時(shí)長(zhǎng),并更新丟包緩存表琅摩,如果此分片的seq和前一個(gè)已接收分片的seq連續(xù)铁孵,則更新base_seq為此分片的seq,再更新max_seq為MAX(max_seq, seq)房资,最后發(fā)送ack給peer端蜕劝。

如下圖5為接收端收到幀分片并存儲(chǔ)到緩存區(qū)的一個(gè)實(shí)例,對(duì)于一個(gè)完整的幀fid1的分片序列為區(qū)間seq [1, 8]轰异,幀fid2的分片序列為區(qū)間seq [9, 20]岖沛。幀的分片seq總是單調(diào)遞增的。

圖5 接收幀分片緩存區(qū)

2.2.2.2 更新丟包緩存區(qū)策略

如下圖所示搭独,接收端已經(jīng)連續(xù)收到了seq [1, 5] 的分片包婴削,此時(shí)base_seq 和 max_seq 都是5,當(dāng)接收到下一個(gè)分片包seq 10時(shí)牙肝,將seq 10從丟包緩存中刪除唉俗,此時(shí)認(rèn)為 seq [6, 9] 是暫時(shí)丟失的(可能亂序不一定真丟失嗤朴,需要后續(xù)的包來(lái)確認(rèn)),如果丟包緩存中沒(méi)有此序號(hào)的丟包互躬,則將它們放入丟包緩存中,同時(shí)更新它們的丟包時(shí)間戳(當(dāng)前時(shí)間減去rtt值)颂郎,等待下一次的接收確認(rèn)吼渡。

圖6 接收端滑動(dòng)窗口

2.2.2.3 接收端發(fā)送回應(yīng)ack策略

當(dāng)接收端每次收到peer端發(fā)來(lái)的分片,需要判斷是否發(fā)送回應(yīng)ack給peer端乓序,發(fā)送周期是10ms(毫秒)寺酪,小于10ms則不發(fā)送ack,發(fā)送太頻繁會(huì)導(dǎo)致網(wǎng)絡(luò)擁塞替劈;否則寄雀,獲取接收緩存中最老的一幀中最小的分片包序號(hào)min_seq,檢查接收端丟包緩存區(qū)陨献,并刪除區(qū)間[base_seq+1, min_seq]中的丟包盒犹,表明這些丟包已經(jīng)處理過(guò)了,同時(shí)設(shè)置滑動(dòng)窗口的base_seq為min_seq眨业,然后循環(huán)掃描丟包緩存區(qū)檢查當(dāng)前時(shí)間是否超過(guò)一個(gè)發(fā)送分片的rtt時(shí)間急膀,如果超過(guò)則累加此分片的丟包計(jì)數(shù)器,并更新丟包分片的時(shí)間為當(dāng)前時(shí)間龄捡,最后將所有超過(guò)rtt時(shí)長(zhǎng)的丟包發(fā)送ack回peer端卓嫂,最后計(jì)算播放緩存延遲時(shí)長(zhǎng)。

在幀緩存中會(huì)選擇性刪除一些播放過(guò)的幀分片聘殖,播放過(guò)的幀分片是不需要進(jìn)行重發(fā)的晨雳。

在接收端設(shè)置了一個(gè)定時(shí)器,每隔5ms(毫秒)也會(huì)檢測(cè)一次是否發(fā)送回應(yīng)ack給peer端奸腺,并掃描檢查和更新丟包緩存區(qū)餐禁。

2.2.3 獲取播放視頻幀處理

2.2.3.1 播放緩存區(qū)策略

在當(dāng)前播放端設(shè)置了一個(gè)幀緩存區(qū),如果緩存區(qū)過(guò)大時(shí)播放延遲就大突照,過(guò)小時(shí)又會(huì)出現(xiàn)播放卡頓情況坠宴。所以設(shè)置播放緩存區(qū)策略就至關(guān)重要,緩沖時(shí)間大小wait_ts應(yīng)該大于rtt + 2 * rtt_val绷旗,根據(jù)重發(fā)報(bào)文的次數(shù)來(lái)決定喜鼓,在接收端的計(jì)時(shí)器中定期檢查丟包數(shù)和rtt時(shí)長(zhǎng)來(lái)動(dòng)態(tài)的確定wait_ts的大小。

每次上層從播放緩存區(qū)獲取一幀時(shí)衔肢,內(nèi)部都會(huì)檢查當(dāng)前播放緩存區(qū)是處于可播放(max_fid>min_fid并且緩存區(qū)中最新幀(max_fid)的時(shí)間戳max_ts>wait_ts * 5 / 4庄岖,則更新可播放的絕對(duì)時(shí)間戳play_ts為當(dāng)前系統(tǒng)時(shí)間且cached_ts = max_ts - wait_ts * 5 / 4)中還是緩沖(max_fid=min_fid)中,如果在緩沖中則返回空數(shù)據(jù)角骤;否則同步更新播放緩沖幀時(shí)間戳隅忿,如果緩存中最久的一幀(min_fid)的所有分片已經(jīng)接收完整并且此幀時(shí)間F_Oldest_ts在播放緩存時(shí)間cached_ts內(nèi)心剥,則合并當(dāng)前幀分片返回給上層解碼播放,同時(shí)從緩存中刪除此幀背桐,并且更新min_fid為此幀的fid和當(dāng)前已經(jīng)緩存到的幀的時(shí)間戳cached_ts优烧。

此cached_ts的計(jì)算方式為:當(dāng) F_Oldest_ts + wait_ts * 5 / 4 >= max_ts(說(shuō)明緩存區(qū)幀很少)或者 min_fid + 1 = max_fid (說(shuō)明只剩一幀)時(shí),cached_ts = F_Oldest_ts链峭;否則cached_ts = max_ts - wait_ts * 5 / 4,說(shuō)明緩存區(qū)的幀足夠畦娄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市弊仪,隨后出現(xiàn)的幾起案子熙卡,更是在濱河造成了極大的恐慌,老刑警劉巖励饵,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驳癌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡役听,警方通過(guò)查閱死者的電腦和手機(jī)颓鲜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)典予,“玉大人灾杰,你說(shuō)我怎么就攤上這事∥醪危” “怎么了艳吠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)孽椰。 經(jīng)常有香客問(wèn)我昭娩,道長(zhǎng),這世上最難降的妖魔是什么黍匾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任栏渺,我火速辦了婚禮,結(jié)果婚禮上锐涯,老公的妹妹穿的比我還像新娘磕诊。我一直安慰自己,他們只是感情好纹腌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布霎终。 她就那樣靜靜地躺著,像睡著了一般升薯。 火紅的嫁衣襯著肌膚如雪莱褒。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天涎劈,我揣著相機(jī)與錄音广凸,去河邊找鬼阅茶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谅海,可吹牛的內(nèi)容都是我干的脸哀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼扭吁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼撞蜂!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起智末,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谅摄,失蹤者是張志新(化名)和其女友劉穎徒河,沒(méi)想到半個(gè)月后系馆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡顽照,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年由蘑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片代兵。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尼酿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出植影,到底是詐尸還是另有隱情裳擎,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布思币,位于F島的核電站鹿响,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谷饿。R本人自食惡果不足惜惶我,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望博投。 院中可真熱鬧绸贡,春花似錦、人聲如沸毅哗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)虑绵。三九已至叉跛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒸殿,已是汗流浹背筷厘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工鸣峭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酥艳。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓摊溶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親充石。 傳聞我的和親對(duì)象是個(gè)殘疾皇子莫换,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345