当前位置: 首页 > 工具软件 > boxbox > 使用案例 >

软编码Flv 到Mp4 容器(十一) fmp4 moof box详解

尹冠宇
2023-12-01

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

暂无

 类似资料: