相关动态
Android音视频系列:视频容器操作篇 -- mp4容器打包实现
2024-11-10 23:12

经过视频编码后的帧数据,需要放到视频容器里,才能成为一个常规的视频文件。我们以mp4容器为例子,聊一聊代码层面上帧数据如何放到mp4容器里。

Android音视频系列:视频容器操作篇 -- mp4容器打包实现

一个友好的mp4视频结构,如下图,ftyp是基本信息,moov是头部信息,mdat是帧数据。moov在mdat前面,支持流媒体边下边播。

开源代码库mp4v2,作为mp4容器操作工具,是如何实现帧数据的容器打包的呢?

下面是mp4标准定义的box结构。

在mp4v2里,用MP4Atom对象定义一个box。虚拟出root box,是MP4RootAtom对象,继承自MP4Atom。

MP4RootAtom

MP4AtomArray是MP4Atom组成的动态数组,动态指数组长度可以动态增长。

函数调用经历以下流程:

一、

----- MP4Create(pFileName, 0);

1. 创建m_pRootAtom1. 创建m_pRootAtom

MP4Atom::CreateAtom()第3个形参是const char* type,取NULL,就意味着创建MP4RootAtom。

Generate()会主动创建它的第一个孩子,moov atom。现在是这样子的:

2. 创建ftyp atom

说到这个InsertChildAtom()就很牛逼了,它把ftyp atom插入child atom array的0位置,已有的元素并不会被覆盖,而是偏移。

现在是这样子的:

3. 创建mdat atom

add_ftyp是为1的,mdat atom被插入child atom array的1位置。现在成了这样子:

4. 创建free atom,并把ftyp atom和free atom写入文件。

MP4RootAtom::BeginWrite()做了这个事情。

注意最后一行,往文件里写mdat的序曲正式拉开了。

二、

---- MP4AddH264VideoTrack()

---- MP4AddH264SequenceParameterSet()

---- MP4AddH264PictureParameterSet()

---- MP4WriteSample()

5. pps, sps, nal数据,都会写到mdat里。

三、

---- MP4Close()

6. 核心数据mdat写完了,会写上moov和free。

MP4RootAtom:FinishWrite()做了这个事情。

于是乎我们得到了这样的视频:

可以看到,现在视频的结构里,有两个问题,一是存在冗余的free box,一是moov在mdat后面。

四、

---- MP4Optimize()

提供了Optimize()接口,可以做到把上面的视频转变为:

7. 读入文件的所有一级atom

8. 写入ftyp和moov

MP4RootAtom::BeginOptimalWrite()做了这个事情:

最后一行开始写mdat。

9. 写入mdat

至此,moov调整到了mdat前面,一个友好的mp4结构就打包完成了。

回头思考一下,既然moov需要在mdat前面,那么为什么mp4v2打包的过程,要反过来把moov写在mdat之后呢?

因为在mdat写完之前,moov的长度是不确定的。所以为了不影响往文件里写mdat,就把moov挪到了mdat后面,等mdat写完之后,再写入moov。

作者简介:tao, 天天P图 AND 工程师

文章后记

天天 P 图是由腾讯公司开发的业内领先的图像处理,相机美拍的 APP。欢迎扫码或搜索关注我们的微信公众号:“天天P图攻城狮”,那上面将陆续公开分享我们的技术实践,期待一起交流学习!

    以上就是本篇文章【Android音视频系列:视频容器操作篇 -- mp4容器打包实现】的全部内容了,欢迎阅览 ! 文章地址:http://dh99988.xhstdz.com/quote/71384.html 
     栏目首页      相关文章      动态      同类文章      热门文章      网站地图      返回首页 物流园资讯移动站 http://dh99988.xhstdz.com/mobile/ , 查看更多   
发表评论
0评