日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入讲解音视频编码原理,H264码流详解——手写H264编码器

發(fā)布時(shí)間:2023/12/29 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入讲解音视频编码原理,H264码流详解——手写H264编码器 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

音視頻高手課08-H264 I幀 P幀 B幀及手寫H264編碼器

1 三種幀的說明

1、I 幀:幀內(nèi)編碼幀,幀表示關(guān)鍵幀,你可以理解為這一幀畫面的完整保留;解碼時(shí)只需要本幀數(shù)據(jù)就可以完成(因?yàn)榘暾嬅?#xff09;

I 幀的特點(diǎn):

  • a. 它是一個(gè)全幀壓縮編碼幀,它將全幀圖像信息進(jìn)行JPEG壓縮編碼及傳輸

  • b. 解碼時(shí)僅用I 幀的數(shù)據(jù)就可重構(gòu)完整圖像

  • c. I 幀描述了圖像背景和運(yùn)動(dòng)主體的詳情

  • d. I 幀不需要參考其他畫面而生成

  • e. I 幀是P幀和B幀的參考幀(其質(zhì)量直接影響到同組中以后各幀的質(zhì)量)

  • f. I 幀不需要考慮運(yùn)動(dòng)矢量

  • g. I 幀所占數(shù)據(jù)的信息量比較大

    P幀:前向預(yù)測編碼幀。P幀表示的是這一幀跟之前的一個(gè)關(guān)鍵幀(或P幀)的差別,解碼時(shí)需要之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P幀沒有完整畫面數(shù)據(jù),只有與前一幀的畫面差別的數(shù)據(jù))

? P幀的預(yù)測與重構(gòu):P幀是以 I 幀為參考幀,在 I 幀中找出P幀“某點(diǎn)”的預(yù)測值和運(yùn)動(dòng)矢量,取預(yù)測差值和運(yùn)動(dòng)矢量一起傳送。在接收端根據(jù)運(yùn)行矢量從 I 幀找出P幀“某點(diǎn)”的預(yù)測值并與差值相加以得到P幀“某點(diǎn)”樣值,從而可得到完整的P幀。

P幀的特點(diǎn):

  • a. P幀是 I 幀后面相隔1~2幀的編碼幀

  • b. P幀采用運(yùn)動(dòng)補(bǔ)償?shù)姆椒▊魉退c前面的I或P幀的差值及運(yùn)動(dòng)矢量(預(yù)測誤差)

  • c. 解碼時(shí)必須將幀中的預(yù)測值與預(yù)測誤差求和后才能重構(gòu)完整的P幀圖像

  • d. P幀屬于前向預(yù)測的幀間編碼。它只參考前面最靠近它的 I 幀或P幀

  • e. 由于P幀是參考幀,它可能造成解碼錯(cuò)誤的擴(kuò)散

  • f. 由于是差值傳送,P幀的壓縮比較高

3、B幀:雙向預(yù)測內(nèi)插編碼幀。B幀是雙向差別幀,也就是B幀記錄的是本幀與前后幀的差別(具體比較復(fù)雜,有4種情況,但我這樣說簡單些),換言之,要解碼B幀。不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過前后畫面的與本幀數(shù)據(jù)的疊加取得最終的畫面。B幀壓縮率高,但是解碼時(shí)CPU會(huì)比較累。

B幀的預(yù)測與重構(gòu)

? B幀以前面的 I 或P幀和后面的P幀為參考幀,“找出”B幀“某點(diǎn)”的預(yù)測值和兩個(gè)運(yùn)動(dòng)矢量,并取預(yù)測差值和運(yùn)動(dòng)矢量傳送。接收端根據(jù)運(yùn)動(dòng)矢量在兩個(gè)參考幀中“找出(算出)”預(yù)測值并與差值求和,得到B幀“某點(diǎn)”樣值,從而可得到完整的B幀。

B幀的特點(diǎn):

  • a. B幀是由前面的 I 或P幀和后面的P幀進(jìn)行預(yù)測的

  • b. B幀傳送的是它與前面的 I 或P幀和后面的P幀之間的預(yù)測誤差及運(yùn)動(dòng)矢量

  • c. B幀是雙向預(yù)測編碼幀

  • d. B幀壓縮比最高,因?yàn)樗环从巢⒖紟g運(yùn)動(dòng)主體的變化情況,預(yù)測比較準(zhǔn)確

  • e. B幀不是參考幀,不會(huì)造成解碼錯(cuò)誤的擴(kuò)散

注:I、B、P幀是根據(jù)壓縮算法的需要,是人為定義的,他們都是實(shí)實(shí)在在的物理幀。 一般來說,幀的壓縮率是7(跟JPG差不多), P幀是20,B幀可以達(dá)到50.可見使用B幀能節(jié)省大量空間, 節(jié)省出來的空間可以用來保存多一些幀,這樣在相同碼率下,可以提供更好的畫質(zhì)。

1.2 壓縮算法的說明

h264的壓縮方法

  • 1、分組:把幾幀圖像分為一組(GOP,也就是一個(gè)序列),為防止運(yùn)動(dòng)變化,幀數(shù)不宜取多
  • 2、定義幀:將每組內(nèi)各幀圖像定義為三種類型,即 I 幀、B幀和P幀
  • 3、預(yù)測幀:以幀作為基礎(chǔ)幀,以幀預(yù)測P幀,再由 I 幀和P幀預(yù)測B幀
  • 4、數(shù)據(jù)傳輸:最后將 I 幀數(shù)據(jù)與預(yù)測的差值信息進(jìn)行存儲(chǔ)和傳輸

? 幀內(nèi)(Intraframe)壓縮也稱為空間壓縮(Spatial compression)。當(dāng)壓縮一幀圖像時(shí),僅考慮本幀的數(shù)據(jù)而不考慮相鄰幀之間的冗余信息,這實(shí)際上與靜態(tài)圖像壓縮類似。幀內(nèi)一般采用有損壓縮算法,由于幀內(nèi)壓縮是編碼一個(gè)完整的圖像,因此可以獨(dú)立的解碼、顯示。幀內(nèi)壓縮一般達(dá)不到很高的壓縮,跟編碼jpeg差不多。

? 幀間(Interframe)壓縮的原理是:相鄰幾幀的數(shù)據(jù)有很大的相關(guān)性,或者說前后兩幀信息變化很小的特點(diǎn),也即連續(xù)的視頻及其相鄰幀之間具有冗余信息,根據(jù)這一特性,壓縮相鄰幀之間的冗余量就可以進(jìn)一步提高壓縮量,減少壓縮比。幀間壓縮也稱為時(shí)間壓縮,它通過比較時(shí)間軸上不同幀之間的數(shù)據(jù)進(jìn)行壓縮。幀間壓縮一般是無損的。幀差值(Frame differencing)算法是一種典型的時(shí)間壓縮發(fā),它通過比較本幀與相鄰幀之間的差異,僅記錄本幀與其相鄰幀的差值,這樣可以大大減少數(shù)據(jù)量。

? 順便說下有損(Lossy)壓縮和無損(Lossy less)壓縮。無損壓縮也即壓縮前和解壓縮后的數(shù)據(jù)完全一致。多數(shù)的無損壓縮都采用RLE行程編碼算法。有損壓縮意味著解壓縮后的數(shù)據(jù)與壓縮前的數(shù)據(jù)不一致。在壓縮的過程中要丟失一些人眼和耳朵所不敏感的圖像或音頻信息,而且丟失的信息不可恢復(fù)。幾乎所有高壓縮的算法都采用有損壓縮,這樣才能達(dá)到低數(shù)據(jù)率的目標(biāo)。丟失的數(shù)據(jù)率與壓縮比有關(guān),壓縮比越小,丟失的數(shù)據(jù)越多,解壓縮后的效果一般越差。此外,某些有損壓縮算法采用多次重復(fù)壓縮的方式,這樣還會(huì)引起額外的數(shù)據(jù)丟失。


2 手寫H264編碼器

要徹底理解視頻編碼原理,看書都是虛的,需要實(shí)際動(dòng)手,實(shí)現(xiàn)一個(gè)簡單的視頻編碼器:

知識(shí)準(zhǔn)備:基本圖像處理知識(shí),信號(hào)的時(shí)域和頻域問題,熟練掌握傅立葉正反變換,一維、二維傅立葉變換,以及其變種,dct變換,快速dct變換。

2.1.1 第一步:實(shí)現(xiàn)有損圖像壓縮和解壓
參考 JPEG原理,將RGB->YUV,然后Y/U/V看成三張不同的圖片,將其中一張圖片分為 8x8的block進(jìn)行 dct變換(可以直接進(jìn)行二維dct變換,或者按一定順序?qū)?x8的二維數(shù)組整理成一個(gè)64字節(jié)的一維數(shù)組),還是得到一個(gè)8x8的整數(shù)頻率數(shù)據(jù)。于是表示圖像大輪廓的低頻信號(hào)(人眼敏感的信號(hào))集中在 8x8的左上角;表示圖像細(xì)節(jié)的高頻信號(hào)集中在右下角。

? 接著將其量化,所謂量化,就是信號(hào)采樣的步長,8x8的整數(shù)頻率數(shù)據(jù)塊,每個(gè)數(shù)據(jù)都要除以對(duì)應(yīng)位置的步長,左上角相對(duì)重要的低頻信號(hào)步長是1,也就是說0-255,是多少就是多少。而右下角是不太重要的高頻信號(hào),比如步長取10,那么這些位置的數(shù)據(jù)都要/10,實(shí)際解碼的時(shí)候再將他們10恢復(fù)出來,這樣經(jīng)過編碼的時(shí)候/10和解碼的時(shí)候10,那么步長為10的信號(hào)1, 13, 25, 37就會(huì)變成規(guī)矩的:0, 10, 20, 30, 對(duì)小于步長10的部分我們直接丟棄了,因?yàn)楦哳l不太重要。

? 經(jīng)過量化以后,8x8的數(shù)據(jù)塊左上角的數(shù)據(jù)由于步長小,都是比較離散的,而靠近右下角的高頻數(shù)據(jù),都比較統(tǒng)一,或者是一串0,因此圖像大量的細(xì)節(jié)被我們丟棄了,這時(shí)候,我們用無損壓縮方式,比如lzma2算法(jpeg是rle + huffman)將這64個(gè)byte壓縮起來,由于后面高頻數(shù)據(jù)步長大,做了除法以后,這些值都比較小,而且比較靠近,甚至右下部分都是一串0,十分便于壓縮。

? JPEG圖像有個(gè)問題就是低碼率時(shí) block邊界比較嚴(yán)重,現(xiàn)代圖片壓縮技術(shù)往往要配合一些de-block算法,比如最簡單的就是邊界部分幾個(gè)像素點(diǎn)和周圍插值模糊一下。

做到這里我們實(shí)現(xiàn)了一個(gè)同 jpeg類似的靜態(tài)圖片有損壓縮算法。在視頻里面用來保存I幀數(shù)據(jù)。

?

2.1.2 第二步:實(shí)現(xiàn)宏塊誤差計(jì)算

? 視頻由連續(xù)的若干圖像幀組成,分為 I幀,P幀,所謂I幀,就是不依賴就可以獨(dú)立解碼的視頻圖像幀,而P幀則需要依賴前面已解碼的視頻幀,配合一定數(shù)據(jù)才能生成出來。所以視頻中I幀往往都比較大,而P幀比較小,如果播放器一開始收到了P幀那么是無法播放的,只有收到下一個(gè)I幀才能開始播放。I幀多了視頻就變大,I幀少了,數(shù)據(jù)量是小了,但視頻受到丟包或者數(shù)據(jù)錯(cuò)誤的影響卻又會(huì)更嚴(yán)重。

? 那么所謂運(yùn)動(dòng)預(yù)測編碼,其實(shí)就是P幀的生成過程:繼續(xù)將圖片分成 16x16的block(為了簡單只討論yuv的y分量壓縮)。I幀內(nèi)部單幀圖片壓縮我們采用了8x8的block,而這里用16x16的block來提高幀間編碼壓縮率(當(dāng)然也會(huì)有更多細(xì)節(jié)損失),我們用 x, y表示像素點(diǎn)坐標(biāo),而s,t表示block坐標(biāo),那么坐標(biāo)為(x,y)的像素點(diǎn)所屬的block坐標(biāo)為:

s = x / 16 = x >> 4 t = y / 16 = y >> 4

? 接著要計(jì)算兩個(gè)block的相似度,即矢量的距離,可以表示為一個(gè)256維矢量(16x16)像素點(diǎn)色彩距離的平方,我們先定義兩個(gè)顏色的誤差為:

PixelDiff(c1, c2) = (c1- c2) ^ 2

? 那么256個(gè)點(diǎn)的誤差可以表示為所有對(duì)應(yīng)點(diǎn)的像素誤差和:

BlockDiff(b1, b2) = sum( PixelDiff(c1, c2) for c1 in b1 for c2 in b2)

代碼化為:

int block_diff(const unsigned char b1[16][16], const unsigned char b2[16][16]) {int sum = 0;for (int i = 0; i < 16; i++) {for (int j = 0; j < 16; j++) {int c1 = b1[i][j];int c2 = b2[i][j];sum += (c1 - c2) * (c1 - c2);}}return sum; }

有了這個(gè)block求差的函數(shù),我們就可以針對(duì)特定block,搜索另外若干個(gè)block中哪個(gè)和它最相似了(誤差最小)。

1.2.3 第三步:實(shí)現(xiàn)運(yùn)動(dòng)預(yù)測編碼

? 根據(jù)上面的宏塊比較函數(shù),你已經(jīng)可以知道兩個(gè)block到底像不像了,越象的block,block_diff返回值越低。那么我們有兩幀相鄰的圖片,P1,P2,假設(shè) P1已經(jīng)完成編碼了,現(xiàn)在要對(duì) P2進(jìn)行P幀編碼,其實(shí)就是輪詢 P2里面的每一個(gè) block,為P2中每一個(gè)block找出上一幀中相似度最高的block坐標(biāo),并記錄下來,具體偽代碼可以表示為:

unsigned char block[16][16]; for (int t = 0; t <= maxt; t++) {for (int s = 0; s <= maxs; s++) {picture_get_block(P2, s * 16, t * 16, block); // 取得圖片 P2 的 blockint x, y;block_search_nearest(P1, &x, &y, block); // 在P1中搜索最相似的blockoutput(x, y); // 將P1中最相似的block的左上角像素坐標(biāo) (x, y) 輸出} }

? 其中在P1中搜索最相似 block的 block_search_nearest 函數(shù)原理是比較簡單的,我們可以暴力點(diǎn)用兩個(gè)for循環(huán)輪詢 P1中每個(gè)像素點(diǎn)開始的16x16的block(速度較慢),當(dāng)然實(shí)際中不可能這么暴力搜索,而是圍繞P2中該block對(duì)應(yīng)坐標(biāo)在P1中位置作為中心,慢慢四周擴(kuò)散,搜索一定步長,并得到一個(gè) :按照一定順序進(jìn)行搜索,并且在一定范圍內(nèi)最相似的宏塊坐標(biāo)。 。

于是P2進(jìn)行運(yùn)動(dòng)預(yù)測編碼的結(jié)果就是一大堆(x,y)的坐標(biāo),代表P2上每個(gè)block在上一幀P1里面最相似的 block的位置。反過來說可能更容易理解,我們可以把第三步整個(gè)過程定義為:

怎么用若干 P1里不同起始位置的block拼湊出圖片P2來,使得拼湊以后的結(jié)果和P2最像。

1.2.4 第四步:實(shí)現(xiàn)P幀編碼

? 拼湊的結(jié)果就是一系列(x,y)的坐標(biāo)數(shù)據(jù),我們繼續(xù)用lzma2將它們先壓縮起來,按照 vcd的分辨率

352 x 240,我們橫向需要 352 / 16 = 22個(gè)block,縱向需要 240 / 16 = 15 個(gè)block,可以用 P1中 22 x 15 = 330

個(gè) block的坐標(biāo)信息生成一張和P2很類似的圖片 P2’ :

for (int t = 0; t < 15; t++) {for (int s = 0; s < 22; s++, next++) {int x = block_positions[next].x; // 取得對(duì)應(yīng) P1上的 block像素位置 xint y = block_positions[next].y; // 取得對(duì)應(yīng) P1上的 block像素位置 y// 將 P1位置(x,y)開始的 16 x 16 的圖塊拷貝到 P2'的 (s * 16, t * 16)處CopyRect(P2', s * 16, t * 16, P1, x, y, 16, 16); } } 我們把用來生成P2的P1稱為 P2的 “參考幀”,再把剛才那一堆P1內(nèi)用來拼成P2的 block坐標(biāo)稱為 “**運(yùn)動(dòng)矢量**”,這是P幀里面最主要的數(shù)據(jù)內(nèi)容。但是此時(shí)由P1和這些坐標(biāo)數(shù)據(jù)拼湊出來的P2,你會(huì)發(fā)現(xiàn)粗看和P2很象,但細(xì)看會(huì)發(fā)現(xiàn)有些支離破碎,并且邊緣比較明顯,怎么辦呢?我們需要第四步。
1.2.5第五步:實(shí)現(xiàn)P幀編碼
有了剛才的運(yùn)動(dòng)預(yù)測矢量(一堆block的坐標(biāo)),我們先用P1按照這些數(shù)據(jù)拼湊出一張類似 P2的新圖片叫做P2',然后同P2上每個(gè)像素做減法,得到一張保存 differ的圖片: D2 = (P2 - P2') / 2

? 誤差圖片 D2上每一個(gè)點(diǎn)等于 P2上對(duì)應(yīng)位置的點(diǎn)的顏色減去 P2’上對(duì)應(yīng)位置的點(diǎn)的顏色再除以2,用8位表示差值,值是循環(huán)的,比如-2就是255,這里一般可以在結(jié)果上 + 0x80,即 128代表0,129代表2,127代表-2。繼續(xù)用一個(gè) 8位的整數(shù)可以表示 [-254, 254] 之間的誤差范圍,步長精度是2。

? 按照第三步實(shí)現(xiàn)的邏輯,P2’其實(shí)已經(jīng)很像P2了,只是有些誤差,我們將這些誤差保存成了圖片D2,所以圖片D2中,信息量其實(shí)已經(jīng)很小了,都是些細(xì)節(jié)修善,比起直接保存一張完整圖片熵要低很多的。所以我們將 D2用類似第一步提到的有損圖片壓縮方法進(jìn)行編碼,得到最終的P幀數(shù)據(jù):

Encode(P2) = Lzma2(block_positions) + 有損圖像編碼(D2)

? 具體在操作的時(shí)候,D2的圖像塊可以用16x16進(jìn)行有損編碼,因?yàn)榍懊娴倪\(yùn)動(dòng)預(yù)測數(shù)據(jù)是按16x16的宏塊搜索的,而不用象I幀那樣精確的用8x8表示,同時(shí)保存誤差圖時(shí),量化的精度可以更粗一些用不著象I幀那么精確,可以理解成用質(zhì)量更低的JPEG編碼,按照16x16的塊進(jìn)行編碼,加上誤差圖D2本來信息量就不高,這樣的保存方式能夠節(jié)省不少空間。

?

1.2.6 第六步:實(shí)現(xiàn)GOP生成

? 通過前面的代碼,我們實(shí)現(xiàn)了I幀編碼和P幀編碼,P幀是參考P1對(duì)P2進(jìn)行編碼,而所謂B幀,就是參考 P1和 P3對(duì)P2進(jìn)行編碼,當(dāng)然間隔不一定是1,比如可以是參考P1和P5對(duì)P2進(jìn)行編碼,前提條件是P5可以依賴P1及以前的數(shù)據(jù)進(jìn)行解碼。

? 不過對(duì)于一個(gè)完整的簡版視頻編碼器,I幀和P幀編碼已經(jīng)夠了,市面上任然有很多面向低延遲的商用編碼器是直接干掉B幀的,因?yàn)樽鰧?shí)時(shí)傳輸時(shí)收到B幀沒法播放,之后再往后好幾幀收到下一個(gè)I或者P幀時(shí),先前收到的B幀才能被解碼出來,造成不少的延遲。

? 而所謂的 GOP (Group of picture) 就是由一系列類似 I, P, B, B, P, B, B, P, B, B P 組成的一個(gè)可以完整被解碼出來的圖像組,而所謂視頻文件,就是一個(gè)接一個(gè)的GOP,每個(gè)GOP由一個(gè)I幀開頭,然后接下來一組連續(xù)的P 或者 B構(gòu)成,播放時(shí)只有完整收到下一個(gè)GOP的I幀才能開始播放。

最后是關(guān)于參考幀選擇,前面提到的 P2生成過程是參考了 P1,假設(shè)一個(gè)GOP中十張圖片,是 I1, P1, P2, P3, P4, ... P9 保存的,如果P1參考I1,P2參考P1, P3參考P2 .... P9參考P8這樣每一個(gè)P幀都是參考上一幀進(jìn)行編碼的話,誤差容易越來越大,因?yàn)镻1已經(jīng)引入一定誤差了,P2在P1的基礎(chǔ)上誤差更大,到了P9的話,圖片質(zhì)量可能已經(jīng)沒法看了。

? 因此正確的參考幀選擇往往不需要這樣死板,比如可以P1-P9全部參考I1來生成,或者,P1-P4參考I1來生成,而P5-P9則參考P5來生成,這樣步子小點(diǎn),誤差也不算太離譜。

1.2.7 第七步:容器組裝

? 我們生成了一組組編碼過的GOP了,這時(shí)候需要一定的文件格式將他們恰當(dāng)?shù)谋4嫦聛?#xff0c;記錄視頻信息,比如分辨率,幀率,時(shí)間索引等,就是一個(gè)類似MP4(h.264的容器)文件的東西。至此一個(gè)簡單的小型編碼器我們已經(jīng)完成了,可以用 SDL / DirectX / OpenGL 配合實(shí)現(xiàn)一個(gè)播放器,愉快的將自己編碼器編碼的視頻播放出來。

1.2.8第八步:優(yōu)化改進(jìn)

? 這時(shí)候你已經(jīng)大概學(xué)習(xí)并掌握了視頻編碼的基礎(chǔ)原理了,接下來大量的優(yōu)化改進(jìn)的坑等著你去填呢。優(yōu)化有兩大方向,編碼效率優(yōu)化和編碼性能優(yōu)化:前者追求同質(zhì)量(同信噪比)下更低的碼率,后者追求同樣質(zhì)量和碼率的情況下,更快的編碼速度。

? 有這個(gè)基礎(chǔ)后接下來可以回過頭去看JPEG標(biāo)準(zhǔn),MPEG1-2標(biāo)準(zhǔn),并閱讀相關(guān)實(shí)現(xiàn)代碼,你會(huì)發(fā)現(xiàn)簡單很多了,接著肯H.264代碼,不用全部看可以針對(duì)性的了解以下H.264的I幀編碼和各種搜索預(yù)測方法,有H.264的底子,你了解 HEVC和 vpx就比較容易了。

? 參考這些編碼器一些有意思的實(shí)現(xiàn)來改進(jìn)自己的編碼器,試驗(yàn)性質(zhì),可以側(cè)重原理,各種優(yōu)化技巧了解下即可,本來就是hack性質(zhì)的。

有卯用呢?首先肯定很好玩,其次,當(dāng)你有需要使用并修改這些編碼器為他們?cè)黾有绿匦缘臅r(shí)候,你會(huì)發(fā)現(xiàn)前面的知識(shí)很管用了。

------有朋友說光有代碼沒有圖片演示看不大明白,好我們補(bǔ)充一下圖片演示:

1.3 畫面演示

  • 3.1 這是第一幀畫面:P1(我們的參考幀)
  • 這是第二幀畫面:P2(需要編碼的幀)

    從視頻中截取的兩張間隔1-2秒的畫面,和實(shí)際情況類似,下面我們進(jìn)行幾次運(yùn)動(dòng)搜索:

    1.3.2 搜索演示1:搜索P2中車輛的車牌在P1中最接近的位置(上圖P1,下圖P2)

    這是一個(gè)演示程序,鼠標(biāo)選中P2上任意16x16的Block,即可搜索出P1上的 BestMatch 宏塊。雖然車輛在運(yùn)動(dòng),從遠(yuǎn)到近,但是依然找到了最接近的宏塊坐標(biāo)

    1.3.3 搜索演示2:空中電線交叉位置(上圖P1,下圖P2)

    1.3.3 搜索演示3:報(bào)刊停的廣告海報(bào)

    同樣順利在P1中找到最接近P2里海報(bào)的宏塊位置。

    圖片全搜索:根據(jù)P1和運(yùn)動(dòng)矢量數(shù)據(jù)(在P2中搜索到每一個(gè)宏塊在P1中最相似的位置集合)還原出來的P2’,即完全用P1各個(gè)位置的宏塊拼湊出來最像P2的圖片P2’,效果如下:

    仔細(xì)觀察,有些支離破碎對(duì)吧?肯定啊,拼湊出來的東西就是這樣,現(xiàn)在我們用P2`和P2像素相減,得到差分圖 D2 = (P2’ - P2) / 2 + 0x80:

    嗯,這就是P2`和P2兩幅圖片的不同處,看到?jīng)]?基本只有低頻了!高頻數(shù)據(jù)少到我們可以忽略,這時(shí)用有損壓縮方式比較差的效果來保存誤差圖D2,只要5KB的大小。
    接著我們根據(jù)運(yùn)動(dòng)矢量還原的 P2’及差分圖D2來還原新的 P2,NewP2 = P2’ + (D2 - 0x80) * 2:

    ? 這就是之前支離破碎的 P2` 加上誤差 D2之后變成了清晰可見的樣子,基本還原了原圖P2。
    ? 由于D2僅僅占5KB,加上壓縮過后的運(yùn)動(dòng)矢量不過7KB,

    ? 所以參考P1我們只需要額外 7KB的數(shù)據(jù)量就可以完整表示P2了,而如果獨(dú)立將P2用質(zhì)量尚可的有損壓縮方式獨(dú)立壓縮,則至少要去到50-60KB,這一下節(jié)省了差不多8倍的空間,正就是所謂運(yùn)動(dòng)編碼的基本原理。

    再者誤差我們保存的是(P2-P2’)/2 + 0x80,實(shí)際使用時(shí)我們會(huì)用更有效率的方式,比如讓[-64,64]之間的色差精度為1,[-255,-64], [64, 255] 之間的色差精度為2-3,這樣會(huì)更加真實(shí)一些。

    ? 現(xiàn)代視頻編碼中,除了幀間預(yù)測,I幀還使用了大量幀內(nèi)預(yù)測,而不是完全dct量化后編碼,前面幀間預(yù)測我們使用了參考幀的宏塊移動(dòng)拼湊新幀的方式進(jìn)行,而所謂幀內(nèi)預(yù)測就是同一幅畫面中,未編碼部分使用已編碼部分拼湊而成。。。。。。。

    H264是新一代的編碼標(biāo)準(zhǔn),以高壓縮高質(zhì)量和支持多種網(wǎng)絡(luò)的流媒體傳輸著稱在編碼方面,

    后續(xù):

    • 音視頻格式封裝原理
    • 視頻壓縮原理
    • 幀內(nèi)預(yù)測
    • 切片
    • H264分層
    • 手寫H264編碼器

    粉絲交流扣裙:

    總結(jié)

    以上是生活随笔為你收集整理的深入讲解音视频编码原理,H264码流详解——手写H264编码器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。