【W(wǎng)eb技術(shù)】1189- 你不知道的前端音視頻知識
Web 音視頻的發(fā)展史
刀耕火種的年代——早期 HTML
在早期的 HTML,由于帶寬、技術(shù)等各種因素限制,網(wǎng)頁主要以簡單的靜態(tài)內(nèi)容為主,只支持一些文字圖片內(nèi)容和簡單的排版,不支持在線觀看音視頻。

(圖為 1994 年的 Yahoo!)
迭起興衰——Flash 的興起與淘汰
20 世紀(jì)初,隨著互聯(lián)網(wǎng)的發(fā)展,各種 Web 應(yīng)用和門戶網(wǎng)站不斷出現(xiàn),人們渴望在網(wǎng)頁上看到更加豐富多彩的內(nèi)容,比如視頻、動畫等等,于是 Flash 進(jìn)入了人們的視野。
彼時的 Flash 沒有像現(xiàn)在大家印象中的那么臃腫,剛誕生的 Flash 小巧、高效、跨平臺,同時憑借幾十 K 的體積做出放大也不會失真的各種矢量彩色動畫,在還是撥號上網(wǎng),帶寬條件受限,加載一個在線視頻需要好幾分鐘的年代脫穎而出,甚至可以做出各種令人沉迷的 Flash 小游戲。

(Flash 塑造了很多經(jīng)典的小游戲角色,火柴人就是其中之一)
Flash 的興起,得益于當(dāng)時 HTML 對于媒體文件支持的匱乏。Flash 以插件的形式,干著平臺才需要負(fù)擔(dān)的繁重工作,并得益于 Adobe 的大力推廣,F(xiàn)lash 先后增加了對 Javascrip、HTML、XML 的支持,并增強(qiáng)了影音方面的功能。同時由于 Flash 跨平臺的特性,非常容易被移植,市面上稍微高端點的設(shè)備,也得乖乖地給 Adobe 交授權(quán)費(fèi)。
然而 2007 年推出的 iPhone 并不買賬,他們以增加續(xù)航、安全為由拋棄了 Flash,很多人一開始對此嗤之以鼻,但事實證明蘋果對此確實有遠(yuǎn)見,大量低質(zhì)量的 Flash 使當(dāng)時續(xù)航本就有限的移動設(shè)備更加不堪重負(fù)。2012 年,Android 也宣布不再支持 Flash,F(xiàn)lash 在移動市場不再有立足之地。
在桌面市場上,F(xiàn)lash 的日子也并不好過。Chrome 從的 Chrome 42 開始,就已經(jīng)強(qiáng)制把 Flash 裝入沙箱,以 PPAPI 的形式運(yùn)行;而從 Chromium 版本號 88 開始,已經(jīng)徹底不再支持 Flash 技術(shù)了。微軟的 Edge 瀏覽器也同步不支持 Flash。Chrome 的前輩 Firefox 更加激進(jìn),從 2016 年就已經(jīng)默認(rèn)禁止 Flash 運(yùn)行了。
至于 Flash 為什么走向了淘汰,除了它的效率變低,不安全因素過多,穩(wěn)定性不足外,還有一個重要原因:Web 音視頻解決方案有了更好的替代品—— HTML5。
新時代的潮流——HTML5 的到來
其實,對于 HTML5 是否可以真正替代 Flash,尤大在 2011 年已經(jīng)給出了預(yù)言:

事實正如預(yù)言所預(yù)料,HTML5 在 2008 年發(fā)布后,經(jīng)過不斷改進(jìn)完善,基本上能包辦 Flash 所有能干的事情了。HTML5 引入了許多新特性和新功能,其中就包含了 video 和 audio 標(biāo)簽,也就是對音視頻的支持。使用了支持 HTML5 標(biāo)準(zhǔn)的網(wǎng)絡(luò)瀏覽器訪問 HTML5 站點,用戶無需在電腦上安裝 Flash 插件就可以在線觀看視頻,擺脫了對 Flash 的依賴。
<video?src="movie.mp4"?poster="movie.jpg"?controls>video>
同時,各大視頻門戶網(wǎng)站也加入了對 HTML5 的支持,并默認(rèn)推薦以 HTML5 的方式來播放視頻。

2021 年 1 月 20 日,chrome 88 正式發(fā)布,徹底的禁止使用 Flash。自此,F(xiàn)lash 算是徹底退出了歷史舞臺。
到底什么是視頻
視頻,其實就是一系列連續(xù)播放的圖片,如果一秒鐘播放 24 張圖片,那么人眼看到的就不再是一張張獨(dú)立的圖片,而是動起來的畫面。其中一張圖片稱為一幀,1s 播放的圖片數(shù)稱為幀率。由于人類眼睛的特殊生理結(jié)構(gòu),如果所看畫面之幀率高于每秒約 10-12 幀的時候,就會認(rèn)為是連貫的;當(dāng)看到幀率為 24 fps 以上時,大腦會認(rèn)為這是流暢播放的視頻。所以一般有聲電影的拍攝及播放幀率大約為每秒 24 幀,歐美、日本那邊由于電視制式不同,大約為 30 幀。
電影的幀率與游戲的幀率
為什么 24 幀的電影比 30 幀的游戲要流暢許多?
這其中的原因就在于,電影和游戲的圖像生成原理不同。
電影的 24 fps,是每 1/24 秒拍攝一副畫面,如果你玩過相機(jī)的手動設(shè)置,你應(yīng)該知道如果以 1/24 秒的快門速度拍攝一個運(yùn)動的物體會“糊”掉,而正是這樣“糊”掉的畫面連起來才讓我們的眼睛看上去很“流暢”。
而游戲畫面不是按 1/24 秒快門拍出來的,而是每一幅畫面都是獨(dú)立渲染出來的,之所以跑成 24fps 是因為顯卡處理能力不夠而“丟棄”了其中的一些畫面,這樣一來每兩幅畫面之間就不連續(xù)了,自然看上去會“卡”。
舉個例子,一個圓從左上角移動到右下角,如果是電影,第一幀與第二幀可能是類似下圖這樣的:

如果是游戲畫面,第一幀與第二幀會類似下面這兩張圖:

此外,幀與幀之間間隔恒定:人眼對于動態(tài)視頻的捕捉是非常敏感的,電影幀率是固定不變,肉眼很難察覺出異常。
而游戲的幀率卻是很容易變化的——如果手動鎖定幀數(shù),顯卡會默認(rèn)渲染最高幀率。
玩家觸發(fā)的很多劇情往往伴隨劇烈的畫面變動,這時顯卡的幀率就會出現(xiàn)下降,前后不一致的幀率很容易被肉眼捕捉,這時我們就會覺得,游戲變“卡”了。
視頻的編碼
視頻是由圖片構(gòu)成的,圖片是由像素構(gòu)成的,假設(shè)尺寸為 1980*1080。每個像素由 RGB 構(gòu)成,每個 8 位,共 24 位。
假設(shè)幀率是 24,那么每秒鐘的視頻的尺寸如下:

一分鐘視頻的尺寸就是 9237888000 Bytes 已經(jīng)是 8.8 個 G 了。
可以看到,如果是不對視頻做任何處理,是非常不方便對于視頻做傳輸與存儲的,所以需要對視頻進(jìn)行壓縮,也就是編碼。
視頻編碼
視頻圖像數(shù)據(jù)有很強(qiáng)的相關(guān)性,也就是說有大量的冗余信息。其中冗余信息可分為空域冗余信息和時域冗余信息。壓縮技術(shù)就是將數(shù)據(jù)中的冗余信息去掉(去除數(shù)據(jù)之間的相關(guān)性),壓縮技術(shù)包含幀內(nèi)圖像數(shù)據(jù)壓縮技術(shù)、幀間圖像數(shù)據(jù)壓縮技術(shù)和熵編碼壓縮技術(shù)。
經(jīng)過編碼之后,視頻由一幀幀的圖片,變成了一串串讓人看不懂的二進(jìn)制代碼,因為編碼的方式(算法)的不同,所以就有了編碼格式的區(qū)分。常見的編碼格式有 H.264,MPEG-4,VP8 等。
我們前端開發(fā)只需要記住一點,主流瀏覽器支持的視頻編碼格式是 H.264。
音頻編碼
CD 音質(zhì)的音頻,存放一分鐘數(shù)據(jù)需要的大小為 10M,太大了,也需要壓縮(編碼)。
常見的編碼方式有:WAV、MP3 和 AAC 格式。
音頻的編碼方式不像視頻那樣那么多,而且音頻在各個瀏覽器基本上都可以播放。
具體的每種編碼格式包含的音頻是怎么構(gòu)成的,這里就不講了。

封裝格式
我們把視頻數(shù)據(jù)、音頻數(shù)據(jù)打包到一起,然后再添加一些基本信息,例如分辨率、時長、標(biāo)題等,構(gòu)成一個文件,這個文件稱為封裝格式。常見的封裝格式有 MP4, AVI, RMVB 等。

可以看出,視頻的封裝格式和視頻的編碼格式往往是無關(guān)的,一個 mp4 文件,里面的視頻流編碼可以是 h264,也可以是 mpeg-4,所以就會出現(xiàn),同樣都是 mp4 文件,有的瀏覽器可以放,有的瀏覽器就放不了的問題,因為能不能放是由視頻碼流的編碼格式?jīng)Q定的。
碼率
碼率,也叫比特率,幀率是 1s 播放多少幀,類比一下,比特率就是 1s 的視頻有多少 bit。
這個參數(shù)直接決定了視頻的大小與清晰程度。
一般網(wǎng)上流傳的電影 MKV(BDrip-1080P)的碼率是 10Mb/s 左右,藍(lán)光原盤是 20Mb/s 左右,這兩者都是 H.264 編碼的。另外一些 MV、PV、演示片什么的除了 H.264 編碼,可能還有 MPEG-2 編碼,碼率大小不等,像 youtube 那些在線的 1080P 的視頻,碼率可能只有 5Mb/s,而一些 MV 的碼率可以高到離譜,可以達(dá)到 110Mb/s 的,3 分多鐘的 MV 差不多有 3GB 大小。
而一般的視頻剪輯、后期軟件,在輸出序列的時候,都會有碼率這個選項。

視頻播放器的原理
播放視頻的基本流程是:解協(xié)議 → 解封裝 → 解碼 → 視音頻同步。如果播放本地文件則不需要解協(xié)議。

解協(xié)議的作用,就是將流媒體協(xié)議的數(shù)據(jù),解析為標(biāo)準(zhǔn)的相應(yīng)的封裝格式數(shù)據(jù)。視音頻在網(wǎng)絡(luò)上傳播的時候,常常采用各種流媒體協(xié)議,例如 HTTP,RTMP,或是 MMS 等等。這些協(xié)議在傳輸視音頻數(shù)據(jù)的同時,也會傳輸一些信令數(shù)據(jù)。這些信令數(shù)據(jù)包括對播放的控制(播放,暫停,停止),或者對網(wǎng)絡(luò)狀態(tài)的描述等。解協(xié)議的過程中會去除掉信令數(shù)據(jù)而只保留視音頻數(shù)據(jù)。
解封裝的作用,就是將輸入的封裝格式的數(shù)據(jù),分離成為音頻流壓縮編碼數(shù)據(jù)和視頻流壓縮編碼數(shù)據(jù)。封裝格式種類很多,例如 MP4,MKV,RMVB,TS,F(xiàn)LV,AVI 等等,它的作用就是將已經(jīng)壓縮編碼的視頻數(shù)據(jù)和音頻數(shù)據(jù)按照一定的格式放到一起。例如,F(xiàn)LV 格式的數(shù)據(jù),經(jīng)過解封裝操作后,輸出 H.264 編碼的視頻碼流和 AAC 編碼的音頻碼流。
解碼的作用,就是將視頻/音頻壓縮編碼數(shù)據(jù),解碼成為非壓縮的視頻/音頻原始數(shù)據(jù)。音頻的壓縮編碼標(biāo)準(zhǔn)包含 AAC,MP3,AC-3 等等,視頻的壓縮編碼標(biāo)準(zhǔn)則包含 H.264,MPEG2,VC-1 等等。解碼是整個系統(tǒng)中最重要也是最復(fù)雜的一個環(huán)節(jié)。通過解碼,壓縮編碼的視頻數(shù)據(jù)輸出成為非壓縮的顏色數(shù)據(jù),例如 YUV420P,RGB 等等;壓縮編碼的音頻數(shù)據(jù)輸出成為非壓縮的音頻抽樣數(shù)據(jù),例如 PCM 數(shù)據(jù)。
視音頻同步的作用,就是根據(jù)解封裝模塊處理過程中獲取到的參數(shù)信息,同步解碼出來的視頻和音頻數(shù)據(jù),并將視頻音頻數(shù)據(jù)送至系統(tǒng)的顯卡和聲卡播放出來。
canvas 播放視頻
如果我們碰到一些特殊機(jī)型或者特殊情況 HTML5 的 video 解決方案不是很好處理,也可以采用 Canvas 去播放這個視頻。
使用 Canvas 播放視頻主要是利用 ctx.drawImage(video, x, y, width, height) 來對視頻當(dāng)前幀的圖像進(jìn)行繪制,其中 video 參數(shù)就是頁面中的 video 對象。所以如果我們按照特定的頻率不斷獲取 video 當(dāng)前畫面,并渲染到 Canvas 畫布上,就可以實現(xiàn)使用 Canvas 播放視頻的功能。
事實上,市面上已經(jīng)有不少 Canvas 播放視頻的解決方案,比較出名的是這個 JSMpeg[1]。它和 PIXI 一樣,可以選擇 WebGL 渲染視頻也可以直接用 Canvas 渲染視頻。
JSMpeg 是沒有 npm 包的,但是社區(qū)上有開發(fā)者基于 JSMpeg 封裝了一個 npm 包:https://github.com/cycjimmy/jsmpeg-player
在官網(wǎng)上是這么介紹的:
JSMpeg is a Video Player written in JavaScript. It consists of an MPEG-TS Demuxer, WebAssembly MPEG1 Video & MP2 Audio Decoders, WebGL & Canvas2D Renderers and WebAudio Sound Output. JSMpeg can load static files via Ajax and allows low latency streaming (~50ms) via WebSocktes.
由于它所支持的編碼格式不是常規(guī)的 H.264,而是比較老的 MPEG1,并且解封裝器為 MPEG-TS。所以一般我們使用它去渲染視頻的格式為 TS。
TS 是日本高清攝像機(jī)拍攝下進(jìn)行的封裝格式,全稱為 MPEG2-TS。它的特點就是要求從視頻流的任一片段開始都是可以獨(dú)立解碼的。
TS 文件通常作為多個文件保存在 DVD 上,雖然它可以在高清攝像機(jī)、藍(lán)光 DVD 中無需借助其他軟件就能直接打開,但是 TS 視頻文件與大多數(shù)的媒體播放器、便攜式播放器或視頻編輯工具都不兼容,所以這個時候,F(xiàn)Fmpeg 就可以出場了。
視頻操作神器——FFmpeg
FFmpeg[2] 是一個開源的軟件,我們直接用 homebrew 就可以安裝
brew install ffmpeg
如果我們想轉(zhuǎn)換為 jsmpeg 所需的 ts 格式視頻,可以執(zhí)行
$ ffmpeg -i input.mp4 -f mpegts \
-codec:v mpeg1video -s 640x360 -b:v 1500k -r 25 -bf 0 \
-codec:a mp2 -ar 44100 -ac 1 -b:a 64k \
output.ts
-i:指定輸入文件,這里指定為input.mp4
-f指明輸出文件的封裝格式,這里為 jsmpeg 所需的mpegts-codec:v指明輸出文件的視頻編碼,這里指明為 jsmpeg 所需的mpeg1video-s設(shè)置視頻分辨率,參數(shù)格式為w*h或w×h-b:v設(shè)置視頻碼率,一般如果想得到高清的效果,至少需要 4000k 以上,如果對視頻體積有要求,可以視情況小一點-r設(shè)置幀率(fps),一般都為 25-bfbframe 數(shù)目控制,一般為 0
B 幀法(B frame)是雙向預(yù)測的幀間壓縮算法。當(dāng)把一幀壓縮成 B 幀時,它根據(jù)相鄰的前一幀、本幀以及后一幀數(shù)據(jù)的不同點來壓縮本幀,也即僅記錄本幀與前后幀的差值。
-codec:a指明輸出文件的音頻編碼-ar設(shè)置音頻編碼采樣率,單位kHz,一般網(wǎng)上的音頻,大多為 44100
音頻采樣率是指錄音設(shè)備在單位時間內(nèi)對模擬信號采樣的多少,采樣頻率越高,機(jī)械波的波形就越真實越自然。
-ac設(shè)置音頻編碼聲道數(shù)-b:a設(shè)置音頻碼率
音頻碼率,指一個音頻流中每秒鐘能通過的數(shù)據(jù)量,碼率越大的話,音質(zhì)越好
最后一個參數(shù)即為輸出文件位置與名稱和后綴格式
FFmpeg 是一個非常強(qiáng)大的音視頻轉(zhuǎn)換工具,不僅可以視頻轉(zhuǎn)換,還可以視頻尺寸裁剪、視頻時長裁剪、視頻拼接等等功能,目前很多在線視頻剪輯工具基本是基于 FFmpeg 開發(fā)的。
音視頻的一些資源推薦
國內(nèi)學(xué)習(xí)音視頻相關(guān)的開發(fā),繞不過的一個大神是 雷霄驊[3],大佬已經(jīng)去世了,但是留下的文章永垂不朽。
本文也是參考了 雷霄驊[3]?的部分博客,如果感興趣,可以從這篇文章看起:\[總結(jié)\]視音頻編解碼技術(shù)零基礎(chǔ)學(xué)習(xí)方法\_雷霄驊\(leixiaohua1020\)的專欄-CSDN 博客\_雷霄驊[4]。
對于直播 webrtc 感興趣的,也可以看一下 Real time communication with WebRTC[5],國內(nèi)慕課網(wǎng)上李超老師也有不錯的教程:李超\_慕課網(wǎng)精英講師[6]
對 ffmpeg 感興趣的,可以看一下這里:https://github.com/leandromoreira/ffmpeg-libav-tutorial
參考資料
JSMpeg: https://github.com/phoboslab/jsmpeg
[2]FFmpeg: https://www.ffmpeg.org/
[3]雷霄驊: https://link.juejin.cn/?target=https://blog.csdn.net/leixiaohua1020
[4][總結(jié)]視音頻編解碼技術(shù)零基礎(chǔ)學(xué)習(xí)方法_雷霄驊(leixiaohua1020)的專欄-CSDN 博客_雷霄驊: https://blog.csdn.net/leixiaohua1020/article/details/18893769
[5]Real time communication with WebRTC: https://codelabs.developers.google.com/codelabs/webrtc-web?spm=a2c6h.12873639.0.0.58004925DffaQU
[6]李超_慕課網(wǎng)精英講師: https://www.imooc.com/t/4873493

回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~
點擊“閱讀原文”查看 130+ 篇原創(chuàng)文章
