x264 碼率控制算法原理

x264 的碼率控制是如何實現的 ?

本文介紹 x264 碼率控制算法的數學原理,和基本框架。

1.理論假設
有助於往下閱讀,可以暫時跳過。

設變量: qscale = 拉格朗日常數 lamda = 0.85 * 2^((QP-12)/6) ≈ 量化步長 Qstep = 2^((QP-4)/6)

設變量: 複雜度 complexity ≈ 運動補償後殘差的satd

                二次編碼中: complexity  ≈  第一趟編碼的實際比特數

設變量: bits = 實際編碼後比特數

假設1: qscale不變, bit 和 複雜度 成正比

假設2: 複雜度不變, bit 和 qscale 成反比

也就是說: complexity ∝ qscale * bits

   或者:    bits   正比於  complexity  / qscale 

x264 的碼率控制的基礎是基於這個假設。

雖然它不是很精確,但是工程上足夠了。

  1. 基本公式
    有助於往下閱讀,可以跳過

qscale = 0.85 * 2^((QP-12)/6) ----- (1)

QP = 12 + 6 * log2(qscale/0.85) ----- (2)

Qstep = 2^((QP-4)/6) ----- (3)

QP = 6 * log2(Qstep) + 4 ----- (4)

  1. 基礎算法–幀間級
    x264 碼率控制分爲幀間級 和 幀內級,這裏先介紹幀間級碼率控制算法。

幀級別碼率控制需要爲每一幀分配QP, 也就是分配每一幀的大小。

每一幀的大小主要取決於兩個變量: 本幀的複雜度,碼率預算。

複雜度更高的幀,需要更多的比特。但給多少碼率,和複雜度不是正比的。

下面是x264模塊控制模塊的簡化框圖。包括了幀間級碼率控制,和幀內級(宏塊級)碼率控制。
在這裏插入圖片描述

x264 中, 首先根據每幀的複雜度,在幀與幀之間分配碼率比例。然後根據碼率預算,將每幀縮放到合適大小。這個縮放係數稱爲 ratefactor 。

然後 qscale = complexity / ratefactor

所謂 crf (constant ratefactor) 模式,就是固定ratefactor 參數, 碼率分配由複雜度決定。(這裏暫不考慮宏塊級碼率控制)

ABR 和 CBR 模式,都是通過實時調整 ratefactor 實現的。

qscale 最後會再經過 vbv 模塊調整,確保不會發生緩衝區下溢。vbv模塊也是實現CBR模式的關鍵模塊。

本文主要關注幀間級,它的主要框架如下:
在這裏插入圖片描述

下文會詳細解釋每個模塊。

  1. 模糊複雜度估計
    碼率控制的第一步是根據每一幀的複雜度,在幀與幀之間分配碼率比例。

一趟編碼中,由經過運動補償後殘差的satd代表一幀的複雜度。

X264中使用模糊複雜度作爲碼率分配的根據。相比使用單獨一幀的複雜度,這樣能避免QP的波動。

一趟編碼中,模糊複雜度基於鄰近已編碼幀的複雜度加權得到:
在這裏插入圖片描述

其中,Cplxsum 和 Cplxcount 更新方法如下:
在這裏插入圖片描述

這一部分代碼位於函數 rate_estimate_qscale():

rcc->last_satd = x264_rc_analyse_slice( h ); //得到 satd

rcc->short_term_cplxsum *= 0.5;

rcc->short_term_cplxcount *= 0.5;

rcc->short_term_cplxsum += rcc->last_satd / (CLIP_DURATION(h->fenc->f_duration) / BASE_FRAME_DURATION);

rcc->short_term_cplxcount ++;

rce.blurred_complexity = rcc->short_term_cplxsum / rcc->short_term_cplxcount;

4.1 感知編碼優化
引用自x264官方文檔:

“ You want the movie to be somewhere approaching constant quality. However, constant quality does not mean constant PSNR nor constant QP.

Details are less noticeable in high-complexity or high-motion scenes, so you can get away with somewhat higher QP for the same perceived quality”

恆定的質量並不代表恆定的QP, 對於高複雜度的場景,細節丟失比較難以發現,因此可以使用比較高的QP。

根據上述原理,x264對幀的複雜度進行了非線性”壓縮”:

在這裏插入圖片描述

rceq 代表壓縮後的“複雜度”,是碼率分配的依據。

qcomp 一個外部可調的參數。

當qcomp = 1,各幀的比重(rceq)都一樣,分配給平緩的幀和複雜的幀的比特是一樣的。

當qcomp= 0, 各幀的比重和其複雜度成正比(各幀QP相等)相當於關閉了此項感知編碼優化。

  1. Ratefactor
    5.1 簡介
    Ratefactor 參數用於控制總體碼流的大小,它只用在一趟編碼中。

ratefactor 和 複雜度rceq 一起,計算出 一幀的 qscale:

在這裏插入圖片描述 --------------------------(5)

一趟編碼中,由於未知未來幀的複雜度,所以ratefactor的選取是基於已編碼幀進行的。

選取的依據是:假如選定的ratefactor被應用到所有已編碼幀中,那麼得到的是希望的碼率。

“We don’t know the complexities of future frames, so we can only scale based on the past.

The scaling factor is chosen to be the one that would have resulted in the desired bitrate if it had been applied to all frames so far.”

— 引自官方文檔

這段話比較難以理解,下文會有詳細解釋。

我們先看看ratefactor的計算方法。

5.2 計算方法
Ratefactor 根據已編碼幀計算:

在這裏插入圖片描述 -------------------------------(6)

其中,wanted_bits_window 表示已編碼幀的目標文件大小。Cplxr_sum 是一個係數。

兩個變量的初始值爲:
在這裏插入圖片描述

每編完一幀,更新這兩個係數(ABR模式):
在這裏插入圖片描述

其中,bitrate表示目標碼率,fps表示幀率,bits表示實際編碼得到的幀大小。

可以看到,wanted_bits_sum變量是累積的目標碼率的大小。

Cpxr_sum 變量代表了bits*qscale/rceq的累積值。

5.3 原理解釋
爲什麼ratefactor這麼計算呢?

回憶第一章(理論假設),有:

complexity 正比於 qscale * bits

所以,可以設

A* complexity = qscale * bits ------- (7)

A 是比例係數。

有: A = bits*qscale/complexity

這裏,complexity = rceq

可以看到,cplr_sum 其實是A的累積值。

Bits 是實際得到的文件大小,跟目標大小(wanted_bits_window)可能不一樣。

根據式(7),可以調整qscale,讓碼率“正確”:
在這裏插入圖片描述

用wanted_bits_window代替每幀大小 wanted_bits_per_frame; 用cplr_sum 代替A :

分母其實就是ratefactor(式6),帶入上式子,得到:
在這裏插入圖片描述

這裏,complexity 是歷史幀的平均複雜度。

假設用這個qscale重新編碼歷史幀,可以得到目標文件大小 wanted_bits_window。

用當前幀的複雜度代替歷史幀的平均複雜度:
在這裏插入圖片描述

就是式(5)qscale的求法。

總結而言,就是6.1節所說: “ratefactor的選取是基於已編碼幀進行的。選取的依據是:假如選定的ratefactor被應用到所有已編碼幀中,那麼得到的是希望的碼率”。

得到ratefactor之後,再結合當前幀的相對複雜度,就可以得到當前幀的qscale。

5.4 CBR 模式
CBR 模式需要保持碼流在局部的穩定性。所以,ratefactor 不是根據所有已編碼幀計算,而是根據局部已編碼幀計算:

在這裏插入圖片描述
-------------------------------(6)

通過給累積項添加一個衰減係數cbr_decay,讓raterfactor主要由鄰近的已編碼幀決定。

Cbr_decay係數是一個由vbv-bufsize, vbv-maxrate, bitrate 決定的係數。

5.5 CRF 模式
CRF 模式也叫恆定質量模式。這種模式下編碼的視頻圖像質量最好。

在CRF模式下,ratefactor是固定不變的。也就是說,沒有全局的碼率控制,視頻的最終碼率是不確定的。

ratefactor的計算基於 命令行參數 --crf 設置的質量參數(rf_const) 。計算方法如下:
在這裏插入圖片描述

上式中,base_cplx是根據經驗得出的常數。

qp2qscale是從從qp變換到qscale的函數,公式可見第二章。

mbtree_offset是針對mbtree算法的偏置。

外部設置的crf 值和編碼器內部使用的ratefactor是不一樣的。

通過上述式子的變換,讓外界輸入的rf_const 跟最終編碼得到的QP近似。

  1. VBV模塊
    VBV 模塊用於控制接收端緩存不上溢不下溢,它實質是對視頻短時碼率進行限制。主要用於CBR模式中。

關於VBV模型的更多基礎信息,可以參見前一帖子: 視頻碼流控制類型和內涵。

VBV 控制流程主要位於函數clip_qscale()中。根據有沒有lookahead, 處理流程不同。

clip_qscale()計算qscale,分配幀級碼率預算。此外, x264 還有宏塊行級別的碼率控制,保證vbv碼率預算的執行。

clip_qscale()函數的主要處理流程如下圖 :
在這裏插入圖片描述

  1. 1 lookahead vbv調整
    從lookahead 模塊可以得到未來若干幀的複雜度。

vbv算法的原理是: 一樣的qscale應用到lookahead中的所有幀中,

檢測不會有幀讓vbv緩存下溢,並且lookahead中所有幀編碼結束後,緩存填充度在一個合理的範圍內。

小步調整qscale,直到上述要求被滿足。

6.2 實時 vbv 調整
如果沒有lookahead, 未來幀的複雜度未知,只能根據當前幀的複雜度,控制緩存的充滿程度。

算法主要流程是:

1,對於P幀和第一個I幀,讓當前幀編碼完成後,緩存區至少還有一半容量。

2,限制每幀大小不能超過當前換存量的一半。

3,限制每幀大小至少是buffer_rate 的一半。buffer_rate =vbv-maxrate/fps 。

4,限制qscale不能小於輸入qscale。(有可能作廢步驟3的更改)

6.3 minGOP vbv 調整。
B幀QP不直接被vbv調整,它由P幀加一個偏置得到。

這一步檢查當前P幀和(編碼順序)到下一個P幀之前的B幀的複雜度。

適當調低qscale (調高碼率預算), 使得本minGOP過後,緩存區沒有上溢。

  1. 總結
    可以看到,x264的碼率控制,是多個模塊聯合作用的結果。

並且對於不同的編碼模式,所用到的模塊有所不同 。

7.1 一趟ABR模式

通過複雜度和ratefactor控制總體碼率大小。

vbv模塊可以選擇使用或者不使用,如果使用vbv, 會取得更加穩定的碼率,同時降低圖像質量。

7.2 一趟CBR模式

通過複雜度和ratefactor控制局部碼率大小,得到可以比較合理的qscale,

然後通過vbv模塊,確保碼率恆定。

7.3 CRF模式

固定質量參數,只根據複雜度分配碼率,最終碼率未知。

一般不使用 vbv 模塊。

  1. ref
    源代碼
    源代碼中文件: \doc\ratecontrol.txt
    殷海兵. 數字視頻編碼-算法優化理論、方法和芯片實現[M]. 北京. 電子工業出版社. 2015.
    https://onlivetest.wordpress.com/2015/02/20/x264-rate-control-part-one/
    ————————————————
    版權聲明:本文爲CSDN博主「shumin1992」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
    原文鏈接:https://blog.csdn.net/soulmate_scut/article/details/89178017
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章