本文來自於騰訊bugly開發者社區,原文地址:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1277php
視頻直播這麼火,再不學就 out 了。html
爲了緊跟潮流,本文將向你們介紹一下視頻直播中的基本流程和主要的技術點,包括但不限於前端技術。前端
固然能夠, H5 火了這麼久,涵蓋了各個方面的技術。html5
對於視頻錄製,可使用強大的 webRTC(Web Real-Time Communication)是一個支持網頁瀏覽器進行實時語音對話或視頻對話的技術,缺點是隻在 PC 的 chrome 上支持較好,移動端支持不太理想。android
對於視頻播放,可使用 HLS(HTTP Live Streaming)協議播放直播流, ios 和 android 都自然支持這種協議,配置簡單,直接使用 video 標籤便可。ios
webRTC 兼容性:nginx
video 標籤播放 hls 協議視頻:git
<video controls autoplay> <source src="http://10.66.69.77:8080/hls/mystream.m3u8" type="application/vnd.apple.mpegurl" /> <p class="warning">Your browser does not support HTML5 video.</p> </video>
簡單講就是把整個流分紅一個個小的,基於 HTTP 的文件來下載,每次只下載一些,前面提到了用於 H5 播放直播視頻時引入的一個 .m3u8 的文件,這個文件就是基於 HLS 協議,存放視頻流元數據的文件。github
每個 .m3u8 文件,分別對應若干個 ts 文件,這些 ts 文件纔是真正存放視頻的數據,m3u8 文件只是存放了一些 ts 文件的配置信息和相關路徑,當視頻播放時,.m3u8 是動態改變的,video 標籤會解析這個文件,並找到對應的 ts 文件來播放,因此通常爲了加快速度,.m3u8 放在 web 服務器上,ts 文件放在 cdn 上。web
.m3u8 文件,其實就是以 UTF-8 編碼的 m3u 文件,這個文件自己不能播放,只是存放了播放信息的文本文件:
#EXTM3U m3u文件頭 #EXT-X-MEDIA-SEQUENCE 第一個TS分片的序列號 #EXT-X-TARGETDURATION 每一個分片TS的最大的時長 #EXT-X-ALLOW-CACHE 是否容許cache #EXT-X-ENDLIST m3u8文件結束符 #EXTINF 指定每一個媒體段(ts)的持續時間(秒),僅對其後面的URI有效 mystream-12.ts
ts 文件:
HLS 的請求流程是:
1 http 請求 m3u8 的 url。
2 服務端返回一個 m3u8 的播放列表,這個播放列表是實時更新的,通常一次給出5段數據的 url。
3 客戶端解析 m3u8 的播放列表,再按序請求每一段的 url,獲取 ts 數據流。
簡單流程:
咱們知道 hls 協議是將直播流分紅一段一段的小段視頻去下載播放的,因此假設列表裏面的包含5個 ts 文件,每一個 TS 文件包含5秒的視頻內容,那麼總體的延遲就是25秒。由於當你看到這些視頻時,主播已經將視頻錄製好上傳上去了,因此時這樣產生的延遲。固然能夠縮短列表的長度和單個 ts 文件的大小來下降延遲,極致來講能夠縮減列表長度爲1,而且 ts 的時長爲1s,可是這樣會形成請求次數增長,增大服務器壓力,當網速慢時回形成更多的緩衝,因此蘋果官方推薦的ts時長時10s,因此這樣就會大改有30s的延遲。參考資料:https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
當視頻直播可大體分爲:
1 視頻錄製端:通常是電腦上的音視頻輸入設備或者手機端的攝像頭或者麥克風,目前以移動端的手機視頻爲主。
2 視頻播放端:能夠是電腦上的播放器,手機端的 native 播放器,還有就是 h5 的 video 標籤等,目前仍是已手機端的 native 播放器爲主。
3 視頻服務器端:通常是一臺 nginx 服務器,用來接受視頻錄製端提供的視頻源,同時提供給視頻播放端流服務。
簡單流程:
當首先明確幾個概念:
視頻編碼:所謂視頻編碼就是指經過特定的壓縮技術,將某個視頻格式的文件轉換成另外一種視頻格式文件的方式,咱們使用的 iphone 錄製的視頻,必需要通過編碼,上傳,解碼,才能真正的在用戶端的播放器裏播放。
編解碼標準:視頻流傳輸中最爲重要的編解碼標準有國際電聯的H.26一、H.26三、H.264,其中 HLS 協議支持 H.264 格式的編碼。
音頻編碼:同視頻編碼相似,將原始的音頻流按照必定的標準進行編碼,上傳,解碼,同時在播放器裏播放,固然音頻也有許多編碼標準,例如 PCM 編碼,WMA 編碼,AAC 編碼等等,這裏咱們 HLS 協議支持的音頻編碼方式是AAC編碼。
下面將利用 ios 上的攝像頭,進行音視頻的數據採集,主要分爲如下幾個步驟:
1 音視頻的採集,ios 中,利用 AVCaptureSession和AVCaptureDevice 能夠採集到原始的音視頻數據流。
2 對視頻進行 H264 編碼,對音頻進行 AAC 編碼,在 ios 中分別有已經封裝好的編碼庫來實現對音視頻的編碼。
3 對編碼後的音、視頻數據進行組裝封包;
4 創建 RTMP 鏈接並上推到服務端。
ps:因爲編碼庫大多使用 c 語言編寫,須要本身使用時編譯,對於 ios,可使用已經編譯好的編碼庫。
x264編碼:https://github.com/kewlbear/x264-ios
faac編碼:https://github.com/fflydev/faac-ios-build
ffmpeg編碼:https://github.com/kewlbear/FFmpeg-iOS-build-script
關於若是想給視頻增長一些特殊效果,例如增長濾鏡等,通常在編碼前給使用濾鏡庫,可是這樣也會形成一些耗時,致使上傳視頻數據有必定延時。
簡單流程:
和以前的 x264 同樣,ffmpeg 其實也是一套編碼庫,相似的還有 Xvid,Xvid 是基於 MPEG4 協議的編解碼器,x264是基於 H.264 協議的編碼器, ffmpeg 集合了各類音頻,視頻編解碼協議,經過設置參數能夠完成基於 MPEG4,H.264 等協議的編解碼,demo 這裏使用的是 x264 編碼庫。
Real Time Messaging Protocol(簡稱 RTMP)是 Macromedia 開發的一套視頻直播協議,如今屬於 Adobe。和 HLS 同樣均可以應用於視頻直播,區別是 RTMP 基於 flash 沒法在 ios 的瀏覽器裏播放,可是實時性比 HLS 要好。因此通常使用這種協議來上傳視頻流,也就是視頻流推送到服務器。
這裏列舉一下 hls 和 rtmp 對比:
簡所謂推流,就是將咱們已經編碼好的音視頻數據發往視頻流服務器中,通常經常使用的是使用 rtmp 推流,可使用第三方庫 librtmp-iOS 進行推流,librtmp 封裝了一些核心的 api 供使用者調用,若是以爲麻煩,可使用現成的 ios 視頻推流sdk,也是基於 rtmp 的,https://github.com/runner365/LiveVideoCoreSDK
簡簡單的推流服務器搭建,因爲咱們上傳的視頻流都是基於 rtmp 協議的,因此服務器也必需要支持 rtmp 才行,大概須要如下幾個步驟:
1 安裝一臺 nginx 服務器。
2 安裝 nginx 的 rtmp 擴展,目前使用比較多的是https://github.com/arut/nginx-rtmp-module
3 配置 nginx 的 conf 文件:
rtmp { server { listen 1935; #監聽的端口 chunk_size 4000; application hls { #rtmp推流請求路徑 live on; hls on; hls_path /usr/local/var/www/hls; hls_fragment 5s; } } }
4 重啓 nginx,將 rtmp 的推流地址寫爲 rtmp://ip:1935/hls/mystream,其中 hls_path 表示生成的 .m3u8 和 ts 文件所存放的地址,hls_fragment 表示切片時長,mysteam 表示一個實例,即未來要生成的文件名能夠先本身隨便設置一個。更多配置能夠參考:https://github.com/arut/nginx-rtmp-module/wiki/
根據以上步驟基本上已經實現了一個支持 rtmp 的視頻服務器了。
簡單來講,直接使用 video 標籤便可播放 hls 協議的直播視頻:
<video autoplay webkit-playsinline> <source src="http://10.66.69.77:8080/hls/mystream.m3u8" type="application/vnd.apple.mpegurl" /> <p class="warning">Your browser does not support HTML5 video.</p> </video>
須要注意的是,給 video 標籤增長 webkit-playsinline 屬性,這個屬性是爲了讓 video 視頻在 ios 的 uiwebview 裏面能夠不全屏播放,默認 ios 會全屏播放視頻,須要給 uiwebview 設置 allowsInlineMediaPlayback=YES。 業界比較成熟的 videojs,能夠根據不一樣平臺選擇不一樣的策略,例如 ios 使用 video 標籤,pc 使用 flash 等。
簡根據以上步驟,筆者寫了一個 demo,從實現 ios 視頻錄製,採集,上傳,nginx 服務器下發直播流,h5 頁面播放直播視頻者一整套流程,總結出如下幾點比較坑的地方:
1 在使用 AVCaptureSession 進行採集視頻時,須要實現 AVCaptureVideoDataOutputSampleBufferDelegate 協議,同時在- (void)captureOutput:(AVCaptureOutput )captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection)connection 捕獲到視頻流,要注意的是 didOutputSampleBuffer 這個方法不是 didDropSampleBuffer 方法,後者只會觸發一次,當時開始寫的是 didDropSampleBuffer 方法,差了半天才發現方法調用錯了。
2 在使用 rtmp 推流時,rmtp 地址要以 rtmp:// 開頭,ip 地址要寫實際 ip 地址,不要寫成 localhost,同時要加上端口號,由於手機端上傳時是沒法識別 localhos t的。
這裏後續會補充上一些坑點,有的須要貼代碼,這裏先列這麼多。
目前,騰訊雲,百度雲,阿里雲都已經有了基於視頻直播的解決方案,從視頻錄製到視頻播放,推流,都有一系列的 sdk 可使用,缺點就是須要收費,若是能夠的話,本身實現一套也並非難事哈。
demo地址:https://github.com/lvming6816077/LMVideoTest/
參考資料:http://www.nihaoshijie.com.cn/index.php/archives/615
更多精彩內容歡迎關注bugly的微信公衆帳號:
騰訊 Bugly是一款專爲移動開發者打造的質量監控工具,幫助開發者快速,便捷的定位線上應用崩潰的狀況以及解決方案。智能合併功能幫助開發同窗把天天上報的數千條 Crash 根據根因合併分類,每日日報會列出影響用戶數最多的崩潰,精準定位功能幫助開發同窗定位到出問題的代碼行,實時上報能夠在發佈後快速的瞭解應用的質量狀況,適配最新的 iOS, Android 官方操做系統,鵝廠的工程師都在使用,快來加入咱們吧!