本文將介紹的是:
2019年4月8日首次完成該文章,內(nèi)容包括:
2019年9月7日進(jìn)行二次修改,修改內(nèi)容如下:
相信所有人對(duì)視頻一定不陌生,平時(shí)也一定經(jīng)常在各大視頻網(wǎng)站(如騰訊視頻、嗶哩嗶哩)瀏覽,甚至偶爾也會(huì)把視頻緩存到本地,保存成.mkv,.avi文件之類啦。前者是我們常說(shuō)的『網(wǎng)絡(luò)流媒體』,后者是『本地視頻文件』。提到這里,兩個(gè)問(wèn)題來(lái)了:
介紹第一個(gè)問(wèn)題之前,必須引入一個(gè)名詞『視頻封裝格式』,簡(jiǎn)稱『視頻格式』,也稱為『容器』。有的說(shuō)法還要區(qū)分是視頻文件格式和視頻封裝格式,本文統(tǒng)一稱『視頻封裝格式』。
問(wèn)題1:本地視頻文件常見(jiàn)有MP4、MKV、AVI等,這些都是什么?有什么區(qū)別?
首先,MP4、AVI、MKV都是本地視頻文件的后綴,在windows系統(tǒng)下,用于提示操作系統(tǒng)應(yīng)該采用哪個(gè)應(yīng)用程序打開(kāi)。而在流媒體領(lǐng)域,這些都被稱為『視頻封裝格式』,因?yàn)槌艘粢曨l流之外,它們還包含了一些輔助信息以及組織視音頻的方式。不同格式的視頻在不同平臺(tái)上用戶體驗(yàn)不同,很大原因在于對(duì)視音頻的組織方式帶來(lái)的差異。筆者以為百度百科上的解釋蠻通俗易懂的(維基百科的說(shuō)法不夠直白):
視頻格式是視頻播放軟件為了能夠播放視頻文件而賦予視頻文件的一種識(shí)別符號(hào)。
簡(jiǎn)言之,視頻格式規(guī)定了和播放器的通信協(xié)議。
其次,筆者最近準(zhǔn)備開(kāi)始深入研究MP4、AVI、MKV等內(nèi)部原理,主要是對(duì)視音頻的組織方式,比如在播放視頻的時(shí)候,我們可以選擇國(guó)語(yǔ)、粵語(yǔ)、英語(yǔ)等各種語(yǔ)言,這就意味著這段視音頻中包括了多個(gè)音頻流。【給自己留個(gè)坑吧。】
最后,筆者推薦一篇非常棒的博客:視頻文件格式知多少,匯總的非常全。
問(wèn)題1引申:對(duì)要做視音頻處理的開(kāi)發(fā)們來(lái)說(shuō),接觸MP4、MKV、AVI等各種格式視音頻文件時(shí),有什么需要注意的嗎?
視音頻處理可以延展出很多領(lǐng)域,包括解碼、編碼、過(guò)濾、增強(qiáng)處理等等。筆者目前只在解碼領(lǐng)域探索,答案是:對(duì)于解碼而言,沒(méi)有區(qū)別。其他領(lǐng)域暫不清楚。
『視頻封裝格式』,是在編碼的視音頻基礎(chǔ)上進(jìn)行一次“包裝”,添加與播放相關(guān)的協(xié)議數(shù)據(jù)(這個(gè)是筆者的認(rèn)知,如有表述不準(zhǔn)確,歡迎批評(píng)指正)。目前主流開(kāi)源的框架,在“解包裝”工作上做的已經(jīng)非常成熟了,如FFMpeg
,提供了用于打開(kāi)視音頻的API,開(kāi)發(fā)人員無(wú)需關(guān)注具體視頻格式,直接可以取出視音頻流做處理。
接下來(lái),介紹第二個(gè)問(wèn)題,筆者再引入名詞『視頻協(xié)議』,也有說(shuō)法認(rèn)為『視頻協(xié)議』也屬于『視頻封裝格式』。
問(wèn)題2:在騰訊視頻、嗶哩嗶哩網(wǎng)上看的視頻,與本地播放的MP4、MKV、AVI文件,有什么區(qū)別?
『視頻協(xié)議』是針對(duì)網(wǎng)絡(luò)流媒體而言的,也就是只有在有網(wǎng)絡(luò)時(shí)通過(guò)瀏覽器或者移動(dòng)端APP才能看到的視頻,目前常見(jiàn)的協(xié)議有RTSP、RTMP、HLS、HTTP等。筆者短暫地接觸過(guò)GStreamer開(kāi)發(fā),在連接到RSTP視頻時(shí),發(fā)現(xiàn)除了視音頻流和metadata之外,還攜帶了播放的信令。
也有文章會(huì)把『視頻協(xié)議』歸入『視頻封裝格式』。筆者看來(lái),這么分類也有其道理:『視頻協(xié)議』和『視頻封裝格式』都同時(shí)攜帶了視音頻和metadata,以及協(xié)議/格式需要的其他信息。以FFMpeg
為例,并不區(qū)分視頻格式和視頻協(xié)議;但是GStreamer
的話,還時(shí)需要指定『視頻協(xié)議』,但是不區(qū)分『視頻封裝格式』。
剝開(kāi)『視頻封裝格式』和『視頻協(xié)議』的外殼,接下來(lái)了解視音頻流本身,這才是流媒體領(lǐng)域中真正的主角。本文僅介紹視頻流。
就視頻流而言,相信大家平時(shí)一定經(jīng)常聽(tīng)到類似“h264碼流”、“yuv流”、“編碼流”、“解碼流”,“原始流”、“裸流”,“壓縮后的流”或者“未壓縮的流”等等。歸納而言,提到『視頻流』的時(shí)候,一定只有兩種形式:
總結(jié)出現(xiàn)的名稱,“h264碼流”、“編碼流”、“壓縮后的流”是壓縮/編碼后的視頻流;而“yuv流”、“解碼流”、“未壓縮的流”則是未經(jīng)壓縮/編碼的視頻流。“裸流”是一個(gè)具有歧義的詞,是上下文內(nèi)容,既可以是前者,也可以是后者。
因此,如果以后閱讀任何流媒體相關(guān)的文章時(shí),看到『視頻流』都應(yīng)該搞清楚,這究竟是編碼/壓縮的,還是沒(méi)有。在生活中,接觸到的視頻文件絕大部分都是編碼/壓縮后的;在網(wǎng)絡(luò)傳輸場(chǎng)景中,絕大部分也是編碼/壓縮后的。只有在視頻播放時(shí),觀眾觀賞到的時(shí)一幀幀被『轉(zhuǎn)碼』為『RGB』的解碼后視頻流。
編碼/壓縮在流媒體領(lǐng)域是一項(xiàng)非常重要的技術(shù):從『H264碼流』到『YUV流』的過(guò)程稱為解碼,反之稱為編碼。
流媒體領(lǐng)域,『流』很重要,『流』的基本元素『幀』同樣重要。原因在于:對(duì)于視頻編碼/壓縮而言,它的核心是采用盡量小的空間存儲(chǔ)一組時(shí)間上連續(xù)的幀數(shù)據(jù);而對(duì)于視頻解碼而言,就是把被編碼/壓縮后的一組幀數(shù)據(jù)盡量恢復(fù)成原來(lái)的樣子。能夠被100%恢復(fù)的編碼/壓縮算法稱為無(wú)損壓縮,反之稱為有損壓縮(雖然無(wú)損壓縮是最理想的,但是在很多實(shí)際場(chǎng)景中為了追求高壓縮率,比如為了減小網(wǎng)絡(luò)帶寬壓力,常常不得不選擇有損壓縮)。由此可見(jiàn),『幀』是視頻流媒體領(lǐng)域的核心。接下來(lái),一起來(lái)認(rèn)識(shí)什么是『幀』。
『幀』,可以聯(lián)想成我們平時(shí)看到的一幅幅“圖像”,只不過(guò)我們平時(shí)接觸的圖片是『RGB』格式的,而視頻幀通常是『YUV』格式的。既然提到了『RGB』和『YUV』,那么就來(lái)了解下幀的格式『YUV』,引出第一個(gè)問(wèn)題:
問(wèn)題3:幀為什么采用『YUV』格式?『YUV』是什么?
為此,筆者曾經(jīng)花了很久去了解顏色空間、電視成像的發(fā)展史等,整理結(jié)論如下:
接下來(lái)解釋『YUV』是什么,筆者以為,『YUV』是一種廣義的概念,在視頻領(lǐng)域,當(dāng)提到『YUV』的時(shí)候,往往是以下幾個(gè)意思:
“Y”表示明亮度(Luminance、Luma),“U”和“V”則是色度(Chrominance)、濃度(Chroma)。這里表示的是色彩空間的基,即類似XYZ坐標(biāo)系的一種色標(biāo)表示基準(zhǔn),也就是說(shuō)每一種顏色可以通過(guò)三維向量<y^i^,u^i^,v^i^>來(lái)表示。與其類似的還有RGB顏色空間、HSV顏色空間等。下圖來(lái)自How does the YUV color coding work?
隨著通信行業(yè)的發(fā)展,實(shí)際應(yīng)用之多之復(fù)雜,導(dǎo)致『YUV』衍生出了一個(gè)大家族。接觸視頻領(lǐng)域的一定聽(tīng)說(shuō)過(guò)YCbCr,甚至還有YPbPr、YIQ等。它們有的已經(jīng)被時(shí)代淘汰,有的現(xiàn)在還在使用。之所以出現(xiàn)『YUV』大家族,完全是因?yàn)閷?shí)際電路系統(tǒng)之間的差異,導(dǎo)致要從『YUV』轉(zhuǎn)到『RGB』空間,實(shí)際對(duì)應(yīng)的轉(zhuǎn)化系數(shù)是有些許差異的,于是各個(gè)部門開(kāi)始制定各種規(guī)范,才有了我們現(xiàn)在看到的『YUV』大家族。
YCbCr是專門針對(duì)數(shù)字電路而誕生的;YPbPr則是模擬電路。但是,現(xiàn)在是數(shù)字時(shí)代,所以為了模擬電路而生的YPbPr已經(jīng)逐漸被淘汰了,而YCbCr還一直發(fā)揮著作用。因此現(xiàn)在,YCbCr有時(shí)也會(huì)被簡(jiǎn)單地稱為/認(rèn)為『YUV』。
2. 采樣率
讀者可能聽(tīng)說(shuō)過(guò)“YUV444”,“YUV422”,“YUV420”,到這里可能會(huì)納悶:“YUV不是顏色空間嗎?為什么后面還會(huì)跟著一串?dāng)?shù)字?” 因?yàn)楫?dāng)你看到Y(jié)UV后面跟著一串?dāng)?shù)字的時(shí)候,『YUV』已經(jīng)不再是顏色空間的基的含義了,而是意味著在原始『YUV流』上的采樣。
在以前流媒體剛剛興起時(shí),還沒(méi)有什么4G/5G,當(dāng)時(shí)為了減小網(wǎng)絡(luò)傳輸?shù)膸挼膲毫Γ芍^做了種種努力。除了編碼/壓縮之外,YUV采樣率也是一種。
444,422和420是三種『YUV』(在數(shù)字電路中指代YCbCr)的采樣,三位數(shù)分別代表Y\U\V(數(shù)字電路中為Y\Cb\Cr,本段后同)通道的抽樣比。所以可以理解,444是全采樣;而422是對(duì)Y進(jìn)行全采樣,對(duì)U\V分別進(jìn)行1/2均勻采樣。有趣的問(wèn)題來(lái)了,420難道是完全丟棄了V通道/分量數(shù)據(jù)嘛?答案是否定的。
首先,必須要搞明白一個(gè)問(wèn)題,一幀圖像是由一個(gè)個(gè)像素組成的矩形,譬如4x4的尺寸的圖像,就是由16個(gè)像素點(diǎn)組成的。在平時(shí)接觸的『RGB』圖像中,每個(gè)像素必然至少由R\G\B這三個(gè)通道組成的(有的圖像還有\(zhòng)alpha分量),每個(gè)分量的取值一般都是[0,255],也就是[2^0,2^8],因此經(jīng)常說(shuō)一個(gè)像素占用3字節(jié)(如果還有其他分量,比如RGBA,就另當(dāng)別論)。『YUV』圖像同理,它的每個(gè)像素是由Y\U\V組成的。
接下來(lái),從整張圖像宏觀考慮采樣問(wèn)題。還是以4X4的圖像為例,444的如下圖2-1,這個(gè)是形象化成圖像的樣子,實(shí)際在機(jī)器內(nèi)存儲(chǔ)并不是這樣,具體可以參見(jiàn)博客《圖像原始格式一探究竟》。422和420分別如下圖2-2和2-3。
?圖2-1對(duì)應(yīng)YUV444采樣,即全采樣,圖示中可以看出每個(gè)像素中的Y\U\V通道都保留下來(lái)了,一般來(lái)說(shuō)YUV444太大了,因此很少使用。
圖2-2對(duì)應(yīng)YUV422采樣,這種采樣方式是:每個(gè)掃描線或者說(shuō)每行相鄰2個(gè)像素,只取1個(gè)像素的U\V分量。此外,可以計(jì)算出來(lái),每個(gè)像素占用的大小為原來(lái)的2/3,因此說(shuō)YUV422是YUV444的2/3大小。
這個(gè)時(shí)候就有一個(gè)問(wèn)題,在『YUV』轉(zhuǎn)『RGB』時(shí),被抽走了U\V分量的像素要怎么辦呢?做法很簡(jiǎn)單,就是相鄰2個(gè)像素的Y分量公用保留著的U\V分量。
圖2-3對(duì)應(yīng)YUV420采樣,這種采樣方式是:隔行進(jìn)行YUV422每行采樣的辦法,即相鄰2個(gè)像素只取1個(gè)像素的U\V分量;下一行丟棄所有的U\V分量。此外,可以計(jì)算出來(lái),每個(gè)像素占用的大小為原來(lái)的1/2,因此說(shuō)YUV420是YUV444的1/2大小。恢復(fù)U\V分量的辦法同YUV422,只不過(guò)這里是2X2的矩陣共享保留著的U\V分量。
這種設(shè)計(jì)辦法真的很巧妙!前文提到的"人眼對(duì)UV的敏感度最低,因此可以極大比例地壓縮UV兩個(gè)通道的數(shù)值",且對(duì)于圖像而言,相鄰的區(qū)域像素的色彩、飽和度一般非常接近,因此這種以2X2矩陣為基本單位,只保留1組U\V分量合情合理。
3. 編碼/存儲(chǔ)格式
大家肯定還聽(tīng)說(shuō)過(guò)YV12、YU12、NV12、NV21吧,看到這里是不是又納悶:“后面的數(shù)字怎么變成2個(gè)了?而且前面的英文字母還變了?”
以上統(tǒng)稱為『視頻的存儲(chǔ)格式』,也就是說(shuō),計(jì)算機(jī)是如何存儲(chǔ)一幀視頻的。
首先,『視頻的存儲(chǔ)格式』總分為兩大類:『打包格式(packed)』和『平面格式(planar)』。前者又被稱作『緊湊格式(packed)』。其實(shí)除此之外還有『半平面模式(Semi-Planar)』,估計(jì)是使用的比較少,因此在很多文章中常被忽略。
筆者很感興趣,為什么會(huì)出現(xiàn)『打包格式』和『平面格式』兩大派系,網(wǎng)上搜了很多資料也沒(méi)找到原因,博客【音視頻基礎(chǔ)】:I420、YV12、NV12、NV21等常見(jiàn)的YUV420存儲(chǔ)格式提到了需要約定存儲(chǔ)格式,但也沒(méi)提到為什么會(huì)分成這兩種。要么就是派系之爭(zhēng),類似貝葉斯學(xué)派和頻率學(xué)派;要么就是實(shí)際應(yīng)用中逐漸衍生出這兩大格式。時(shí)至今日,這兩個(gè)格式還在被使用,因此對(duì)于多媒體開(kāi)發(fā)者們都有必要了解。
『打包格式』是把Y\U\V分量交叉存儲(chǔ),『平面格式』則是把Y\U\V嚴(yán)格分開(kāi)存儲(chǔ),『半平面模式』介于兩者之間,Y分量分開(kāi)存儲(chǔ),U\V交叉存儲(chǔ)。
以下圖為例說(shuō)明『打包格式』、『平面格式』和『半平面模式』應(yīng)該是非常清楚的,圖摘自博客YUV格式初探:
但是關(guān)于上圖的『打包格式』,筆者是是有一點(diǎn)疑惑的,大多數(shù)的說(shuō)法是”Y\U\V通道交叉存儲(chǔ),相鄰的像素盡量打包在一起“,圖3-3中U1后面跟著的是U2而不是V1,而且Y\U\V的排列方式似乎也不完全是交叉?筆者嘗試在網(wǎng)上搜索『打包格式』更多的例子,沒(méi)有找到特別好的資料,【這里給自己挖一個(gè)坑吧】。
接下來(lái),我們繼續(xù)了解一些幀相關(guān)的概念。
常見(jiàn)的幀名詞
『幀率』『分辨率』和『碼率』三者之間的關(guān)系
最理想的情況是畫面越清晰、越流暢是最好的。但在實(shí)際應(yīng)用中,還需要結(jié)合硬件的處理能力、實(shí)際帶寬條件選擇。高『幀率』高『分辨率』,也就意味著高『碼率』,也意味著需要高帶寬和強(qiáng)大的硬件能力進(jìn)行編解碼和圖像處理。所以『幀率』和『分辨率』應(yīng)該視情況而定。
要說(shuō)三者之間的關(guān)系,其實(shí)就是對(duì)于『碼率』的理解。在碼率(BPS)概念中提到了幾段摘自網(wǎng)上的說(shuō)法,說(shuō)的都太模糊了,筆者直到閱讀了文章Video Bitrate Vs. Frame Rate,才真的理解了『碼率』。
首先,這些說(shuō)法都沒(méi)有交代一個(gè)前提:『幀率』、『分辨率』和『壓縮率』都會(huì)影響『碼率』。Video Bitrate Vs. Frame Rate](https://www.techwalla.com/articles/video-bitrate-vs-frame-rate)文章在一開(kāi)始就明確指出:
Bitrate serves as a more general indicator of quality, with higher resolutions, higher frame rates and lower compression all leading to an increased bitrate.
『碼率』是更廣泛的(視頻)質(zhì)量指標(biāo):更高的『分辨率』,更高的『幀率』和更低的『壓縮率』,都會(huì)導(dǎo)致『碼率』增加。
文章后面又特別強(qiáng)調(diào)『分辨率』和『壓縮率』對(duì)『碼率』的影響:高分辨率意味著圖片可以包括更多的細(xì)節(jié),低壓縮率意味著圖片壓縮損失越少,即失真越少,越清晰。那為什么不特地討論『幀率』呢?筆者認(rèn)為原因有二:一個(gè)是『幀率』的影響非常直觀,每秒幀數(shù)增加必然導(dǎo)致數(shù)據(jù)量增加;另一個(gè)是實(shí)際應(yīng)用場(chǎng)景中『幀率』是相對(duì)固定的,我們觀看的一般視頻都在25-30fps之間,現(xiàn)在一些高幀視頻是60fps,可見(jiàn)視頻『幀率』在實(shí)際場(chǎng)景中被討論的很少。
奇怪的幀名詞:1080p和1080i、場(chǎng)
筆者僅僅出于覺(jué)得有趣才放上來(lái)的,1080p和1080i、場(chǎng)都是相對(duì)比較“老”的概念了,在還是CRT電視的時(shí)代,顯示器顯示畫面都是靠電子槍一行一行掃描畫面才能產(chǎn)生一副完整的圖像,這就被稱作『場(chǎng)』,后來(lái)這個(gè)名詞也不常使用了,被取代它的是『幀』。【科技在進(jìn)步,過(guò)時(shí)的概念、應(yīng)用都會(huì)被新興的替換,所以真的要不斷學(xué)習(xí)緊跟時(shí)代啊!】
1080p和1080i也是『場(chǎng)』同一時(shí)期的概念:
既然都是老概念了,那為什么還要再提呢?借用文章1080P和1080i是什么意思?的一段來(lái)說(shuō):
進(jìn)入液晶時(shí)代的如今,隔行和逐行其實(shí)已經(jīng)沒(méi)有太大的意義了,現(xiàn)在的電視或者是顯示器都屬于固定像素設(shè)備,像素點(diǎn)同時(shí)發(fā)光,并不需要掃描,但是硬要說(shuō)的話可以認(rèn)為現(xiàn)在的顯示設(shè)備都是逐行掃描的,但也并不是說(shuō)1080P和1080i等就可以淘汰了,畢竟還涉及到攝像機(jī)的格式,不過(guò)普通觀眾也不會(huì)關(guān)心是用什么攝像機(jī)拍的,只關(guān)心呈現(xiàn)出來(lái)的樣貌就好了。
視頻『幀』和編解碼密切相關(guān),因此還有不少『幀』的概念是和視頻編解碼相關(guān)的。
視頻編解碼而衍生的幀名詞
I/P/B幀,并不是依據(jù)視頻幀數(shù)據(jù)內(nèi)部的元素的不同來(lái)區(qū)分的,從解碼后的幀本身而言,它們沒(méi)有任何區(qū)別。僅僅是在編碼時(shí),對(duì)幀處理的方式不同而已。
這個(gè)概念在做視音頻同步的時(shí)候特別重要,尤其是PTS,目前常見(jiàn)的視音頻同步的三種策略“同步到音頻的PTS”、“同步到視頻的PTS”和“同步到系統(tǒng)/外部時(shí)鐘”,都是基于PTS完成的。
快搜