媒體檔案格式分析FMP4
媒體檔案格式分析之FMP4
號外:金山雲全線已經支援dash和HLS Fmp4直播協議,歡迎大家試用!!
MP4 中最基本的單元就是Box,它內部是通過一個一個獨立的Box拼接而成的。所以,這裡,我們先從 Box 的講解開始,每個 Box 是由 Header 和 Data 組成的,FullBox 是 Box 的擴充套件,Box 結構的基礎上在 Header 中增加 8bits version 和 24bits flags
1. 名詞解釋
2. 最小單元Box
3. Mp4檔案整體結構
這裡,我們按照 MP4 box 的劃分來進行相關的闡述。先看一張 MP4 給出的結構圖:
3.1 File Type Box (ftyp)
通常放在MP4檔案的開頭,告訴解碼器基本的解碼版本和相容格式。
- 基本格式如下:
aligned(8) class FileTypeBox
extends Box(‘ftyp’) {
unsigned int(32) major_brand;
unsigned int(32) minor_version;
unsigned int(32) compatible_brands[];
}
- 欄位說明:
欄位 | 長度 | 說明 | 預設值 |
---|---|---|---|
major_brand | 4 | 推薦相容性的版本 | iso6 |
minor_version | 4 | 最低相容性的版本 | 1 |
compatible_brands | 列表值 | 所有的相容性的版本 | ‘iso6’ ‘isom’ ‘dash’ |
- Nginx模組實現
ngx_int_t ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b) { u_char *pos; pos = ngx_rtmp_mp4_start_box(b, "ftyp"); /* major brand */ ngx_rtmp_mp4_box(b, "iso6"); /* minor version */ ngx_rtmp_mp4_field_32(b, 1); /* compatible brands */ ngx_rtmp_mp4_box(b, "isom"); ngx_rtmp_mp4_box(b, "iso6"); ngx_rtmp_mp4_box(b, "dash"); ngx_rtmp_mp4_update_box_size(b, pos); return NGX_OK; }
3.2 Movie Box (moov)
作為容器盒子,存放相關的trak及meta資訊.
- 基本格式如下:
aligned(8) class MovieExtendsBox extends Box(‘mvex’){ }
3.2.1 Movie Header Box (mvhd)
mvhd 是 moov 下的第一個 box,用來描述 media 的相關資訊:
- 基本格式如下:
aligned(8) class MovieHeaderBox extends FullBox(‘mvhd’, version, 0) {
if (version==1) {
unsigned int(64) creation_time;
unsigned int(64) modification_time;
unsigned int(32) timescale;
unsigned int(64) duration;
} else { // version==0
unsigned int(32) creation_time;
unsigned int(32) modification_time;
unsigned int(32) timescale;
unsigned int(32) duration;
}
template int(32) rate = 0x00010000; // typically 1.0
template int(16) volume = 0x0100; // typically, full volume
const bit(16) reserved = 0;
const unsigned int(32)[2] reserved = 0;
template int(32)[9] matrix =
{ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
// Unity matrix
bit(32)[6] pre_defined = 0;
unsigned int(32) next_track_ID;
}
- 欄位說明:
欄位 | 長度 | 說明 | 預設值 |
---|---|---|---|
version | 4 | 版本 | 0 or 1s |
creation_time | 4 | 建立的UTC時間。從1904年開始算起, 用秒來表示 | 無 |
modification_time | 4 | 最後一次修改時間 | 無 |
timescale | 4 | 檔案媒體在1秒時間內的刻度值,可以理解為1秒長度的時間單元數 | 無 |
duration | 4 | 該track的時間長度,用duration和time scale值可以計算track時長s | 實際時間為:duration/timescale = xx 秒 |
rate | 4 | 推薦播放速率 | 0x00010000 |
volume | 2 | 音量大小 | 0x0100 為最大值 |
reserved | 10 | 保留欄位 | 0 |
matrixs | 4 * 9 | 視訊變換矩陣 | {0x00010000,0,0,0,0x0001s0000,0,0,0,0x40000000} |
next_track_ID | 4 | 下一個track使用的id號 |
- Nginx模組實現
static ngx_int_t
ngx_rtmp_mp4_write_mvhd(ngx_buf_t *b)
{
u_char *pos;
pos = ngx_rtmp_mp4_start_box(b, "mvhd");
/* version */
ngx_rtmp_mp4_field_32(b, 0);
/* creation time */
ngx_rtmp_mp4_field_32(b, 0);
/* modification time */
ngx_rtmp_mp4_field_32(b, 0);
/* timescale */
ngx_rtmp_mp4_field_32(b, 1000);
/* duration */
ngx_rtmp_mp4_field_32(b, 0);
/* reserved */
ngx_rtmp_mp4_field_32(b, 0x00010000);
ngx_rtmp_mp4_field_16(b, 0x0100);
ngx_rtmp_mp4_field_16(b, 0);
ngx_rtmp_mp4_field_32(b, 0);
ngx_rtmp_mp4_field_32(b, 0);
ngx_rtmp_mp4_write_matrix(b, 1, 0, 0, 1, 0, 0);
/* reserved */
ngx_rtmp_mp4_field_32(b, 0);
ngx_rtmp_mp4_field_32(b, 0);
ngx_rtmp_mp4_field_32(b, 0);
ngx_rtmp_mp4_field_32(b, 0);
ngx_rtmp_mp4_field_32(b, 0);
ngx_rtmp_mp4_field_32(b, 0);
/* next track id */
ngx_rtmp_mp4_field_32(b, 1);
ngx_rtmp_mp4_update_box_size(b, pos);
return NGX_OK;
}
3.2.2 Movie Extends Box (mvex)
mvex 是 fMP4 的標準盒子。它的作用是告訴解碼器這是一個 fMP4 的檔案,具體的 samples 資訊內容不再放到 trak 裡面,而是在每一個 moof 中。基本格式為:
aligned(8) class MovieExtendsHeaderBox extends FullBox(‘mehd’, version, 0) { if (version==1) {
unsigned int(64) fragment_duration;
} else { // version==0
unsigned int(32) fragment_duration;
}
}
3.2.2.1 Track Extends Box (trex)
trex 是 mvex 的子一級 box 用來給 fMP4 的 sample 設定預設值。基本內容為
aligned(8) class TrackExtendsBox extends FullBox(‘trex’, 0, 0){
unsigned int(32) track_ID;
unsigned int(32) default_sample_description_index;
unsigned int(32) default_sample_duration;
unsigned int(32) default_sample_size;
unsigned int(32) default_sample_flags
}
3.2.3 Track Box (trak)
trak box 就是主要存放相關 media stream 的內容。
3.2.3.1 Track Header Box (tkhd)
tkhd 是 trak box 的子一級 box 的內容。主要是用來描述該特定 trak 的相關內容資訊。其主要內容為:
- 基本格式如下:
aligned(8) class TrackHeaderBox
extends FullBox(‘tkhd’, version, flags){
if (version==1) {
unsigned int(64) creation_time;
unsigned int(64) modification_time;
unsigned int(32) track_ID;
const unsigned int(32) reserved = 0;
unsigned int(64) duration;
} else { // version==0
unsigned int(32) creation_time;
unsigned int(32) modification_time;
unsigned int(32) track_ID;
const unsigned int(32) reserved = 0;
unsigned int(32) duration;
}
const unsigned int(32)[2] reserved = 0;
template int(16) layer = 0;
template int(16) alternate_group = 0;
template int(16) volume = {if track_is_audio 0x0100 else 0}; const unsigned int(16) reserved = 0;
template int(32)[9] matrix=
{ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
// unity matrix
unsigned int(32) width;
unsigned int(32) height;
}
- 欄位說明:
欄位 | 長度 | 說明 | 預設值 |
---|---|---|---|
version | 4 | 版本 | |
creation_time | 4 | 建立時間,非必須 | 0 |
modification_time | 4 | 修改時間,非必須 | 0 |
track_ID | 4 | 指明當前描述的 track ID | 1 |
reserved | 4 | 保留 | 0 |
duration | 4 | 當前 track 內容持續的時間。通常結合 timescale 進行相關計算 | 0 |
reserved | 12 | 保留欄位 | 0 |
reserved | 2 | 保留欄位 | 0 |
alternate_group | 2 | 保留欄位 | 0 |
volume | 2 | 保留欄位 | if track_is_audio 0x0100 else 0 |
reserved | 2 | 保留欄位 | 0 |
matrix | 9 * 4 | matrix | b, 1, 0, 0, 1, 0, 0 , width , height |
3.2.3.2 Media Box (media)
mdia 主要用來包裹相關的 media 資訊。
(1) Media Header Box (mdhd)
- 基本格式如下:
aligned(8) class MediaHeaderBox extends FullBox(‘mdhd’, version, 0) { if (version==1) {
unsigned int(64) creation_time;
unsigned int(64) modification_time;
unsigned int(32) timescale;
unsigned int(64) duration;
} else { // version==0
unsigned int(32) creation_time;
unsigned int(32) modification_time;
unsigned int(32) timescale;
unsigned int(32) duration;
}
bit(1) pad = 0;
unsigned int(5)[3] language; // ISO-639-2/T language code unsigned int(16) pre_defined = 0;
}
- 欄位說明:
欄位 | 長度 | 說明 | 預設值 |
---|---|---|---|
version | 4 | 版本 | |
creation_time | 4 | 建立時間,非必須 | 0 |
modification_time | 4 | 修改時間,非必須 | 0 |
timescale | 4 | 檔案媒體在1秒時間內的刻度值,可以理解為1秒長度的時間單元數 | 無 |
duration | 4 | 當前 track 內容持續的時間。通常結合 timescale 進行相關計算 | 0 |
lanuage | 4s | 表明當前 trak 的語言。因為該欄位總長為 15bit,通常是和 pad 組合成為 2B 的長度。 | - |
(2) Handler Reference Box(hdlr)
- 基本格式如下:
aligned(8) class HandlerBox extends FullBox(‘hdlr’, version = 0, 0) {
unsigned int(32) pre_defined = 0;
unsigned int(32) handler_type;
const unsigned int(32)[3] reserved = 0;
string name;
}
- 欄位說明:
欄位 | 長度 | 說明 | 預設值 |
---|---|---|---|
version | 4 | 版本 | |
pre_defined | 4 | 版本 | 0 |
handler_type | 4 | 是代指具體 trak 的處理型別 | 0 |
reserved | 4 * 3 | reserved | 0 |
data | string | reserved | “VideoHandler” or “SoundHandler” |
- handler_type 型別如下:
vide : Video track
soun : Audio track
hint : Hint track
meta : Timed Metadata track
auxv : Auxiliary Video track
3.2.3.3 Media Information Box (minf)
minf 是子屬內容中,重要的容器 box,用來存放當前 track 的基本描述資訊。
######(1) Video Media Header Box(vmhd)
- 基本格式如下:
aligned(8) class VideoMediaHeaderBox
extends FullBox(‘vmhd’, version = 0, 1) {
template unsigned int(16) graphicsmode = 0; // copy, see below
template unsigned int(16)[3] opcolor = {0, 0, 0};
}
######(2) Sound Media Header Box(smhd)
- 基本格式如下:
aligned(8) class SoundMediaHeaderBox
extends FullBox(‘smhd’, version = 0, 0) {
template int(16) balance = 0;
const unsigned int(16) reserved = 0;
}
######(3) Data Information Box(dinf)
dinf 是用來說明在 trak 中,media 描述資訊的位置。其實本身就是一個容器,沒啥內容:
- 基本格式如下:
aligned(8) class SoundMediaHeaderBox
extends FullBox(‘smhd’, version = 0, 0) {
template int(16) balance = 0;
const unsigned int(16) reserved = 0;
}
######(4) Data Reference Box(dref)
dref 是用來設定當前Box描述資訊的 data_entry。
- 基本格式如下:
aligned(8) class DataReferenceBox
extends FullBox(‘dref’, version = 0, 0) {
unsigned int(32) entry_count;
for (i=1; i <= entry_count; i++) {
DataEntryBox(entry_version, entry_flags) data_entry; }
}