首页 > 音视频技术 > mp4文件elst研究
2016
06-16

mp4文件elst研究

elst也就是Edit List Box,不是所有的mp4文件有这个box,作用是使某个track的时间戳产生偏移。

结构

在ISO_IEC_14496-12中,elst结构如下:
mp4文件elst研究 - 第1张  | Jianchihu
segment_duration:表示该edit段的时长,以Movie Header Box(mvhd)中的timescale为单位。
media_time:表示该edit段的起始时间,以track中Media Header Box(mdhd)中的timescale为单位。如果值为-1,表示是空edit,一个track中最后一个edit不能为空。
media_rate:edit段的速率为0的话,edit段相当于一个”dwell”,即画面停止。画面会在media_time点上停止segment_duration时间。否则这个值始终为1。

例子

现在我们手里有个mp4文件,我们要让封装的视频延迟10秒才开始显示,封装的音频不变,这个可以通过修改视频的时间戳实现,将视频的所有时间戳都加上10秒,但是一个个改太麻烦了,此时elst就派上用场了,我们要通过它让视频时间戳偏移10秒。

首先我们先动手操作番,了解elst如何起作用。

1)找一个没有elst box的mp4文件:test.mp4,假设我放在D:\\bin目录下。至于mp4有没有包含elst可以用文章末尾链接提供的mp4分析工具Mp4Reader分析下。用mediainfo查看该视频的信息:
mp4文件elst研究 - 第2张  | Jianchihu
该mp4音视频时长都为3分32秒。

2)得到带elst的mp4。到https://gpac.wp.mines-telecom.fr/mp4box/ 下载windows下的mp4box,按提示一步步安装。
打开windows cmd命令行,cd到test.mp4目录,然后敲入Mp4Box的命令:

得到:
mp4文件elst研究 - 第3张  | Jianchihu
由此可知test.mp4中,视频的track id 为1,音频track id为2。

3)接着我们敲如下命令:

由于我们只对视频操作,视频track id是1,所以是#1:delay=10000。得到:
mp4文件elst研究 - 第4张  | Jianchihu
此时在bin目录下会生成一个delay_10s.mp4,该mp4中视频track延迟了10秒,音频track不变。mediainfo查看delay_10s.mp4信息:
mp4文件elst研究 - 第5张  | Jianchihu
可以看到视频的时长多了10秒

4)打开mp4reader查看视频track的elst信息:
mp4文件elst研究 - 第6张  | Jianchihu
也就是:

可以看到有两个elst entry,第一个为空,Segment-duration为6000,由于timescale为600(该timescale在mvhd中获
得),6000除以timescale刚好为10秒。由此可知我们要延迟播放某个track,可以在elst中插入一个空的entry,Segment-duration设置为需要延迟播放的时间,Media-Time设置为-1,然后在插入一个entry,Segment-duration设置为正常播放时间,Media-Time也就是起始时间设置为0。

5)播放器验证。我们使用vlc播放器打开delay_10s.mp4:
mp4文件elst研究 - 第7张  | Jianchihu
前10秒视频没有播放,而声音正常播放,到第10秒时视频才开始播放,等声音播放结束后,视频还会播放10秒,可以看出视频确实是推迟了10秒播放,此时音视频已经不同步了。

不是所有的播放器都支持elst的,我测试了下,vlc与potplayer支持,windows自带播放器就不支持。

ffmpeg相关代码分析

下面结合ffmpeg中相关代码以及上面的视频延迟10秒的例子分析,看ffmpeg中对elst数据如何处理。ffmpeg中elst entry数据存放在MOVElst 结构体中:

duration对应mp4标准中的segment_duration
time对应mp4标准中的media_time

在ffmpeg代码libavformat\mov.c中的mov_build_index函数中有如下代码:

第8行代码中可以知道,如果e->time == -1,也就是第一个elst为空,此时得到empty_duration,按前面的例
子该值为10*timescale,下一个for循环得到start_time =e->time,值为0。

在第26行代码中,可知sc->time_offset =0 -10*timescale = -10timescale,然后所有dts都要减去该sc->time_offse,最后结果是都加上10timescale,与原来时间戳比相当于延迟了10s。所以当mp4存在elst时,dts要按如下计算:
1.参考上述ffmpeg代码得到time_offset
2.解码时间戳dts = sample_delta * n – time_offset,其中sample_delta在stts中获得,如果存在B帧,还要从ctts中获得sample_offset,此时:
显示时间戳pts= dts+ sample_offset
否则pts = dts。

接下来我们使用ffmpeg验证下,打印出所有viedeo packet的dts与pts:
mp4文件elst研究 - 第8张  | Jianchihu

可以看到所有时间戳都偏移了230000,也就是10timescale,在video track的mdhd中可知timescale为23000,刚好是10timescale = 23000*10:
mp4文件elst研究 - 第9张  | Jianchihu

由此可知elst的作用就是使某个track时间戳偏移,达到延迟播放的效果。在我们解析mp4文件时,如果存在elst,一定要解析,然后配合stts与ctts,这样才可以得到正确的时间戳。

相关下载

Mp4Reader:http://jchblog.u.qiniudn.com/software/MP4Reader_v0.9.0.6.zip

最后编辑:
作者:Jianchihu
管理员——低调做事,低调做人

留下一个回复

你的email不会被公开。

This site uses Akismet to reduce spam. Learn how your comment data is processed.