MP4文件stsd box的解析

簡單記錄一次MP4文件stsd box的解析過程,被解析的MP4文件stsd box信息如下:
00 00 00 B5 73 74 73 64 00 00 00 00 00 00 00 01 00 00 00 A5 61 76 63 31 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 80 01 68 00 48 00 00 00 48 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 FF FF 00 00 00 3F 61 76 63 43 01 64 00 1E FF E1 00 28 27 64 00 1E AC 13 16 C0 A0 2F F9 7F F0 13 F0 14 01 00 00 27 10 00 07 A1 20 E0 60 00 BB 80 00 2E E0 BD EF 83 E1 10 8D C0 01 00 04 28 EE 1F 2C 

首先熟悉stsd box的標準規範,參考ISO/IEC 14496-12:

stsd box(The sample description table gives detailed information about the coding type used, and any initialization information needed for that coding. 即定義了視頻/音頻解碼相關的參數,如h264的sps,pps)。stsd box的數據結構用類SampleDescriptionBox去描述。SampleDescriptionBox定義在ISO/IEC 14496-12中,如下:


aligned(8) class SampleDescriptionBox (unsigned int(32) handler_type) extends FullBox('stsd', 0, 0){
    int i ;//不算成員哦
    unsigned int(32) entry_count;//一般爲1,一個trak只有一套解碼參數
    for (i = 1 ; i u entry_count ; i++){
        switch (handler_type){
        case ‘soun’: // for audio tracks
            AudioSampleEntry();
            break;
        case ‘vide’: // for video tracks
            VisualSampleEntry();
            break;
        case ‘hint’: // Hint track
            HintSampleEntry();
            break;
        }
    }
}
SampleDescriptionBox繼承了FullBox,FullBox又繼承了Box,這裏把FullBox和Box也貼出來:

//最頂層box,所有box都直接或間接繼承Box
aligned(8) class Box (unsigned int(32) boxtype, optional unsigned int(8)[16] extended_type) {
    unsigned int(32) size;
    unsigned int(32) type = boxtype;
    if (size==1) {
        unsigned int(64) largesize;
    } else if (size==0) {
        // box extends to end of file
    }
    if (boxtype==‘uuid’) {
        unsigned int(8)[16] usertype = extended_type;
    }
}



//大部分box都會繼承FullBox,也有直接繼承Box的。
aligned(8) class FullBox(unsigned int(32) boxtype, unsigned int(8) v, bit(24) f) extends Box(boxtype) {
    unsigned int(8) version = v;
    bit(24) flags = f;
}


可知SampleDescriptionBox根據handler_type不同持有entry_count個AudioSampleEntry或VisualSampleEntry或HintSampleEntry對象。以視頻爲例,SampleDescriptionBox持有一個VisualSampleEntry,VisualSampleEntry定義如下:
//基類VisualSampleEntry
class VisualSampleEntry(codingname) extends SampleEntry (codingname){
    unsigned int(16) pre_defined = 0;
    const unsigned int(16) reserved = 0;
    unsigned int(32)[3] pre_defined = 0;
    unsigned int(16) width;//視頻寬
    unsigned int(16) height; //視頻高
    template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
    template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
    const unsigned int(32) reserved = 0;
    template unsigned int(16) frame_count = 1;
    string[32] compressorname;
    template unsigned int(16) depth = 0x0018;
    int(16) pre_defined = -1;
}


//VisualSampleEntry又繼承了SampleEntry:

//抽象接口SampleEntry
aligned(8) abstract class SampleEntry (unsigned int(32) format) extends Box(format){
    const unsigned int(8)[6] reserved = 0;
    unsigned int(16) data_reference_index;
}

VisualSampleEntry類沒有默認構造,需要傳入參數codingname,codingname由具體的VisualSampleEntry子類傳入。VisualSampleEntry只是各種編碼格式(h264,h265)視頻XXXSampleEntry基類,ISO/IEC 14496-12只定義了VisualSampleEntry這個基類,具體是哪種編碼格式則在其他文檔裏定義。如h264使用AVCSampleEntry,AVCSampleEntry繼承了VisualSampleEntry,構造時codingname爲“avc1”。AVCSampleEntry是在ISO/IEC 14496-15中定義,如下:


//具體的AVCSampleEntry子類,繼承了VisualSampleEntry,複合AVCConfigurationBox等
class AVCSampleEntry() extends VisualSampleEntry (‘avc1’){
    AVCConfigurationBox config;
    MPEG4BitRateBox (); // optional,可選
    MPEG4ExtensionDescriptorsBox (); // optional
}
其中AVCSampleEntry成員也在ISO/IEC 14496-15中定義,持有一個AVCDecoderConfigurationRecord,如下
class AVCConfigurationBox extends Box(‘avcC’) {
    AVCDecoderConfigurationRecord() AVCConfig;
}
同樣AVCDecoderConfigurationRecord也在ISO/IEC 14496-15中定義,如下
aligned(8) class AVCDecoderConfigurationRecord {
    unsigned int(8) configurationVersion = 1;
    unsigned int(8) AVCProfileIndication;
    unsigned int(8) profile_compatibility;
    unsigned int(8) AVCLevelIndication;
    bit(6) reserved = ‘111111’b;
    unsigned int(2) lengthSizeMinusOne;
    bit(3) reserved = ‘111’b;
    unsigned int(5) numOfSequenceParameterSets;//SPS數據個數
    for (i=0; i< numOfSequenceParameterSets; i++) {
        unsigned int(16) sequenceParameterSetLength ;//一個SPS數據內容長度
        bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit; //一個SPS數據內容
    }
    unsigned int(8) numOfPictureParameterSets; //PPS數據個數
    for (i=0; i< numOfPictureParameterSets; i++) {
        unsigned int(16) pictureParameterSetLength; //一個PPS數據內容長度
        bit(8*pictureParameterSetLength) pictureParameterSetNALUnit; //一個PPS數據內容
    }
    if( profile_idc == 100 || profile_idc == 110 ||
        profile_idc == 122 || profile_idc == 144 )
    {
        bit(6) reserved = ‘111111’b;
        unsigned int(2) chroma_format;
        bit(5) reserved = ‘11111’b;
        unsigned int(3) bit_depth_luma_minus8;
        bit(5) reserved = ‘11111’b;
        unsigned int(3) bit_depth_chroma_minus8;
        unsigned int(8) numOfSequenceParameterSetExt;
        for (i=0; i< numOfSequenceParameterSetExt; i++) {
            unsigned int(16) sequenceParameterSetExtLength;
            bit(8*sequenceParameterSetExtLength) sequenceParameterSetExtNALUnit;
        }
    }
}
參考以上各類的說明,結合ISO/IEC 14496-12和ISO/IEC 14496-15文檔的具體描述,相應各字節的解析結果如下:
00 00 00 B5 73 74 73 64 :box size(181字節)+boxtype("stsd")
00 00 00 00 :fullbox,verison+flag
00 00 00 01 : entry_count=1,持有一個VisualSampleEntry,如下 
00 00 00 A5 61 76 63 31 ::size(165字節)+boxtype("avc1")
00 00 00 00 00 00  :const unsigned int(8)[6] reserved = 0;
00 01  :unsigned int(16) data_reference_index;
00 00 :unsigned int(16) pre_defined = 0;
00 00 :const unsigned int(16) reserved = 0;
00 00 00 00 00 00 00 00 00 00 00 00 :unsigned int(32)[3] pre_defined = 0;
02 80 :視頻寬640,unsigned int(16) width;
01 68 :視頻高360,unsigned int(16) height;
00 48 00 00 :template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
00 48 00 00 :template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
00 00 00 00 :const unsigned int(32) reserved = 0;
00 01 :template unsigned int(16) frame_count = 1;//視頻必須爲1
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :string[32] compressorname;
00 18 :template unsigned int(16) depth = 0x0018;
FF FF :int(16) pre_defined = -1;
00 00 00 3F 61 76 63 43 : box size(63字節)+boxtype("avcC")
01 :unsigned int(8) configurationVersion = 1;
64 : Profile爲100,unsigned int(8) AVCProfileIndication;
00 : unsigned int(8) profile_compatibility;
1E : unsigned int(8) AVCLevelIndication
FF : bit(6) reserved = ‘111111’b; unsigned int(2) lengthSizeMinusOne;//讀出的每個packet的前幾字節代表數據大小,3+1字節
E1 : sps個數爲1 =1,bit(3) reserved = ‘111’b ;unsigned int(5) numOfSequenceParameterSets;
00 28 :sps長度爲40字節 。unsigned int(16) sequenceParameterSetLength ;
27 64 00 1E AC 13 16 C0 A0 2F F9 7F F0 13 F0 14 01 00 00 27 10 00 07 A1 20 E0 60 00 BB 80 00 2E E0 BD EF 83 E1 10 8D C0
:40字節的sps數據。bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;


01 :pps個數爲1. unsigned int(8) numOfPictureParameterSets;
00 04 :pps數據長度4。unsigned int(16) pictureParameterSetLength;
28 EE 1F 2C :4字節的pps數據。bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
//avcCbox數據結束。
以上沒按標準來,按AVCDecoderConfigurationRecord規定,profile_idc == 100時理應還有部分數據,但size已經到頭了



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