關於H.264 profile-level-id

我們在WebRTC開發中,如果採用的是H.264來作爲視頻流編碼類型,就會面臨一個問題,那就是編碼端和解碼端需要進行協商各自的編解碼能力。例如,如果編碼端使用了高級別的profile和level,或使用瞭解碼器不支持的編碼特性,那麼對解碼端來說就是個災難了。

大家知道,H.264的Profile以及Level有好多種,而並不是每一種編碼器或者解碼器都支持每一個Profile和Level。實際應用當中,我們經常會看到一個3個字節的值(例如42801f),它是H.264 SPS信息的頭三個字節,用來標識H.264的profile和level,這篇文章就是來簡單記錄和說明一下H.264的profile-level-id怎麼來看。

H.264的Profile和Level有哪些?

這個就不贅述了,在以下2個鏈接有詳盡的列表:
https://en.wikipedia.org/wiki/Advanced_Video_Coding#Profiles
https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels
雖然有這麼多種Profiles和Levels,但是在WebRTC,或者實時流媒體處理中,常見的就只有幾種。例如WebRTC默認使用的是OpenH264,它的編碼器只支持Constrained Baseline + Level 5.2(見OpenH264 github首頁說明)。

參考文檔

典型的profile-level-id示例

profile-level-id常見於sdp中,例如,在chrome://webrtc-internals中,我們如果推送一個H.264編碼的視頻流,在local sdp中可以看到這樣的profile-level-id:
在這裏插入圖片描述
這個profile-level-id在我們上面參考資料的RFC6184中的8.1 Media Type Registration一節中有比較詳細的說明。

下面我舉例子來說明一下怎麼來看。就拿上圖中出現的那幾個值來說吧。包括以下四種:

42001f
42e01f
4d0032
640032

這3個字節都是16進製表示。第一個字節表示profile_idc(0x42, 0x4d, 0x64),第二個字節表示profile-iop,第三個字節表示level。其中第一個字節和第三個字節比較好理解,例如:

  • 42001f : 第一個字節0x42 = 十進制66,根據參考資料維基百科頁面上得知,66對應Baseline Profile (BP, 66)。第三個字節0x1f = 十進制31,對應的Level就是3.1
  • 42e01f : 第一個字節和第三個字節同上,中間的0xe0我們一會兒說
  • 4d0032 : 第一個字節 0x4d = 十進制77 = Main Profile (MP, 77)。第三個字節0x32 = 十進制50,Level就是5.0
  • 640032 : 第一個字節 0x64 = 十進制100 = High Profile (HiP, 100)。第三個字節同上
    所以,第一個和第三個字節就很簡單,一看就明白。

下面我們來看看中間的那個字節。

在RFC6184中介紹,第二個字節是profile-iop,它的每一位對應:constraint_set{0,1,2,3,4,5}_flag,共6位,最後2位是保留位,始終爲0。

所以讓我們回頭看看上面的那個42e01f。首先通過第一個字節和第三個字節,我們知道它是Baseline Profile + Level 3.1,但是42001f和42e01f的差別是什麼呢?那就要看第二個字節0xe0了,它的二進制是:

1 1 1 0 0 0 00

我們通過查詢參考資料中ITU制定的那個文檔的A.2.1.1 Constrained Baseline profile一節看到以下描述:

Decoders conforming to the Constrained Baseline profile at a specific level shall be capable of decoding all bitstreams in which all of the following are true:
– profile_idc is equal to 66 or constraint_set0_flag is equal to 1,
– constraint_set1_flag is equal to 1,
– level_idc and constraint_set3_flag represent a level less than or equal to the specified level.

意思是解碼器在以下3個條件符合時具有解碼所有比特流的能力:

  1. profile_idc是66或者constraint_set0_flag=1,OK,成立(profile_idc是0x42,也就是十進制66,constraint_set0_flag等於1)
  2. constraint_set1_flag=1,OK,成立(constraint_set1_flag等於1)
  3. 這一條我不是特別理解,level_idc(3.1) 和 constraint_set3_flag(0) 表示一個小於或者等於指定level的level?

所以通過猜想,42e01f應該是Constrained Baseline Profilee,而42001f是BaselineProfile,因爲42001f至少不滿足上面條件1和2。

另外,在WebRTC的移動端Native SDK源碼中也可以找到2種profile和level的定義,源碼分別位於:

\sdk\android\api\org\webrtc\VideoCodecInfo.java (Android Native SDK)
\sdk\objc\components\video_codec\RTCH264ProfileLevelId.mm (iOS Native SDK)

我們在代碼中可以看到,它只定義了2種profile和level組合:

42e01f : Constrained Baseline Profile + Level 3.1
640c1f : Constrained High Profile + Level 3.1

順便,我們看看640c1f中那個0x0c,它的二進制是:

0 0 0 0 1 1 00

查閱ITU文檔(A.2.4.2 Constrained High profile一節),看到有一條描述:

profile_idc is equal to 100, constraint_set4_flag is equal to 1, constraint_set5_flag is equal to 1, and level_idc represents a level less than or equal to the specified level.

profile_idc等於100(即0x64),constraint_set4_flag和constraint_set5_flag要等於1(滿足),所以640c表示的就是Constrained High Profile。

另外,也可以簡單地通過上面參考資料中那個維基百科頁面上來判斷是什麼profile,如下圖:
在這裏插入圖片描述
constraint set x (x = 1,3,4, 4&5…)對應的就是constraint_set{0,1,2,3,4,5}_flag相應位的值需要是1

OK,至此,我們以後再見到profile-level-id,就可以很快知道它是什麼含義了。

再隨便來幾個:
64001f (High Profile + Level 3.1)
640016 (High Profile + Level 2.2)
640c34 (Constrained High Profile + Level 5.2)
42801e (Baseline Profile + Level 3.0)

最後,在github上還有人用js寫了一個profile-level-id解析工具,https://github.com/ibc/h264-profile-level-id,也可以協助我們理解profile-level-id。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章