1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #define PRINTF_DEBUG 6 7 #define BOX_TYPE_FTYPE "ftyp" 8 #define BOX_TYPE_MOOV "m ...
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #define PRINTF_DEBUG 6 7 #define BOX_TYPE_FTYPE "ftyp" 8 #define BOX_TYPE_MOOV "moov" 9 #define BOX_TYPE_MVHD "mvhd" 10 #define BOX_TYPE_TRAK "trak" 11 #define BOX_TYPE_TKHD "tkhd" 12 #define BOX_TYPE_EDTS "edts" 13 #define BOX_TYPE_MDIA "mdia" 14 #define BOX_TYPE_MDHD "mdhd" 15 #define BOX_TYPE_HDLR "hdlr" 16 #define BOX_TYPE_MINF "minf" 17 #define BOX_TYPE_VMHD "vmhd" 18 #define BOX_TYPE_DINF "dinf" 19 #define BOX_TYPE_DREF "dref" 20 #define BOX_TYPE_STBL "stbl" 21 #define BOX_TYPE_STSD "stsd" 22 #define BOX_TYPE_STTS "stts" 23 #define BOX_TYPE_STSS "stss" 24 #define BOX_TYPE_STSC "stsc" 25 #define BOX_TYPE_STSZ "stsz" 26 #define BOX_TYPE_STCO "stco" 27 #define BOX_TYPE_UDTA "udta" 28 29 #define MAX_BOX_SIZE_LEN 4 30 #define MAX_BOX_TYPE_LEN 4 31 #define MAX_HANDLER_TYPE_LEN 4 32 #define MAX_FTYP_BRABDS_LEN 4 33 #define MAX_FTYP_BRABDS_NUM 4 34 #define MAX_STTS_ENTRY_NUM 8 35 #define MAX_STSS_ENTRY_NUM 8 36 #define MAX_STSC_ENTRY_NUM 100 37 #define MAX_STSZ_ENTRY_NUM 100 /* now parse 100 frame */ 38 #define MAX_STCO_ENTRY_NUM 100 39 #define MAX_MVHD_RESERVED_LEN 10 40 #define MAX_PRE_DEFINE_LEN 24 41 #define MAX_MATRIX_LEN 36 42 #define MAX_HDLR_NAME_LEN 100 43 44 45 typedef struct t_box_header 46 { 47 int boxSize; 48 49 unsigned char boxType[MAX_BOX_TYPE_LEN+1]; 50 51 long largeBoxSize; /* if boxSize=1 use, if boxSize=0, end of file */ 52 } T_BOX_HEADER; 53 54 /******************************************************************************************** 55 ** File Type Box (ftyp): file type, 表明文件類型 56 ** 57 -------------------------------------------------------------------------------------------- 58 ** 欄位名稱 | 長度(bytes) | 有關描述 59 -------------------------------------------------------------------------------------------- 60 ** boxsize | 4 | box的長度 61 ** boxtype | 4 | box的類型 62 ** major_brand | 4 | 63 ** minor_version | 4 | 版本號 64 ** compatible_brands | 4 * N | 本文件遵從的多種協議(ismo, iso2, mp41) 65 ********************************************************************************************/ 66 typedef struct t_box4ftyp_brand 67 { 68 unsigned char brands[MAX_FTYP_BRABDS_LEN+1]; 69 } T_BOX4FTYP_BRAN; 70 71 typedef struct t_box4ftyp 72 { 73 unsigned char major_brand[MAX_FTYP_BRABDS_LEN+1]; 74 75 int minor_version; 76 77 T_BOX4FTYP_BRAN compatible_brands[MAX_FTYP_BRABDS_NUM]; 78 } T_BOX4FTYP; 79 80 /************************************************************************************************************ 81 ** mvhd: movie header, 文件的總體信息: 時長, 創建時間等 82 ** 83 -------------------------------------------------------------------------------------------- 84 ** 欄位名稱 | 長度(bytes) | 有關描述 85 -------------------------------------------------------------------------------------------- 86 ** boxsize | 4 | box的長度 87 ** boxtype | 4 | box的類型 88 ** version | 1 | box版本,0或1,一般為0(以下位元組數均按version = 0) 89 ** flags | 3 | 90 ** creation time | 4 | 創建時間(相對於UTC時間1904 - 01 - 01零點的秒數) 91 ** modification time | 4 | 修改時間 92 ** time scale | 4 | 文件媒體在1秒時間內的刻度值,可以理解為1秒長度的時間單元數 93 ** duration | 4 | 該track的時間長度,用duration和time scale值可以計算track時長 94 ** rate | 4 | 推薦播放速率,高16位和低16位分別為小數點整數部分和小數部分,即[16.16] 格式.該值為1.0 (0x00010000) 95 ** volume | 2 | 與rate類似,[8.8] 格式,1.0(0x0100)表示最大音量 96 ** reserved | 10 | 保留位 97 ** matrix | 36 | 視頻變換矩陣 98 ** pre-defined | 24 | 99 ** next track id | 4 | 下一個track使用的id號 100 ** 101 if (version==1) 102 { 103 unsigned int(64) creation_time; 104 unsigned int(64) modification_time; 105 unsigned int(32) timescale; 106 unsigned int(64) duration; 107 } 108 else 109 { 110 unsigned int(32) creation_time; 111 unsigned int(32) modification_time; 112 unsigned int(32) timescale; 113 unsigned int(32) duration; 114 } 115 ************************************************************************************************************/ 116 typedef struct t_box4mvhd 117 { 118 int creation_time; 119 int modification_time; 120 int timescale; 121 int duration; 122 float rate; 123 float volume; 124 int next_track_id; 125 } T_BOX4MVHD; 126 127 /************************************************************************************************************ 128 ** tkhd: track header, track的總體信息, 如時長, 寬高等 129 ** 130 ------------------------------------------------------------------------------------------------------------- 131 ** 欄位名稱 | 長度(bytes) | 有關描述 132 ------------------------------------------------------------------------------------------------------------- 133 ** boxsize | 4 | box的長度 134 ** boxtype | 4 | box的類型 135 ** version | 1 | box版本,0或1,一般為0。(以下位元組數均按version = 0) 136 ** flags | 3 | 按位或操作結果值,預定義如下; 137 0x000001 track_enabled,否則該track不被播放; 138 0x000002 track_in_movie,表示該track在播放中被引用; 139 0x000004 track_in_preview,表示該track在預覽時被引用。 140 一般該值為7,如果一個媒體所有track均未設置track_in_movie和track_in_preview,將被理解為所有track均設置了這兩項; 141 對於hint track,該值為0; 142 ** creation_time | 4 | 創建時間(相對於UTC時間1904 - 01 - 01零點的秒數) 143 ** modification_time | 4 | 修改時間 144 ** track_id | 4 | id號 不能重覆且不能為0 145 ** reserved | 4 | 保留位 146 ** duration | 4 | track的時間長度 147 ** reserved | 8 | 保留位 148 ** layer | 2 | 視頻層,預設為0,值小的在上層 149 ** alternate_group | 2 | track分組信息,預設為0表示該track未與其他track有群組關係 150 ** volume | 2 | [8.8] 格式,如果為音頻track,1.0(0x0100)表示最大音量;否則為0 151 ** reserved | 2 | 保留位 152 ** matrix | 36 | 視頻變換矩陣 153 ** width | 4 | 寬 154 ** height | 4 | 高,均為[16.16] 格式值 與sample描述中的實際畫面大小比值,用於播放時的展示寬高 155 if (version==1) 156 { 157 unsigned int(64) creation_time; 158 unsigned int(64) modification_time; 159 unsigned int(32) track_ID; 160 const unsigned int(32) reserved = 0; 161 unsigned int(64) duration; 162 } 163 else 164 { 165 unsigned int(32) creation_time; 166 unsigned int(32) modification_time; 167 unsigned int(32) track_ID; 168 const unsigned int(32) reserved = 0; 169 unsigned int(32) duration; 170 } 171 ************************************************************************************************************/ 172 typedef struct t_box4tkhd 173 { 174 int flags; 175 int creation_time; 176 int modification_time; 177 int track_id; 178 int duration; 179 int layer; 180 int alternate_group; 181 float volume; 182 float width; 183 float height; 184 } T_BOX4TKHD; 185 186 /************************************************************************************************************ 187 ** mdhd: 包含了了該track的總體信息, mdhd和tkhd 內容大致都是一樣的. 188 ** 189 ------------------------------------------------------------------------------------------------------------- 190 ** 欄位名稱 | 長度(bytes) | 有關描述 191 ------------------------------------------------------------------------------------------------------------- 192 ** boxsize | 4 | box的長度 193 ** boxtype | 4 | box的類型 194 ** version | 1 | box版本0或1 一般為0 (以下位元組數均按version=0) 195 ** flags | 3 | 196 ** creation_time | 4 | 創建時間(相對於UTC時間1904 - 01 - 01零點的秒數) 197 ** modification_time | 4 | 修改時間 198 ** time_scale | 4 | 199 ** duration | 4 | track的時間長度 200 ** language | 2 | 媒體語言碼,最高位為0 後面15位為3個字元[見ISO 639-2/T標準中定義] 201 ** pre-defined | 2 | 保留位 202 203 ** tkhd通常是對指定的track設定相關屬性和內容, 而mdhd是針對於獨立的media來設置的, 一般情況下二者相同. 204 ************************************************************************************************************/ 205 typedef struct t_box4mdhd 206 { 207 int creation_time; 208 int modification_time; 209 int timescale; 210 int duration; 211 short language; 212 } T_BOX4MDHD; 213 214 /************************************************************************************************************ 215 ** hdlr: Handler Reference Box, 媒體的播放過程信息, 該box也可以被包含在meta box(meta)中 216 ** 217 ------------------------------------------------------------------------------------------------------------- 218 ** 欄位名稱 | 長度(bytes) | 有關描述 219 ------------------------------------------------------------------------------------------------------------- 220 ** boxsize | 4 | box的長度 221 ** boxtype | 4 | box的類型 222 ** version | 1 | box版本0或1 一般為0 (以下位元組數均按version=0) 223 ** flags | 3 | 224 ** pre-defined | 4 | 225 ** handler type | 4 | 在media box中,該值為4個字元 226 "vide"— video track 227 "soun"— audio track 228 "hint"— hint track 229 ** reserved | 12 | 230 ** name | 不定 | track type name,以‘\0’結尾的字元串 231 ************************************************************************************************************/ 232 typedef struct t_box4hdlr 233 { 234 unsigned char handler_type[MAX_HANDLER_TYPE_LEN+1]; 235 unsigned char name[MAX_HDLR_NAME_LEN+1]; 236 } T_BOX4HDLR; 237 238 /************************************************************************************************************ 239 ** vmhd: Video Media Header Box 240 ** 241 ------------------------------------------------------------------------------------------------------------- 242 ** 欄位名稱 | 長度(bytes) | 有關描述 243 ------------------------------------------------------------------------------------------------------------- 244 ** boxsize | 4 | box的長度 245 ** boxtype | 4 | box的類型 246 ** version | 1 | box版本0或1 一般為0 (以下位元組數均按version=0) 247 ** flags | 3 | 248 ** graphics_mode | 4 | 視頻合成模式,為0時拷貝原始圖像,否則與opcolor進行合成 249 ** opcolor | 2 ×3 | {red,green,blue} 250 251 "vide"—vmhd 視頻 252 "soun"— smhd 音頻 253 "hint"—hmhd 忽略 254 ************************************************************************************************************/ 255 typedef struct t_box4vmhd 256 { 257 int graphics_mode; 258 } T_BOX4VMHD; 259 260 /************************************************************************************************************ 261 ** dref: data reference box 262 ** 263 ------------------------------------------------------------------------------------------------------------- 264 ** 欄位名稱 | 長度(bytes) | 有關描述 265 ------------------------------------------------------------------------------------------------------------- 266 ** boxsize | 4 | box的長度 267 ** boxtype | 4 | box的類型 268 ** version | 1 | box版本0或1 一般為0 (以下位元組數均按version=0) 269 ** flags | 3 | 270 ** entry count | 4 | "url"或"urn"表的元素個數 271 ** "url"或"urn"列表 | 不定 | 272 273 ** "dref"下會包含若幹個"url"或"urn", 這些box組成一個表, 用來定位track數據. 簡單的說, track可以被分成若幹段, 274 每一段都可以根據"url"或"urn"指向的地址來獲取數據, sample描述中會用這些片段的序號將這些片段組成一個完整的track. 275 一般情況下, 當數據被完全包含在文件中時, "url"或"urn"中的定位字元串是空的. 276 ************************************************************************************************************/ 277 typedef struct t_box4dref 278 { 279 int entry_count; 280 } T_BOX4DREF; 281 282 /************************************************************************************************************ 283 ** stsd: Sample Description Box 284 ** 285 ------------------------------------------------------------------------------------------------------------- 286 ** 欄位名稱 | 長度(bytes) | 有關描述 287 ------------------------------------------------------------------------------------------------------------- 288 ** boxsize | 4 | box的長度 289 ** boxtype | 4 | box的類型 290 ** version | 1 | box版本0或1 一般為0 (以下位元組數均按version=0) 291 ** entry count | 4 | "url"或"urn"表的元素個數 292 293 ** box header和version欄位後會有一個entry count欄位, 根據entry的個數, 每個entry會有type信息, 如"vide", "sund"等, 294 根據type不同sample description會提供不同的信息, 例如對於video track, 會有"VisualSampleEntry"類型信息, 295 對於audio track會有"AudioSampleEntry"類型信息. 視頻的編碼類型, 寬高, 長度, 音頻的聲道, 採樣等信息都會出現在這個box中 296 ************************************************************************************************************/ 297 typedef struct t_box4stsd 298 { 299 int entry_count; 300 301 //TODO 302 } T_BOX4STSD; 303 304 /************************************************************************************************************ 305 ** stts: Time To Sample Box 306 ** 307 ------------------------------------------------------------------------------------------------------------- 308 ** 欄位名稱 | 長度(bytes) | 有關描述 309 ------------------------------------------------------------------------------------------------------------- 310 ** boxsize | 4 | box的長度 311 ** boxtype | 4 | box的類型 312 ** version | 1 | box版本,0或1,一般為0(以下位元組數均按version = 0) 313 ** flags | 3 | 314 ** entry count | 4 | sample_count和sample_delta的個數 315 ** sample_count | 4 | 316 ** sample_delta | 4 | 317 318 ** "stts”"存儲了sample的duration, 描述了sample時序的映射方法, 我們通過它可以找到任何時間的sample. "stts"可以 319 包含一個壓縮的表來映射時間和sample序號, 用其他的表來提供每個sample的長度和指針. 表中每個條目提供了在同一個 320 時間偏移量裡面連續的sample序號, 以及samples的偏移量. 遞增這些偏移量, 就可以建立一個完整的time to sample表. 321 322 例: 說明該視頻包含87幀數據(sample_count), 每幀包含512個採樣(sample_delta). 總共512*87=44544個採樣, 323 和我們前面mdhd box的Duration完全一致。 324 Duration/TimeScale = 44544/12288 = 3.625s, 正是我們的視頻播放長度. 325 12288/512 = 24 p/s (幀率) 326 ************************************************************************************************************/ 327 typedef struct t_box4stts_entry 328 { 329 int sample_count; 330 int sample_delta; 331 } T_BOX4STTS_ENTRY; 332 333 typedef struct t_box4stts 334 { 335 int entry_count; 336 337 T_BOX4STTS_ENTRY entrys[MAX_STTS_ENTRY_NUM]; 338 } T_BOX4STTS; 339 340 /************************************************************************************************************ 341 ** stss: Sync Sample Box 342 ** 343 ------------------------------------------------------------------------------------------------------------- 344 ** 欄位名稱 | 長度(bytes) | 有關描述 345 ------------------------------------------------------------------------------------------------------------- 346 ** boxsize | 4 | box的長度 347 ** boxtype | 4 | box的類型 348 ** version | 1 | box版本,0或1,一般為0(以下位元組數均按version = 0) 349 ** flags | 3 | 350 ** entry count | 4 | sample_num的個數 351 ** sample_num | 4 | 352 353 ** "stss"確定media中的關鍵幀. 對於壓縮媒體數據, 關鍵幀是一系列壓縮序列的開始幀, 其解壓縮時不依賴以前的幀, 354 而後續幀的解壓縮將依賴於這個關鍵幀. "stss"可以非常緊湊的標記媒體內的隨機存取點, 它包含一個sample序號表, 355 表內的每一項嚴格按照sample的序號排列, 說明瞭媒體中的哪一個sample是關鍵幀. 如果此表不存在, 說明每一個sample 356 都是一個關鍵幀, 是一個隨機存取點. 357 ************************************************************************************************************/ 358 typedef struct t_box4stss_entry 359 { 360 int sample_num; 361 } T_BOX4STSS_ENTRY; 362 363 typedef struct t_box4stss 364 { 365 int entry_count; 366 367 T_BOX4STSS_ENTRY entrys[MAX_STSS_ENTRY_NUM]; 368 } T_BOX4STSS; 369 370 /************************************************************************************************************ 371 ** stsc: Sample To Chunk Box 372 ** 373 ------------------------------------------------------------------------------------------------------------- 374 ** 欄位名稱 | 長度(bytes) | 有關描述 375 ------------------------------------------------------------------------------------------------------------- 376 ** boxsize | 4 | box的長度 377 ** boxtype | 4 | box的類型 378 ** version | 1 | box版本,0或1,一般為0(以下位元組數均按version = 0) 379 ** flags | 3 | 380 ** entry count | 4 | entry的個數 381 ** first_chunk | 4 | 382 ** samples_per_chunk | 4 | 383 ** sample_des_index | 4 | 384 385 ** 用chunk組織sample可以方便優化數據獲取, 一個thunk包含一個或多個sample. "stsc"中用一個表描述了sample與chunk的映射關係, 386 查看這張表就可以找到包含指定sample的thunk, 從而找到這個sample. 387 ************************************************************************************************************/ 388 typedef struct t_box4stsc_entry 389 { 390 int first_chunk; 391 int samples_per_chunk; 392 int sample_description_index; 393 } T_BOX4STSC_ENTRY; 394 395 typedef struct t_box4stsc 396 { 397 int entry_count; 398 399 T_BOX4STSC_ENTRY entrys[MAX_STSC_ENTRY_NUM]; 400 } T_BOX4STSC; 401 402 /************************************************************************************************************ 403 ** stsz: Sample To Chunk Box 404 ** 405 ------------------------------------------------------------------------------------------------------------- 406 ** 欄位名稱 | 長度(bytes) | 有關描述 407 ------------------------------------------------------------------------------------------------------------- 408 ** boxsize | 4 | box的長度 409 ** boxtype | 4 | box的類型 410 ** version | 1 | box版本,0或1,一般為0(以下位元組數均按version = 0) 411 ** flags | 3 | 412 ** sample_size | 4 | 413 ** sample_count | 4 | entry的個數 414 ** entry_size | 4 | 415 416 ** "stsz"定義了每個sample的大小, 包含了媒體中全部sample的數目和一張給出每個sample大小的表. 這個box相對來說體積是比較大的. 417 ************************************************************************************************************/ 418 typedef struct t_box4stsz_entry 419 { 420 int entry_size; 421 } T_BOX4STSZ_ENTRY; 422 423 typedef struct t_box4stsz 424 { 425 int sample_size; 426 int sample_count; 427 428 T_BOX4STSZ_ENTRY entrys[MAX_STSZ_ENTRY_NUM]; 429 } T_BOX4STSZ; 430 431 /************************************************************************************************************ 432 ** stco: Chunk Offset Box 433 ** 434 ------------------------------------------------------------------------------------------------------------- 435 ** 欄位名稱 | 長度(bytes) | 有關描述 436 ------------------------------------------------------------------------------------------------------------- 437 ** boxsize | 4 | box的長度 438 ** boxtype | 4 | box的類型 439 ** version | 1 | box版本,0或1,一般為0(以下位元組數均按version = 0) 440 ** flags | 3 | 441 ** entry_count | 4 | 442 ** chunk_offset | 4 | 443 444 ** "stco"定義了每個thunk在媒體流中的位置, sample的偏移可以根據其他box推算出來. 位置有兩種可能, 32位的和64位的, 445 後者對非常大的電影很有用. 在一個表中只會有一種可能, 這個位置是在整個文件中的, 而不是在任何box中的. 446 這樣做就可以直接在文件中找到媒體數據, 而不用解釋box. 需要註意的是一旦前面的box有了任何改變, 這張表都要重新建立, 因為位置信息已經改變了. 447 ************************************************************************************************************/ 448 typedef struct t_box4stco_entry 449 { 450 int chunk_offset; 451 } T_BOX4STCO_ENTRY; 452 453 typedef struct t_box4stco 454 { 455 int entry_count; 456 457 T_BOX4STCO_ENTRY entrys[MAX_STCO_ENTRY_NUM]; 458 } T_BOX4STCO; 459 460 typedef struct t_box 461 { 462 T_BOX_HEADER boxHeader; 463 464 unsigned char *boxData; 465 } T_BOX; 466 467