人間觀察
因為窮,人會放棄體面: 個人形象的體面,作業的體面,社交的體面,尊嚴的體面,
在分析H.264碼流前,我們得得先獲取一個H.264的碼流,兩種方法獲取:一是自己寫個代碼編碼為h264的碼流(后續介紹),二是是直接從視頻檔案里抽取,我們這里采用方法二,當然也有其它方法,
快手抖音的短視頻/直播,毫無疑問采取的編碼方式肯定是H.264和AAC生成的MP4封裝格式的視頻,我們下載一個mp4(可以看一下檔案的簡介中的編解碼器是否是H.264,AAC),用如下ffmpeg命令抽取h264和aac:
// ffmpeg命令 抽取aac到檔案
ffmpeg -i v0200f7b0000bq9dpgfiv42bsnt20920.MP4 -acodec copy -vn 1.aac
// ffmpeg命令 抽取h264到檔案
ffmpeg -i v0200f7b0000bq9dpgfiv42bsnt20920.MP4 -c:v copy -bsf:v h264_mp4toannexb -an 1.h264
抽取的h264和aac可以播放嗎?當然可以,我用的是mac,mac上可以用vlc播放,
ffmpeg命令可以從官網直接下載可執行的二進制
關于在Android中如何利用clang交叉編譯ffmpeg后續文章介紹
H.264碼流格式
h264的有兩種碼流格式:位元組流格式和RTP包格式,
位元組流格式
Annex-B Byte stream format,這個是官方h264協議檔案中規定的格式,所以它是大多數編碼器默認的編碼后的輸出格式,它的基本資料單位為NAL單元,簡稱NALU(Network Abstraction Layer Unit),每個NALU的前面加上起始碼:0x000001(3個位元組)或0x00000001(4個位元組)用于分割,后面會介紹,
RTP包格式
這種格式沒有在h264中規定,這種格式不需要起始碼分割NALU,而是在NALU開始的幾個位元組代表NALU的長度,這個我沒有過多研究,應該是不常用的,
所以我們這里主要介紹的就是位元組流格式的h264裸流,所謂的裸流就是經編碼器編碼后輸出的資料,而沒有經過傳輸協議(比如flv)封裝的資料,這樣的資料就叫做裸流,
H.264結構
碼流分層
如上所說h264碼流是由一個接一個的 NALU組成的,但是它按照功能分為
視頻編碼層:VCL(Video Coding Layer),編碼器壓縮處理后的壓縮視頻資料序列,
網路抽象層:NAL(Network Abstraction Layer),負責以網路要求的格式對資料進行打包和傳送,是傳輸層,不管是本地保存還是在網路上傳送,都需要通過這一層來傳輸,
也就是視頻編碼資料(VCL)在傳輸或存盤(保存到檔案)之前,會先被封裝進NAL(也就是NALU)單元才可以,
NALU(NAL單元)
h264碼流是一系列的NALU組成,用起始碼分割每個,所以整體看碼流的格式就是:
H264碼流 = …Start_Code_Prefix + NALU + Start_Code_Prefix + NALU + …
Start_Code_Prefix 標示的就是起始碼,起始碼為:0x000001(3個位元組)或0x00000001(4個位元組),起始碼中間的部分就是NALU的部分,
我們看下我們從抖音/快手提取的h264檔案的開始部分(因為h264格式開始有SPS,PPS,SEI 分割較多,你可以搜索一下檔案后后面的資料流也有):

NALU的主體是:NALU=NALU Header + EBSP
NALU的主體有細分:分別為EBSP、RBSP和SODB,其中EBSP完全等價于NALU主體,而且它們三個的結構關系為:
EBSP包含RBSP,RBSP包含SODB,
EBSP名字叫:擴展位元組序列載荷(Encapsulated Byte Sequence Payload)
RBSP名字叫:原始位元組序列載荷(Raw Byte Sequence Payload)
SODB(String Of Data Bits)就是最原始的編碼資料,
后續介紹,先有個大概的概念區分,真的是概念非常多,
NALU Header
NALU Header 在每個的NALU中,占據一個位元組也就是8位,分三部分,如下:
| 名稱 | 占據位數bit | 代表的意義 |
|---|---|---|
forbidden_zero_bit | 1bit | h264檔案規定,這個值應該為0,當它不為0時,表示網路傳輸程序中,當前NALU中可能存在錯誤,解碼器可以考慮不對這個NALU進行解碼 |
nal_ref_idc | 2bit | 取值0~3,代表當前這個NALU的重要性,取值越大,代表當前NALU越重要 |
nal_unit_type | 5bit | NALU的資料型別,比如是sps,pps,sei,idr等 |
我們主要看一下nal_unit_type在h264協議中定義如下:

nal_unit_type =1-5是VCL(視頻編碼層)單元,
6-代表當前NALU為輔助增強資訊(SEI),一般會埋入視頻著作權等資訊,
7-代表當前NALU為序列引數集SPS,包括一個影像序列的所有資訊,即兩個 IDR 影像間的所有影像資訊,如影像尺寸、視頻格式等
8-代表當前NALU為影像引數集PPS,包括一個影像的所有分片的所有相關資訊, 包括影像型別、序列號等
一般h264的碼流最開始都是SEI,SPS,PPS,IDR(I幀)…,SPS,PPS,IDR(I幀). 一般在IDR(I幀)前有SPS,PPS,也就是每一組影像(GOP序列,圖片組)都給予了影像引數集(PPS)和這個序列引數集SPS(SPS),我們看下最開始提取的抖音的h264檔案(也就是上面啟始碼的后一位元組),
// 這里只貼了關鍵位元組,省略其它的
// 16進制打開,每2位數是一個位元組byte=8位(bit)
// 1F的二進制位的后五位為:11111
0000 0001 0605 ffff e1dc 45e9 bde6 d948 SEI 06&1F取該位元組的后五位=6
3d31 3a31 2e30 3000 8000 0000 0167 6400 SPS 67&1F取該位元組的后五位=7
0303 c0f1 8319 a000 0000 0168 e978 b2c8 PPS 68&1F取該位元組的后五位=8
b000 0001 6588 8400 4ffe 841f c0a5 9f35 IDR 65&1F取該位元組的后五位=5
71b9 4cd3 13c1 0000 0001 419a 246c 47ff slice(片) 41&1F取該位元組的后五位=1
視頻的寬高就是在SPS中取出來的,
EBSP和RBSP
NALU的起始碼為0x000001或0x00000001,但是有一種在NALU的內部也有0x000001或0x00000001的資料怎么辦?H264采用了一種方法如果NALU內部出現了編碼器就在最后一個位元組前,插入一個新的位元組:0x03,做了如下4種情況的處理:
0x000000 插入x03 0x00000300
0x000001 插入x03 0x00000301
0x000002 插入x03 0x00000302
0x000003 插入x03 0x00000303
0x000003是為了防止NALU內部本來就有0x000003這樣的資料,
所以說EBSP相較于RBSP,多了防止沖突的一個位元組:0x03,當使用EBSP時,就需要檢測EBSP內是否有序列:0x000003,如果有,則去掉其中的0x03,這樣一來,我們就能得到原始位元組序列載荷:RBSP,
我們用提取的抖音的h264檔案找下:
3d31 3a31 2e30 3000 8000 0000 0167 6400
1fac d980 b40a 1b01 1000 0003 0010 0000
// 比如67=SPS 的NALU就有一個0303
0303 c0f1 8319 a000 0000 0168 e978 b2c8
b000 0001 6588 8400 4ffe 841f c0a5 9f35
11fe 06cb d3bf 26e6 9d1f ff2c e1b1 aaf2
RBSP和SODB
原始編碼資料SODB(String Of Data Bits)他們2個的關系是:
RBSP = SODB + RBSP尾部
RBSP尾部
H264協議檔案中有兩種尾部表示,如下:

尾部特RBSP語法
RBSP最后一個位元組的最后一個位元為rbsp_stop_one_bit,其值為1,并且當rbsp_stop_one_bit不是最后一個位元時,用一個或多個rbsp_alignment_zero_bit,其值為0,補齊以形成一個位元組對齊,
條帶RBSP尾部
當 nal_unit_type等于1~5時采用這種尾部,在尾部特RBSP語法的基礎上,如果當entropy_coding_mode_flag值為1,也即當前采用的熵編碼為CABAC,而且more_rbsp_trailing_data回傳為true,也即RBSP中有更多資料時,添加一個或多個0x0000,
H264的碼流結構
所以整體H.264的Annex-B碼流格式從概念上來看就是,SODB里就是原始的編碼資料,

如有描述不準確歡迎指正,
H.264的協議檔案
http://www.itu.int/rec/T-REC-H.264
http://www.itu.int/rec/T-REC-H.264-200503-S/en
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/237549.html
標籤:其他
上一篇:音頻編解碼介紹(最全v1.0)
