mp4文件格式解析

目录

概述

mp4文件基本信息

封装格式重要概念

重要box介绍

其他box介绍

实用技术

开源软件

参考

[1]ISO/IEC 14496-12:2015

[2]wikipedia/MPEG-4

[3]wikipedia/ISO base media file format

[4]wikipedia/MPEG-4 Part 14

[5]Tocy/多媒体文件格式之MP4

[6]Phil Cluff/What's in the box_!

[7]github.com/gpac/mp4box.js

[8]tao/Android音视频系列:视频容器操作篇 -- mp4容器打包实现

[9]LiaoJunXiong/使用gpac封装mp4

[10]Jameson Steiner/Fun with Container Formats  – Part 2

1. 概述

mp4或称MPEG-4 Part 14,是一种多媒体容器格式,扩展名为.mp4。

历史[6]:

2001年,apple的QuickTime格式,.qt和.mov的后缀名。

2001年,MPEG-4 Part1,把基于QuickTime的box布局的容器格式添加到了MPEG-4标准。

2004年,标准文档把编码和容器格式的说明分开。

MPEG-4 Part12,定义了容器格式通用的box结构,即ISO媒体文件格式(ISO base media file format, ISOBMFF)

MPEG-4 Part14,基于Part12进行了细化,定义了用于存储MPEG-4内容的容器格式,即.mp4格式。

图1 MP4 File Format.png

以下是各标准文档的链接:

QuickTime:QuickTime/QTFF

MPEG-4 Part12:ISO/IEC 14496-12:2015

MPEG-4 Part14:ISO/IEC 14496-14:2018,官网上这部分是付费的。

MP4文件由许多box组成,每个box包含不同的信息, 这些box以树形结构的方式组织。以下是主要box的简要说明:

图2 主要box说明

根节点之下,主要包含三个节点:ftyp、moov、mdat。

ftyp:文件类型。描述遵从的规范的版本。

moov box:媒体的metadata信息。

mdat:具体的媒体数据。

说明:在 mp4 中默认写入字节序是 Big-Endian的。

2. mp4文件基本信息

分析mp4文件的工具:

mp4box.js:一个在线解析mp4的工具。

bento4:包含mp4dump、mp4edit、mp4encrypt等工具。

MP4Box:类似于bento4,包含很全面的工具。

mp4info.exe: windows平台图形界面展示mp4基本信息的工具。

下图为使用mp4info.exe打开mp4文件的界面:

图3 mp4info.PNG

mp4文件基本信息

audio信息:

smplrate:sample rate(采样率)。

channel:通道个数。

bitrate:比特率。

audiosamplenum:音频sample的个数。

video信息:

width、height:视频的宽/高。

bitrate:比特率(码率),秒为单位。等于视频总的大小/时长。

frames:视频帧数。

fps:帧率(frame per second)。

total_time:时间长度,ms为单位。等于duration/timescale。

timescale:时间的粒度,1000表示1000个单位为1s。

duration:时间粒度的个数。

videosamplenum:视频sample的个数。

3. 封装格式重要概念

3.1 box

mp4文件由若干个box组成。下面是box结构的一个示意图。

图4 mp4_box.png

box由header和body组成,header指明box的size和type。size是包含box header的整个box的大小。

box type,通常是4个ASCII码的字符如“ftyp”、“moov”等,这些box type都是已经预定义好的,表示固定的含义。如果是“uuid”,表示该box为用户自定义扩展类型,如果box type是未定义的,应该将其忽略。

如果header中的size为1,则表示box长度需要更多的bits位来描述,在后面会有一个64bits位的largesize用来描述box的长度。如果size为0,表示该box为文件的最后一个box,文件结尾(同样只存在于“mdat”类型的box中)。

box中可以包含box,这种box称为container box。

box分为两种,Box和Fullbox。FullBox 是 Box 的扩展,Header 中增加了version 和 flags字段,分别定义如下:

aligned(8)classBox(unsignedint(32)boxtype,optionalunsignedint(8)[16]extended_type){unsignedint(32)size;unsignedint(32)type=boxtype;if(size==1){unsignedint(64)largesize;}elseif(size==0){// box extends to end of file}if(boxtype==‘uuid’){unsignedint(8)[16]usertype=extended_type;}}

FullBox有version和flags字段,

aligned(8)classFullBox(unsignedint(32)boxtype,unsignedint(8)v,bit(24)f)extendsBox(boxtype){unsignedint(8)version=v;bit(24)flags=f;}

3.2 track

一些sample的集合,对于媒体数据来说,track表示一个视频或者音频序列。

3.3 sample

video sample即为一帧或者一组连续视频帧,audio sample即为一段连续的音频。

3.4. sample table

指明sample时序和物理布局的表。

3.5. chunk

一个track的几个sample组成的单元。

mp4文件中,媒体内容在moov的box中。一个moov包含多个track。每个track就是一个随时间变化的媒体序列,track里的每个时间单位是一个sample,sample按照时间顺序排列。注意,一帧音频可以分解成多个音频sample,所以音频一般用sample作为单位,而不用帧。

4. 重要box介绍

4.1 Sample Table Box(stbl)

“stbl”是mp4文件中最复杂的一个box了,也是解开mp4文件格式的主干。

stbl :sample table是一个container box。

语法:

classSampleTableBoxextendsBox(‘stbl’){}

其子box包括:

stsd:sample description box,样本的描述信息。

stts:time to sample box,sample解码时间的压缩表。

ctts:composition time to sample box,sample的CTS与DTS的时间差的压缩表。

stss:sync sample box,针对视频,关键帧的序号。

stsz/stz2:sample size box,每个sample的字节大小。

stsc:sample to chunk box,sample-chunk映射表。

stco/co64:chunk offset box,chunk在文件中的偏移。

sample是媒体数据存储的单位,存储在media的chunk中,chunk和sample的长度均可互不相同,如下图所示。

图5 sample.jpg

4.2 Sample Description Box(stsd)

存储了编码类型和初始化解码器需要的信息。

有与特定的track-type相关的信息,相同的track-type也会存在不同信息的情况如使用不一样的编码标准。

语法:

classSampleDescriptionBox(unsignedint(32)handler_type)extendsFullBox('stsd',0,0){int i;unsignedint(32)entry_count;for(i=1;i<=entry_count;i++){switch(handler_type){case‘soun’:// for audio tracksAudioSampleEntry();break;case‘vide’:// for video tracksVisualSampleEntry();break;case‘hint’:// Hint trackHintSampleEntry();break;case‘meta’:// Metadata trackMetadataSampleEntry();break;}}}}

主要字段说明:

entry count:entry的个数。

handler_type:类型信息如“vide”、“soud”等,不同类型会提供不同的信息。

对于audio track,使用“AudioSampleEntry”类型信息。

abstract class SampleEntry(unsignedint(32)format)extendsBox(format){constunsignedint(8)[6]reserved=0;unsignedint(16)data_reference_index;}classAudioSampleEntry(codingname)extends SampleEntry(codingname){constunsignedint(32)[2]reserved=0;templateunsignedint(16)channelcount=2;templateunsignedint(16)samplesize=16;unsignedint(16)pre_defined=0;constunsignedint(16)reserved=0;templateunsignedint(32)samplerate={defaultsamplerate of media}<<16;}

format:视频或者音频的编码格式。

比如aac音频的format值为mp4a。

AVC-1/H.264视频的format值为avc1。

data_reference_index:利用这个索引可以检索与当前sample description关联的数据。数据引用存储在data reference box。

channelcount:通道个数。

samplesize:采样位数。默认是16比特。

samplerate:采样率。[16.16]格式的数据。

对于video track,使用“VisualSampleEntry”类型信息。

classVisualSampleEntry(codingname)extends SampleEntry(codingname){unsignedint(16)pre_defined=0;constunsignedint(16)reserved=0;unsignedint(32)[3]pre_defined=0;unsignedint(16)width;unsignedint(16)height;templateunsignedint(32)horizresolution=0x00480000;// 72 dpitemplateunsignedint(32)vertresolution=0x00480000;// 72 dpiconstunsignedint(32)reserved=0;templateunsignedint(16)frame_count=1;string[32]compressorname;templateunsignedint(16)depth=0x0018;int(16)pre_defined=-1;// other boxes from derived specificationsCleanApertureBox clap;// optionalPixelAspectRatioBox pasp;// optional}

width、height:像素宽高。

horizresolution、vertresolution:每英寸的像素值(dpi),[16.16]格式的数据。

frame_count:每个sample中的视频帧数,默认是1。可以是一个sample中有多帧数据。

4.3 Decoding Time to Sample Box(stts)

包含了一个压缩版本的表,通过这个表可以从解码时间映射到sample序号。表中的每一项是连续相同的编码时间增量(Decode Delta)的个数和编码时间增量。通过把时间增量累加就可以建立一个完整的time to sample表。

以下是Decoding Timing和Decode delta关系的一个图示:

图6 STTS_sample.PNG

DT(decoding time):编码时间。

CT(composition time):创作时间。

Decode Delta:编码时间增量。

Composition offset:显示时间同解码时间的差值,等于CT - DT。

计算方式:

DT(n+1)=DT(n)+STTS(n)whereSTTS(n)注:这里的STTS(n)是未压缩的DecodeDelta表。DT(i)=SUM(forj=0to i-1ofdelta(j))

语法:

classTimeToSampleBoxextendsFullBox(’stts’,version=0,0){unsignedint(32)entry_count;inti;for(i=0;i<entry_count;i++){unsignedint(32)sample_count;unsignedint(32)sample_delta;}}

重要字段说明:

entry_count:表中条目的个数。

sample_count: 连续相同时间长度的sample个数。

sample_delta:以timescale为单位的时间长度。

4.4 composition time to sample box(ctts)

这个box提供了decoding time到composition time的offset的表,用于计算pts。

这个表在Decoding time和composition time不一样的情况下时必须的。

如果box的version等于0,decoding time必须小于等于composition time,因而差值用一个无符号的数字表示。

有以下公式:

注:CTTS(n)是未压缩的表的第n个sample对应的offset。

语法:

classCompositionOffsetBoxextendsFullBox(‘ctts’,version=0,0){unsignedint(32)entry_count;inti;if(version==0){for(i=0;i<entry_count;i++){unsignedint(32)sample_count;unsignedint(32)sample_offset;}}elseif(version==1){for(i=0;i<entry_count;i++){unsignedint(32)sample_count;signedint(32)sample_offset;}}}

主要字段说明:

sample_count:连续相同的offset的个数。

sample_offset:CT和DT之间的offset。

4.5 sync sample box(stss)

它包含media中的关键帧的sample表。如果此表不存在,说明每一个sample都是一个关键帧。

语法:

classSyncSampleBoxextendsFullBox(‘stss’,version=0,0){unsignedint(32)entry_count;int i;for(i=0;i<entry_count;i++){unsignedint(32)sample_number;}}

主要字段说明:

sample_number:媒体流中同步sample的序号。

4.6 Sample Size Box(stsz/stz2)

包含sample的数量和每个sample的字节大小,这个box相对来说体积比较大的。

语法:

classSampleSizeBoxextendsFullBox(‘stsz’,version=0,0){unsignedint(32)sample_size;unsignedint(32)sample_count;if(sample_size==0){for(i=1;i<=sample_count;i++){unsignedint(32)entry_size;}}}

主要字段说明:

sample_size:指定默认的sample字节大小,如果所有sample的大小不一样,这个字段为0。

sample_count:track中sample的数量。

entry_size:每个sample的字节大小。

Compact Sample SizeBox(stz2):一种压缩的sample大小存储方式。

classCompactSampleSizeBoxextendsFullBox(‘stz2’,version=0,0){unsignedint(24)reserved=0;unisgnedint(8)field_size;unsignedint(32)sample_count;for(i=1;i<=sample_count;i++){unsignedint(field_size)entry_size;}}

field_size:指定表中条目的比特大小,取值为4、8或16。

(1) 如果使用值4,则每个字节存储两个sample的大小:

entry[i] << 4 + entry[i + 1]。

(2) 如果大小没有填充满整数个字节,则用最后一个字节未使用部分填充0。

sample_count是一个整数,它给出了下表中的条目数。

entry_size是一个整数,它指定一个sample的大小,并根据其编号进行索引。

4.7 Sample To Chunk Box(stsc)

media中的sample被分为组成chunk。chunk可以有不同的大小,chunk内的sample可以有不同的大小。

通过stsc中的sample-chunk映射表可以找到包含指定sample的chunk,从而找到这个sample。结构相同的chunk可以聚集在一起形成一个entry,这个entry就是stsc映射表的表项。

语法:

classSampleToChunkBoxextendsFullBox(‘stsc’,version=0,0){unsignedint(32)entry_count;for(i=1;i<=entry_count;i++){unsignedint(32)first_chunk;unsignedint(32)samples_per_chunk;unsignedint(32)sample_description_index;}}

主要字段说明:

first_chunk:一组chunk的第一个chunk的序号。

chunk的编号从1开始。

samples_per_chunk:每个chunk有多少个sample。

sample_desc_idx:stsd 中sample desc信息的索引。

把一组相同结构的chunk放在一起进行管理,是为了压缩文件大小。

mp4box.js查看的stsc box的信息如下:

image.png

第一组chunk的first_chunk序号为1,每个chunk的sample个数为1,因为第二组chunk的first_chunk序号为2,可知第一组chunk中只有一个chunk。

第二组chunk的first_chunk序号为2,每个chunk的sample个数为2,因为第三组chunk的first_chunk序号为24,可知第二组chunk中有22个chunk,有44个sample。

4.8 Chunk Offset Box(stco/co64)

Chunk Offset表存储了每个chunk在文件中的位置,这样就可以直接在文件中找到媒体数据,而不用解析box。

需要注意的是一旦前面的box有了任何改变,这张表都要重新建立。

语法:

classChunkOffsetBoxextendsFullBox(‘stco’,version=0,0){unsignedint(32)entry_count;for(i=1;i<=entry_count;i++){unsignedint(32)chunk_offset;}}

主要字段说明:

chunk_offset:chunk在文件中的位置。

stco 有两种形式,如果你的视频过大的话,就有可能造成 chunkoffset 超过 32bit 的限制。所以,这里针对大 Video 额外创建了一个 co64 的 Box。它的功效等价于 stco,也是用来表示 sample 在 mdat box 中的位置。只是,里面 chunk_offset 是 64bit 的。

aligned(8)classChunkLargeOffsetBoxextendsFullBox(‘co64’,version=0,0){unsignedint(32)entry_count;for(i=1;i<=entry_count;i++){unsignedint(64)chunk_offset;}}

5. 其他box介绍

以下是ISO/IEC 14496-12:2015文档给出的box的描述图:

box.png

5.1 File Type Box(ftyp)

File Type Box一般在文件的开头,用来指示该 mp4文件使用的标准规范。为了早期规范版本兼容,允许不包含ftyp box。

语法:

classFileTypeBoxextendsBox(‘ftyp’){unsignedint(32)major_brand;// is a brand identifierunsignedint(32)minor_version;// is an informative integer for the minor version of the major brandunsignedint(32)compatible_brands[];//is a list, to the end of the box, of brands}

没有ftyp box的文件应该处理成ftyp的major_brand为'mp41',minor_version为0,compatible_brands只包含一个'mp41'。

5.2 Movie Box(moov)

Movie Box包含了文件媒体的metadata信息,“moov”是一个container box,具体内容信息在其子box中。一般情况下,“moov”会紧随着“ftyp”。

“moov”中包含1个“mvhd”和若干个“trak”。其中“mvhd”是header box,一般作为“moov”的第一个子box出现。“trak”包含了一个track的相关信息,是一个container box。

语法:

classMovieBoxextendsBox(‘moov’){}

5.3 Movie Header Box(mvhd)

语法:

class MovieHeaderBox extendsFullBox(‘mvhd’,version,0){if(version==1){unsignedint(64)creation_time;unsignedint(64)modification_time;unsignedint(32)timescale;unsignedint(64)duration;}else{// version==0unsignedint(32)creation_time;unsignedint(32)modification_time;unsignedint(32)timescale;unsignedint(32)duration;}templateint(32)rate=0x00010000;// typically 1.0templateint(16)volume=0x0100;// typically, full volumeconstbit(16)reserved=0;constunsignedint(32)[2]reserved=0;templateint(32)[9]matrix={0x00010000,0,0,0,0x00010000,0,0,0,0x40000000};// Unity matrixbit(32)[6]pre_defined=0;unsignedint(32)next_track_ID;}

主要字段含义:

version : box版本,0或1,一般为0。

creation time : 创建时间(相对于UTC时间1904-01-01零点的秒数)。

modification time : 修改时间 。

timescale : 文件媒体在1秒时间内的刻度值,可理解为1秒长度的时间单元数。

duration : 该track的时间长度,用duration和time scale值可以计算track时长,比如audio track的time scale = 8000, duration = 560128,时长为70.016,video track的time scale = 600, duration = 42000,时长为70。

rate : 推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,该值为1.0(0x00010000)表示正常前向播放。

volume : 推荐播放音量,[8.8] 格式,1.0(0x0100)表示最大音量。

5.4 Track Box(trak)

Track Box是一个container box,其子box包含了该track的媒体数据引用和描述(hint track除外)。一个mp4文件可以包含多个track,且至少有一个track,track之间是独立,有自己的时间和空间信息。“trak”必须包含一个“tkhd”和一个“mdia”,此外还有很多可选的box。其中“tkhd”为track header box,“mdia”为media box,该box是一个包含一些track媒体数据信息box的container box。

语法:

classTrackBoxextendsBox(‘trak’){}

5.5 Track Header Box(tkhd)

语法:

class TrackHeaderBox    extendsFullBox(‘tkhd’,version,flags){if(version==1){unsignedint(64)creation_time;unsignedint(64)modification_time;unsignedint(32)track_ID;constunsignedint(32)reserved=0;unsignedint(64)duration;}else{// version==0unsignedint(32)creation_time;unsignedint(32)modification_time;unsignedint(32)track_ID;constunsignedint(32)reserved=0;unsignedint(32)duration;}constunsignedint(32)[2]reserved=0;templateint(16)layer=0;templateint(16)alternate_group=0;templateint(16)volume={iftrack_is_audio0x0100else0};constunsignedint(16)reserved=0;templateint(32)[9]matrix={0x00010000,0,0,0,0x00010000,0,0,0,0x40000000};// unity matrixunsignedint(32)width;unsignedint(32)height;}

主要字段含义:

version : box版本,0或1,一般为0。

flags : 24-bit整数,按位或操作结果值,预定义的值(0x000001 ,track_enabled,表示track是有效的)、(0x000002,track_in_movie,表示该track在播放中被使用)、(0x000004,track_in_preview,表示track在预览时被使用。

track id : track id号,不能重复且不能为0。

duration : track的时间长度,计量单位timescale在mvhd中。

volume : [8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0。

width : 宽,[16.16] 格式值。

height : 高,[16.16] 格式值,不必与sample的像素尺寸一致,用于播放时的展示宽高。

5.6 Media Box(mdia)

Media Box也是个container box。

语法:

classMediaBoxextendsBox(‘mdia’){}

其子box的结构和种类还是比较复杂的。

“mdia”定义了track媒体类型以及sample数据,描述sample信息。

一个“mdia”必须包含如下容器:

一个Media Header Atom(mdhd)

一个Handler Reference(hdlr)

一个media information(minf)和User Data

下面依次看一下这几个box的结构。

5.7 Media Header Box(mdhd)

mdhd 和 tkhd ,内容大致都是一样的。不过tkhd 通常是对指定的 track 设定相关属性和内容。而 mdhd 是针对于独立的 media 来设置的。不过两者一般都是一样的。

语法:

class MediaHeaderBox extendsFullBox(‘mdhd’,version,0){if(version==1){unsignedint(64)creation_time;unsignedint(64)modification_time;unsignedint(32)timescale;unsignedint(64)duration;}else{// version==0unsignedint(32)creation_time;unsignedint(32)modification_time;unsignedint(32)timescale;unsignedint(32)duration;}bit(1)pad=0;unsignedint(5)[3]language;// ISO-639-2/T language codeunsignedint(16)pre_defined=0;}

主要字段含义:

version: box版本,0或1,一般为0。

timescale: 同mvhd中的timescale。

duration: track的时间长度。

language: 媒体语言码。最高位为0,后面15位为3个字符(见ISO 639-2/T标准中定义)。

5.8 Handler Reference Box(hdlr)

“hdlr”解释了媒体的播放过程信息,该box也可以被包含在meta box(meta)中。

语法:

classHandlerBoxextendsFullBox(‘hdlr’,version=0,0){unsignedint(32)pre_defined=0;unsignedint(32)handler_type;constunsignedint(32)[3]reserved=0;string name;}

主要字段含义:

handler type: 在media box中,该值为4个字符,会有以下取值:

‘vide’ Video track‘soun’ Audio track‘hint’ Hint track‘meta’ Timed Metadata track‘auxv’ Auxiliary Video track

name:  human-readable name for the track

type,以‘\0’结尾的 UTF-8 字符串。用于调试后者检查的目的。

5.9 Media Information Box(minf)

重要的容器 box,“minf”存储了解释track媒体数据的handler-specific信息,media handler用这些信息将媒体时间映射到媒体数据并进行处理。“minf”是一个container box,其实际内容由子box说明。

语法:

classMediaInformationBoxextendsBox(‘minf’){}

“minf”中的信息格式和内容与媒体类型以及解释媒体数据的media handler密切相关,其他media handler不知道如何解释这些信息。

一般情况下,“minf”包含一个header box,一个“dinf”和一个“stbl”,其中,header box根据track type(即media handler type)分为“vmhd”、“smhd”、“hmhd”和“nmhd”,“dinf”为data information box,“stbl”为sample table box。下面分别介绍。

5.10 Media Information Header Box(vmhd、smhd、hmhd、nmhd)

vmhd、smhd这两个box在解析时,非不可或缺的(有时候得看播放器),缺了的话,有可能会被认为格式不正确。

Video Media Header Box(vmhd)

语法:

classVideoMediaHeaderBoxextendsFullBox(‘vmhd’,version=0,1){template unsignedint(16)graphicsmode=0;// copy, see belowtemplate unsignedint(16)[3]opcolor={0,0,0};}

主要字段含义:

graphics mode:视频合成模式,为0时拷贝原始图像,否则与opcolor进行合成。

opcolor: 一组(red,green,blue),graphics modes使用。

Sound Media Header Box(smhd)

语法:

classSoundMediaHeaderBoxextendsFullBox(‘smhd’,version=0,0){templateint(16)balance=0;constunsignedint(16)reserved=0;}

主要字段含义:

balance:立体声平衡,[8.8] 格式值,一般为0表示中间,-1.0表示全部左声道,1.0表示全部右声道。

Hint Media Header Box(hmhd)

Null Media Header Box(nmhd)

非视音频媒体使用该box。

5.11 Data Information Box(dinf)

“dinf”解释如何定位媒体信息,是一个container box。

语法:

classDataInformationBoxextendsBox(‘dinf’){}

“dinf”一般包含一个“dref”(data reference box)。

“dref”下会包含若干个“url”或“urn”,这些box组成一个表,用来定位track数据。简单的说,track可以被分成若干段,每一段都可以根据“url”或“urn”指向的地址来获取数据,sample描述中会用这些片段的序号将这些片段组成一个完整的track。一般情况下,当数据被完全包含在文件中时,“url”或“urn”中的定位字符串是空的。

“dref”的语法:

classDataEntryUrlBox(bit(24)flags)extendsFullBox(‘url ’,version=0,flags){string location;}classDataEntryUrnBox(bit(24)flags)extendsFullBox(‘urn ’,version=0,flags){string name;string location;}classDataReferenceBoxextendsFullBox(‘dref’,version=0,0){unsignedint(32)entry_count;for(i=1;i<=entry_count;i++){DataEntryBox(entry_version,entry_flags)data_entry;}}

主要字段含义:

entry count:“url”或“urn”表的元素个数。

entry_version:entry格式的版本。

entry_flags:当“url”或“urn”的box flag为1时,表示数据在该文件的Moov

Box中。

“url”或“urn”都是box,“url”的内容为location字符串,“urn”的内容为名称字符串和location字符串。

6. 实用技术

6.1 moov移到mdat前面

ffmpeg默认情况下生成moov是在mdat写完成之后再写入,所以moov是在mdat的后面,使用faststart参数可以将moov移到mdat前面。

./ffmpeg-i demo.flv-ccopyoutput.mp4

moov在mdat后面

image.png

使用faststart参数

ffmpeg -i out.flv -c copy -movflags faststart out2.mp4

moov在mdat前面

image.png

6.2 如何实现seek

stbl.png

例如,我们需要seek到30s。

需要做如下工作:

使用timescale将目标时间标准化。timescale为90000,30*90000=2700000。

通过time-to-sample box找到指定track的给定时间之前的第一个sample number。2700000/3000 = 900。

通过sync sample table查询sample number之前的第一个sync sample。对应为795的sample。

通过sample-to-chunk table查找到对应的chunk number。

对应的chunk号假设是400。

通过chunk offset box查找到对应chunk在文件中的起始偏移量。第14个chunk的offset是3481072。

最后使用sample-to-chunk box和sample size box的信息计算出该chunk中需要读取的sample在文件中的起始偏移量,即完成seek。

7. 开源软件

gpac:开源的多媒体工具包,包括用于MP4打包的mp4box等。

mp4v2:提供了API来创建和修改mp4文件。

注意:window下用Binary Viewer查看二进制文件

链接:https://www.jianshu.com/p/529c3729f357

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容