音视频 TS格式解析
Posted baiiu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了音视频 TS格式解析相关的知识,希望对你有一定的参考价值。
前言
本文介绍TS文件封装格式,是一种被广泛应用的文件格式。全称为MPEG2-TS。其中TS即"Transport Stream"的缩写。
PS和TS
如下图所示,PES封包后能按需打出PS流和TS流,其中区别如下:
MPEG2-PS主要应用于存储的具有固定时长的节目,全称是Program Stream,如DVD电影;
MPEG-TS则主要应用于实时传送的节目,比如实时广播的电视节目。
PS 流 (Program Stream):节目流,PS 流由 PS 包组成,而一个 PS 包又由若干个 PES 包组成。一个 PS 包由具有同一时间基准的一个或多个 PES 包复合合成。
TS 流 (Transport Stream):传输流,TS 流由固定长度(188 字节)的 TS 包组成,TS 包是对 PES 包的另一种封装方式,同样由具有同一时间基准的一个或多个 PES 包复合合成。PS 包是不固定长度,而 TS 包为固定长度。
这两种格式的主要区别是将DVD上的VOB文件的前面一截剪掉(或者干脆就是数据损坏),那么就会导致整个文件无法解码,而电视节目是你任何时候打开电视机都能解码(收看)的。
所以,MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。
TS格式概览
TS是一种音视频封装格式,全称为MPEG2-TS。其中TS即"Transport Stream"的缩写。
TS格式是主要用于直播的码流结构,具有很好的容错能力。通常TS流的后缀是.ts、.mpg或者.mpeg,多数播放器直接支持这种格式的播放。
TS流中不包含快速seek的机制,只能通过协议层实现seek。HLS协议基于TS流实现的。
- TS文件(码流)由多个TS Packet组成的,其TS包大小固定为188字节,以包头sync_byte为起始的一连串流。
TS文件(码流)可以分为三层:TS层(Transport Stream)、PES层(Packet Elemental Stream)、ES层(Elementary Stream)。
ES层就是音视频数据;
PES层是在音视频数据上加了时间戳等对数据帧的说明信息;
TS层是在PES层上加入了数据流识别和传输的必要信息。
TS层
TS层分为三个部分:TS Header、Adaptation Field、Payload。
TS Header固定4个字节;Adaptation Field可能存在也可能不存在,主要作用是给不足188字节的数据做填充;Payload是PES数据。
header,4字节
-
sync_byte(同步字节):
固定为0x47
;该字节由解码器识别,使包头和有效负载可相互分离。 -
transport_error_indicator(传输错误标志):
1
表示在相关的传输包中至少有一个不可纠正的错误位。当被置1后,在错误被纠正之前不能重置为0。 -
payload_unit_start_indicator(负载起始标志):
1
表示该包是一个完整的包的开始;0
表示是不是一个完整的包; -
transport_priority(传输优先级标志):
‘1’表明当前TS包的优先级比其他具有相同PID, 但此位没有被置‘1’的TS包高。 -
PID:
指示存储与分组有效负载中数据的类型。
PID的作用就好比是一份文件的文件名。有了标识值的TS包,会放进一个叫节目映射表(PMT)的控制信息中,PMT本身就是一个TS包,所以也有自己的PID值(有PAT包指定),这个表里面的PID值与该路节目ES的音频、视频、数据的PID一一对应。最后将与该路节目有关的传送包复接起来,共同形成单路节目传送流,即TS流,从上图可以看出,视频数据的PID值是45,音频数据的PID值是78,填充数据的PID值是69…。
在多路节目传送流中,还有一个特殊的控制信息PAT(它是节目辅助表的意思),PAT本身也是一个TS包(在ISO/IEC 13818-1里有说明,PAT(Program Association Table)的PID值为0x00,所有TS包的标识(即sync_byte)为0x47),即上图中的表格数据部分。在PAT中,包含的就是每路TS流对应的PMT表所在的TS包的PID信息,其实PAT表中的数据为TS包的PID,这个TS包的内容为PMT。
通过对PID的译码,就可以对单个节目传送流进行解码。
所以解析起来就像这样: 先接收一个负载为PAT的TS包(TS包头为0x47 0xXX 0x00 0xXX),在整个数据包里找到一个PMT包的PID(program_map_PID)。然后再接收一个含有PMT的TS包(TS包头为0x47 0x00 program_map_PID 0xXX),在这个TS包里找到有关填入数据类型的PID,PMT中可能含有不止一个TS包的PID数据,PMT中stream_type、elementary_PID决定了TS包的类型和PID,然后用PMT中的PID值匹配接收到的TS包,如果匹配上,那么该TS包的负载内容就是填入实际的数据。
-
transport_scrambling_control(加扰控制标志):
表示TS流分组有效负载的加密模式。空包为‘00’,如果传输包包头中包括调整字段,不应被加密。其他取值含义是用户自定义的。 -
adaptation_field_control(适配域控制标志):
表示包头是否有调整字段或有效负载。‘00’为ISO/IEC未来使用保留;‘01’仅含有效载荷,无调整字段;‘10’ 无有效载荷,仅含调整字段;‘11’ 调整字段后为有效载荷,调整字段中的前一个字节表示调整字段的长度length,有效载荷开始的位置应再偏移[length]个字节。空包应为‘10’。
-
continuity_counter(连续性计数器):
随着每一个具有相同PID的TS流分组而增加,当它达到最大值后又回复到0。范围为0~15。
Adaptation Field
Adaptation Field的长度要包含传输错误指示符标识的一个字节。
PCR是节目时钟参考,PCR、DTS、PTS都是对同一个系统时钟的采样值,PCR是递增的,因此可以将其设置为DTS值,音频数据不需要PCR。
打包TS流时PAT和PMT表是没有Adaptation Field的,不够的长度直接补0xff即可。
视频流和音频流都需要加adaptation field,通常加在一个帧的第一个ts包和最后一个ts包里,中间的ts包不加。
Payload
TS包中Payload所传输的信息包括两种类型:视频、音频的PES包以及辅助数据;节目专用信息PSI。
TS包也可以是空包。空包用来填充TS流,可能在重新进行多路复用时被插入或删除。
视频、音频的ES流需进行打包形成视频、音频的 PES流。辅助数据(如图文电视信息)不需要打成PES包。
PES层
从上面的结构图可以看出,PES层是在每一个视频/音频帧上加入了时间戳等信息,PES包内容很多,下面我们说明一下最常用的字段:
- packet_start_code_prefix:
3字节,开始码,固定为0x000001。 - stream id:
音频取值(0xc0-0xdf),通常为0xc0;视频取值(0xe0-0xef),通常为0xe0。 - pes packet length:
后面pes数据的长度,0表示长度不限制,只有视频数据长度会超过0xffff。 - pes data length:
后面数据的长度,取值5或10。 - pts:
33bit值 - dts:
33bit值
ES层
ES层指的就是音视频数据。
一般的,视频为H.264视频,音频为AAC音频。
PAT
Program Association Table 节目关联表,每个 TS 流对应一张,用来描述该 TS 流中有多少个节目。
TS 流中中,PAT 包重复实现,大约 0.5 秒出现一个,保证实时解码性
表示 PAT 表的 TS 包 PID 值为 0,便于识别
PAT 的 payload 中传送特殊 PID 的列表,每个 PID 对应一个节目(对应一张 PMT 表)
PAT 表是 TS 流的基础,任何一个 TS 流解析寻找节目都是从 PAT 表开始查找
typedef struct TS_PAT_Program
unsigned program_number :16; // 节目号,为 0x0000 时表示这是 NIT,节目号为 0x0001 时, 表示这是 PMT
unsigned reserved :3 // 保留,固定为 111
unsigned program_map_PID :13; // 节目号对应内容的 PID 值
TS_PAT_Program;
typedef struct TS_PAT
unsigned table_id : 8; // 固定 0x00 ,标志是该表是 PAT
unsigned section_syntax_indicator : 1; // 段语法标志位,固定为 1
unsigned zero : 1; // 0
unsigned reserved_1 : 2; // 保留位,固定为 11
unsigned section_length : 12; // 段长度,表示从下一个字段开始到 CRC32(含) 之间有用的字节数
unsigned transport_stream_id : 16; // TS 流 ID,一般为 0x0001,区别于一个网络中其它多路复用的流
unsigned reserved_2 : 2; // 保留位,固定为 11
unsigned version_number : 5; // PAT 版本号,固定为 00000,如果 PAT 有变化则版本号加 1
unsigned current_next_indicator : 1; // 固定为 1,表示这个 PAT 表有效,如果为 0 则要等待下一个 PAT 表
unsigned section_number : 8; // 分段的号码。PAT 可能分为多段传输,第一段为 00,以后每个分段加 1,最多可能有 256 个分段
unsigned last_section_number : 8; // 最后一个分段的号码
std::vector<TS_PAT_Program> program;
unsigned CRC_32 : 32; // CRC32 校验码
TS_PAT;
PMT
Program Map Table,节目映射表,该表的 PID 是由 PAT 表 提供给出的。表征一路节目所有流信息。包含:
当前节目中包含的所有 Video 数据的 PID
当前节目中包含的所有 Audio 数据的 PID
与当前节目关联在一起的其他数据的 PID(如数字广播,数据通讯等使用的 PID)
如果 TS 流中包含多个节目,那么就会有多个 PMT 表。只要我们处理了 PMT 表,那么我们就可以获取该节目中所有的流信息,如当前节目包含多少个 Video、多少个 Audio 和其他数据及每种数据对用的流 PID 分别是多少。
typedef struct TS_PMT_Stream
unsigned stream_type : 8; // 指示本节目流的类型,H.264 编码对应 0x1b,AAC 编码对应 0x0f,MP3 编码对应 0x03
unsigned reserved1 : 3; // 保留位,固定为 111
unsigned elementary_PID : 13; // 指示该流的 PID 值
unsigned reserved2 : 3; // 保留位,固定为 1111
unsigned ES_info_length : 12; // 前两位 bit 为 00,指示跟随其后的描述相关节目元素的字节数
std::vector<unsigned> descriptor;
TS_PMT_Stream;
typedef struct TS_PMT
unsigned table_id : 8; // 取值随意,一般使用 0x02, 表示 PMT 表
unsigned section_syntax_indicator : 1; // 段语法标志位,固定为 1
unsigned zero : 1; // 固定为 0
unsigned reserved_1 : 2; // 保留位,固定为 11
unsigned section_length : 12; // 段长度,表示从下一个字段开始到 CRC32(含) 之间有用的字节数
unsigned program_number : 16; // 当前 PMT 表映射到的节目号,1、2、3
unsigned reserved_2 : 2; // 保留位,固定为 11
unsigned version_number : 5; // PMT 版本号码,固定为 00000,如果 PAT 有变化则版本号加 1
unsigned current_next_indicator : 1; // 发送的 PMT 表 是当前有效还是下一个 PMT 有效
unsigned section_number : 8; // 分段的号码。PMT 可能分为多段传输,第一段为 00,以后每个分段加 1,最多可能有 256 个分段
unsigned last_section_number : 8; // 分段数
unsigned reserved_3 : 3; // 保留位,固定为 111
unsigned PCR_PID : 13; // 指明 TS 包的 PID 值,该 TS 包含有 PCR 同步时钟,
unsigned reserved_4 : 4; // 预留位,固定为 1111
unsigned program_info_length : 12; // 前 2bit 为 00,该域指出跟随其后对节目信息的描述的字节数。
std::vector<TS_PMT_Stream> PMT_Stream;
unsigned reserved_5 : 3; // 保留位,0x07
unsigned reserved_6 : 4; // 保留位,0x0F
unsigned CRC_32 : 32; // CRC32 校验码
TS_PMT;
TS流生成及解析流程
-
TS 流生成流程
将原始音视频数据压缩之后,压缩结果组成一个基本码流(ES)。
对ES(基本码流)进行打包形成PES。
在PES包中加入时间戳信息(PTS/DTS)。
将PES包内容分配到一系列固定长度的传输包(TS Packet)中。
在传输包中加入定时信息(PCR)。
在传输包中加入节目专用信息(PSI) 。
连续输出传输包形成具有恒定比特率的MPEG-TS流。 -
TS 流解析流程
复用的MPEG-TS流中解析出TS包;
从TS包中获取PAT及对应的PMT;
从而获取特定节目的音视频PID;
通过PID筛选出特定音视频相关的TS包,并解析出PES;
从PES中读取到PTS/DTS,并从PES中解析出基本码流ES;
将ES交给解码器,获得压缩前的原始音视频数据。
以上是关于音视频 TS格式解析的主要内容,如果未能解决你的问题,请参考以下文章
利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4