第一步,先說說如何對獲得MPEG-4編碼的視頻。我的方法是從純視頻格式(.yuv)利用軟件ffmpeg經過MPEG-4編碼得到.m4v文件,這個文件就是我們所需要分析的文件。
第二步,得到MPEG-4編碼的視頻後,我們就可以根據圖中所示的文件結構再利用ultraedit分析它的碼流結構了。MPEG-4編碼與MPEG-2編碼最大的不同之處就在於它是基於對象的編碼,可以合成媒體對象以創建所需的視聽場景以及多路傳播和同步媒體數據項的位流,以保證它們在傳輸過程中的服務質量,並能在接收端與視聽場景進行交互。先來分析它的層次結構,它可以分爲5個層次(對應着圖看,非常清楚):
1. 視頻對象序列VOS
2. 視頻對象VO
3. 視頻對象層VOL
4. 視頻對象平面組GOV
5. 視頻對象平面VOP(也就是所謂的“幀”)
圖1
(二)下面來詳細分析mpeg碼流頭
關於MPEG4 碼流(mpeg4 raw data)的格式分析
MPEG4碼流開頭往往如下:
00 00 01 B0 F5 00 00 01 B5 09 00 00 01 00 00 00
01 20 08 86 84 00 3F 18 58 21 20 A3 1F 00 00 01
B2 58 76 69 44 30 30 36 32 00 00 01 B6
其格式爲:
MP4V type b0 size 5 //vosh
MP4V type b5 size 5 //vo
MP4V type 0 size 4
MP4V type 20 size 16 //vol
ParseVol: timeBits 15 timeTicks 24000 frameDuration 1001
MP4V type b6 size 5606 //vop
其宏定義爲:
#define MP4AV_MPEG4_VOL_START 0x20
#define MP4AV_MPEG4_VOSH_START 0xB0
#define MP4AV_MPEG4_VO_START 0xB5
#define MP4AV_MPEG4_VOP_START 0xB6
#define MP4AV_MPEG4_USER_DATA_START 0xB2
00 00 01 B0是視頻對象序列開始標誌(VISOBJSEQ_START_CODE),其後的數據只有一位F4,表示此視頻對象編碼序列編碼的Profile與Level類型是XVID_PROFILE_AS_L4, Profile類型數值定義於xvid.h。
00 00 01 B5是視頻對象開始標誌(VISOBJ_START_CODE),其後只有一位16進制數據09,從這一位數據可以獲得視頻對象版本號、視頻類型和視頻信號類型信息。
00 00 01 00是視頻對象開始標誌 (VIDOBJ_START_CODE)。
00 00 01 20是視頻對象層開始標誌(VIDOBJLAY_START_CODE),其後的11位16進制數據比較重要,解碼所需要的VOP縱橫比、視頻對象形狀和圖像分辨率等數據都是從這11位數據獲得的,詳細介紹見圖5-11,圖中未標記用途的數據表示未使用。
00 00 01 B2是用戶數據開始標誌(USERDATA_START_CODE),十六進制用戶數據共有8位。
00 00 01 B6是VOP開始標誌(VOP_START_CODE),每個VOP編碼數據都以VOP標識頭開始,VOP標識頭比較簡單,如果用16進制數據表示其數值爲00 00 01 B6。解碼的時候,以00 00 01 B6來判定是不是一個VOP的開始,並從VOP標識頭後的數據讀取編碼類型,量化值等參數後完成一幀VOP的解碼。
(三)MPEG4碼流視頻關鍵幀頭部16個字節,非關鍵幀8個字節。
MPEG4碼流視頻關鍵幀頭部16個字節,非關鍵幀8個字節(均包含四字節ID),說明如下:
關鍵幀:
字節 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
F |
值 |
0 |
0 |
1 |
FB |
XX |
R |
W&H |
Date time |
Length |
|||||||
含義 |
ID |
|
|
圖像大小 |
時間戳 |
幀長度 |
非關鍵幀
字節 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
值 |
0 |
0 |
1 |
FA |
Length |
|||
含義 |
ID |
幀長度 |
XX:保留。
RATE: 幀率,低5位表示幀率,目前取值從1到30,高三位表示解交錯,可選0,1,2其中0做解交錯,2不做解交錯。
WIDTH和HEIGHT表示視頻數據高度和寬度,一個字節最大256,所以存儲的信息爲真實高度和寬度的1/8。
TIMESTAMP:幀時間戳:
struct DateTime
{
DWORD second :6; // 秒 1-60
DWORD minute :6; // 分 1-60
DWORD hour :5; // 時 1-24
DWORD day :5; // 日 1-31
DWORD month :4; // 月 1-12
DWORD year :6; // 年 2000-2063
};
非關鍵幀的時間戳是根據幀率和對關鍵幀的偏移計數計算出來的。
LENGTH:幀長度,低字節優先,不包括幀頭長度(16字節或者8字節,這個需要注意)
H.264碼流跟MPEG4的最大不同在於ID,關鍵幀ID爲000001FD,非關鍵幀ID爲000001FC。
給一個例子: