FFmpeg之音视频编解码协议和传输流格式、时间戳和时间基、视频像素数据、音频采样数据

视频编解码协议:音频数据和音频采样数据PCM的转换;视频数据和视频像素数据YUV或者RGB的转换;编解码协议H264(视频)、AAC(音频)有软编解码和硬编解码。

在视频编解码技术定义方面有两大标准机构。一个是国际电信联盟 (ITU) 致力于电信应用,已经开发了用于低比特率视频电话的 H.26x 标准,其中包括 H.261、H.262、H.263 与 H.264;另一个是国际标准化组织 (ISO) 主要针对消费类应用,已经针对运动图像压缩定义了 MPEG 标准。MPEG 标准包括 MPEG1、MPEG2 与 MPEG4。https://blog.youkuaiyun.com/eydwyz/article/details/78497534

国际电信联盟ITU-T在完成H.263(针对视频会议之用的串流视频标准)后,与ISO/IEC机构连手合作,由两机构共同成立一个名为JVT(Joint Video Team)的联合工作小组,以MPEG-4技术为基础进行更适于视频会议(Video Conference)运用的衍生发展,联合制订了一个新的标准。 这个标准,ITU-T方面称之为H.264。但ISO/IEC的则将这个新标准归纳于MPEG系列,称为MPEG-4 Part 10(第10部分,也叫ISO/IEC 14496-10),MPEG-4 Part 10的另一个代称是MPEG-4 AVC(Advanced Video Coding,先进视频编码)。

所谓的H.264其实与MPEG-4/AVC就是同一回事,即H.264=MPEG-4 Part 10=ISO/IEC 14496-10=MPEG-4 AVC。

编码规范和封装格式多种多样,是因为它们对应的最佳码率不同:

640x272低分辨率的主要是Real Video,最佳码率在350-600Kbps,封装文件格式为RM或者RMVB,我们经常在网上下载的300M左右的电影基本都是RealVideo规范的RMVB文件;

分辨率为1024x438时,一般就开始使用Xvid编码了,码率也在800-1300Kbps不等,封装文件经常是AVI,文件体积在700MB左右;

720P的影片,我们经常下载的X264/AVC编码MKV封装文件,码率5-6MB,音频部分可以达到5.1音效,影音效果很不错,但文件体积都在4.3GB上下,一张DVD碟的容量,网上下载往往需要数天;

1080P影片经常采用的有H.264编码和VC1编码,码率30Mbps上下,体积达到22-40GB,虽然效果震撼,但是不方便网络共享。对于容量8GB左右的MP4,综合视频来源以及体积,最适合的是Xvid编码、码率在1300Kbps左右、文件体积700MB-1.4GB的AVI,以及同样码率和体积的RV40编码RMVB,还有码率350-600Kbps的RMVB。

常见封装格式和编解码器常用组合:(标注所有格式的,表示大多数的格式都可以用;下面的表格中只标注了主要格式/常用格式,还有其他比较老的格式/用的不多的格式,具体情况自行网络查询)

封装容器视频流编码格式音频流编码格式
AVIXvidMP3
AVIDivxMP3
Matroska(后缀就是MKV)Xvid(所有格式)MP3(所有格式)
Matroska(后缀就是MKV)Xvid(所有格式)AAC(所有格式)
Matroska(后缀就是MKV)H264(所有格式)AAC(所有格式)
MP4XvidMP3
MP4H264AAC
3GPH.263AAC
封装容器视频流编码格式音频流编码格式
flv H264AAC、MP3
f4vH264AAC、MP3
mov所有格式所有格式
tsMPEG-4、H264AAC
ASF所有格式所有格式
   
   
   

 

***MPEG-4(Xvid 和Divx)***

Xvid是一个开放源代码的视频编解码器。

Divx是基于MPEG4标准的编码器。有免费和收费版本。

***H265***

***H264***

h264的压缩比是最高的,主要应用于低码率下的实时在线播放。

h264文档:http://read.pudn.com/downloads147/ebook/635957/新一代视频压缩编码标准H.264.pdf

h264原理:https://www.jianshu.com/p/1b3f8187b271

H264码流结构分析:https://www.cnblogs.com/mamamia/p/8580097.htmlhttps://www.jianshu.com/p/9522c4a7818d

h264协议帧头数据解析:https://www.jianshu.com/p/e061bc1c20c8

H264中的NALU概念解析:https://blog.youkuaiyun.com/pkx1993/article/details/79974858

FFmpeg的H.264解码器源代码简单分析:https://blog.youkuaiyun.com/leixiaohua1020/article/details/45001033

数据有大小不定的nalu构成,最常见的是一个nalu存储了一帧压缩编码后的数据.H.264编解码比较复杂,要经过帧内预测、帧间预测、熵编码、环路滤波;

对于一段连续的帧图像来说,前一帧和后一帧之间的关联度和相似性很高,只记录当前帧和下一帧与当前帧之间的帧数据差,能够快速的帮助我们实现视频压缩编解码。为了方便图像之间的压缩,将原图像当前帧设置为Fn,下一帧设置为Fn-1;

对Fn进行帧内相似压缩编码,使用估计函数进行重新映射(图像还原);再利用当前帧对图和帧差信息对下一帧图片进行估计和还原。具体编码框架如下图:


在上图中,输入的帧或场Fn以宏块为单位被编码器处理。首先,按帧内或者帧间预測编码的方法进行处理。假设採用帧间预測编码,其预測值PRED是由当前片中前面已编码的參考图像经运动补偿(MC)后得到,当中參考图像用F’n-1表示。预測值PRED和当前块相减后,产生一个残差块Dn,经块变换、量化后产生一组量化后的变换系数X,再经熵编码,与解码所需的一些头信息一起组成压缩后的码流,经NAL(网络自适应层)供传输和存储用。

 

将编码器的NAL输出的H264比特流经熵解码得到量化后的一组变换系数X,再经反量化、反变换,得到残差D’n。利用从该比特流中解码出的头信息,解码器就产生一个预測块PRED,它和编码器中的原始PRED是同样的。当该解码器产生的PRED与残差D’n相加后,就得到了uF’n,再经滤波后,最后就得到滤波后的解码输出图像F’n

H264采用了独特的I帧、P帧和B帧策略来实现,连续帧之间的压缩

h264的压缩方法:H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流,以I帧开始,到下一个I帧结束。一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以编一个I帧,然后一直P帧、B帧了。当运动变化多时,可能一个序列就比较短了,比如就包含一个I帧和3、4个P帧。GOP,也就是一个序列;

1.分组:把几帧图像分为一组(GOP,也就是一个序列),为防止运动变化,帧数不宜取多。 
2.定义帧:将每组内各帧图像定义为三种类型,即I帧、B帧和P帧; 
3.预测帧:以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧; 
4.数据传输:最后将I帧数据与预测的差值信息进行存储和传输。

宏块: 在H.264中,句法元素被组织成五个层次:序列(sequence)、图像(frame/field-picture)、片(slice)、宏块(macroblock)、子块(sub-block)。https://blog.youkuaiyun.com/ivy_reny/article/details/47144121

宏块是编码处理的基本单元,通常宏块大小为16x16个像素。一个编码图像首先要划分成多个块(4x4 像素)才能进行处理,显然宏块应该由整数个块组成. 输入的帧或场Fn以宏块为单位被编码器处理。

    视频压缩中,一幅图像(picture)可以分成一帧(frame)或两场(field)。在H.264中,一幅图像可以编码为一个或多个片(slice),每个slice由宏块组成,一个宏块由一个16×16亮度像素和附加的一个8×8 Cb和一个8×8 Cr彩色像素块组成。宏块是H.264编码的基本单位,可以采用不同的编码类型。slice共有5种类型。slice的目的是为了限制误码的扩散和传输,使编码片相互间保持独立。一个slice编码之后被打包进一个NALU(NALU相当一个片),NALU除了容纳slice还可以容纳其它数据,如序列参数集SPS、PPS、SEI等。 

H.264 原始码流(又称为裸流),是有一个接一个的 NALU 组成的,而它的功能分为两层:视频编码层(VCL, Video Coding Layer)和网络提取层(NAL, Network Abstraction Layer)。
VCL数据是被压缩编码后的视频数据序列。在 VCL 数据传输或存储之前,这些编码的 VCL 数据,先被映射或封装进 NAL 单元(以下简称 NALU,Nal Unit) 中。在VCL数据要封装到NAL单元中之后,才可以用来传输或存储。
一个原始的H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成,第一部分 Start Code 用于标示这是一个NALU 单元的开始,必须是"00 00 00 01"(帧开始) 或"00 00 01"(帧中)。第二部分是对应于视频编码的 NALU 头部信息。第三部分是一个原始字节序列负荷(RBSP, Raw Byte Sequence Payload),它的基本结构是:在原始编码数据的后面填加了结尾 比特。一个 bit“1”若干比特“0”,以便字节对齐。

(1)VCL只关心编码部分,重点在于编码算法以及在特定硬件平台的实现,VCL输出的是编码后的纯视频流信息,没有任何冗余头信息。
(2)NAL关心的是VCL的输出纯视频流如何被表达和封包以利于网络传输。

做编码器的人关心的是VCL部分;做视频传输和解码播放的人关心的是NAL部分。

slice的概念:slice的目的是为了限制误码的扩散和传输,使编码片相互间保持独立。一幅图像(picture)可以分成一帧(frame)或两场(field)。在H.264中,一幅图像可以编码为一个或多个片(slice),每个slice由宏块组成。https://www.jianshu.com/p/c38506f50eb7

一帧图片经过 H.264 编码器之后,就被编码为一个或多个片(slice),而装载着这些片(slice)的载体,就是 NALU 了。一个frame是可以分割成多个Slice来编码的,而一个Slice编码之后被打包进一个NAL单元,不过NAL单元除了容纳Slice编码的码流外,还可以容纳其他数据,比如序列参数集SPS。
(1)SODB:String Of Data Bits ,最原始 的编码数据,没有任何附加数据 。
(2)RBSP:Raw Byte Sequence Payload ,在 SODB 的基础上加了rbsp_stop_ont_bit(bit 值为 1)并用 0 按字节补位对齐 。
(3)EBSP:在 RBSP 的基础上在最后一个字节前增加了防止伪起始码字节(0X03) 。
(4)NALU:Network Abstraction Layer Units,是对RBSP的封装。RTP是对NALU的封装。

  (5)关系:SODB + RBSP trailing bits = RBSP。
   NAL header(1 byte) + RBSP = NALU。

 

RBSP:封装于网络抽象单元的数据称之为原始字节序列载荷RBSP,它是NAL的基本传输单元。其中,RBSP又分为视频编码数据和控制数据。其基本结构是:在原始编码数据的后面填加了结尾比特。一个bit“1”若干比特“0”,以便字节对齐。

码流是由一个个的NAL Unit组成的,NALU是由NALU头和RBSP数据组成,RBSP可能是SPS,PPS,Slice或SEI,目前我们这里SEI不会出现,而且SPS位于第一个NALU,PPS位于第二个NALU,其他就是Slice(严谨点区分的话可以把IDR等等再分出来)了。

 

NALU头由一个字节(8bit)组成,它的语法如下:

forbidden_zero_bit:禁止位,占一个bit, 在 H.264 规范中规定了这一位必须为 0, 0表示网络传输没有出错 ,1表示语法出错。

nal_reference_bit:占两个bit,取值范围为0~3,取值越大,表示当前NAL越重要,需要优先受到保护。如果当前NAL是属于参考帧的片,或是序列参数集,或是图像参数集这些重要的单位时,本句法元素必需大于0。

nal_unit_type:占5个bit,NAL的类型,1~12由H.264使用,24~31由H.264以外的应用使用,简述如下:

0     没有定义

1-23  NAL单元  单个 NAL 单元包

1     不分区,非IDR图像的片-----0x61

2     片分区A

3     片分区B-------0x01

4     片分区C

5     IDR图像中的片段------------0x65

6     补充增强信息单元(SEI)-------0x06

7     序列参数集SPS---------0x67

8     图像参数集PPS---------0x68

9     分割符

10    序列结束符

11    码流结束符

12    填充数据

13-23 保留

24    STAP-A   单一时间的组合包

25    STAP-B   单一时间的组合包

26    MTAP16   多个时间的组合包

27    MTAP24   多个时间的组合包

28    FU-A     分片的单元

29    FU-B     分片的单元

30-31 没有定义

 

SPS PPS详解https://zhuanlan.zhihu.com/p/27896239

          I帧前面必须有SPS和PPS数据,也就是类型为7和8,类型为1表示这是一个P帧或B帧。
        SPS序列参数集: 包含的是针对一连续编码视频序列的参数,保存了一组编码视频序列(Coded video sequence)的全局参数,如标识符 seq_parameter_set_id、帧数及 POC 的约束、参考帧数目、解码图像尺寸和帧场编码模式选择标识等等。 所谓的编码视频序列即原始视频的一帧一帧的像素数据经过编码之后的结构组成的序列。而每一帧的编码后数据所依赖的参数保存于图像参数集中。https://www.jianshu.com/p/19fa110c2383
        PPS图像参数集:对应的是一个序列中某一幅图像或者某几幅图像,其参数如标识符 pic_parameter_set_id、可选的 seq_parameter_set_id、熵编码模式选择标识、片组数目、初始量化参数和去方块滤波系数调整标识等等。

各种封装格式中的NAlU有一些区别,由于NAL的语法中没有给出长度信息,实际的传输、存储系统需要增加额外的头实现各个NAL单元的定界。 
AVI文件和MPEG TS流采取的是字节流的语法格式,即在NAL单元之前增加0x00000001的同步码(即看到0x00000001,便知道到了NALU的开头),则从AVI文件或MPEG TS PES 包中读出的一个H.264视频帧以下面的形式存在: 
00 00 00 01 06 ... 00 00 00 01 67 ... 00 00 00 01 68 ... 00 00 00 01 65 ... 
SEI信息                   SPS                             PPS                          IDR                      Slice 
而对于MP4文件,NAL单元之前没有同步码,却有若干字节的长度码,来表示NAL单元的长度,这个长度码所占用的字节数由MP4文件头给出;此外,从MP4读出来的视频帧不包含PPS和SPS,这些信息位于MP4的文件头中,解析器必须在打开文件的时候就获取它们。

NALU的顺序要求 :
H.264/AVC标准对送到解码器的NAL单元顺序是有严格要求的,如果NAL单元的顺序是混乱的,必须将其重新依照规范组织后送入解码器,否则解码器不能够正确解码。 
(1)序列参数集NAL单元(nal_unit_type为7)必须在传送所有以此参数集为参考的其他NAL单元之前传送,不过允许这些NAL单元中间出现重复的序列参数集NAL单元。所谓重复的详细解释为:序列参数集NAL单元都有其专门的标识,如果两个序列参数集NAL单元的标识相同,就可以认为后一个只不过是前一个的拷贝,而非新的序列参数集。 
(2)图像参数集NAL单元(nal_unit_type为8)必须在所有以此参数集为参考的其他NAL单元之先,不过允许这些NAL单元中间出现重复的图像参数集NAL单元,这一点与上述的序列参数集NAL单元是相同的。 
(3)不同基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元在顺序上不可以相互交叉,即不允许属于某一基本编码图像的一系列片段(slice)单元和数据划分片段(data partition)单元中忽然出现另一个基本编码图像的片段(slice)单元片段和数据划分片段(data partition)单元。 
(4)参考图像的影响:如果一幅图像以另一幅图像为参考,则属于前者的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于后者的片段和数据划分片段之后,无论是基本编码图像还是冗余编码图像都必须遵守这个规则 
(5)基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于相应冗余编码图像的片段(slice)单元和数据划分片段(data partition)单元之前。 
(6)如果数据流中出现了连续的无参考基本编码图像,则图像序号小的在前面。 
(7)如 果arbitrary_slice_order_allowed_flag置为1,一个基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元的顺序是任意的,如果arbitrary_slice_order_allowed_flag置为零,则要按照片段中第一个宏块的位置来确定片段的顺序,若使用数据划分,则A类数据划分片段在B类数据划分片段之前,B类数据划分片段在C类数据划分片段之前,而且对应不同片段的数据划分片段不能相互交叉,也不能与没有数据划分的片段相互交叉。 
(8)如果存在SEI(补充增强信息) 单元的话,它必须在它所对应的基本编码图像的片段(slice)单元和数据划分片段(data partition)单元之前,并同时必须紧接在上一个基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元后边。假如SEI属于多个基本编码图像,其顺序仅以第一个基本编码图像为参照。 
(9)如果存在图像分割符的话,它必须在所有SEI 单元、基本编码图像的所有片段slice)单元和数据划分片段(data partition)单元之前,并且紧接着上一个基本编码图像那些NAL单元。 
(10)如果存在序列结束符,且序列结束符后还有图像,则该图像必须是IDR(即时解码器刷新)图像。序列结束符的位置应当在属于这个IDR图像的分割符、SEI 单元等数据之前,且紧接着前面那些图像的NAL单元。如果序列结束符后没有图像了,那么它的就在比特流中所有图像数据之后。 

 

**********************************编码协议的传输流格式*******************************************************

  • AAC音频文件(传输流)格式有ADIF和ADTS:
  • ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
  • ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。

 

H264网络传输的startcode是数据的length,不是0x00000001,网络传输都是用的大端序(高地址低字节)。NALU 有两种格式:Annex B 和 AVCC。Annex B 格式startcode以 0x 00 00 01 或 0x 00 00 00 01 开头, AVCC 格式以 NALU 的长度开头。

**************************************************************************************************

DTS、PTShttps://blog.youkuaiyun.com/ai2000ai/article/details/77367481https://www.cnblogs.com/leisure_chn/p/10584910.html

在视频流中,先到来的 B 帧无法立即解码,需要等待它依赖的后面的 I、P 帧先解码完成,这样一来播放时间与解码时间不一致了,顺序打乱了,那这些帧该如何播放呢?这时就需要我们来了解另外两个概念:DTS 和 PTS。

  • DTS(Decoding Time Stamp):即解码时间戳,这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。
  • PTS(Presentation Time Stamp):即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。

虽然 DTS、PTS 是用于指导播放端的行为,但它们是在编码的时候由编码器生成的。

当视频流中没有 B 帧时,通常 DTS 和 PTS 的顺序是一致的。但如果有 B 帧时,就回到了我们前面说的问题:解码顺序和播放顺序不一致了。

音频帧的 DTS、PTS 顺序是一致的。

DTS(解码时间戳)和PTS(显示时间戳)分别是解码器进行解码和显示帧时相对于SCR(系统参考)的时间戳。SCR可以理解为解码器应该开始从磁盘读取数据时的时间。mpeg文件中的每一个包都有一个SCR时间戳并且这个时间戳就是读取这个数据包时的系统时间。通常情况下,解码器会在它开始读取mpeg流时启动系统时钟(系统时钟的初始值是第一个数据包的SCR值,通常为0但也可以不从0开始)。

 

采集顺序指图像传感器采集原始信号得到图像帧的顺序。
编码顺序指编码器编码后图像帧的顺序。存储到磁盘的本地视频文件中图像帧的顺序与编码顺序相同。
传输顺序指编码后的流在网络中传输过程中图像帧的顺序。
解码顺序指解码器解码图像帧的顺序。
显示顺序指图像帧在显示器上显示的顺序。
采集顺序与显示顺序相同。编码顺序、传输顺序和解码顺序相同。
以图中“B[1]”帧为例进行说明,“B[1]”帧解码时需要参考“I[0]”帧和“P[3]”帧,因此“P[3]”帧必须比“B[1]”帧先解码。这就导致了解码顺序和显示顺序的不一致,后显示的帧需要先解码。

 

 时间基与时间戳的概念

在FFmpeg中,时间基(time_base)是时间戳(timestamp)的单位,时间戳值乘以时间基,可以得到实际的时刻值(以秒等为单位)。例如,如果一个视频帧的dts是40,pts是160,其time_base是1/1000秒,那么可以计算出此视频帧的解码时刻是40毫秒(40/1000),显示时刻是160毫秒(160/1000)。FFmpeg中时间戳(pts/dts)的类型是int64_t类型,把一个time_base看作一个时钟脉冲,则可把dts/pts看作时钟脉冲的计数。

三种时间基tbr、tbn和tbc

不同的封装格式具有不同的时间基。在FFmpeg处理音视频过程中的不同阶段,也会采用不同的时间基。
FFmepg中有三种时间基,命令行中tbr、tbn和tbc的打印值就是这三种时间基的倒数:
tbn:对应容器中的时间基,也是AVPacket中的时间基。值是AVStream.time_base的倒数。
tbc:对应编解码器中的时间基。值是AVCodecContext.time_base的倒数,每帧时间戳递增1,解码过程中,此参数已过时,建议直接使用帧率倒数用作时间基。
tbr:从视频流中猜测得到,可能是帧率或场率(帧率的2倍)

FFmpeg还有一个内部时间基AV_TIME_BASE(以及分数形式的AV_TIME_BASE_Q),AV_TIME_BASE及AV_TIME_BASE_Q用于FFmpeg内部函数处理,使用此时间基计算得到时间值表示的是微秒,如下:

  1. // Internal time base represented as integer

  2. #define AV_TIME_BASE 1000000

  3.  
  4. // Internal time base represented as fractional value

  5. #define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}

 在封装格式处理例程中,不深入理解时间戳也没有关系。但在编解码处理例程中,时间戳处理是很重要的一个细节,必须要搞清楚。

容器(文件层)中的时间基(AVStream.time_base)与编解码器上下文(视频层)里的时间基(AVCodecContex.time_base)不一样,解码编码过程中需要进行时间基转换。

视频按帧进行播放,所以原始视频帧时间基为 1/framerate。视频解码前需要处理输入 AVPacket 中各时间参数,将输入容器中的时间基转换为 1/framerate 时间基;视频编码后再处理输出 AVPacket 中各时间参数,将 1/framerate 时间基转换为输出容器中的时间基。(编解码中的时间基一般为帧率的倒数)

音频按采样点进行播放,所以原始音频帧时间为 1/sample_rate。音频解码前需要处理输入 AVPacket 中各时间参数,将输入容器中的时间基转换为 1/sample_rate 时间基;音频编码后再处理输出 AVPacket 中各时间参数,将 1/sample_rate 时间基转换为输出容器中的时间基。如果引入音频 FIFO,从 FIFO 从读出的音频帧时间戳信息会丢失,需要使用 1/sample_rate 时间基重新为每一个音频帧生成 pts,然后再送入编码器

编解码的时间基转换:

 
  1. 解码前的时间基转换:封装格式的时间基转换为编解码的时间基

  2.  
  3. av_packet_rescale_ts(ipacket, sctx->i_stream->time_base, sctx->o_codec_ctx->time_base);

  4.  
  5. 编码后的时间基转换:编解码的时间基转换为封装格式的时间基

  6.  
  7. av_packet_rescale_ts(&opacket, sctx->o_codec_ctx->time_base, sctx->o_stream->time_base);

  8.  

 

转封装的时间基转换:直接从一种封装格式的时间基转换到另一种封装格式的时间基;不需要流的时间基和编码的时间基转换。

 
  1. 不同封装格式具有不同的时间基,在转封装(将一种封装格式转换为另一种封装格式)过程中,时间基转换如下:

  2.  
  3. 这里是分别转换pts、dts、duration;

  4. av_read_frame(ifmt_ctx, &pkt);

  5. pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);

  6. pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);

  7. pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);

  8.  
  9. 下面的代码具有和上面代码相同的效果:

  10. 这里是一次性吧所有时间基转换;

  11. // 从输入文件中读取packet

  12. av_read_frame(ifmt_ctx, &pkt);

  13. // 将packet中的各时间值从输入流封装格式时间基转换到输出流封装格式时间基

  14. av_packet_rescale_ts(&pkt, in_stream->time_base, out_stream->time_base);

  15.  
  16. 这里流里的时间基in_stream->time_base和out_stream->time_base,是容器中的时间基

************************************************************************************************************************************************

视频像素数据:https://blog.youkuaiyun.com/mydear_11000/article/details/50404084https://www.cnblogs.com/blogs-of-lxl/p/10839053.htmlhttps://blog.youkuaiyun.com/weixin_42229404/article/details/81937646

保存了屏幕上每个点的像素值;视频像素体积很大;一个小时RGB24的视频体积计算:3600*25(帧率)*1920*1080*3(取样精度为8bit,每个像素点占3字节的数据)=559.9GB;

常见的视频像素数据类型(颜色编码方法)有RGB24、RGB32、YUV420P、YUV422P、YUV444P;最常用的是YUV420P;

Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异,而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异,此即所谓的色差信号,一般所讲的YUV大多是指YCbCr。

从摄像头采集到的数据一般都是YUV或者RGB格式(这个由摄像头决定),不管是YUV还是RGB,他们都是原始的图像数据,是没有经过压缩的。

数字媒体采样: 其实就是对媒体内容进行数字化,主要有两种方式:①时间采样,用来捕捉一个信号在一个周期内的变化.如录音时的音高和声调变化. ②空间采样: 一般用在可视化内容的数字化过程中,对一幅图片在一定分辨率下捕捉其亮度和色度。

音频采样:用麦克风把声波机械能量转换成电信号, 再通过一个编码方法(LPCM)进行数字化. 此过程中 采样或测量一个音频信号过程的周期率 被称为采样率, 采样率越高信号越完整清晰。

视频采样: 视频其实就由一系列"帧"图片组成,时间轴线上每一帧都表示一个场景. 要显示出连续的动画,其实就是在短时间间隔内提供特定数量的帧. 1s内所连续展现的帧数就称为帧率。

视频内容的存储: 我们先确定每个独立帧图片的大小,以1280x720分辨率为例,一帧像素数量约等于一百万个像素点,通常称1M . 如果对每个像素点使用8位的RGB三原色存储,一个像素就需要24位存储空间. 一帧就需要2.6MB的存储空间. 而一个帧率30FBS的一秒视频就需要79MB存储. 显然,这不合实际. 所以需要专门对其的存储和传输格式做压缩处理 .

色彩二次抽样: 实际上视频数据一般不以RGB而是以YUV颜色模式存在的. YUV使用色彩通道替换了RBG像素的亮度通道. 这样可以大幅减少存储在每个像素中的颜色信息,而不至于让图片质量严重受损.这个过程就叫色彩二次抽样.

YUV相比于RGB格式最大的好处是可以做到在保持图像质量降低不明显的前提下,减小文件大小。YUV格式之所以能够做到,是因为进行了采样操作。

YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。YUV是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。

YUV几种采样格式:https://www.cnblogs.com/cumtchw/p/10224329.html

一个宏块由一个16×16亮度像素和附加的一个8×8 Cb和一个8×8 Cr彩色像素块组成。

YUV数据的几种采样格式如下

4:4:4 这个不用解释了,这是每个像素占三个字节的内存.

4:2:2  Y0U0V0  Y1U1V1  Y2U2V2  Y3U3V3对于这四个像素,采样之后存放的码流为:Y0U0 Y1V1 Y2U2 Y3V3,占用的内存大小为4+4/2 +4/2=8

4:2:0并不意味着只有Y和U而没有V,他指的是对于每行扫描线来说,只有一种色度分量以2:1的抽样率存储,相邻的扫描行存储不同的色度分量,也就是说,如果一行是4:2:0的话,下一行就是4:0:2, 对于[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3] [Y4 U4 V4] [Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] 。采样之后存放的码流为Y0 U0 Y1 Y2 U2 Y3 Y4 V4 Y5 Y6 V6 Y7.  占用的内存是width*height*3/2.

YUV的优点之一是色度通道可以具有比Y通道更低的采样率而不会显着降低感知质量。称为A:B:C符号的符号用于描述U和V相对于Y的采样频率:

  • 4:4:4 表示没有对色度通道进行缩减采样。
  • 4:2:2 意味着2:1的水平缩减采样,没有垂直下采样。每扫描一行,每两个U或V采样包含四个Y采样。
  • 4:2:0 表示2:1水平缩减采样,2:1垂直缩减采样。
  • 4:1:1 表示4:1水平缩减采样,没有垂直下采样。每个扫描线对于每个U或V采样包含四个Y采样。4:1:1采样比其他格式少见。

               YUV 4:4:4采样,每一个Y对应一组UV分量。数据大小:Y*1+Y*1+Y*1
    YUV 4:2:2采样,每两个Y共用一组UV分量。数据大小: Y*1+Y*1/2+Y*1/2
    YUV 4:2:0采样,每四个Y共用一组UV分量。数据大小:Y*1+Y*1/4+Y*1/4

 

 

 YUV格式有两大类:packedplanar。注:planar还分平面存储和平面打包格式。

packed模式的YUV格式,每个像素点的Y,U,V是连续交错存储的。三个分量存在一个Byte型数组里;

Plane模式,即平面模式,并不是将YUV数据交错存储,而是先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,这个是平面存储格式。相邻的两个Y共用其相邻的两个Cb、Cr。先存放所有的Y分量,然后紧接着UV交错存储叫平面打包格式。Y、U、V分量分别存在三个Byte型数组中。

YUV像素格式来源于RGB像素格式,通过公式运算,YUV三分量可以还原出RGB,YUV转RGB的公式如下:

 
  1. R = Y + 1.403V

  2. G = Y - 0.344U - 0.714V

  3. B = Y + 1.770U

一般,将RGB和YUV的范围均限制在[0, 255]间,则有如下转换公式:

 
  1. R = Y + 1.403(V - 128)

  2. G = Y - 0.344(U - 128) - 0.714(V - 128)

  3. B = Y + 1.770(U - 128)

保存YUV420P格式的数据,用以下代码:output是文件名(xx.rgb或者xx.yuv),保存最终存储YUV或者RGB的数据;

 
  1.  
  2. fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height),1,output);

  3.  
  4. fwrite(pFrameYUV->data[1],(pCodecCtx->width)*(pCodecCtx->height)/4,1,output);

  5.  
  6. fwrite(pFrameYUV->data[2],(pCodecCtx->width)*(pCodecCtx->height)/4,1,output);

 

保存RGB24格式的数据,用以下代码:

fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height)*3,1,output);

保存UYVY格式的数据,用以下代码:

fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height),2,output);

YUV420P格式需要写入data[0],data[1],data[2];而RGB24,UYVY格式却仅仅是写入data[0],他们的区别到底是什么呢?经过研究发现,在FFMPEG中,图像原始数据包括两种:planar和packed。planar就是将几个分量分开存,比如YUV420中,data[0]专门存Y,data[1]专门存U,data[2]专门存V。而packed则是打包存,所有数据都存在data[0]中。具体哪个格式是planar,哪个格式是packed,可以查看pixfmt.h文件。注:有些格式名称后面是LE或BE,分别对应little-endian或big-endian。另外名字后面有P的是planar格式。

************************************************************************************************************************************************

音频编解码协议:

mp3:

*************

aac:

我们采用的是脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。

ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。

AAC原始流能让ffmpeg软解或系统硬解码,需要在ES流前面加上ADTS头,打包成ADTS的格式,一般是在AAC ES流前添加7个字节的ADTS header。

AAC音频文件的每一帧由ADTS Header和AAC Audio Data组成。https://www.cnblogs.com/zhangxuan/p/8809245.html

一般情况下ADTS的头信息是7个字节,分为2部分:

  • 抽样:对模拟信号进行周期性扫描,把时间上连续的信号变成时间上离散的信号;
  • 量化:用一组规定的电平,把瞬时抽样值用最接近的电平值来表示,通常是用二进制表示;
  • 编码:用一组二进制码组来表示每一个有固定电平的量化值;
  • 采样后的数据大小 = 采样率值×采样大小值×声道数 bps。
    一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率=44.1K×16×2 bps=1411.2 Kbps= 176.4 KB/s。

  •   AAC是高级音频编码(Advanced Audio Coding)的缩写,出现于1997年,最初是基于MPEG-2的音频编码技术。由Fraunhofer IIS、Dolby Laboratories、AT&T、Sony等公司共同开发,目的是取代MP3格式。2000年,MPEG-4标准出台,AAC重新集成了其它技术(PS,SBR),为区别于传统的MPEG-2 AAC,故含有SBR或PS特性的AAC又称为MPEG-4 AAC。

        AAC是新一代的音频有损压缩技术,它通过一些附加的编码技术(比如PS,SBR等),衍生出了LC-AAC,HE-AAC,HE-AACv2三种主要的编码,LC-AAC就是比较传统的AAC,相对而言,主要用于中高码率(>=80Kbps),HE-AAC(相当于AAC+SBR)主要用于中低码(<=80Kbps),而新近推出的HE-AACv2(相当于AAC+SBR+PS)主要用于低码率(<=48Kbps),事实上大部分编码器设成<=48Kbps自动启用PS技术,而>48Kbps就不加PS,就相当于普通的HE-AAC。

  • AAC共有9种规格,以适应不同的场合的需要:

           MPEG-2 AAC LC 低复杂度规格(Low Complexity)--比较简单,没有增益控制,但提高了

      编码效率,在中等码率的编码效率以及音质方面,都能找到平衡点

           MPEG-2 AAC Main 主规格

           MPEG-2 AAC SSR 可变采样率规格(Scaleable Sample Rate)

           MPEG-4 AAC LC 低复杂度规格(Low Complexity)------现在的手机比较常见的MP4文件中 的音频部份就包括了该规格音频文件

           MPEG-4 AAC Main 主规格 ------包含了除增益控制之外的全部功能,其音质最好

           MPEG-4 AAC SSR 可变采样率规格(Scaleable Sample Rate)

           MPEG-4 AAC LTP 长时期预测规格(Long Term Predicition)

          MPEG-4 AAC LD 低延迟规格(Low Delay)

          MPEG-4 AAC HE 高效率规格(High Efficiency)-----这种规格适合用于低码率编码,有Nero ACC 编码器支持

                 目前使用最多的是LC和HE(适合低码率)。流行的Nero AAC编码程序只支持LC,HE,HEv2这三种规格,编码后的AAC音频,规格显示都是LC。HE其实就是AAC(LC)+SBR技术,HEv2就是AAC(LC)+SBR+PS技术;

     

       

     

    AAC音频文件(传输流)格式有ADIF和ADTS:
  • ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
  • ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。

adts_fixed_header();固定的头部

adts_variable_header();可变的头部

 

syncword :同步头 总是0xFFF, all bits must be 1,代表着一个ADTS帧的开始

ID:MPEG标识符,0标识MPEG-4,1标识MPEG-2

Layer:always: '00'

protection_absent:表示是否误码校验。Warning, set to 1 if there is no CRC and 0 if there is CRC

profile:表示使用哪个级别的AAC,如01 Low Complexity(LC)--- AAC LC。有些芯片只支持AAC LC 。

在MPEG-2 AAC中定义了3种:

sampling_frequency_index:表示使用的采样率下标,通过这个下标在 Sampling Frequencies[ ]数组中查找得知采样率的值。

channel_configuration: 表示声道数 

frame_length : 一个ADTS帧的长度包括ADTS头和AAC原始流.

adts_buffer_fullness:0x7FF 说明是码率可变的码流

 

在AAC中,原始数据块的组成可能有六种不同的元素:

       SCE: Single Channel Element单通道元素。单通道元素基本上只由一个ICS组成。一个

           原始数据块最可能由16个SCE组成。

       CPE: Channel Pair Element 双通道元素,由两个可能共享边信息的ICS和一些联合立体

            声编码信息组成。一个原始数据块最多可能由16个SCE组成。

       CCE: Coupling Channel Element 藕合通道元素。代表一个块的多通道联合立体声信息

           或者多语种程序的对话信息。

       LFE: Low Frequency Element 低频元素。包含了一个加强低采样频率的通道。

       DSE: Data Stream Element 数据流元素,包含了一些并不属于音频的附加信息。

       PCE: Program Config Element 程序配置元素。包含了声道的配置信息。它可能出现在

            ADIF 头部信息中。

       FIL: Fill Element 填充元素。包含了一些扩展信息。如SBR,动态范围控制信息等。

 

 

 

术语说明:

AAC: Advanced Audio Coding 高级音频编码

AAC LC: AAC with Low Complexity AAC的低复杂度配置

AAC plus: 也叫HE-AAC, AAC+,MPEG4 AAC LC加入SBR模块后形成的一个AAC版本

MPEG:Motion Picture Expert Group

IMDCT:反离散余弦变换

ADIF:Audio Data Interchange Format 音频数据交换格式

ADTS:Audio Data Transport Stream 音频数据传输流

SCE: Single Channel Element单通道元素

CPE: Channel Pair Element 双通道元素

CCE: Coupling Channel Element 藕合通道元素

DSE: Data Stream Element 数据流元素

PCE: Program Config Element 程序配置元素

FIL: Fill Element 填充元素

ICS: Individual Channel Stream 独立通道流

PNS: Perceptual Noise Substitution 知觉噪声替换

SBR: Spectral Band Replication 频段复制

TNS: Temporal Noise Shaping 瞬时噪声整形

ch:channel 通道

PS:parametric stereo 参数立体声

SBR:Spectral Band Replication 频段复制

 

***************

ac-3:

 

************************************************************************************************************************************************

音频采样数据:PCM压缩成音频码流,从而降低数据量;

音频采样数据保存了每一个采样点的值;

一个4分钟的采样数据大小:4*60*44100(采样频率,每秒钟取的点数)*2*2(采样精度是16bit,就是两个字节,双声道)=42.3MB;

位深度:

也叫采样位深,音频的位深度决定动态范围。

我们常见的16Bit(16比特),可以记录大概96分贝的动态范围。那么,您可以大概知道,每一个比特大约可以记录6分贝的声音。同理,20Bit可记录的动态范围大概就是120dB;24Bit就大概是144dB。

假如,我们定义0dB为峰值,那么声音振幅以向下延伸计算,那么,CD音频可的动态范围就是"-96dB~0dB。",依次类推,24Bit的HD-Audio高清音频的的动态范围就是"-144dB~0dB。"。由此可见,位深度较高时,有更大的动态范围可利用,可以记录更低电平的细节。

在数字音频中,位深度描述的是振幅(纵轴),采样率描述的是频率(横轴)。所以,增加我们使用的位数就是提高声音振幅的解析度,而增加每秒的采样数则是在增加对声音频率的解析度。增加位深度能极大地提升振幅解析度和动态范围。动态范围的增加会在哪里得以体现呢?因为振幅不能超过0dB,所以增加的dB会被分配到振幅较小的采样上。因此人们能听到更多微小的声音(比如延展到-130dB的混响轨迹),而这些声音在16位,-96dB的情况下会被削减掉。

若要尽可能精确地还原声音,只有高采样率是不够的。描述一个采样点,横轴(时间)代表采样率,纵轴(幅度)代表位深度。16bit表示用16位(2个字节)来表示对该采样点的电平(通俗点来说和音量大小成正比)进行编码时所能达到的精确程度,也就是把纵轴分为16份描述电平大小,如-3dB和-3.1415926dB的精度差别。同理还有20bit和24bit。16bit被认为是专业音频领域里面最低的位深度标准,和44.1kHz的采样率一样,共同作为专业音频和消费产品的标准。位深度也直接关系到信号噪声比的大小,直接影响到所录制信号的整体动态范围。

采样频率:
采样频率最直观的影响是什么?是影响声音的频率范围表现力,采样频率越高,能表现的频率范围就越大。44.1KHz采样频率,可以表现的频率范围是0Hz-22050Hz;48KHz采样频率可以表现的频率范围就是0Hz-24000Hz;96KHz采样频率可以表现的频率范围是0Hz-48000Hz。人耳能听到的平均频率范围,大概是20Hz-20000Hz。
综合以上两条,那么,假如您看到一个参数:
16Bit 44.1KHz,代表这个数字音频能够表现"96dB的动态范围"和"0赫兹-22050赫兹"的频率范围;
24Bit 48KHz,代表这个数字音频能够表现"144dB的动态范围"和"0赫兹-24000赫兹"的频率范围;

外界的声音都是模拟信号,在数字设备中A/D转化成为了由0、1表示的数字信号后被储存下来。数字信号都是离散的,所以采样率是指一秒钟采样的次数,采样率越高,还原的声音也就越真实。由于人耳听觉范围是20Hz~20kHz,根据香农采样定理(也叫奈奎斯特采样定理),理论上来说采样率大于40kHz的音频格式都可以称之为无损格式。但在40kHz采样率下得到的声音已没有细节可言,所有频率都是只采样了一个波峰一个波谷。现一般的专业设备的采样频率为44.1kHz。44.1kHz是专业音频中的最低采样率,也叫“CD级音质”(22.05kHz采样率为广播级音质)。更细化的还有96kHz,192kHz等等,当然要听到这些更高采样率中的细节取决于耳朵和设备了。


音频位速,也叫码率,或者比特率。
位速是指在一个数据流中每秒钟能通过的信息量,也可以理解为:每秒钟用多少比特的数据量去表示。原则上,音频位速越高质量越好。如果是有损压缩音频,不同的压缩算法,即使位速相同,也会导致音质结果完全不同。在无损无压缩格式中(如.wav),码率=采样率x位深度x声道数。在有损压缩中(如.mp3)码率便不等于这个公式了,因为原始信息已经被破坏。码率描述了一秒钟的该音频的信息量,因而声音文件总的大小是码率x总时长。压缩后码率便发生了变化。无损压缩中的码率与音质无关,有损压缩中的码率和音质正相关。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值