03 如何做音视频的封装与转码?
你好,我是刘歧。今天我们来讲讲做视频转码时需要具备的知识。
我们平时看视频、拍视频,还有传输视频的时候,经常出现播放不了,报错的情况。这主要是因为我们拿到的文件格式有很多不同的种类,比如RMVB、AVI、WMV、MP4、FLV等,而里面的视频编码格式也有很多种,比如Mpeg-4,所以播放器既要能够解析出对应的文件格式,又要能够对文件中的音视频流进行解码,只要有一个不支持就会导致视频播放出错。这个时候我们就需要给视频做一下转码。
视频转码主要涉及编码压缩算法(Encoding)、格式封装操作(Muxing)、数据传输(例如RTMP、RTP)、格式解封装(Demuxing)、解码解压缩算法(Decoding)几方面的操作。这些操作需要一个共识的协定,所以通常音视频技术都会有固定的参考标准,如封装格式标准、编解码操作标准、传输协议标准等等。
标准中没有写明的,通常兼容性不会太好。例如FLV参考标准协议中没有定义可以存储H.265视频压缩数据,如果我们自己将H.265的视频数据存储到FLV容器中,其他播放器不一定能够很好地播放这个视频。所以在我们将视频流、音频流写入到一个封装容器中之前,需要先弄清楚这个容器是否支持我们当前的视频流、音频流数据。
如果你对音视频编解码、视频封装、MP4格式几方面的知识比较了解的话,那么解决这些问题就会游刃有余了,所以这节课我们来学习一下这几个知识点。
音视频编解码
我们先来看音视频编码方面的基础知识。就像前面两节课介绍的,音频的PCM数据、视频的YUV和RGB的图像数据直接存储或者通过带宽传输会比较消耗空间,那么为了节省存储,或者确保占用的带宽更少一些,就需要把音频、视频的数据压缩一下。
音频是连续的采样序列,而视频则是连续的图像序列,这些序列是有前后关系的,为了方便理解,我们用图像来举例,看上去会更直观一些。
我们有一个6帧的连续视频图像,每一帧都是宽100、高100的画幅,在每一帧的正中央都有一个字母在变化。遇到这种情况时,如果我们每一帧图像全都做传输或存储操作的话,占用的带宽或空间都会很大。
为了节省空间,我们可以来分析一下图像的规律。因为这6帧图像大范围是相同的,只有正中心的一小部分内容是变化的,所以我们分析后可以得到结论,刷新第一帧图像后,从第二帧开始,我们只要刷新正中心字母区域的内容即可。这个叫局部更新,只需要逐步更新A、B、C、D、E、F的区域就可以了,这样在传输内容的时候既节省带宽,又能在存储内容的时候节省画幅的数据存储空间。
而我们在看视频的时候可不仅仅是内容的更新,还涉及内容位置的运动等变化,所以视频内容更新的算法会更复杂一些。在做视频压缩的时候,就拿前面的这个例子来说,需要有一个参考帧,这里参考的是第一帧,后面每一帧都参考前面一帧做了局部更新。而我们的视频图像序列不能只做局部更新,因为里面的目标对象还会运动,所以我们不仅可以前向做参考,还有可以做双向参考的技术。在这个过程中就涉及了图像的类型,通常我们遇到的是这三类帧:I帧、P帧和B帧。
其中I帧作为关键帧,仅由帧内预测的宏块组成。而P帧代表预测帧,通过使用已经编码的帧进行运动估计,B帧则可以参考自己前后出现的帧。如果比较IBP帧包所占空间大小的话,通常是I帧>P帧>B帧,所以适当地增加B帧可以减少视频流占用的带宽或者存储空间。我们可以看一下,I、P、B帧在视频解码显示时的顺序。
从这个示意图里,我们可以看出,解码顺序是1423756,但是显示顺序却是1234。当编码中存在B帧的时候,因为解码需要双向参考帧,所以需要多缓存几帧作为参考数据,从而也就带来了一定的显示延迟。所以在实时直播场景下,参考标准中推荐的做法通常是不带B帧。
在视频编码时,因为图像的画面以及图像中对象运动的复杂程度比较高,为了保证清晰度,运动的图像组中通常也会包含更多的图像运动参考信息,所以压缩难度也提升了很多,压缩后的视频码率也就变得比常规图像更高一些,这个码率的波动通常时高时低,具有可变性,我们一般称之为可变码率(VBR)。
而在有些直播场景下,因为一个传输信号通道中会携带多条流,为了确保多条流在同一个信号通道中互不干扰,一般会要求编码时采用恒定码率的方式(CBR)。但是如果采用CBR的话,画质往往会有一些损耗,这也就是为什么我们现在在一些老式的电视直播场景中看到的画质偶尔会变得很差,比如交通广播电视场景。
视频封装
我们平时经常会听到有人说自己的视频是MP4格式的,有些人也会说自己的音乐格式是M4A,这些都是什么意思呢?
其实我们可以粗略地认为他们说的是封装格式,也就是常说的容器格式。在容器格式的内部会存储音频、视频的数据,这些数据我们可以称之为视频流、音频流。音视频流在容器中的存储形式有两种,既可以交错式存储,也可以是不同类型的流单独存储在自己的连续区域。
我们用两张图来说明一下问题。
这两种方式都比较常见,也都各有利弊,后面我们介绍具体的封装容器格式时会做详细地说明。
音视频编码后的数据流与封装的关系如果根据上面两张图来理解可能会略微抽象,我们如果以生活中的例子来说明的话,可以这么理解音视频编码数据流与封装的关系:我们有一碗稻米,可以理解为每一粒米都是一帧视频数据,例如 H.264。我们还有一碗小米,可以理解为每一粒小米都是一个音频采样,例如 AAC。我们把稻米和小米装到一个袋子里,这一袋装有稻米和小米的整体叫做音视频封装容器格式,例如MP4、FLV。
接下来,为了方便你理解,我们以互联网中最常见的封装格式——MP4为例,来详细地讲一讲音视频封装容器格式
封装容器格式:MP4
在互联网常见的格式中,跨平台最好用的应该是MP4文件,因为MP4文件既可以在PC平台的Flashplayer中播放,又可以在移动平台的Android、iOS等平台中播放,而且使用系统默认的播放器就能播放,因此我们说MP4格式是最常见的多媒体文件格式,接下来我们就来详细地看一下MP4这种文件格式。
MP4格式标准为ISO-14496 Part 12、ISO-14496 Part 14,标准内容并不是特别多,如果要了解MP4的格式信息,我们首先要清楚几个概念:
- MP4文件由许多个Box与FullBox组成;
- 每个Box由Header和Data两部分组成;
- FullBox则是Box的扩展,在Box结构的基础上,在Header中增加8bit位version标志和24bit位的flags标志;
- Header包含了整个Box的长度的大小(Size)和类型(Type),当Size等于0时,代表这个Box是文件中的最后一个Box;当Size等于1时说明Box长度需要更多的bits位来描述,在后面会定义一个64bits位的largesize用来描述Box的长度;当Type为uuid时,说明这个Box中的数据是用户自定义扩展类型;
- Data为Box的实际数据,可以是纯数据,也可以是更多的子Box;
- 当一个Box中Data是一系列的子Box时,这个Box又可以称为Container Box。
而MP4文件中Box的组成,你可以仔细阅读一下参考标准ISO-14496 Part 12,我们这里就不再逐字解读了。但是有几个关键的Box我们需要知道。
MP4封装格式文件中,我们经常会遇到moov box与mdat box。我们存储音频与视频数据的索引信息,就是存在moov box中,音频和视频的索引信息在moov中分别存储在不同的trak里面,trak里面会保存对应的数据采样相关的索引信息,通过获得moov中的索引信息之后,根据索引信息我们才能从mdat中读取音视频数据,所以MP4文件中必不可少的是moov信息,如果缺少moov信息的话,这个点播文件将无法被成功打开。
关于MP4封装里面能否存放我们当前想存的codec,还需要查找一下参考标准或者公共约定的标准,看看是否允许存放,你可以参考MP4网站里面的表格。
我们刚才介绍视频封装的时候有提到过,音视频数据存储的时候有交错存储的方式也有音频存在一个区域,视频存在一个区域的方式。其实两种方式都比较常见,但是需要注意一个问题,我们在存储音视频数据的时候,如果是顺序读取音视频数据的话,当然就是音视频数据交错存储比较好,这样会给内存、硬盘或者网络节省很多开销。
如果音视频分开,单独存放在各自的区域的话,为了更好地做音视频同步,通常会读取一段视频帧数据,再读取一段音频采样数据,这样势必会不断跳跃式地读取硬盘中的数据,或者不断地发起网络请求,如果是http请求的话,我们会看到大量的http range请求,给网络开销与服务器并发造成很大的压力。
当我们基于网络请求播放MP4点播文件时,如果moov box存储在mdat box后面的话,播放器需要先读取到MP4文件的moov以后,才能够开始播放MP4文件,而这个读取的动作,有些播放器是选择先下载全部MP4文件,有些则是需要先解析一下mdat,跳过mdat以后再读取moov,所以为了节省播放器操作,兼容性更好,通常我们需要将moov移到MP4文件的头部,节省播放MP4文件开始时间段的开销。
这里我们需要注意的是,这个moov的生成,一般需要先写入mdat中的音视频数据,这样我们就知道数据采样存储的位置和大小,然后才能写入到moov中,所以是先写入mdat后写入moov这样一个顺序。解决办法是生成文件之后做一个后处理,也就是将moov移动到mdat前面。
小结
好了,这就是今天音视频封装与转码的相关内容,最后我们来回顾一下吧!
这节课我们对音视频编码的基础操作方式,视频封装的基本原理有了一个大致的了解,对于常见的点播视频文件MP4也有了一个基础的认识,并且了解了一些常见的MP4视频点播问题。其实,我们这节课在视频点播文件中选择去介绍MP4,主要还是因为MP4是最常用的一个,你理解起来也会更容易。当然也有一些其他的视频点播格式,在之后的课程还会涉及,例如MKV、FLV、MPEGTS等。
这里,我们只要记住一个重要的信息,在音视频技术领域,编解码、封装格式都有对应的参考标准,并且都是开放标准,我们要善于借助网上搜到的参考标准文档和详细的解析资料,如果你希望对音视频技术有更深的了解,除了学习我们这节课的基础知识外,还是需要自己动手实操,照着参考标准写一下对应的实现代码。
思考题
我们这节课讲解了MP4文件可以作为视频点播文件,那么MP4是否能够应用于直播场景中呢?怎么处理才能够支持直播?欢迎你在评论区留言与我交流,也欢迎你把这节课分享给身边需要的朋友,我们下节课再见!
- Geek_wad2tx 👍(1) 💬(1)
mp4 不能直接用于直播,因为mp4 中有一个“索引表”,是对全局视频信息的描述,直播流是一个开放式的流媒体,所以没有办法做到事先拿到所有音视频流数据。 FLV 的封装格式可以很好的支持直播流
2022-09-15 - Nue Kool 👍(1) 💬(1)
ibp帧解码顺序能细说下吗?图中的IBBPBBP不应该是1423756吗?
2022-08-02 - 破绽 👍(2) 💬(0)
讲的真好,打好基础很重要
2022-07-29 - 刘晨光 👍(1) 💬(0)
mp4不能用于直播,因为直播的特征是用户可以随时进入房间,从任一帧画面开始播放,所以直播流的特征通常为:每一个关键帧都会附带序列参数集,mp4封装格式不符合这一特征
2022-12-20 - 我的無力雙臂 👍(1) 💬(1)
moov box 和 mdat box最好给出一个示例图
2022-07-30 - ifelse 👍(0) 💬(0)
学习打卡
2023-12-21 - keepgoing 👍(0) 💬(0)
MP4能用于视频直播,只不过需要使用扩展的格式fmp4,主要因为需要支持动态的类似moov索引 flv这种支持流式解析的封装格式可以支持直播
2022-08-19