文章

音视频入门

音视频入门

该文记录音视频入门学习。

音视频入门

1. 学习框架

2. 基础知识篇1

2.1. 音视频播放原理

音视频播放主要分为两大类:在线播放和本地播放。在线播放即通过互联网,在线播放音视频;本地播放及播放本地存放的音视频文件。

音视频播放的原理主要分为:解协议->解封装->解码->音视频同步->播放。当然,如果是本地播放,没有解协议这一步骤。

2.2. 录播、点播、直播

  • 录播:录播更侧重于“录”,比如录播系统,主要集成了音视频的采集、后期剪辑、工具软件的系统。通俗的讲录播就是生产音视频。
  • 点播:点播从字面意义上讲是播放选择的视频,比如观看爱奇艺、腾讯等视频网站的电影和综艺,可以随意拖动视频进度,这些音视频共性特点是提前录制好的。通俗的讲点播就是播放录制好的视频,点播是消费音视频。
  • 直播:直播相对好理解,虎牙、斗鱼等直播平台上的游戏、才艺直播,这些音视频共性特点是实时的,观看者不能拖动音视频进度。通俗的讲直播就是播放实时直播视频,直播既生产又消费音视频。

2.3. 图像篇(YUV和RGB)

音视频中编码前的图像格式,即 YUVRGBYUVRGB,包括 YcbCr 是色彩空间的模型,而平常所说的 BMPPNGJPEG 是文件的存储形式。而 YUV 是音视频(编解码)最常用的格式。

YUV 是编译 true-color 颜色空间(color space)的种类,Y'UV, YUV, YCbCr, YPbPr等专有名词都可以称为 YUV,彼此有重叠。Y 表示明亮度(Luminance、Luma),UV 则是色度、浓度(Chrominance、Chroma)。

2.3.1. YUV空间-间的数据划分

YUV 按照“空间-间”的划分方式,分为 YUV444YUV422YUV420

2.3.2. YUV空间-内的数据划分

半平面格式有时被归入平面系列。

  • 紧缩格式(packed formats):Y、U、V 是交错出现的。例如: $Y_{1}U_{1}Y_{2}V_{1}Y_{3}U_{2}Y_{4}V_{2}…Y_{n-1}U_{n/2}Y_{n}V_{n/2}$。
  • 平面格式(planar formats, p):Y、U、V 每个单独的。例如:$Y_{1}Y_{2}…Y_{n}U_{1}U_{2}…U_{n/2}V_{1}V_{2}…V_{n/2}$。
  • 半平面格式( Semi-planar formats, sp):Y 单独,U、V是组合在一起的。例如:$Y_{1}Y_{2}…Y_{n}U_{1}V_{1}U_{2}V_{2}…U_{n/2}V_{n/2}$。

下图描述了以下格式2

  • YV12
  • I420 = IYUV = YUV420p (有时YUV420p可以指YV12
  • NV21
  • NV12 = YUV420sp (有时YUV420sp可以指NV21

2.3.3. RGB

RGB:即 redgreenblue 三色存储空间。

2.4. 图像篇(H.264)

2.4.1. 什么是H.264

H.264 是由 ITU-T 视频编码专家组(VCEG)和 ISO/IEC 动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编解码器标准

H264编码的输入数据需要是 YUV420P。

2.4.2. H.264的数据格式

H.264 的功能分为两层:视频编码层(VCL, Video Coding Layer)和网络提取层(NAL,Network Abstraction Layer)。

  • VCL:H264 编码/压缩的核心,主要负责将视频数据编码/压缩,再切分。
  • NAL:因为 H264 最终还是要在网络上进行传输,在传输的时候,网络包的最大传输单元是 1500 字节,一个 H264 的帧往往是大于 1500 字节的,所以需要将一个帧拆成多个包进行传输。这些拆包、组包等工作都在 NAL 层去处理。

2.4.3. H.264码流结构

码流名称中文意义
SODBString Of Data Bits 原始数据比特流因为它是流的形式,所以长度不一定是8倍数,它是由 VLC 层产生的。由于我们计算机是以 8 倍数去处理数据所以计算机在处理 H264 时,就需要 RBSP。
RBSPSODB + tailing bits (原始字节序列载荷)由于它是一个压缩流,SODB 不知道是在何处结束,所以算法在 SODB 最后一位补一个 1,没有按字节对齐的则补 0。
EBSPEBSP (扩展字节序列载荷)在生成压缩流之后,在每一帧的开头加一个起始位,这个起始位一般是 00 00 00 01 或者是 00 00 01。所以在 h264 码流中规定每有两个连续的 00 00,就增加一个 0x03。

  • H.264 = start_code + NALU(start_code:00000001 or 000001)

  • 每个 NAL 前有一个起始码 0x000001(或者0x00000001),解码器检测每个起始码,作为一个 NAL 的起始标识,当检测到下一个起始码时,当前 NAL 结束。

  • 同时 H.264 规定,当检测到 0x000000 时,也可以表征当前 NAL 的结束。那么 NAL 中数据出现 0x0000010x000000 时怎么办?H.264 引入了防止竞争机制,如果编码器检测到 NAL 数据存在 0x0000010x000000 时,编码器会在最后个字节前插入一个新的字节0x03,这样:

    1
    2
    3
    4
    
    0x000000 --> 0x00000300
    0x000001 --> 0x00000301
    0x000002 --> 0x00000302
    0x000003 --> 0x00000303
    

2.4.4. NALU

NALU = NALU header + NALU payload,下图显示的是 NALU header

  • F(forbidden_zero_bit):1 位,初始为 0。当网络识别此单元存在比特错误时,可将其设为 1,以便接收方丢掉该单元
  • NRI(nal_ref_idc):2 位,用来指示该 NALU 的重要性等级。值越大,表示当前 NALU 越重要。具体大于 0 时取何值,没有明确规定
  • Type(nal_unit_type):5 位,指出 NALU 的类型,如下所示:
nal_unit_typeNAL 单元和 RBSP 语法结构的内容
0未指定
1非 IDR 图像的编码条带 slice_layer_without_partitioning_rbsp ( )
2编码条带数据分割块 A slice_data_partition_a_layer_rbsp ( )
3编码条带数据分割块 B slice_data_partition_b_layer_rbsp ( )
4编码条带数据分割块 C slice_data_partition_c_layer_rbsp ( )
5IDR 图像的编码条带 slice_layer_without_partitioning_rbsp ( )
6辅助增强信息 (SEI) sei_rbsp ( )
7序列参数集 seq_parameter_set_rbsp ( )
8图像参数集 pic_parameter_set_rbsp ( )
9访问单元分隔符 access_unit_delimiter_rbsp ( )
10序列结尾 end_of_seq_rbsp ( )
11流结尾 end_of_stream_rbsp ( )
12填充数据 filler_data_rbsp ( )
13序列参数集扩展 seq_parameter_set_extension_rbsp ( )
14…18保留
19未分割的辅助编码图像的编码条带 slice_layer_without_partitioning_rbsp ( )
20…23保留
24…31未指定

常见 NALU Type

1
2
3
4
5
6
7
8
9
0x06(0 00 00110)	SEI		type = 6
0x67(0 11 00111)	SPS		type = 7
0x68(0 11 01000)	PPS		type = 8

0x65(0 11 00101)	IDR		type = 5

0x61(0 11 00001)	I帧		type = 1
0x41(0 10 00001)	P帧		type = 1
0x01(0 00 00001)	B帧		type = 1

2.4.5. I帧、P帧和B帧

帧的分类中文意义
I帧(Intra-coded picture)帧内编码图像帧I 帧通常是每个 GOP(MPEG 所使⽤的⼀种视频压缩技术)的第⼀个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。I 帧可以看成是⼀个图像经过压缩后的产物。⾃身可以通过视频解压算法解压成⼀张单独的完整的图⽚。
P帧(Predictive-coded picture)前向预测编码图像帧通过充分将低于图像序列中前⾯已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧。需要参考其前⾯的⼀个 I frame 或者 P frame 来⽣成⼀张完整的图⽚。
B帧(Bidirectionally predicted picture)双向预测编码图像帧既考虑与源图像序列前⾯已编码帧,也顾及源图像序列后⾯已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧。则要参考其前⼀个 I 或者 P 帧及其后⾯的⼀个 P 帧来⽣成⼀张完整的图片。
IDR帧(Instantaneous Decoding Refresh)即时解码刷新首个I帧,是立刻刷新,使错误不致传播,IDR导致DPB(DecodedPictureBuffer参考帧列表——这是关键所在)清空;在IDR帧之后的所有帧都不能引用任何IDR帧之前的帧的内容;IDR具有随机访问的能力,播放器可以从一个IDR帧播放。
GOP(Group Of Picture)图像序列两个I帧之间是一个图像序列,一个GOP包含一个I帧

2.4.6. 解码时间戳和显示时间戳

H.264 中还有两个重要的概念:DTSPTS

  • DTS(Decoding Time Stamp,解码时间戳解):读入内存中的比特流在什么时候开始送入解码器中进行解码
  • PTS(Presentation Time Stamp,显示时间戳):解码后的视频帧什么时候被显示出来

image-20230709222758396

2.4.7. H.264码流分层结构3

image-20230709222758396

宏块分类意义
mb_type确定该 MB 是帧内或帧间(P 或 B)编码模式,确定该 MB 分割的尺寸
mb_pred确定帧内预测模式(帧内宏块)确定表 0 或表 1 参考图 像,和每一宏块分割的差分编码的运动矢量(帧间宏块,除 8×8 宏块分割的帧内 MB)
sub_mb_pred(只对 8×8MB 分割的帧内 MB)确定每一子宏块的子宏 块分割,每一宏块分割的表 0 和/或表 1 的参考图象;每一 宏块子分割的差分编码运动矢量。
coded_block_pattern指出哪个 8×8 块(亮度和彩色)包 编码变换系数
mb_qp_delta量化参数的改变值
residual(残差数据)预测后对应于残差图象取样的编码变换系数

H.264 编码后视频的每一组图像(GOP,图像组)都给予了传输中的序列(PPS)和本身这个帧的图像参数(SPS),所以,我们的整体结构,应该如此:

在这里插入图片描述

1帧 = n个片,1片 = n个宏块,1宏块 = 16x16yuv数据。

2.5. 音频篇(PCM)

2.5.1. 什么是PCM

PCM (Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准数字音频数据。

2.5.2. 如何理解PCM

PCM 是一种用数字表示采样模拟信号方法。主要包括采样,量化,编码三个主要过程。

  • 采样:模拟信号转数字信号。模拟信号转换至 4-bit PCM 的取样和量化。

在这里插入图片描述

  • 采样率:每秒钟采样的样本数。比如我们常说的 44.1kHz,即每秒钟采样 44100 次。

  • 量化:将采样信号数据四舍五入到一个可用整数表示的过程。(位深)4

在这里插入图片描述

位深度信噪比整数取值总数(单个采样点)有符十进制取值范围(单个采样点)
424.08 dB16−8至+7
848.16 dB256−128至+127
1166.22 dB2,048−1,024至+1,023
1272.24 dB4,096−2,048至+2,047
1696.33 dB65,536−32,768至+32,767
18108.37 dB262,144−131,072至+131,071
20120.41 dB1,048,576−524,288至+524,287
24144.49 dB16,777,216−8,388,608至+8,388,607
32192.66 dB4,294,967,296−2,147,483,648至+2,147,483,647
48288.99 dB281,474,976,710,656−140,737,488,355,328至+140,737,488,355,327
64385.32 dB18,446,744,073,709,551,616−9,223,372,036,854,775,808至+9,223,372,036,854,775,807
  • 编码:将量化后的信号转换成二进制数据。

2.5.3. 描述PCM数据的6个参数

参数中文举例
Sample Rate采样频率8kHz(电话)、44.1kHz(CD)、48kHz(DVD)。
Sample Size量化位数常见值为8-bit、16-bit
Number of Channels通道个数常见的音频有立体声(stereo)和单声道(mono)两种类型,立体声包含左声道和右声道。另外还有环绕立体声等其它不太常用的类型。
Sign表示样本数据是否是有符号位比如用一字节表示的样本数据,有符号的话表示范围为-128 ~ 127,无符号是0 ~ 255。
Byte Ordering字节序字节序是little-endian还是big-endian。通常均为little-endian
Integer Or Floating Point整形或浮点型大多数格式的PCM样本数据使用整形表示,而在一些对精度要求高的应用方面,使用浮点类型表示PCM样本数据。

2.6. 音频篇(AAC)

2.6.1. 什么是AAC

AAC (Advanced Audio Coding,高级音频编码)是一种声音数据的文件压缩格式。AAC 分为 ADIFADTS 两种文件格式。

2.6.2. 什么是ADIF和ADTS

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

2.6.3. ADTS的数据结构

ADTS 帧首部结构5

字母长度(位)描述
A12同步字(所有位必须设置为1)
B1MPEG版本,设置为0表示MPEG-4,设置为1表示MPEG-2
C2Layer,始终设置为0
D1CRC校验位,如果没有CRC,则设置为1,如果有CRC,则设置为0
E2Profile,MPEG-4音频对象类型减去1
F4MPEG-4采样频率索引(禁止使用15)
G1私有位,MPEG保证不使用,编码时设置为0,解码时忽略
H3MPEG-4声道配置(如果为0,则通过内部的PCE(程序配置元素)发送声道配置)
I1原始性,设置为1表示音频为原始内容,设置为0表示非原始内容
J1家庭使用,设置为1表示音频为家庭使用,设置为0表示非家庭使用
K1版权标识位,用于传输中心注册的版权标识符的下一位,以LSB优先顺序滑动位字符串,将当前位值放在该字段中,如果到达末尾,则回到开头(循环缓冲区)
L1版权标识起始位,设置为1表示该帧的版权标识位为第一个,否则设置为0
M13帧长度,包括ADTS头部和CRC校验的长度
O11缓冲区满度,表示每帧的位保留池状态
P2AAC帧数减1(RDBs(原始数据块)在ADTS帧中),为确保最大兼容性,请始终每个ADTS帧使用一个AAC帧
Q16CRC校验(根据ISO/IEC 11172-3,条款2.4.3.1),如果Protection absent为0,则存在CRC校验位

2.7. 字幕篇(SSA&&ASS)

2.7.1. 什么是SSA

  • SSA(SubStation Alpha),是由CS Low(亦称Kotus)创建,比传统字幕格式(如SRT)功能更加先进的字幕文件格式。
  • 该格式字幕的外挂文件以 *.ssa 作为后缀。

2.7.2. 什么是ASS

  • ASS(Advanced SubStation Alpha),是一种比 SSA 更为高级的字幕格式, 其实质版本是 SSA v4.00+,它是基于 SSA 4.00+ 编码构建的。
  • ASS 的主要变化就是在 SSA 编写风格的基础上增添更多的特效和指令。
  • 该格式字幕的外挂文件以 *.ass 作为后缀。

2.7.3. SSA&ASS的基本结构

SSA/ASS 字幕是一种类 ini 风格纯文本文件;包含五个 section:[Script Info]、[v4+ Styles]、[Events]、[Fonts]、[Graphics]。

  • [Script Info]:包含了脚本的头部和总体信息。[Script Info] 必须是 v4 版本脚本的第一行。
  • [v4 Styles]:包含了所有样式的定义。每一个被脚本使用的样式都应该在这里定义。ASS 使用 [v4+ Styles]。
  • [Events]:包含了所有脚本的事件,有字幕、注释、图片、声音、影像和命令。基本上,所有在屏幕上看到的内容都在这一部分。
  • [Fonts]:包含了脚本中内嵌字体的信息。
  • [Graphics]:包含了脚本中内嵌图片的信息。

2.7.4. SSA字幕示例6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[Script Info]
; This is a Sub Station Alpha v4 script.
; For Sub Station Alpha info and downloads,
; go to http://www.eswat.demon.co.uk/
; or email kotus@eswat.demon.co.uk
Title: Spirited Away
Original Script: Ian Roberts
Original Translation: Eisuke Ishibashi
ScriptType: v4.00
Collisions: Normal
PlayResY: 480
PlayDepth: 0
Wav: 0, 28688,H:\3.wav
LastWav: 1
Timer: 100.0000

[V4 Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding
Style: ICredit,Gill Sans Condensed,36,16777215,65535,65535,-2147483640,-1,0,1,3,0,2,70,70,40,0,0
Style: IDefault,Gill Sans Condensed,30,65535,65535,65535,-2147483640,-1,0,1,3,0,2,70,70,40,0,0
Style: IScreenText,Gill Sans Condensed,30,16744576,65535,65535,-2147483640,-1,0,1,3,5,2,70,70,40,0,0

[Events]
Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: Marked=0,0:00:06.60,0:00:08.90,IScreenText,,0000,0000,0000,,{\a10}See you again... Best wishes
Dialogue: Marked=0,0:00:11.84,0:00:14.74,ICredit,,0000,0000,0100,,{\a2}Story, Script & Direction - MIYAZAKI Hayao

3. 视频

将图像、音频、字幕封装在一起,就形成了我们常见的视频。

3.1. 视频封装格式篇(FLV)

3.1.1. FLV的封装格式

FLV(Flash Video),Adobe公司设计开发的一种流行的流媒体格式,由于其视频文件体积轻巧、封装简单等特点,使其很适合在互联网上进行应用。除了播放视频,在直播时也可以使用。采用FLV格式封装的文件后缀为 .flv,格式如下(FLV = FLV Header + Body):

在实际讲解 FLV 协议前,首先对单位进行约定:

类型定义
0x16进制数据
SI8有符号8位整数
SI16有符号16位整数
SI24有符号24位整数
SI32有符号32位整数
STRINGUnicode 8位字符序列(UTF-8) ,以0x00结束(除非另有说明)
UI8无符号8位整数
UI16无符号16位整数
UI24无符号24位整数
UI32无符号32位整数
xxx [ ]类型为xxx的数组
xxx [n]类型为xxx的数组,数组长度为n

3.1.2. FLV Header7

FLV header 由如下字段组成,其中:

  1. 前三个字节内容固定是FLV
  2. 最后4个字节内容固定是9(对FLV版本1来说)
字段字段类型字段含义
SignatureUI8签名,固定为’F’ (0x46)
SignatureUI8签名,固定为’L’ (0x4c)
SignatureUI8签名,固定为’V’ (0x56)
VersionUI8版本,比如 0x01 表示 FLV 版本 1
TypeFlagsReservedUB[5]保留字段,全为0
TypeFlagsAudioUB[1]1表示有音频标志,0表示没有
TypeFlagsReservedUB[1]保留字段,全为0
TypeFlagsVideoUB[1]1表示有视频标志,0表示没有
DataOffsetUI32版本为 0x01 时,一般是9,大于9表示下面还有扩展信息

3.1.3. FLV Body

Body 是由一个个 Tag 组成的,每个 Tag 下面有一块4个字节的空间,用来记录这个 Tag 的长度。这个后置的 PreviousTagSize 用于逆向读取处理,表示的是前面的 Tag 的大小。

3.1.4. FLV Tag

FLV tagtag header + tag body 组成。

3.1.4.1. Tag Header

tag header 如下,总共占据11个字节:

字段字段类型字段含义
ReservedUB[2]为 FMS 保留,应该为0
FilterUB[1]通常为0
TagTypeUB[5]tag类型:0x08表示audio;0x09表示video;0x12表示script data
DataSizeUI24tag body的大小
TimestampUI24相对于第一个tag的时间戳(单位是毫秒) 第一个tag的Timestamp为0
TimestampExtendedUI8时间戳的扩展字段,当 Timestamp 3个字节不够时,会启用这个字段,代表高8位
StreamIDUI24总是0
Data取决于根据TagTypeTagType=8,则为AUDIODATA;TagType=9,则为VIDEODATA;TagType=18,则为SCRIPTDATAOBJECT
3.1.4.2. Tag Data

Tag Data 分成 AudioVideoScript 三种。

3.1.4.2.1. Audio Tag Data
字段字段类型字段含义
SoundFormatUB[4]音频格式,重点关注10=AAC
0 = Linear PCM, platform endian
1 = ADPCM
2 = MP3
3 = Linear PCM, little endian
4 = Nellymoser 16-kHz mono
5 = Nellymoser 8-kHz mono
6 = Nellymoser
7 = G.711 A-law logarithmic PCM
8 = G.711 mu-law logarithmic PCM
9 = reserved
10 = AAC
11 = Speex
14 = MP3 8-Khz
15 = Device-specific sound
SoundRateUB[2]采样率,对AAC来说,永远等于3
0 = 5.5-kHz
1 = 11-kHz
2 = 22-kHz
3 = 44-kHz
SoundSizeUB[1]采样精度,对于压缩过的音频,永远是16位
0 = snd8Bit
1 = snd16Bit
SoundTypeUB[1]声道类型,对Nellymoser来说,永远是单声道;对AAC来说,永远是双声道;
0 = sndMono 单声道
1 = sndStereo 双声道
AACPacketTypeUI8SoundFormat等于10才存在,0表示AAC序列头,1表示AAC裸数据
SoundDataUI8[size of sound data]如果是AAC,则为 AACAUDIODATA; 其他请参考规范;
3.1.4.2.2. Video Tag Data
字段字段类型字段含义
FrameTypeUB[4]重点关注1、2:
1: keyframe (for AVC, a seekable frame) —— 即H.264的IDR帧;
2: inter frame (for AVC, a non- seekable frame) —— H.264的普通I帧;
3: disposable inter frame (H.263 only)
4: generated keyframe (reserved for server use only)
5: video info/command frame
CodecIDUB[4]编解码器,主要关注 7(AVC)
1: JPEG (currently unused)
2: Sorenson H.263
3: Screen video
4: On2 VP6
5: On2 VP6 with alpha channel
6: Screen video version 2
7: AVC
VideoData取决于CodecID实际的媒体类型,主要关注 7:AVCVIDEOPACKE
2: H263VIDEOPACKET
3: SCREENVIDEOPACKET
4: VP6FLVVIDEOPACKET
5: VP6FLVALPHAVIDEOPACKET
6: SCREENV2VIDEOPACKET
7: AVCVIDEOPACKE
3.1.4.2.3. Script Tag Data
字段字段类型字段含义
TypeUI8变量类型:
0 = Number type
1 = Boolean type
2 = String type
3 = Object type
4 = MovieClip type
5 = Null type
6 = Undefined type
7 = Reference type
8 = ECMA array type
10 = Strict array type
11 = Date type
12 = Long string type
ECMAArrayLength如果Type为8(数组),则为UI32数组长度
ScriptDataValue根据Type的值来决定
If Type == 0 DOUBLE
If Type == 1 UI8
If Type == 2 SCRIPTDATASTRING
变量的值
ScriptDataValueTerminatorType==3,则为SCRIPTDATAOBJECTEND
Type==8,则为SCRIPTDATAVARIABLEEND
Object、Array的结束符

3.2. 视频封装格式篇(TS)

3.2.1. 什么是TS8

TS(Transport Stream,传输流),一种常见的视频封装格式,是基于 MPEG-2 的封装格式(所以也叫MPEG-TS),后缀为 .ts

3.2.2. TS的分层结构

TS 文件分为三层,如下所示(可以倒序看更好理解):

  • TS(Transport Stream):在PES层基础上加入了数据流识别信息和传输信息。
  • PES(Packet Elemental Stream):在ES层基础上加入时间戳(PTS/DTS)等信息。
  • ES(Elementary Stream):压缩编码后的音视频数据。

3.2.3. TS层

  • ts包大小固定为188字节,ts层分为三个部分:ts headeradaptation fieldpayload
  • ts header 固定4个字节;
  • adaptation field 可能存在也可能不存在,主要作用是给不足 188 字节的数据做填充。
  • payload 是 PES 数据,或者 PATPMT 等。
  • ts Header + adaptation field 格式如下:

TS 分层结构

3.2.3.1. TS Header
字段字段类型字段含义
sync_byteUB[8]同步字节,为固定的 8 比特字段,其值为 0100 0111 (0x47)
transport_error_indicatorUB[1]传输错误指示位,1 比特,发送时(调制前)值为 0。接收方的解调器在无法成功解调(即使有前向纠错机制)TS 分组内容时,将该位设置为 1,表示该 TS 分组损坏。
payload_unit_start_indicatorUB[1]载荷单元开始指示位,1 比特,负载单元起始标示符,一个完整的数据包开始时标记为 1, 表示携带的是 PES 或 PSI 第一个包。PSI(Program Specific Information)由对于传输流的多路分解以及节目成功再现所必要的标准数据组成。
transport_priorityUB[1]传输优先级,1 比特,值为 1 时,在相同 PID 的分组中具有更高的优先权。传输机制可以使用该字段优先考虑基本流内的该包数据。
PIDUB[13]用于识别 TS 分组的 ID,13 比特。一个 PID 对应一个特定的 PES。
transport_scrambling_controlUB[2]传输加扰控制,2 比特。值为 00 时表示载荷未加扰。其余值由具体系统定义。
adaptation_field_controlUB[2]适配域存在标志,2 比特。值的含义如下:
00,供未来使用,由 ISO/IEC 所保留。解码器应丢弃设置为 00 值的传输流包。
01,无 adaptation_field,仅有效载荷。在空包的情况中,值应为 01
10,仅有 Adaptation_field,无有效载荷。
11,Adaptation Field 后跟着有效载荷。
continuity_counterUB[4]连续性计数器,4 比特。取值为 0x000x0F,循环使用。用于检查同一个 PID 的 TS 分组的连续性。每当一个 TS 分组中包含载荷时,该计数器加 1。
  • pid 决定了负载内容的类型,主要包括:PAT表,PMT表,视频流,音频流。常用的PID值:
PATCATTSDTEIT,STRST,STTDT,TOT,ST
PID0x00000x00010x00020x00120x00130x0014
3.2.3.2. Adaptation Field

适配域(Adaptation Field)中的数据主要用于携带一些额外信息以及做数据填充以确保 TS 的一个包大小固定在 188 字节。

TS Header 中的 adaptation_field_control 字段值为 1011 时,这就表明存在适配域(Adaptation Field)部分。

3.2.3.3. PAT表结构(指明PMT表的PID值)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typedef struct TS_PAT{
    unsigned table_id                 :8  //固定位0x00,表示该表是PAT
    unsigned section_syntax_indicator :1  //段语法标志,固定为1
    unsigned zero                     :1  //固定为0
    unsigned reserved_1               :2  //第一个保留位
    unsigned section_length           :12 //表示这个字节之后有用的字节数,包括CRC_32
    unsigned transport_stream_id      :16 //传输流的ID,区别于一个网络中其他多路复用的流
    unsigned reserved_2               :2  //第二个保留位
    unsigned version_number           :5  //表示PAT的版本号
    unsigned current_next_indicator   :1  //表示发送的PAT是当前有效还是下一个有效,为1时代表当前有效
    unsigned section_number           :8  //如果PAT分段传输,那么此值每次递增1
    unsigned last_section_number      :8  //最后一个分段的号码
    for(int i=0;i<N;i++){
        unsigned Program_number       :16 //节目号
        unsigned Reversed_3           :3  //保留位
        if(Program_number == 0)
            Network_id                :13 //网络信息表(NIT)的PID
        else
            Program_MAP_PID           :13 //节目映射表的PID,每个节目都有一个
    }
    unsigned CRC_32                   :32 //CRC32校检码
}TS_PAT
3.2.3.4. PMT表(指明音视频流的PID值)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
typedef struct TS_program_map_section{
    unsigned Table_id                    :8  //标志PSI分段的内容,对于PMT,此值为0x02
    unsigned Section_syntax_indicator    :1  //置为1
    unsigned '0'                         :1
    unsigned Reserved                    :2  //保留位
    unsigned Section_length              :12 //指明了自此到最后CRC_32的字节数
    unsigned Program_number              :16 //指出该节目的节目号,与PAT表对应
    unsigned Reserved                    :2  //保留位
    unsigned Version_number              :5  //取值0-31,代表当前PMT的版本号
    unsigned Current_next_indicator      :1  //代表当前PMT是否有效
    unsigned Section_number              :8  //给出了当前所处段的数目
    unsigned Last_section_number         :8  //给出了最后一个分段,即分段的最大数目
    unsigned Reserved                    :3  //保留位
    unsigned PCR_PID                     :13 //指示TS包的PCR值,该TS包含有PCR字段
    unsigned Reserved                    :4  //保留位
    unsigned Program_info_length         :12 //该字段描述跟随其后对节目信息描述的字节数
    for(int i = 0; i < N; i++)
        Descriptr()
    for(int i = 0; i < N; i++){
        unsigned Stream_type             :8  //0x00:保留, 0x01:MPEG1视频,0x02:MPEG2视频,0x03:MPEG1音频,0x04:MPEG2音频,0x05:私有字段,0x06:含有私有数据的PES包 ......
        unsigned Reserved                :3  //保留
        unsigned Elementary_PID          :13 //指示TS包的PID,这些TS包含有相同的PID
        unsigned Reserved                :4  //保留
        unsigned ES_info_length          :12 //指示跟随其后描述相关节目元素的字节数
        for(int j = 0; j < N2; j++)
            Descriptr()
    }
    unsigned CRC_32                      :32 //循环校检位
}

3.2.4. PES层

PES(Packetized Elementary Stream,打包的ES),在 ES 层的基础上加入了时间戳(PTS/TDS)等信息。

  • ES 数据包比较大,加入PES头时需将ES进行分割,只在第一个分割的ES上加PES头,
  • PES packet length:指示 PES 包中跟随该字段最后字节的字节数。0 值指示PES 包长度既未指示也未限定并且仅在这样的PES 包中才被允许,该 PES 包的有效载荷由来自传输流包中所包含的视频基本流的字节组成。

img

3.2.5. ES层

  • ES(Elementary Stream,基本码流),就是音视频编码数据流,比如视频 H.264,音频 AAC
  • 一个 ES 流中只包含一种类型的数据(视频,或音频,或字幕)。

3.2.6. 总结

3.2.6.1. TS 流生成流程
  • 将原始音视频数据压缩之后,压缩结果组成一个基本码流(ES)。
  • 对ES(基本码流)进行打包形成PES。
  • 在PES包中加入时间戳信息(PTS/DTS)。
  • 将PES包内容分配到一系列固定长度的传输包(TS Packet)中。
  • 在传输包中加入定时信息(PCR)。
  • 在传输包中加入节目专用信息(PSI) 。
  • 连续输出传输包形成具有恒定比特率的MPEG-TS流。
3.2.6.2. TS 流解析流程
  • 复用的MPEG-TS流中解析出TS包;
  • 从TS包中获取PAT及对应的PMT;
  • 从而获取特定节目的音视频PID;
  • 通过PID筛选出特定音视频相关的TS包,并解析出PES;
  • 从PES中读取到PTS/DTS,并从PES中解析出基本码流ES;
  • 将ES交给解码器,获得压缩前的原始音视频数据。

3.3. 视频封装格式篇(MP4)

3.3.1. MP4(MPEG-4)

  • MP4 是一套用于音频、视频信息的压缩编码标准,由国际标准化组织(ISO)和国际电工委员会(IEC)下属的“动态图像专家组”(Moving Picture Experts Group,即MPEG)制定,第一版在1998年10月通过,第二版在1999年12月通过。MPEG-4格式的主要用途在于网上流、光盘、语音发送(视频电话),以及电视广播。
  • MP4 由许多box组成,每个box包含不同的信息,这些box以树形结构的方式组成,box 当中可以包含 box

3.3.2. box

mp4 文件由若干个 box 组成。下面是 box 结构的一个示意图:

  • box 由 header 和 body 组成,header 指明 box 的 size 和 type。size 是包含 box header 的整个 box 的大小。
  • box type,通常是4个ASCII码的字符如“ftyp”、“moov”等,这些 box type都是已经预定义好的,表示固定的含义。如果是“uuid”,表示该box为用户自定义扩展类型,如果 box type 是未定义的,应该将其忽略。
  • 如果 header 中的 size 为1,则表示 box 长度需要更多的bits位来描述,在后面会有一个 8自己 位的 largesize 用来描述 box 的长度。如果 size 为0,表示该 box 为文件的最后一个box,文件结尾(同样只存在于“mdat”类型的box中)。
  • box 分为两种,BoxFullbox。FullBox 是 Box 的扩展,Header 中增加了 versionflags 字段。

参考

本文由作者按照 CC BY 4.0 进行授权