為了強化官方驗的心智,平臺要做一版新的質檢直播間,將我們的質檢車間全方位透明的展現給用戶。按照產品的設計來實現的話,其實就是將各個鏡頭的內容同時在一個頁面內進行播放,除了工作時間的直播,還有休息時間的錄播播放。不過直播和錄播的生成都是在后端實現,前端只負責視頻資源的播放。
對于簡單的直播場景,我們需要關注的主要是「編解碼格式」和「直播協議」,因為這兩點直接決定直播能否播放。
「編解碼格式:」視頻的編碼方式決定了視頻的壓縮方式,同樣的需要對應的解碼格式才能正常播放視頻。但視頻編碼這個過程是在推流端做的,通常會采用H.264,目前基本上所有的播放器和瀏覽器都支持該解碼方式,其兼容性基本不用考慮;所以雖然視頻的編解碼格式很重要,但只要沒有特殊的場景如4k,一般無需過多考慮。
「拉流端直播協議:」不同的直播協議,其兼容性和直播效果有一些差異,而前端對兼容性的差異是敏感的,所以對于Web端,盡量選擇兼容性最佳的HLS。
以下是我了解到的不同直播協議的特點及他們的優劣勢:
「RTMP」
特點/優點:
1.基于TCP長連接,不需要多次建連,延時低,通常只有1~3s;2.技術成熟,配套完善。
缺點:
1.兼容性差,需要依賴flash,因此無法在移動端使用。2.容易被防火墻攔截。
「HLS」
特點/優點:
1.其工作原理是切片式傳輸,把直播流切成無數片,用戶在觀看視頻時,每次客戶端可以只下載一部分;2.基于 HTTP協議,所以接入CDN較為容易,很少被防火墻攔下;3.自帶多碼率自適應;4.幾乎支持所有設備;
缺點:
1.延時較大,通常不低于10s;2.大量的TS片文件,會造成服務器存儲和請求的壓力;
「HTTP-FLV」
特點/優點:
1.把音視頻數據封裝成FLV,然后通過HTTP連接傳輸,與RTMP相比只是傳輸協議變了,能有效避免防火墻和代理的影響;2.低延時,整體效果與RTMP非常接近;
缺點:
1.它的傳輸特性會讓流媒體資源緩存在本地客戶端,保密性較差;2.不支持IOS;
在確定了我所需要使用的直播協議后,我調研了一些社區推薦的播放器:tcplayer.js、xgplayer、DPlayer、plyr、ArtPlayer.js、Video.js。
其實以上的播放器在功能上都可以滿足我的需求,并且也都支持H.264編碼格式;在直播能力的支持上也都會在底層依賴hls.js,flv.js,不過像tcplayer和xgplayer還單獨包了一層,使得直播的實現更加的符合播放器的體系;
在我所調研的播放器里xgPlayer的文檔是最清晰和完善的,并且xgPlayer使用插件機制,所有功能均可插拔,而且支持自定義擴展能力,十分方便,所以在開發體驗上我認為更勝一籌。
import Player from 'xgplayer'
import FlvPlugin from 'xgplayer-flv'
import "xgplayer/dist/index.min.css"
new Player({
id:'dom-id', // 播放器實例化所需的dom
url: 'test.flv', // 視頻源
width: '100%',
height: '100%'
})
初始化時可以使用選擇器id或容器el。但對于同時實例化多個播放器的場景,使用Id很容易導致最終只實例化成功一個,雖然你可以通過ID+索引的方式避免,但使用容器el還是更為簡潔的。
<div ref="playerRef"></div>
const playerRef = ref()
new Player({
el: playerRef.value,
...
})
new Player({
poster // 封面
autoplay // 自動播放,基本上不支持有聲自動播放;
autoplayMuted // 自動靜音播放,需要自動播放可使用改屬性
playsinline // 對于移動 Safari 瀏覽器來說是必需的,它允許視頻播放時不強制全屏模式
loop // 循環播放
fitVideoSize // 根據視頻內容調整容器寬高
videoFillMode // 視頻畫面填充模式
controls // 是否展示進度條
videoAttributes // 透傳給video標簽的屬性
})
關于自動播放的限制還是很多的,所以把預期降低到大部分設備可以靜音播放即可...
關于自動播放
「FLV協議:」使用xgplayer-flv,可用于PC、安卓。
import FlvPlugin from 'xgplayer-flv'
if (FlvPlugin.isSupported()) { // 第一步,檢測當前環境是否支持
const player = new Player({
id: 'dom-id',
url: 'test.flv', // flv 流地址
isLive: true,
plugins: [FlvPlugin] // 第二步
})
}
「HLS協議:」使用xgplayer-hls,可用于PC、安卓、IOS(ios&部分andr不需要插件,原生支持)。
在原生支持hls的情況下盡可能不使用xgplayer-hls,IOS瀏覽器原生即支持hls格式播放,但是缺少xgplayer-hls運行所需的Media Source Extensions。
import Player from 'xgplayer'
import HlsPlugin from 'xgplayer-hls'
let player
if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
// 原生支持 hls 播放
player = new Player({
el: document.querySelector('.player'),
url: 'test.m3u8'
})
} else if (HlsPlugin.isSupported()) { // 第一步,檢測當前環境是否支持
player = new Player({
el: document.querySelector('.player'),
isLive: true,
url: 'test.m3u8', // hls 流地址
plugins: [HlsPlugin] // 第二步
})
}
xgplayer提供了十分便捷的方式去配置icon。
const playerConfig = {
icons: {
// 1.通過function方式 返回一個dom
play: () => {
const dom = Util.createDom('div', '<img src="./start"/>', {}, 'customclass')
return dom
},
// 2.直接html代碼
pause: `<div class='customclass'><img src="./start"/></div>`,
// 3.直接一張圖片鏈接
startPlay: 'https://xxx.zhuanzhuan.com/xxx.png'
}
}
但是很多地方的icon大小尺寸是固定死的,如果想要修改還是要去覆蓋xgplayer默認的樣式
image-20231123163802551
xgplayer支持插件的擴展機制,無論是簡單的功能按鈕還是復雜的播放邏輯都可以通過插件的形式來實現。
這里實現一個簡單的插件,結合我們的通用組件庫,用于在視頻暫停時,展示一些提示。
// demoPlugin.js
import Vue from 'vue'
import { Events, Plugin } from 'xgplayer'
import Demo from './demoPlugin.vue'
const { POSITIONS } = Plugin
export default class DemoPlugin extends Plugin {
// 插件的名稱,將作為插件實例的唯一key值
static get pluginName() {
return 'demoPlugin'
}
static get defaultConfig() {
return {
// 掛載在播放器最上方
position: POSITIONS.ROOT_TOP
}
}
constructor(args) {
super(args)
this.vm = null
}
// 插件實例化之后
afterCreate() {
// 使用vue組件
const Component = Vue.extend(Demo)
this.vm = new Component().$mount('.demo-plugin')
// 視頻播放時
this.on(Events.PLAY, () => {
this.vm.hide()
})
// 視頻暫停時
this.on([Events.PAUSE], () => {
this.vm.show()
})
}
destroy() {
// 播放器銷毀的時候一些邏輯
}
render() {
return '<div class="demo-plugin"></div>'
}
}
// demoPlugin.vue
<template>
<NoticeBar v-show="visible" swipe>
<span style="padding-right: 50px;">我一定會回來的~我一定會回來的~我一定會回來的~</span>
</NoticeBar>
</template>
<script setup lang="ts">
import { ref, defineExpose } from 'vue'
import { NoticeBar } from '@zz-common/zz-ui';
const visible = ref(true)
const show = () => {
visible.value = true
}
const hide = () => {
visible.value = false
}
defineExpose({
show,
hide
})
</script>
// 使用
import DemoPlugin from './demoPlugin.js'
...
new Player({
...,
plugins: [DemoPlugin]
})
image
在播放器的事件中有兩個與播放操作相關的事件——play、canplay
「play」表示播放已開始。
「canplay」表示瀏覽器可以播放媒體文件了,但估計沒有足夠的數據來支撐播放到結束,不必停下來進一步緩沖內容。
簡單區分下這兩個事件:play可以具象的理解為點擊播放按鈕或者自動播放成功,canplay則表示視頻資源已經開始加載并緩沖了一部分數據達到了啟播的條件。
這兩個事件的先后順序不固定——如果沒有設置自動播放、也沒有設置預加載,那應該是play、canplay。如果設置了預加載,但沒有設置自動播放,則應該是canplay、play,到目前按照事件的定義來看,還是能抓住一些規律的。但是呢經過我測試發現,同樣的設置,在原生video標簽和xgplayer上執行順序不同。另外在不同的操作系統上也會導致執行順序不同,比如 ios Safari 從不預加載導致無法在未播放時觸發canplay事件。所以十分不建議根據這兩個事件的執行時機來做一些事(不過目前也想不到這種場景,只是無意中發現的)
問題的起因是當時的直播流內容總是會間隔性的黑屏,而且后端無法監控到并調整視頻源。于是需要前端通過截取畫面并分析截圖的像素點來判斷是否黑屏,以實現黑屏自動切換視頻源的能力。
但是當通過canvas獲取圖片數據時getImageData報了一個SecurityError異常。
經查閱發現這是瀏覽器的安全策略,不通過CORS使用其他來源的資源,會污染畫布。
在"被污染"的 canvas 中調用以下方法將會拋出安全錯誤:
所以如果要對視頻內容進行截圖或者對視頻畫面做一些操作處理,需要給video標簽設置crossOrigin屬性,在xgplayer中可以通過videoAttributes屬性傳入。
const player = new Player({
...,
videoAttributes: {
crossOrigin: 'anonymous'
}
})
當不需要播放器時,記得及時銷毀,否則可能會導致內存溢出。(尤其是多實例、切換播放的場景)
player.destroy() // 銷毀播放器
player = null // 將實例引用置空
「無需單獨銷毀插件實例,xgplayer自動會幫我們執行該操作。」—— xgplayer將所有注冊的插件維護在pluginGroup對象中,當我們調用播放器的destroy方法時,遍歷所有插件并依次執行插件的銷毀方法。
image
image
image
在測試的時候發現,iPhone 14Pro機型,直播播放的時候,如果跳轉到其他頁面,再返回到直播頁,會導致視頻播放錯誤;該問題暫時沒有思路,不清楚原因...
目前的解決辦法是,在頁面不可見時,記錄并銷毀該播放器,在頁面展現時再重新實例化之前的播放器。
目前線上正常運行,暫時沒有發現其他問題。
1.允許圖片和 canvas 跨源使用(https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_image)
2.西瓜播放器(https://h5player.bytedance.com/guide/)
3.Safari HTML5 Audio and Video Guide(https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/AudioandVideoTagBasics/AudioandVideoTagBasics.html)
作者:楊雙星
來源:微信公眾號:大轉轉FE
出處:https://mp.weixin.qq.com/s/Q7XZIOLH-nSYtZ4F6MKs8w
前,視頻直播(尤其是移動端的視頻直播)已經火到不行了,基本上各大互聯網公司都有了自己的直播產品,所以對于我們而言,了解直播的一些基本知識和主要技術點是有必要的。
可以看到,直播從 PC 到一直發展到移動端,越來越多的直播類 App 上線,同時移動直播進入了前所未有的爆發階段,但是對于大多數移動直播來說,還是要以 Native 客戶端實現為主,但是 HTML5 在移動直播端也承載著不可替代的作用,例如 HTML5 有著傳播快,易發布的優勢,同時最為關鍵的時 HTML5 同樣可以播放直播視頻。
完整的直播可以分為以下幾塊:
視頻錄制端:一般是電腦上的音視頻輸入設備或者手機端的攝像頭或者麥克風,目前以移動端的手機視頻為主。
視頻播放端:可以是電腦上的播放器,手機端的 Native 播放器,還有就是 HTML5 的 video 標簽等,目前還是已手機端的 Native 播放器為主。
視頻服務器端:一般是一臺 nginx 服務器,用來接受視頻錄制端提供的視頻源,同時提供給視頻播放端流服務。
流程如下:
1、HLS
HLS 全稱是 HTTP Live Streaming。這是 Apple 提出的直播流協議。目前,IOS 和 高版本 Android 都支持 HLS。
那什么是 HLS 呢?
HLS 主要的兩塊內容是 .m3u8 文件和 .ts 播放文件。接受服務器會將接受到的視頻流進行緩存,然后緩存到一定程度后,會將這些視頻流進行編碼格式化,同時會生成一份 .m3u8 文件和其它很多的 .ts 文件。
根據 wiki 闡述,HLS 的基本架構為:
服務器:后臺服務器接受視頻流,然后進行編碼和片段化。
編碼:視頻格式編碼采用 H.264。音頻編碼為 AAC, MP3, AC-3,EC-3。然后使用 MPEG-2 Transport Stream 作為容器格式。
分片:將 TS 文件分成若干個相等大小的 .ts 文件。并且生成一個 .m3u8 作為索引文件(確保包的順序)
分發:由于 HLS 是基于 HTTP 的,所以,作為分發,最常用的就是 CDN 了。
客戶端:使用一個 URL 去下載 m3u8 文件,然后,開始下載 ts 文件,下載完成后,使用 playback software(即時播放器) 進行播放。
2、RTMP
RTMP 全稱為:Real-Time Messaging Protocol 。它是專門應對實時交流場景而開發出來的一個協議。它爹是 Macromedia,后來賣身給了 Adobe。RTMP 根據不同的業務場景,有很多變種:
純 RTMP 使用 TCP 連接,默認端口為 1935(有可能被封)。
RTMPS: 就是 RTMP + TLS/SSL
RTMPE: RTMP + encryption。在 RTMP 原始協議上使用,Adobe 自身的加密方法
RTMPT: RTMP + HTTP。使用 HTTP 的方式來包裹 RTMP 流,這樣能直接通過防火墻。
RTMFP: RMPT + UDP。該協議常常用于 P2P 的場景中,針對延時有變態的要求。
3、HLS與RTMP
關于音視頻采集錄制,首先明確下面幾個概念:
視頻編碼:所謂視頻編碼就是指通過特定的壓縮技術,將某個視頻格式的文件轉換成另一種視頻格式文件的方式,我們使用的 iPhone 錄制的視頻,必須要經過編碼,上傳,解碼,才能真正的在用戶端的播放器里播放。
編解碼標準:視頻流傳輸中最為重要的編解碼標準有國際電聯的 H.261、H.263、H.264,其中 HLS 協議支持 H.264 格式的編碼。
音頻編碼:同視頻編碼類似,將原始的音頻流按照一定的標準進行編碼,上傳,解碼,同時在播放器里播放,當然音頻也有許多編碼標準,例如 PCM 編碼,WMA 編碼,AAC 編碼等等,這里我們 HLS 協議支持的音頻編碼方式是 AAC 編碼。
1、HTML5錄制視頻
對于HTML5視頻錄制,可以使用強大的 webRTC (Web Real-Time Communication)是一個支持網頁瀏覽器進行實時語音對話或視頻對話的技術,缺點是只在 PC 的 Chrome 上支持較好,移動端支持不太理想。
使用 webRTC 錄制視頻基本流程是:
調用 window.navigator.webkitGetUserMedia() 獲取用戶的PC攝像頭視頻數據。
將獲取到視頻流數據轉換成 window.webkitRTCPeerConnection (一種視頻流數據格式)。
利用 webscoket 將視頻流數據傳輸到服務端
由于許多方法都要加上瀏覽器前綴,所以很多移動端的瀏覽器還不支持 webRTC,所以真正的視頻錄制還是要靠客戶端(iOS,Android)來實現,效果會好一些。
2、iOS錄制視頻
利用 iOS 上的攝像頭,進行音視頻的數據采集,主要分為以下幾個步驟:
音視頻的采集,iOS 中,利用 AVCaptureSession 和 AVCaptureDevice 可以采集到原始的音視頻數據流。
對視頻進行 H264 編碼,對音頻進行 AAC 編碼,在 iOS 中分別有已經封裝好的編碼庫來實現對音視頻的編碼。
對編碼后的音、視頻數據進行組裝封包;
建立 RTMP 連接并上推到服務端。
所謂推流,就是將我們已經編碼好的音視頻數據發往視頻流服務器中,在 iOS 代碼里面一般常用的是使用 RTMP 推流,可以使用第三方庫 librtmp-iOS 進行推流,librtmp 封裝了一些核心的 API 供使用者調用。例如推流 API 等等,配置服務器地址,即可將轉碼后的視頻流推往服務器。
那么如何搭建一個推流服務器呢?
簡單的推流服務器搭建,由于我們上傳的視頻流都是基于 RTMP 協議的,所以服務器也必須要支持 RTMP 才行,大概需要以下幾個步驟:
安裝一臺 nginx 服務器。
安裝 nginx 的 RTMP 擴展,目前使用比較多的是 https://github.com/arut/nginx-rtmp-module
配置 nginx 的 conf 文件
重啟 nginx,將 RTMP 的推流地址寫為 rtmp://ip:1935/hls/mystream, 其中 hls_path 表示生成的 .m3u8 和 ts 文件所存放的地址,hls_fragment 表示切片時長,mysteam 表示一個實例,即將來要生成的文件名可以先自己隨便設置一個。
更多配置可以參考:https://github.com/arut/nginx-rtmp-module/wiki/
下面是 nginx 的配置文件
對于視頻播放,可以使用 HLS(HTTP Live Streaming)協議播放直播流,iOS和 Android 都天然支持這種協議,配置簡單,直接使用 video 標簽即可。
下面是簡單的代碼使用 video 播放直播視頻:
本文轉載于互聯網,如侵犯你的權益,請及時告知。
參考地址:http://geek.csdn.net/news/detail/95188、https://aotu.io/notes/2016/10/09/HTML5-SopCast/
osted by Red5 Pro
url : https://www.red5pro.com/blog/3-problems-with-cdn-video-streaming-and-how-we-solved-them/
由于CDN要求您通過其數據網導入所有的內容,因此一些流媒體提供商發現他們需要使用多個CDN來到達不同的地區。這意味著管理不同的系統、分散的流媒體以及添加更多的連接來傳輸流會帶來更長時間的延遲以及額外的復雜性。
這促使實時流媒體市場的許多人開始轉向multi-CDN解決方案。事實上,據預測,到2025年,multi-CDN市場將增長到240億美元。雖然multi-CDN解決了單個CDN網絡的一些問題(地區/區域可用性、價格等),但實際上它只是實時視頻流的權宜之計。現在,純WebRTC分發服務是創建實時流媒體的最佳方式。
因此,純CDN解決方案正逐漸退出市場,至少在直播視頻分發方面是如此。原因如下:
延遲
基于HTTP體系架構構建的CDN根本不具備處理動態更新內容(如實時視頻)的傳輸的能力。它們的工作原理是在區域數據中心緩存數據,以便高效地傳遞大量數據。這種設計的重點在于吞吐量和可伸縮性,從而形成了最適合處理靜態對象(例如網站或預先錄制的視頻)的網絡。
緩存會影響延遲,而延遲與傳遞靜態元素(例如網頁和VOD)無關緊要。隨著實時視頻體驗變得更具交互性,這意味著它們越來越依賴于低延遲傳輸。即使只有一秒鐘的延遲也會對用戶體驗和應用程序的實用性產生負面影響。如果它不是實時流式傳輸,就無法直播。
為了解決這個延遲問題,我們需要使用一種新的方案:WebRTC。WebRTC是圍繞低延遲流媒體設計的。它可以以小于500毫秒的端到端延遲傳輸實時視頻,這比HLS傳輸快得多,后者即使經過修改,也只能在最低的情況下降低到2-3秒。因此,純WebRTC服務預計將從多CDN總流量(total Multi-CDN traffic)的1.2%增長到8.3%。
除了高延遲之外,CDN實際上是圍繞著將數據分發到客戶端而不是回接收信息而設計的。隨著現場體驗變得更具交互性,將諸如縮放呼叫、共同查看和粉絲墻體驗等功能集成到這些事件中,無法在多個方向上流傳輸內容對CNDs的實用性是一個重大的損害。
CDN中的每個服務器本質上都被用作一個攝取點,它將流推送到CDN以進行大規模的傳輸。這意味著它可以很好地將數據從原點分發到邊緣,但對于反向傳輸流信息(從邊緣返回原點)則不太好。在這種架構下,雙向通信效率不高,因為CDN最適合于廣播只由訂閱者觀看的單個流,而不是雙向聊天,其中訂閱者在訂閱視頻的同時也在廣播視頻。對話在雙方之間來回進行,因此他們都必須發送和接收視頻。這意味著CDN根本不提供這一功能,而想要構建交互式視頻體驗的開發人員則不得不將完全不同的技術拼湊在一起,而這些技術從來都是預備過的。
在CDN模型中,請求的數據需要從原點傳輸到邊緣。一旦中繼到最近的邊緣服務器,它就必須與每個試圖訪問流的客戶機建立單獨的連接。這被稱為“最后一英里”,是CDN視頻流解決方案帶寬消耗的主要來源。一些網絡已經找到了解決這個問題的方法來降低數據傳輸成本。
一些提供商使用WebRTC來提高CDN容量。使用WebRTC的話,將有高達70%的峰值流量可以被卸載,這有助于CDN供應商避免基礎設施升級,并使CDN分銷商能夠利用現有預算做更多事情。
例如,Peer5、StreamRoot和StriveCast已經創建了點對點共享網絡,以轉移它們在CDN上的總帶寬消耗。他們不必將所有的內容一對一地從edge流到客戶端,而是在流相同文件的所有客戶端之間創建數據通道連接。這樣,視頻通過高效的分塊傳輸HLS協議從源服務器發送到邊緣服務器。一旦訂閱者拉出那些HLS (.ts)段,它就可以在WebRTC數據通道上建立一個P2P連接來將那些段轉發給那個對等者。然后,該對等端可以與另一方建立連接。然后重復這個連接過程,這樣他們就可以共享相同的視頻文件了。這意味著每個用戶都不必從CDN(為數據傳輸收費的網絡)中冗余地拉出所有的數據段。
雖然這些點對點的網狀網絡對于VOD傳輸是有效的,但是對于低延遲的實時流媒體則不是有效的。首先,他們仍然使用HLS段作為流的源,這將導致高延遲的問題。其次,這種網狀網絡并沒有解決雙向流的問題。此外,還有另一類新興的純WebRTC基礎提供商,他們根本不使用CDN,事實上它們已經完全取代了CDN。
實時延遲還釋放了與視頻流的其他數據正確同步的能力。這開啟了添加聊天功能、實時覆蓋疊加和交互式圖形、虛擬黑板、實時下注和拍賣出價、GPS數據和許多其他的功能。例如,一個體育廣播可以有一個實時的圖形顯示功能,它可以與屏幕上發生的最新狀態保持同步。正確的同步與實時延遲相結合,也可以防止惱人的劇透,從而確保不會破壞其他人的觀看體驗。它還可以確保聊天中的評論與當前顯示的內容一致。
對于這些用例,數據可以通過WebRTC數據通道或單獨的websocket通道發送,這可以使用SharedObjects方法實現。SharedObjects管理多個客戶端之間的數據提要,從而實現數據的一致傳輸。這樣可以確保廣播者,訂戶和任何其他功能之間的完全交互。
在GitHub上可以找到更多示例:
iOS:https://github.com/red5pro/streaming-ios/tree/master/R5ProTestbed/Tests/SharedObject
Android:https://github.com/red5pro/streaming-android/tree/master/app/src/main/java/red5pro/org/testandroidproject/tests/SharedObjectTest
所有這些關于CDN實時流傳輸局限性的討論可能會給你一種印象:即它們應該被純WebRTC解決方案所取代。然而,它們在視頻流媒體中仍然扮演著非常有價值的角色。CDN對于交付視頻點播內容以及靜態對象(如網站和靜態圖像)仍然很有用。然而,當涉及到動態更新的元素(如實時視頻流)時,CDN永遠無法正確處理它們。與許多其他技術要素一樣,市場的需求也擴大并發生了變化。CND正在試圖適應這種情況,但它們基于HTTP的基本架構造成了高延遲、單向流限制和同步問題。這些問題,會由新的直播架構模型來解決。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。