軟編碼Flv 到Mp4 容器(十一) fmp4 moof box詳解

https://github.com/332065255/flv2fmp4

代碼庫


軟編碼Flv 到Mp4 容器(一)
軟編碼Flv 到Mp4 容器(二) flv tag拆解
軟編碼Flv 到Mp4 容器(三) flv metadata tag解析
軟編碼Flv 到Mp4 容器(四) fmp4 總覽和基礎講解
軟編碼Flv 到Mp4 容器(五) fmp4 ftyp box 和moov>mvhd box詳解
軟編碼Flv 到Mp4 容器(六) fmp4 moov>trak>tkhd box 和 moov>trak>mdia>mdhd box講解
軟編碼Flv 到Mp4 容器(七) fmp4 mdia>hdlr box 和 mdia>minf> smhd 和dinf box講解
軟編碼Flv 到Mp4 容器(八) fmp4 mdia>stbl>stsd box 講解
軟編碼Flv 到Mp4 容器(九) fmp4 stts stsc stsz stco box 講解
軟編碼Flv 到Mp4 容器(十) fmp4 mvex box 講解
軟編碼Flv 到Mp4 容器(十一) fmp4 moof box詳解
軟編碼Flv 到Mp4 容器(十二) fmp4 mdat box詳解
軟編碼Flv 到Mp4 容器(十三) fmp4 生成ftyp和moov所必要的 flv數據


 - ftyp
 - moov
     - mvhd
     - trak
         - tkhd
         - mdia
             - mdhd
             - hdlr
             - minf
                 - smhd
                 - dinf
                     - dref
                         - url
                 - stbl
                     -  stsd
                         - mp4a(avc1)
                             - esds(avcC)
                     - stts
                     - stsc
                     - stsz
                     - stco


     - mvex
        -trex
 - moof
    - mfhd
    - traf
        -tfhd
        -tfdt
        -sdtp
        -trun
 - mdat

首先對應標題的box在 fmp4容器中的位置

moof是 fmp4中數據追加的box,moof 和mdat是成對出現的

moof box

Box Type: ‘moof’
Container: File
Mandatory: No
Quantity: Zero or more

定義

aligned(8) class MovieFragmentBox extends Box(‘moof’){ }

從官方定義來看,moof是一個頂級box,同時是一個容器box.
下面緊跟一個mfhd


mfhd box

Box Type: ‘mfhd’
Container: Movie Fragment Box (‘moof’)
Mandatory: Yes
Quantity: Exactly one

定義


aligned(8) class MovieFragmentHeaderBox extends FullBox(‘mfhd’, 0, 0){
   unsigned int(32)  sequence_number;
}
        var mfhd=new Uint8Array([
            0x00, 0x00, 0x00, 0x00, // 1字節版本,3字節保留位
            (sequenceNumber >>> 24) & 0xFF, // sequence_number: int32
            (sequenceNumber >>> 16) & 0xFF,
            (sequenceNumber >>> 8) & 0xFF,
            (sequenceNumber) & 0xFF
        ]);

mfhd是一個fullbox,4字節長度+4字節mfhd+1字節版本,3字節保留位+4字節的sequence_number


traf box

Box Type: ‘traf’
Container: Movie Fragment Box (‘moof’)
Mandatory: No
Quantity: Zero or more

Within the movie fragment there is a set of track fragments, zero or
more per track. The track fragments in turn contain zero or more track
runs, each of which document a contiguous run of samples for that
track. Within these structures, many fields are optional and can be
defaulted.

It is possible to add ‘empty time’ to a track using these structures,
as well as adding samples. Empty inserts can be used in audio tracks
doing silence suppression, for example.

定義

aligned(8) class TrackFragmentBox extends Box(‘traf’){ }

traf box 是一個容器box


tfhd box

Box Type: ‘tfhd’
Container: Track Fragment Box (‘traf’)
Mandatory: Yes
Quantity: Exactly one

The following flags are defined in the tf_flags:

0x000001 base-data-offset-present: indicates the presence of the
base-data-offset field. This provides an explicit anchor for the data
offsets in each track run (see below). If not provided, the base-data-
offset for the first track in the movie fragment is the position of
the first byte of the enclosing Movie Fragment Box, and for second and
subsequent track fragments, the default is the end of the data defined
by the preceding fragment. Fragments ‘inheriting’ their offset in this
way must all use the same data-reference (i.e., the data for these
tracks must be in the same file).

0x000002 sample-description-index-present: indicates the presence of
this field, which over-rides, in this fragment, the default set up in
the Track Extends Box.

0x000008 default-sample-duration-present

0x000010 default-sample-size-present

0x000020 default-sample-flags-present

0x010000 duration-is-empty: this indicates that the duration provided
in either default-sample-duration, or by the default-duration in the
Track Extends Box, is empty, i.e. that there are no samples for this
time interval. It is an error to make a presentation that has both
edit lists in the Movie Box, and empty- duration fragments.

定義

aligned(8) class TrackFragmentHeaderBox extends FullBox(‘tfhd’, 0, tf_flags){
unsigned int(32) track_ID;
// all the following are optional fields 
unsigned int(64) base_data_offset; 
unsigned int(32) sample_description_index; 
unsigned int(32) default_sample_duration; 
unsigned int(32) default_sample_size; 
unsigned int(32) default_sample_flags
}
var tfhd = new Uint8Array([
            0x00, 0x00, 0x00, 0x00, // version(0) & flags
            (trackId >>> 24) & 0xFF, // track_ID
            (trackId >>> 16) & 0xFF,
            (trackId >>> 8) & 0xFF,
            (trackId) & 0xFF
        ])

tfdt box

MP4 14496-12中沒有定義這個box,但是w3c中說這個box是必須的

tfd如果不存在,會引起decode錯誤

At least one Track Fragment Box does not contain a Track Fragment Decode Time Box (tfdt)

flv.js中對tfdt的定義(其實hls.js中也是這樣,flv.js應該是繼承自hls.js)

var tfdt = new Uint8Array([
            0x00, 0x00, 0x00, 0x00, // version(0) & flags
            (baseMediaDecodeTime >>> 24) & 0xFF, // baseMediaDecodeTime: int32
            (baseMediaDecodeTime >>> 16) & 0xFF,
            (baseMediaDecodeTime >>> 8) & 0xFF,
            (baseMediaDecodeTime) & 0xFF
        ])

baseMediaDecodeTime 回頭來補註釋

sdtp box

Box Types: ‘sdtp’
Container: Sample Table Box (‘stbl’) or Track Fragment Box (‘traf’)
Mandatory: No
Quantity: Zero or one

定義


aligned(8) class SampleDependencyTypeBox extends FullBox(‘sdtp’, version = 0, 0) { for (i=0; i < sample_count; i++){
      unsigned int(2) reserved = 0;
      unsigned int(2) sample_depends_on;
      unsigned int(2) sample_is_depended_on;
      unsigned int(2) sample_has_redundancy;
} }
static sdtp(track) {
        let samples = track.samples || [];
        let sampleCount = samples.length;
        let data = new Uint8Array(4 + sampleCount);
        // 0~4 bytes: version(0) & flags
        for (let i = 0; i < sampleCount; i++) {
            let flags = samples[i].flags;
            data[i + 4] = (flags.isLeading << 6) // is_leading: 2 (bit)
                |
                (flags.dependsOn << 4) // sample_depends_on
                |
                (flags.isDependedOn << 2) // sample_is_depended_on
                |
                (flags.hasRedundancy); // sample_has_redundancy
        }
        return MP4.box(MP4.types.sdtp, data);
    }

//這塊也會着重在後面開個章節來講

trun box

Box Type: ‘trun’
Container: Track Fragment Box (‘traf’)
Mandatory: No
Quantity: Zero or more

The following flags are defined:

0x000001 data-offset-present.

0x000004 first-sample-flags-present; this over-rides the default flags
for the first sample only. Thismakes it possible to record a group of
frames where the first is a key and the rest are difference frames,
without supplying explicit flags for every sample. If this flag and
field are used, sample-flags shall not be present.

0x000100 sample-duration-present: indicates that each sample has its
own duration, otherwise the default is used.

0x000200 sample-size-present: each sample has its own size, otherwise
the default is used.

0x000400 sample-flags-present; each sample has its own flags,
otherwise the default is used.

0x000800 sample-composition-time-offsets-present; each sample has a
composition time offset (e.g. asused for I/P/B video in MPEG).

aligned(8) class TrackRunBox extends FullBox(‘trun’, 0, tr_flags) {
   unsigned int(32)  sample_count;
   // the following are optional fields
   signed int(32) data_offset;
   unsigned int(32)  first_sample_flags;
   // all fields in the following array are optional
   {
        unsigned int(32) sample_duration;
        unsigned int(32) sample_size;
        unsigned int(32) sample_flags
        unsigned int(32) sample_composition_time_offset;
   }[ sample_count ]
}
// Track fragment run box
    static trun(track, offset) {
        let samples = track.samples || [];
        let sampleCount = samples.length;
        let dataSize = 12 + 16 * sampleCount;
        let data = new Uint8Array(dataSize);
        offset += 8 + dataSize;

        data.set([
            0x00, 0x00, 0x0F, 0x01, // version(0) & flags
            (sampleCount >>> 24) & 0xFF, // sample_count
            (sampleCount >>> 16) & 0xFF,
            (sampleCount >>> 8) & 0xFF,
            (sampleCount) & 0xFF,
            (offset >>> 24) & 0xFF, // data_offset
            (offset >>> 16) & 0xFF,
            (offset >>> 8) & 0xFF,
            (offset) & 0xFF
        ], 0);

        for (let i = 0; i < sampleCount; i++) {
            let duration = samples[i].duration;
            let size = samples[i].size;
            let flags = samples[i].flags;
            let cts = samples[i].cts;
            data.set([
                (duration >>> 24) & 0xFF, // sample_duration
                (duration >>> 16) & 0xFF,
                (duration >>> 8) & 0xFF,
                (duration) & 0xFF,
                (size >>> 24) & 0xFF, // sample_size
                (size >>> 16) & 0xFF,
                (size >>> 8) & 0xFF,
                (size) & 0xFF,
                (flags.isLeading << 2) | flags.dependsOn, // sample_flags
                (flags.isDependedOn << 6) | (flags.hasRedundancy << 4) | flags.isNonSync,
                0x00, 0x00, // sample_degradation_priority
                (cts >>> 24) & 0xFF, // sample_composition_time_offset
                (cts >>> 16) & 0xFF,
                (cts >>> 8) & 0xFF,
                (cts) & 0xFF
            ], 12 + 16 * i);
        }
        return MP4.box(MP4.types.trun, data);
    }

Mdat box

暫無

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