mp4封装格式各box类型讲解及IBP帧计算

作者 —— 靑い空゛ 出处:http://www.cnblogs.com/ailumiyana/

音视频流媒体高级开发教程

MP4文件封装格式,对应的标准为ISO/IEC 14496-12,即信息技术 视听对象编码的第12部分 ISO 基本媒体文件格式(Information technology Coding of audio-visual objects Part 12: ISO base media file format)

box

如果从整体上看,mp4所有的数据全部存放在 一个叫box的结构中。
box,顾名思义,可以简单的理解为一个箱子里面可以放任何符合大小的东西,也可以继续放箱子,箱子里面再放东西,这种箱子里面仍然放箱子的箱子称为容器箱子(container box) 你可以想象你要搬家,把你的家具全部放在一个个的箱子里面,然后一个大箱子把小箱子一个个再装箱。MP4中的 moov box 就是一种容器箱子。
在这里插入图片描述
在这里插入图片描述
box的字节序为网络字节序,也就是大端字节序(Big-Endian)Box由header和body组成,其中header统一指明box的大小和类型,body根据类型有不同的意义和作用。

在这里插入图片描述
在这里插入图片描述

box size 有三种可能:

1、通常的box开头的4个字节(32位)为box size,该大小包括box header和box body整个box的大小,这样我们就可以在文件中定位各个box。

2、如果 box size为1,则表示这个box的大小为large size(“mdat”类型)。

3、如果box size为0,表示该box为文件的最后一个box,文件结尾即为该box结尾。(同样只存在于“mdat”类型的box中。)

size后面紧跟的32位为box type,一般是4个字符,如“ftyp”、“moov”等,这些box type都是已经预定义好的,分别表示固定的意义。如果是“uuid”,表示该box为用户扩展类型,如果box type是未定义的,应该将其忽略。

14496-12标准中box的都有这些类型,这张表,也能从整体上了解完各类型box的说明:
在这里插入图片描述

MP4文件分析工具。

两个在线的MP4 分析工具,下面内容全部以此工具来分析一份demo
online-mp4-parser
online-mp4-parser-2

可以看到这份标准的mp4视频根路径上有四个box – ftypmoovuuidmdat
ftyp 指定了文件类型
moov 保存了音视频数据的时空间信息
mdat 存放音视频数据

下面依赖工具简单依次分析一份普通mp4文件

ftyp box

该box有且只有1个,并且只能被包含在文件层,而不能被其他box包含。该box应该被放在文件的最开始,指示该MP4文件应用的相关信息。

“ftyp” body依次包括1个32位的major brand(4个字符),1个32位的minor version(整数)和1个以32位(4个字符)为单位元素的数组compatible brands。这些都是用来指示文件应用级别的信息。
在这里插入图片描述

moov box

moov box 是一个 container box 该box包含了文件媒体的元数据信息,具体内容信息由子box诠释。同File Type Box一样,该box有且只有一个,且只被包含在文件层。一般情况下,“moov”会紧随“ftyp”出现。

可以看到这个demo 中有 mvhd、trak、udta 三种 box 一般情况下 “moov”中会包含1个“mvhd”和若干个“trak”。其中“mvhd”为header box,一般作为“moov”的第一个子box出现。“trak”包含了一条音、视频轨/流/track的相关信息,也是一个container box。

该box是解析MP4文件里面最重要的一个box,它包含了音视频数据的编码格式、音视频数据样本,chunks的大小、存储位置也即偏移offset、时间戳单位、DTS,CTS(PTS),解码时间、显示时间等等…

moov box中记录的每帧音视频数据位置信息,实际上都在mdat box中,通过解析moov box来获取到每帧音视频数据具体位置后,使得播放器能方便的拖拉进度条。

mvhd box (Movie Header Box)

mvhd 描述了与具体音频或视频流无关的文件整体信息,其中的duration/timescale的值即为单位为秒的媒体时长。
在这里插入图片描述

trak box (Track Box)

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

tkhd(track header box)

tkhd 描述的该track的,如果是视频会有宽、高信息、 还有文件创建时间、修改时间等。
在这里插入图片描述

mdia (Track Media Structure)

mdia box 描述了这条音视频轨/流(trak)的媒体数据样本的主要信息,对播放器来说是一个很重要的box…

mdhd (Media Header Box)

当前音/视频轨/流(trak)的总体信息, 该box中有duration字段和timescale字段,duration/timescale的值即为当前流的时长。

hdlr box用来指定该流的类型
在这里插入图片描述stsd box的子box用于保存该流的编码类型

在这里插入图片描述
avcC box指定了该流的编码类型为H264,储了解码所需的SPS、PPS信息。

stsc stsz stco三个box用于保存每帧视频或音频数据在文件中的保存位置。

stts stss ctts三个box用于保存媒体数据和时间戳的对应关系。

在同级的stbl的样本表box里面可以查到对应的样本 描述信息(stsd),时序信息(stts),样本的大小信息(stsz),样本到chunk的映射信息(stsc),chunk的位置信息(stco)等等

下面计算下PTS,来了解stbl box…

PTS和DTS的计算

I P B 帧的概念

在音视频中,为了提高压缩效率,会将每帧画面压缩为不同类型的视频帧数据。
I帧表示关键帧,包含有一帧画面的完整信息,解码时只需要本帧数据就可以解码出完整的一帧画面。
P帧表示前向参考帧,它保存了本帧与上一帧的差异信息,它不能单独解码,需要根据上一帧的画面加上本帧保存的差值来获取本帧的完整画面。
B帧为双向参考帧,它解码时需要依赖它之前和之后的帧来获取最终的画面
因为B帧需要依赖它后面的帧来进行解码,所以它的解码顺序就必然和显示顺序不能保持一致,这时就需要解码时间戳(DTS)和显示时间戳(PTS)来共同决定一帧视频数据何时解码,然后何时显示了。

举个例子
一小段视频帧序列如下 :
type : I — B — B — P — B — B — P
PTS : 0.33 0.67 1.00 1.33 1.67 2.00 2.33
DTS : 0.00 0.67 1.00 0.33 1.67 2.00 1.33

PTS >= DTS

根据mp4 stts和ctts 可以得到DTS和PTS

stts(Decoding Time to Sample Box)

在这里插入图片描述
stts 可以计算出每个sample的dts,其中sample_delta为该sample的dts相对于上一个smaple的差值,
那么此样本数据的dts为 :

0   1000 2000 3000 4000 ···

ctts(Composition Time to Sample Box)

Composition Time 构成时间目前我直接理解的PTS。。
在这里插入图片描述
ctts 有每个sample的构成时间(Composition Time)和解码时间(DTS)之间的差值(CTTS)即图中的composition_offset。
如果不存在ctts,则代表该流不存在B帧,那么PTS就直接等于DTS。

timescale

最后就是关于单位,你可以看到图中样本的单位都是以1000为单位浮动,实际上真实DTS和PTS时间是需要除以mdia/mdhd中的timescale。这里是30000。

有了这些,我们就可以在ctts里面计算出pts了 :

 else if (box_type_equa(uint32_to_str(bh.type, sbuffer), "ctts")) {
        uint32_t version = 0;
        read_net_bytes_to_host_uint32(&box[8], &version);
        if(version != 0) {
            LOG_E("ctts unsupport version :%d ", version)
            return;
        }

        uint32_t entry_cnt = 0;
        read_net_bytes_to_host_uint32(&box[12], &entry_cnt);
        char buf[128] = {0};
        tree_childs_insert_with_val(tree, "version", uint32_to_ascii(version, buf));
        tree_childs_insert_with_val(tree, "entry_cnt", uint32_to_ascii(entry_cnt, buf));
        
        uint32_t i = 0, j = 0, num = 0, pos = 16;
        for (i = 0; i < entry_cnt; i++) {
            uint32_t sample_cnt;
            read_net_bytes_to_host_uint32(&box[pos], &sample_cnt);
            pos += 4;
        
            uint32_t sample_offset;
            read_net_bytes_to_host_uint32(&box[pos], &sample_offset);
            pos += 4;

            for (j = 0; j < sample_cnt; j++) {
                PushBack_Array(pts_array, At_Array(dts_array, num++) + sample_offset);
                float dt, pt = 0.0;
                printf("dts : %9.3f ms | pts : %9.3f ms | \n", At_Array(dts_array, num - 1) / (mdhd_time_scale * 1.0), At_Array(pts_array, num - 1) / (mdhd_time_scale * 1.0));
            }

stss (Sync Sample Box)

stss 里面存放了关键帧的序号(I帧),跳转时,需要从关键帧开始解码,否则会花屏。
在这里插入图片描述

stsz (Sample Size Boxes):

顾名思义,样本大小
在这里插入图片描述

stsc (Sample To Chunk Box):

媒体数据的样本是被打包进chunks(块)的,chunks和样本(samples)的大小不固定,该box用于说明chunks关联样本的信息。

first_chunk 该入口第一个chunks的索引(index).
samples_per_chunk 样本数量/chunks.

在这里插入图片描述

stco (Chunk Offset Box)

描述每个chunks相对文件的偏移量。
在这里插入图片描述
如图 第一个chunks即前10个样本(此例), samples.1起始地址为 423257, samples.1的地址则为 423257 + 140798 = 564055, 依此类推…

有了这些即可计算出音视频的时间和空间信息了
在这里插入图片描述

mdat box

Meida Data Box 媒体数据box 位于顶层,定义是一个字节数组,用来存储媒体数据。该box数量可以为0个,也可以有多个(当媒体数据全部为外部文件引用时),数据直接跟在box type字段后面,具体数据结构的意义需要参考metadata(主要在sample table中描述)。
在这里插入图片描述
参考 : ISO/IEC 14496-12:2015规范

整理了一些学习书籍、视频资料(Linux C/C++后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全学习资料、教学视频和学习路线图),有需要的可以自行添加学习交流群:739729163 领取哦!!!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/153403.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最新版仿东郊到家小程序源码 上门服务小程序源码

最新版仿东郊到家小程序源码 上门服务小程序源码 1、数据概况&#xff08;新增业务城市用户投票功能&#xff0c;更加直观的查看业务城市的关注度、人气和影响力,促进业务开展&#xff09; 2、数据概况 &#xff08;增加可视化数据大盘&#xff0c;代理商端可查看自己下面的技…

【java学习—十五】线程的同步与死锁(5)

文章目录 1. 多线程产生的问题2. Synchronized 的使用方法3. 线程的死锁问题 1. 多线程产生的问题 问题&#xff1a; 同一个账户&#xff0c;支付宝转账&#xff0c;微信转账。两个手机&#xff0c;一个手机开支付宝&#xff0c;另一个手机开微信。假设账户上有3000元&#xff…

OCC教学:拓扑

拓扑&#xff1a;1.介绍 几何限制 OCCT 曲面支持矩形修剪。布尔运算后可能会出现非矩形域。 如何存储剪切操作的结果&#xff1f; 拓扑的目的 一般来说&#xff0c;拓扑是描述对象局限性的一种手段。 OCC拓扑被用于用于描述&#xff1a; 物体的边界&#xff1b;对象之…

Mars3d-vue最简项目模板集成使用Mars3d的UI控件样板

备注说明&#xff1a; 1.小白可看步骤一二&#xff0c;进阶小白可直接看步骤三 步骤一&#xff1a;新建文件夹<uitest>&#xff0c;在mars3d仓库拉一份最简项目模板&#xff1a; git clone mars3d-vue-template: Vue3.x 技术栈下的Mars3D项目模板 步骤二&#xff1a;运…

01_SHELL编程之变量定义(一)

SHELL编程 该课程主要包括以下内容&#xff1a; ① Shell的基本语法结构 如&#xff1a;变量定义、条件判断、循环语句(for、until、while)、分支语句、函数和数组等&#xff1b; ② 基本正则表达式的运用&#xff1b; ③ 文件处理三剑客&#xff1a;grep、sed、awk工具的使用&…

最好用的Python库推荐总结,每一个都用处很大!

文章目录 分词 - jieba词云库 - wordcloud可视化进度条 - tpdm优美的表格 - PrettyTable多进程 - multiprocessing多线程 - threading谷歌翻译 - googletrans重复回调 - retrying游戏开发 - pygame绘图教程 - turtle数据分析 - pandas算法加密 - pycryto操作 win 电脑 - pywin3…

2—10岁女童羽绒服,黑色长款也太好看了吧

冬天怎么能没有一件暖呼呼的羽绒服呢&#xff1f; 黑色长款羽绒服也赞了吧 大长款连帽&#xff0c;防风保暖设计 时尚与美观度都兼具呢&#xff01;好穿又耐穿&#xff01;

qt定时器的使用

在QWidget中进行声明

大数据毕业设计之前端01:我的前端之路

初遇前端 初次接触前端还是2016年&#xff0c;那一年暑假心血来潮&#xff0c;在网易云课堂上学着前端三剑客&#xff08;html、js、css&#xff09;。18年毕业&#xff0c;把用各色水笔手写的花花绿绿笔记寄回家里&#xff0c;投身奔赴后端与大数据开发的征程。 遥记18年的毕…

关于hadoop报错ERROR: Cannot set priority of namenode process与jps仅有自身的某类解决办法

运行start-sh.all发现了如图的问题 也是搞了很久搜了很多教程&#xff0c;发现很多人并不是大毛病而是很多小细节出了错误。 首先检查如下hadoop-env.sh &#xff0c;core-site.xml &#xff0c;hdfs-site.xml &#xff0c;mapred-site.xml &#xff0c;yarn-site.xml 内容是…

flutter 绘制右上角圆角三角形标签

绘制&#xff1a; import package:jade/utils/JadeColors.dart; import package:flutter/material.dart; import dart:math as math;class LabelTopRightYellow extends StatefulWidget {final String labelTitle; // 只能两个字的&#xff08;文字偏移量没有根据文字长度改变…

要在伦敦银技术分析史上留名 这可能吗?

在学习伦敦银投资的时候&#xff0c;我们都很羡慕那些以人的名字命名的交易工具或者策略&#xff0c;例如布林带、帝纳波利点位、加特利形态、艾略特波浪理论等等。投资者也有一个希望&#xff0c;就是开发属于自己的交易策略或者工具&#xff0c;这并不是不可能的&#xff0c;…

C 语言指针和数组

C 语言指针和数组 在本教程中&#xff0c;您将了解C语言编程中数组与指针之间的关系。您还将学习使用指针访问数组元素。 在了解数组与指针之间的关系之前&#xff0c;请确保检查以下两个主体&#xff1a; [C 数组](C 语言数组-CSDN博客)[C 指针](C 语言指针-CSDN博客) 数组…

springboot327基于Java的医院急诊系统

交流学习&#xff1a; 更多项目&#xff1a; 全网最全的Java成品项目列表 https://docs.qq.com/doc/DUXdsVlhIdVlsemdX 演示 项目功能演示&#xff1a; ————————————————

解决编译时提示“没有那个文件或目录 #include <pcap.h>”的问题

解决编译时提示“没有那个文件或目录 #include 当你在编译代码时遇到“没有那个文件或目录 #include <pcap.h>”的错误提示&#xff0c;这通常意味着编译器在你的系统路径中找不到 pcap.h 头文件。pcap.h 是网络流量捕获库 pcap 的头文件&#xff0c;用于在 C/C 程序中捕…

高效能人士的七个习惯

今天小编给大家推荐最近读的一本书&#xff0c;史蒂芬柯维的《高效能人士的七个习惯》&#xff0c;分别是积极主动、以始为终、要事第一、双赢思维、知己解彼、综合高效及不断更新。 一、个人领域&#xff1a;从依赖到独立 习惯一&#xff1a;积极主动——个人愿景的原则付诸行…

哪种猫罐头比较好?推荐给新手养猫的5款好口碑猫罐头!

新手养猫很容易陷入疯狂购买的模式&#xff0c;但有些品牌真的不能乱买&#xff01;现在的大环境不太好&#xff0c;我们需要学会控制自己的消费欲望&#xff0c;把钱花在刀刃上&#xff01;哪种猫罐头比较好&#xff1f;现在宠物市场真的很内卷&#xff0c;很多品牌都在比拼产…

雷达模糊函数及MATLAB仿真

文章目录 前言一、雷达模糊函数二、Matlab 仿真1、单脉冲模糊函数①、MATLAB 源码②、仿真结果1&#xff09;不确定函数三维图2&#xff09;不确定函数的等高图3&#xff09;模糊函数的三维图4&#xff09;模糊函数的等高图 2、单脉冲多普勒频率轴上的切面①、MATLAB 源码②、仿…

nvm安装详细教程(卸载旧的nodejs,安装nvm、node、npm、cnpm、yarn及环境变量配置)

文章目录 一、完全卸载旧的nodejs1、打开系统的控制面板&#xff0c;点击卸载程序&#xff0c;卸载nodejs&#xff08;1&#xff09;打开系统的控制面板&#xff0c;点击程序下的卸载程序&#xff08;2&#xff09;找到node.js&#xff0c;鼠标右击出现下拉框&#xff0c;点卸载…

11月编程语言排行榜出炉:C#超越Java已成定局!

TIOBE最新的编程语言排行榜刚刚出炉了&#xff0c;本月Java依然大幅下跌3.63%&#xff0c;C#本月上涨3.4%&#xff0c;C#和Java仅相差0.7%。 就像网友评论说的&#xff1a;Java成于互联网的兴起&#xff0c;败于互联网的衰落。 一直以来我也都是从事互联网行业、主要是电商行业…