現(xiàn)今移動直播技術(shù)上的挑戰(zhàn)要遠(yuǎn)遠(yuǎn)難于傳統(tǒng)設(shè)備或電腦直播,其完整的處理環(huán)節(jié)包括但不限于:音視頻采集酬核、美顏/濾鏡/特效處理蜜另、編碼、封包嫡意、推流举瑰、轉(zhuǎn)碼、分發(fā)鹅很、解碼/渲染/播放等。
直播常見的問題包括
主播在不穩(wěn)定的網(wǎng)絡(luò)環(huán)境下如何穩(wěn)定推流罪帖?
偏遠(yuǎn)地區(qū)的觀眾如何高清流暢觀看直播促煮?
直播卡頓時如何智能切換線路?
如何精確度量直播質(zhì)量指標(biāo)并實時調(diào)整整袁?
移動設(shè)備上不同的芯片平臺如何高性能編碼和渲染視頻菠齿?
美顏等濾鏡特效處理怎么做?
如何實現(xiàn)播放秒開坐昙?
如何保障直播持續(xù)播放流暢不卡頓绳匀?
本次分享將為大家揭開移動直播核心技術(shù)的神秘面紗。
視頻炸客、直播等基礎(chǔ)知識
什么是視頻疾棵?
首先我們需要理解一個最基本的概念:視頻。從感性的角度來看痹仙,視頻就是一部充滿趣味的影片是尔,可以是電影,可以是短片开仰,是一連貫的視覺沖擊力表現(xiàn)豐富的畫面和音頻拟枚。但從理性的角度來看薪铜,視頻是一種有結(jié)構(gòu)的數(shù)據(jù),用工程的語言解釋恩溅,我們可以把視頻剖析成如下結(jié)構(gòu):
內(nèi)容元素 ( Content )
? ? ? ? 圖像 ( Image )
? ? ? ? 音頻 ( Audio )
? ? ? ? 元信息 ( Metadata )
編碼格式 ( Codec )
? ? ? ? Video : H.264隔箍,H.265, …
? ? ? ? Audio : AAC, HE-AAC, …
容器封裝 (Container)
? ? ? ?MP4脚乡,MOV蜒滩,F(xiàn)LV,RM每窖,RMVB帮掉,AVI,…
任何一個視頻 Video 文件窒典,從結(jié)構(gòu)上講蟆炊,都是這樣一種組成方式:
? ? ? ?由圖像和音頻構(gòu)成最基本的內(nèi)容元素;
? ? ? ?圖像經(jīng)過視頻編碼壓縮格式處理(通常是 H.264)瀑志;
? ? ? ?音頻經(jīng)過音頻編碼壓縮格式處理(例如 AAC)涩搓;
? ? ? ? 注明相應(yīng)的元信息(Metadata);
最后經(jīng)過一遍容器(Container)封裝打包(例如 MP4)劈猪,構(gòu)成一個完整的視頻文件昧甘。
如果覺得難以理解,可以想象成一瓶番茄醬战得。最外層的瓶子好比這個容器封裝(Container)充边,瓶子上注明的原材料和加工廠地等信息好比元信息(Metadata),瓶蓋打開(解封裝)后常侦,番茄醬本身好比經(jīng)過壓縮處理過后的編碼內(nèi)容浇冰,番茄和調(diào)料加工成番茄醬的過程就好比編碼(Codec),而原材料番茄和調(diào)料則好比最原本的內(nèi)容元素(Content)聋亡。
視頻的實時傳輸
簡而言之肘习,理性的認(rèn)知視頻的結(jié)構(gòu)后,有助于我們理解視頻直播坡倔。如果視頻是一種“有結(jié)構(gòu)的數(shù)據(jù)”漂佩,那么視頻直播無疑是實時傳輸這種“有結(jié)構(gòu)的數(shù)據(jù)”(視頻)的方式。
那么一個顯而易見的問題是:如何實時(Real-Time)傳輸這種“有結(jié)構(gòu)的數(shù)據(jù)”(視頻)呢罪塔?
這里邊一個悖論是:一個經(jīng)過容器(Container)封裝后的視頻投蝉,一定是不可變的 ( Immutable ) 視頻文件,不可變的 ( Immutable ) 的視頻文件已經(jīng)是一個生產(chǎn)結(jié)果征堪,根據(jù)“相對論”墓拜,而這個生產(chǎn)結(jié)果顯然不可能精確到實時的程度,它已經(jīng)是一段時空的記憶请契。
因此視頻直播咳榜,一定是一個 “邊生產(chǎn)夏醉,邊傳輸,邊消費”的過程涌韩。這意味著畔柔,我們需要更近一步了解視頻從原始的內(nèi)容元素 ( 圖像和音頻 ) 到成品 ( 視頻文件 ) 之前的中間過程 ( 編碼 )。
視頻編碼壓縮
不妨讓我們來深入淺出理解視頻編碼壓縮技術(shù)臣樱。
為了便于視頻內(nèi)容的存儲和傳輸靶擦,通常需要減少視頻內(nèi)容的體積,也就是需要將原始的內(nèi)容元素(圖像和音頻)經(jīng)過壓縮雇毫,壓縮算法也簡稱編碼格式玄捕。例如視頻里邊的原始圖像數(shù)據(jù)會采用 H.264 編碼格式進(jìn)行壓縮,音頻采樣數(shù)據(jù)會采用 AAC 編碼格式進(jìn)行壓縮棚放。
視頻內(nèi)容經(jīng)過編碼壓縮后枚粘,確實有利于存儲和傳輸; 不過當(dāng)要觀看播放時,相應(yīng)地也需要解碼過程飘蚯。因此編碼和解碼之間馍迄,顯然需要約定一種編碼器和解碼器都可以理解的約定。就視頻圖像編碼和解碼而言局骤,這種約定很簡單:
編碼器將多張圖像進(jìn)行編碼后生產(chǎn)成一段一段的 GOP ( Group of Pictures ) 攀圈, 解碼器在播放時則是讀取一段一段的 GOP 進(jìn)行解碼后讀取畫面再渲染顯示。
GOP ( Group of Pictures ) 是一組連續(xù)的畫面峦甩,由一張 I 幀和數(shù)張 B / P 幀組成赘来,是視頻圖像編碼器和解碼器存取的基本單位,它的排列順序?qū)恢敝貜?fù)到影像結(jié)束凯傲。
I 幀是內(nèi)部編碼幀(也稱為關(guān)鍵幀)犬辰,P 幀是前向預(yù)測幀(前向參考幀),B 幀是雙向內(nèi)插幀(雙向參考幀)泣洞。簡單地講忧风,I 幀是一個完整的畫面默色,而 P 幀和 B 幀記錄的是相對于 I 幀的變化球凰。
如果沒有 I 幀,P 幀和 B 幀就無法解碼腿宰。
小結(jié)一下呕诉,一個視頻 ( Video ) ,其圖像部分的數(shù)據(jù)是一組 GOP 的集合, 而單個 GOP 則是一組 I / P / B 幀圖像的集合吃度。
在這樣的一種幾何關(guān)系中甩挫,Video 好比一個 “物體”,GOP 好比 “分子”椿每,I / P / B 幀的圖像則好比 “原子”伊者。
想象一下英遭,如果我們把傳輸一個 “物體”,改成傳輸一個一個的 “原子”亦渗,將最小顆粒以光速傳送挖诸,那么以人的生物肉眼來感知,將是一種怎樣的體驗法精?
什么是視頻直播多律?
不難腦洞大開一下,直播就是這樣的一種體驗搂蜓。視頻直播技術(shù)狼荞,就是將視頻內(nèi)容的最小顆粒 ( I / P / B 幀,…)帮碰,基于時間序列相味,以光速進(jìn)行傳送的一種技術(shù)。
簡而言之收毫,直播就是將每一幀數(shù)據(jù) ( Video / Audio / Data Frame )攻走,打上時序標(biāo)簽 ( Timestamp ) 后進(jìn)行流式傳輸?shù)倪^程。發(fā)送端源源不斷的采集音視頻數(shù)據(jù)此再,經(jīng)過編碼昔搂、封包、推流输拇,再經(jīng)過中繼分發(fā)網(wǎng)絡(luò)進(jìn)行擴(kuò)散傳播摘符,播放端再源源不斷地下載數(shù)據(jù)并按時序進(jìn)行解碼播放。如此就實現(xiàn)了 “邊生產(chǎn)策吠、邊傳輸逛裤、邊消費” 的直播過程。
理解以上兩個關(guān)于?視頻和直播兩個基礎(chǔ)概念后猴抹,接下來我們就可以一窺直播的業(yè)務(wù)邏輯了带族。
直播的業(yè)務(wù)邏輯
如下是一個最精簡的一對多直播業(yè)務(wù)模型,以及各個層級之間的協(xié)議蟀给。
各協(xié)議差異對比如下
以上就是關(guān)于直播技術(shù)的一些基礎(chǔ)概念蝙砌。下面我們進(jìn)一步了解下影響人們視覺體驗的直播性能指標(biāo)。
影響視覺體驗的直播性能指標(biāo)
直播第一個性能指標(biāo)是延遲跋理,延遲是數(shù)據(jù)從信息源發(fā)送到目的地所需的時間择克。
根據(jù)愛因斯坦的狹義相對論,光速是所有能量前普、物質(zhì)和信息運(yùn)動所能達(dá)到的最高速度肚邢,這個結(jié)論給傳播速度設(shè)定了上限。因此拭卿,即便我們?nèi)庋鄹杏X到的實時骡湖,實際上也是有一定的延遲贱纠。
由于 RTMP/HLS 是基于 TCP 之上的應(yīng)用層協(xié)議,TCP 三次握手响蕴,四次揮手并巍,慢啟動過程中的每一次往返來回,都會加上一次往返耗時 ( RTT )换途,這些交互過程都會增加延遲懊渡。
其次根據(jù) TCP 丟包重傳特性,網(wǎng)絡(luò)抖動可能導(dǎo)致丟包重傳军拟,也會間接導(dǎo)致延遲加大剃执。
一個完整的直播過程,包括但不限于以下環(huán)節(jié):采集懈息、處理肾档、編碼、封包辫继、推流怒见、傳輸、轉(zhuǎn)碼姑宽、分發(fā)遣耍、拉流、解碼炮车、播放舵变。從推流到播放,再經(jīng)過中間轉(zhuǎn)發(fā)環(huán)節(jié)瘦穆,延遲越低纪隙,則用戶體驗越好。
第二個直播性能指標(biāo)卡頓扛或,是指視頻播放過程中出現(xiàn)畫面滯幀绵咱,讓人們明顯感覺到“卡”。單位時間內(nèi)的播放卡頓次數(shù)統(tǒng)計稱之為卡頓率熙兔。
造成卡頓的因素有可能是推流端發(fā)送數(shù)據(jù)中斷悲伶,也有可能是公網(wǎng)傳輸擁塞或網(wǎng)絡(luò)抖動異常,也有可能是終端設(shè)備的解碼性能太差黔姜÷G校卡頓頻次越少或沒有蒂萎,則說明用戶體驗越好秆吵。
第三個直播性能指標(biāo)首屏耗時,指第一次點擊播放后五慈,肉眼看到畫面所等待的時間纳寂。技術(shù)上指播放器解碼第一幀渲染顯示畫面所花的耗時主穗。通常說的 “秒開”,指點擊播放后毙芜,一秒內(nèi)即可看到播放畫面忽媒。首屏打開越快,說明用戶體驗越好腋粥。
如上三個直播性能指標(biāo)晦雨,分別對應(yīng)一個低延遲、高清流暢隘冲、極速秒開 的用戶體驗訴求闹瞧。了解這三個性能指標(biāo)嗽交,對優(yōu)化移動直播 APP 的用戶體驗至關(guān)重要运准。
那么移動直播場景下具體而言有哪些常見的坑呢碗短?
根據(jù)實踐總結(jié)下來的經(jīng)驗片部,移動平臺上視頻直播的坑主要可以總結(jié)為兩方面:設(shè)備差異姨蝴,以及網(wǎng)絡(luò)環(huán)境這些場景下帶來的技術(shù)考驗勋颖。
移動直播場景的坑與規(guī)避措施
不同芯片平臺上的編碼差異
iOS 平臺上無論硬編還是軟編武福,由于是 Apple 一家公司出廠淡诗,幾乎不存在因為芯片平臺不同而導(dǎo)致的編碼差異覆旱。
然而蘸朋,在 Android 平臺上,Android Framework SDK 提供的 MediaCodec 編碼器扣唱,在不同的芯片平臺上度液,差異表現(xiàn)很大, 不同的廠家使用不同的芯片画舌,而不同的芯片平臺上 Android MediaCodec 表現(xiàn)略有差異堕担,通常實現(xiàn)全平臺兼容的成本不低。
另外就是 Android MediaCodec 硬編層面的 H.264 編碼畫質(zhì)參數(shù)是固定的 baseline曲聂,所以畫質(zhì)通常也一般霹购。因此,在 Android 平臺下朋腋,推薦是用軟編齐疙,好處是畫質(zhì)可調(diào)控,兼容性也更好旭咽。
低端設(shè)備如何上高性能地采集和編碼贞奋?
例如 Camera 采集輸出的可能是圖片,一張圖的體積并不會小穷绵,如果采集的頻次很高轿塔,編碼的幀率很高,每張圖都經(jīng)過編碼器,那么編碼器又可能會出現(xiàn)過載勾缭。
這個時候揍障,可以考慮在編碼前,不影響畫質(zhì)的前提下(前面我們講過幀率的微觀意義)俩由,進(jìn)行選擇性丟幀毒嫡,以此降低編碼環(huán)節(jié)的功耗開銷。
弱網(wǎng)下如何保障高清流暢推流
移動網(wǎng)絡(luò)下幻梯,通常容易遇到網(wǎng)絡(luò)不穩(wěn)定兜畸,連接被重置,斷線重連碘梢,一方面頻繁重連膳叨,建立連接需要開銷。另一方面尤其是發(fā)生 GPRS / 2G / 3G / 4G 切換時痘系,帶寬可能出現(xiàn)瓶頸菲嘴。當(dāng)帶寬不夠,幀率較高/碼率較高的內(nèi)容較難發(fā)送出去汰翠,這個時候就需要可變碼率支持龄坪。
即在推流端,可檢測網(wǎng)絡(luò)狀態(tài)和簡單測速复唤,動態(tài)來切換碼率健田,以保障網(wǎng)絡(luò)切換時的推流流暢。
其次編碼佛纫、封包妓局、推流 這一部分的邏輯也可以做微調(diào),可以嘗試選擇性丟幀呈宇,比如優(yōu)先丟視頻參考幀(不丟 I 幀和音頻幀 )好爬,這樣也可以減少要傳輸?shù)臄?shù)據(jù)內(nèi)容,但同時又達(dá)到了不影響畫質(zhì)和版視聽流暢的目的甥啄。
需要區(qū)分直播流的狀態(tài)和業(yè)務(wù)狀態(tài)
直播是媒體流存炮、APP 的交互是 API 信令流,兩者的狀態(tài)不能混為一談蜈漓。尤其是不能基于 APP 的交互的 API 狀態(tài)來判斷直播流的狀態(tài)穆桂。
以上是移動直播場景下常見的幾個坑和規(guī)避措施。
移動直播場景其他優(yōu)化措施
一融虽、怎么優(yōu)化打開速度享完,達(dá)到傳說中的 “秒開”?
大家可能會看到有额,市面上某些手機(jī)直播 APP 的打開速度非嘲阌郑快彼绷,一點就開。而某些手機(jī)直播 APP倒源,點擊播放后要等好幾秒以后才能播放。是什么原因?qū)е氯绱说奶烊乐畡e呢句狼?
大部分播放器都是拿到一個完成的 GOP 后才能解碼播放笋熬,基于 FFmpeg 移植的播放器甚至需要等待音畫時間戳同步后才能播放(如果一個直播里邊沒有音頻只有視頻相當(dāng)于要等待音頻超時后才能播放畫面)。
“秒開”可以從以下幾個方面考慮:
1. 改寫播放器邏輯讓播放器拿到第一個關(guān)鍵幀后就給予顯示腻菇。
GOP 的第一幀通常都是關(guān)鍵幀胳螟,由于加載的數(shù)據(jù)較少,可以達(dá)到 “首幀秒開”筹吐。
如果直播服務(wù)器支持 GOP 緩存糖耸,意味著播放器在和服務(wù)器建立連接后可立即拿到數(shù)據(jù),從而省卻跨地域和跨運(yùn)營商的回源傳輸時間丘薛。
GOP 體現(xiàn)了關(guān)鍵幀的周期嘉竟,也就是兩個關(guān)鍵幀之間的距離,即一個幀組的最大幀數(shù)洋侨。假設(shè)一個視頻的恒定幀率是 24fps(即1秒24幀圖像)舍扰,關(guān)鍵幀周期為 2s,那么一個 GOP 就是 48 張圖像希坚。一般而言边苹,每一秒視頻至少需要使用一個關(guān)鍵幀。
增加關(guān)鍵幀個數(shù)可改善畫質(zhì)(GOP 通常為 FPS 的倍數(shù))裁僧,但是同時增加了帶寬和網(wǎng)絡(luò)負(fù)載个束。這意味著,客戶端播放器下載一個 GOP聊疲,畢竟該 GOP 存在一定的數(shù)據(jù)體積茬底,如果播放端網(wǎng)絡(luò)不佳,有可能不是能夠快速在秒級以內(nèi)下載完該 GOP获洲,進(jìn)而影響觀感體驗桩警。
如果不能更改播放器行為邏輯為首幀秒開,直播服務(wù)器也可以做一些取巧處理昌妹,比如從緩存 GOP 改成緩存雙關(guān)鍵幀(減少圖像數(shù)量)捶枢,這樣可以極大程度地減少播放器加載 GOP 要傳輸?shù)膬?nèi)容體積。
2. 在 APP 業(yè)務(wù)邏輯層面方面優(yōu)化飞崖。
比如提前做好 DNS 解析(省卻幾十毫秒)烂叔,和提前做好測速選線(擇取最優(yōu)線路)。經(jīng)過這樣的預(yù)處理后固歪,在點擊播放按鈕時蒜鸡,將極大提高下載性能胯努。
一方面,可以圍繞傳輸層面做性能優(yōu)化逢防;另一方面叶沛,可以圍繞客戶播放行為做業(yè)務(wù)邏輯優(yōu)化。兩者可以有效的互為補(bǔ)充忘朝,作為秒開的優(yōu)化空間灰署。
二、美顏等濾鏡如何處理局嘁?
在手機(jī)直播場景下溉箕,這就是一個剛需。沒有美顏功能的手機(jī)直播 APP悦昵,主播基本不愛用肴茄。可以在采集畫面后但指,將數(shù)據(jù)送給編碼器之前寡痰,將數(shù)據(jù)源回調(diào)給濾鏡處理程序,原始數(shù)據(jù)經(jīng)過濾鏡處理完后棋凳,再送回給編碼器進(jìn)行編碼即可氓癌。
除了移動端可以做體驗優(yōu)化之外,直播流媒體服務(wù)端架構(gòu)也可以降低延遲贫橙。例如收流服務(wù)器主動推送 GOP 至邊緣節(jié)點贪婉,邊緣節(jié)點緩存 GOP,播放端則可以快速加載卢肃,減少回源延遲疲迂。
其次,可以貼近終端就近處理和分發(fā)
三莫湘、如何保障直播持續(xù)播放流暢不卡頓尤蒿?
“秒開”解決的是直播首次加載的播放體驗,如何保障直播持續(xù)播放過程中的畫面和聲音視聽流暢呢幅垮?因為腰池,一個直播畢竟不是一個 HTTP 一樣的一次性請求,而是一個 Socket 層面的長連接維持忙芒,直到直到主播主動終止推流示弓。
上述我們講過卡頓的定義:即播放時畫面滯幀,觸發(fā)了人們的視覺感受呵萨。在不考慮終端設(shè)備性能差異的情況下奏属,針對網(wǎng)絡(luò)傳輸層面的原因,我們看看如何保障一個持續(xù)的直播不卡頓潮峦。
這其實是一個直播過程中傳輸網(wǎng)絡(luò)不可靠時的容錯問題囱皿。例如勇婴,播放端臨時斷網(wǎng)了,但又快速恢復(fù)了嘱腥,針對這種場景耕渴,播放端如果不做容錯處理,很難不出現(xiàn)黑屏或是重新加載播放的現(xiàn)象齿兔。
為了容忍這種網(wǎng)絡(luò)錯誤橱脸,并達(dá)到讓終端用戶無感知,客戶端播放器可以考慮構(gòu)建一個FIFO(先進(jìn)先出)的緩沖隊列愧驱,解碼器從播放緩存隊列讀取數(shù)據(jù)慰技,緩存隊列從直播服務(wù)器源源不斷的下載數(shù)據(jù)椭盏。通常组砚,緩存隊列的容量是以時間為單位(比如3s),在播放端網(wǎng)絡(luò)不可靠時掏颊,客戶端緩存區(qū)可以起到“斷網(wǎng)無感”的過渡作用糟红。
顯然,這只是一個“緩兵之計”乌叶,如果直播服務(wù)器邊緣節(jié)點出現(xiàn)故障盆偿,而此時客戶端播放器又是長連接,在無法收到對端的連接斷開信號准浴,客戶端的緩沖區(qū)容量再大也不管用了事扭,這個時候就需要結(jié)合客戶端業(yè)務(wù)邏輯來做調(diào)度。
重要的是客戶端結(jié)合服務(wù)端乐横,可以做精準(zhǔn)調(diào)度求橄。在初始化直播推流之前,例如基于 IP 地理位置和運(yùn)營商的精確調(diào)度葡公,分配線路質(zhì)量最優(yōu)的邊緣接入節(jié)點罐农。在直播推流的過程中,可以實時監(jiān)測幀率反饋等質(zhì)量數(shù)據(jù)催什,基于直播流的質(zhì)量動態(tài)調(diào)整線路涵亏。
Q & A
1. 關(guān)鍵幀設(shè)置頻率一般是多少?有沒有根據(jù)接入動態(tài)設(shè)置蒲凶?過長首屏秒會很難做到气筋。
徐立:關(guān)鍵幀間隔越長,也就是 GOP 越長旋圆,理論上畫面越高清裆悄。但是生成 HLS 直播時,最小切割粒度也是一個 GOP臂聋,所以針對交互直播光稼,通常不建議 GOP 設(shè)置太長或南。直播一般 2 個關(guān)鍵幀間隔即可。比如幀率是 24fps艾君, 那么 2 個關(guān)鍵幀的間隔就是 48fps 采够,這個 GOP 就是2s。
2. 七牛這個直播是用的網(wǎng)宿加速冰垄?有遇到什么坑沒蹬癌?
徐立:七牛在直播方面主要是自建節(jié)點,也支持融合眾多第三方 CDN 服務(wù)商虹茶,多樣化的線路組合為客戶提供更優(yōu)質(zhì)的服務(wù)逝薪。在和第三方 CDN 合作的過程中遇到的問題等有機(jī)會再做更細(xì)粒度的交流和分享。
3. RTMP 直播流除了優(yōu)化線路外蝴罪,還有什么加速手段嗎董济?
徐立:物理上優(yōu)化線路,邏輯上優(yōu)化策略要门,比如選擇性丟幀虏肾,不影響編碼畫質(zhì)的前提下減輕傳輸體積。
4. OBS 推流欢搜,播放端 HLS 出現(xiàn)視/音頻不同步是哪個環(huán)節(jié)的問題封豪?怎么優(yōu)化?
徐立:有可能是采集端的問題炒瘟,如果是采集端編碼環(huán)節(jié)就出現(xiàn)音畫不同步吹埠,可以在收流服務(wù)器上做音畫時間戳同步,這樣是全局的校對疮装。如果是播放端解碼性能問題缘琅,那么需要調(diào)節(jié)播放邏輯,比如保證音畫時間戳強(qiáng)一致性的前提下斩个,選擇性丟一部幀胯杭。
5. PPT 前幾頁中一個概念好像錯了,I 幀不是關(guān)鍵幀受啥,IDR 幀才是做个。IDR 幀是 I 幀,但是 I 幀不一定是 IDR 幀滚局。只有 IDR 幀才是可重入的居暖。
徐立:中文都把 I 幀翻譯成關(guān)鍵幀了,不過既然提到了 IDR 幀藤肢,可以展開說明一下太闺。所有的 IDR 幀都是 I 幀,但是并不是所有 I 幀都是 IDR 幀嘁圈,IDR 幀是 I 幀的子集省骂。I 幀嚴(yán)格定義是幀內(nèi)編碼幀蟀淮,由于是一個全幀壓縮編碼幀,通常用 I 幀表示 “關(guān)鍵幀”钞澳。IDR 是基于 I 幀的一個 “擴(kuò)展”怠惶,帶了控制邏輯,IDR 圖像都是 I 幀圖像轧粟,當(dāng)解碼器解碼到 IDR 圖像時策治,會立即將參考幀隊列清空,將已解碼的數(shù)據(jù)全部輸出或拋棄兰吟。重新查找參數(shù)集通惫,開始一個新的序列。這樣如果前一個序列出現(xiàn)重大錯誤混蔼,在這里可以獲得重新同步的機(jī)會履腋。IDR 圖像之后的圖像永遠(yuǎn)不會使用 IDR 之前的圖像的數(shù)據(jù)來解碼。
6. 有沒有調(diào)研過 nginx rtmp module拄丰,為什么沒有用府树,對它有什么評價俐末?
徐立:有調(diào)研過料按,nginx_rtmp_module 是單進(jìn)程多線程,非 go 這種輕量級線程/協(xié)程用并發(fā)自然語義的方式編寫流業(yè)務(wù)卓箫。nginx 原本的代碼量較大(約 16 萬行载矿,但和直播業(yè)務(wù)相關(guān)的功能并不是很多)。且主要靠寫 nginx.conf 做配置租戶烹卒,通常單租戶可以闷盔,但業(yè)務(wù)可擴(kuò)展性方面不是很靈活,可滿足基本需求旅急,不滿足高級功能逢勾。
7. 用到了那些開源軟件?編碼用的是 x264 嗎藐吮?直播服務(wù)器你們自己開發(fā)還是開源的溺拱?
徐立:直播服務(wù)器用 go 開發(fā)的,移動端編碼優(yōu)先硬編谣辞,軟編用 x264
8. 請教一下用 OBS 推流到 nginx_rtmp_module 的時候是已經(jīng)做了視頻壓縮了還是需要基于 OBS 再開發(fā)迫摔?
徐立:OBS 把編碼壓縮都做了,不需要再開發(fā)泥从。
9. 視頻直播想在 HLS 流中無縫插入一段廣告的 ts 文件句占,有問題想請教一下:1、這段 ts 的分辨率是否一定要和之前的視頻流一致躯嫉?2纱烘、pts 時間戳是否要和上一個 ts 遞增杨拐?
徐立:1、可以不一致擂啥。這種情況兩段視頻完全是獨立狀態(tài)戏阅,可以沒有任何關(guān)系,只需要插入 discontinue 標(biāo)記啤它,播放器在識別到這個標(biāo)記之后重置解碼器參數(shù)就可以無縫播放奕筐,畫面會很平滑的切換。2变骡、不需要遞增离赫。舉個例子,視頻 A 正在直播塌碌,播放到 pts 在 5s 的時候渊胸,插入一個視頻 B,需要先插入一個 discontinue台妆,再插入 B翎猛,等 B 播放完之后,再插入一個 discontinue接剩,再插入 A切厘,這個時候 A 的 pts 可以和之前遞增,也可以按照中間插入的 B 的時長做偏移懊缺,一般做點播和時移的時候 pts 會連續(xù)遞增疫稿,直播的話會算上 B 的時長。
將bilibili自帶的Demo運(yùn)行起來
一般我們用到的任何一個播放器都是基于FFmpeg播放的鹃两,但蘋果提供的AiPlayer不支持直播文件遗座,而bilibili已經(jīng)將FFmpeg封裝好,用它可以面向?qū)ο笕ラ_發(fā)俊扳。
1.在GitHub搜索ijkplayer途蒋,可以看到,Android,iOS都是基于此
2.找到Build iOS,打開終端
3.輸入:cd Desktop/
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-ios
下載ijkplayer-ios到桌面
cd Desktop/ijkplayer-ios
./init-ios.sh? ? (下載FFmpeg)
cd ios? (跳到ios文件夾下編譯FFmpeg)
./compile-ffmpeg.sh clean
./complie-ffmpeg.sh all
4.編譯完成后透敌,運(yùn)行Demo,出現(xiàn)如下界面表示完成
此時需要將bilibili的dome集成到我們自己的工程中筋帖,方法有兩個:
1、官方給出的方法是工程里集成工程冤馏,比較復(fù)雜日麸;
2、將ijk所有的源碼打包成framework,只需要繼承這個framework就可以了代箭。
生成framework步驟如下:
1.運(yùn)行IJKMediaPlayer下的工程墩划,點擊Edit Scheme…
2.彈出如下窗口,將Debug改成Release嗡综,然后點擊Close
3.我們需要Build一個模擬器版本和一個真機(jī)版本乙帮,然后合并
Build模擬器版本:隨意選一個模擬器
4.command+B,紅色變?yōu)楹谏募汛嬖诩埃瑂how in Finder可查看
5.然后是真機(jī)版本察净,當(dāng)沒有連接手機(jī)時,我們選Generic iOS Device
再次command+B盼樟,生成真機(jī)版本
我們真正要合并的是這個文件
6.合并方法
7.完成后氢卡,將IJKMediaFramework文件替換到之前真機(jī)里面,然后復(fù)制上一級IJKMediaFramework.framework文件到桌面晨缴,以備后用译秦。
(播直播就是播一個URL,我們已經(jīng)拿到了URL击碗,已經(jīng)寫到我們的數(shù)據(jù)源里了筑悴,把數(shù)據(jù)源拿過來。我們需要導(dǎo)入一個播放的框架稍途,來到target->General->Linked Frameworks and Libraries阁吝,點擊加號,添加AVFoundation.framework晰房,導(dǎo)入#import,
MPMoviePlayerViewController *movieVC? = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:live.streamAddr]];
[self presentViewController:movieVC animated:YES completion:nil];
至此求摇,當(dāng)點擊cell時射沟,可以彈出播放界面殊者,但并不能播放,因為無法解碼验夯,SO猖吴,我們只能放棄這個MP方法)
這時就需要用到我們事先準(zhǔn)備的IJKMediaFramework.framework。
8.將我們合并的IJKMediaFramework.framework拖到我們的工程挥转,一定要點擊這個Copy
9.同時它還會依賴一些框架海蔽,在GitHub上,搜索ijkPlayer,找到需要導(dǎo)入的框架绑谣,如下
開始導(dǎo)入:來到target->General->Linked Frameworks and Libraries党窜,點擊加號,開始添加借宵,導(dǎo)完編譯一下幌衣,查看是否成功
10.接著我們就需要自己創(chuàng)建一個播放的界面了,新建
11.將IJKMediaDemo里的東西復(fù)制到Y(jié)KPlayerViewController來
導(dǎo)入頭文件#import <IJKMediaFramework/IJKMediaFramework.h>
添加協(xié)議@property(atomic, retain) idplayer
然后注冊通知,remove通知(將相應(yīng)代碼復(fù)制過來),但還是有黃色警告豁护,說明有方法沒實現(xiàn)哼凯,需要把方法在復(fù)制過來,剩下的就是創(chuàng)建真正的直播了(配置直播)
來到viewDidLoad楚里,[self initPlayer];
然后完成這個初始化 -(void)initPlayer 断部,
IJKFFOptions *options = [IJKFFOptions optionsByDefault];
IJKFFMoviePlayerController *player = [[IJKFFMoviePlayerController alloc] initWithContentURLString:self.live.streamAddr withOptions:options];
self.player = player;
self.player.view.frame = self.view.bounds;
self.player.shouldAutoplay = YES;
[self.view addSubview:self.player.view];
然后傳值過去
YKPlayerViewController *playerVC = [[YKPlayerViewController alloc] init];
playerVC.live = live;
[self.navigationController pushViewController:playerVC animated:YES];
至此就可以播放了。