大家好,欢迎来到IT知识分享网。
三篇相关联的文章:
ffmpeg下HLS解析过程-CSDN博客
TS文件格式详解及解封装过程-CSDN博客
FFMPEG解析ts流-CSDN博客
简要
ts是一种封装格式,全名为MPEG-TS,文件分为三层:ts层(Transport Stream)、pes层(Packet Elemental Stream)、es层(Elementary Stream)。es层就是音视频数据,pes层是在音视频数据上加了时间戳等对数据帧的说明信息,ts层是在pes层上加入了数据流识别和传输的必要信息(header)。
“PSI是对单一TS流的描述,是TS流中的引导信息”
PSI信息由节目关联表PAT、条件接收表CAT、节目映射表PMT和网络信息表NIT组成。这些表会被插入到TS流中。PSI信息是对单一TS流的描述,它是TS流的引导信息;PSI信息指定了如何从一个携带多个节目的传输流中找到指定的节目(见Q1)。
下面给出的是节目引导信息(或称节目特定信息,PSI)的四个表结构。
结构名 |
中文 |
所定义标准 |
PID |
描述 |
PAT |
节目关联表 |
MPEG2标准 |
0x0000 |
将节目号码和节目映射表PID相关联,是获取数据的开始 |
PMT |
节目映射表 |
MPEG2标准 |
在PAT中指出 |
指定一个或多个节目的PID |
CAT |
条件接收表 |
MPEG2标准 |
0x0001 |
将一个或多个专用EMM流分别与唯一的PID相关联 |
NIT |
网络信息表 |
SI标准 |
PAT中指出 |
描述整个网络,如多少个TS流、频点和调制方式等信息 |
相关概念
PAT:Program Association Table,节目关联表
PMT:Program Map Table,节目映射表
ES流(Elementary Stream):基本码流,不分段的音频、视频或其他信息的连续码流。
PES流:把基本流ES分割成段,在每一个视频/音频帧上加入了时间戳等信息。
PS流(Program Stream):节目流,将具有共同时间基准的一个或多个PES组合(复合)而成的单一数据流(用于播放或编辑系统,如m2p)。
TS流(Transport Stream):传输流,将具有共同时间基准或独立时间基准的一个或多个PES组合(复合)而成的单一数据流(用于数据传输)
ES你可以理解为一段音频或者视频的数据,ES流可能会很大,所以要拆分成PES包,PES包的长度是有限制的,64KB。所以并不是一个ES对应一个PES。
TS:ts_header(0x47开头)+payload(负载)——-188个字节
PES:pes_header( 0x000001开头)+ES(包含时间戳)——64K
ES:NAL(0x0001开头(3或者4个字节),SPS(0x67),PPS(0x68),I帧(0x65),I帧(0x65))+编码data—–不限制大小,比如I帧可能有好几百K
scrambling (system): 加扰,以改变视频,音频或编码数据流的特性,防止以明文形式传输,使未经授权者接收明文数据。
PCR (system): Program Clock Reference
PTS(system):presentation time-stamp 显示时间戳,可能存在于PES包头中的字段,用于指示在系统目标解码器中显示帧数据的时间。
DTS(system):decoding time-stamp 解码时间戳,可能存在于PES包头中的字段,用于指示在系统目标解码器中解码访问帧数据的时间。
CRC:Cyclic Redundancy Check 循环冗余检查,以验证数据的正确性。
PSI:Program Specific Information 程序特定信息,提供了单个TS流的信息,使接收方能够对单个TS流中的不同节目进行解码,这些信息都存在用表的形式提供给,如PAT、PMT、CAT等。但它无法提供多个TS流的相关业务,也不能提供节目的类型、节目名称、开始时间、节目简介等信息。
结构图
通过av_read_frame获取到原始的es数据流对比可以看出.和ts原始数据缺少了ts和pes的头.左边为.ts文件,右边为.264文件。
流程图
编码过程
TS解析图
先看下数据ts,这张图是借用别人的图,之前忘记分析这个图,觉得挺好的
下面开始分析
这个图主要解析的是流的基本信息:format,filesize,duration,bitrate以及音视频的Count
PAT和PMT的相关基本信息
下面图是多音轨的TS
各种流的PID,索引及数量占的百分比,可以看到PAT和PMT是一一对应的,同时对应多个音频或者视频数据
分析
TS层的packet都是固定等长的188字节包,由ts header、adaptation field、payload组成,其中ts header固定4个字节(32位);adaptation field可能存在也可能不存在,主要作用是给不足188字节的数据做填充;payload是pes数据。结构图如下
Ts header部分
Packet Header |
Packet Data |
0x47 0x40 0x00 0x10 |
0000 b0 11 00 01 c1 00 00 00 00 e0 1f 00 01 e1 00 24 ac48 84 ff ff…… ff ff |
分析Packet Header如下表所示:
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 |
30 |
31 |
32 |
… |
|
Packet(十六进制) |
4 |
7 |
4 |
0 |
0 |
0 |
1 |
0 |
… |
||||||||||||||||||||||||
Packet(二进制) |
0 |
1 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
… |
Packet Header Bits |
1 sync_byte=0x47 |
2 |
3 |
4 |
5 PID=0x0000 |
6 |
7 |
8 |
… |
根据包头数据格式,我们可以知晓整个数据包的属性,列表如下:
sync_byte |
0x47 |
占用8bit,同步字节,默认为0x47 |
transport_error_indicator |
“0” |
占用1bit,传输错误指示位,1:表示传输包中至少有一个不可纠正的错误位,一般为0. |
payload_unit_start_indicator |
“1” |
负载单元开始标识 占用1bit,负载单元起始标识位,1:表示起始数据 0:表示累加数据.一个TS包固定为188字节,而一帧数据将会被分割为多个包,故通过起始标识符可以得知是否为新的数据帧. 在前4个字节后会有一个调整字节。所以实际数据应该为去除第一个字节后的数据。即上面数据中红色部分不属于有效数据包。 该字段用来表示TS包的有效净荷带有PES包或者PSI数据的情况。 当TS包带有PES包数据时,payload_unit_start_indicator具有以下特点:置为1,表示TS包的有效净荷以PES包的第一个字节开始;置为0,表示TS包的开始不是PES包。 当TS包带有PSI数据时,payload_unit_start_indicator具有以下特点:置为1,表示TS包带有PSI部分的第一个字节,即第一个字节带有指针pointer_field;置为0,表示TS包不带有一个PSI部分的第一个字节,即在有效净荷中没有指针pointer_field。 |
transport_priority |
“0” |
占用1bit,传输优先级 |
PID |
0x0000 |
PID=0x0000说明数据包是PAT表信息,共13bit |
transport_scrambling_control |
“00” |
占用2bit,加密标识.一般为00 未加密/传输扰乱控制 |
adaptation_field_control |
“01” |
附加区域控制/自适应区域控制 |
continuity_counte |
“0000” |
占用4bit,连续计数器.随着相同pid的ts包增加而增加.可用于重复包的丢弃. |
如上表所示,我们可以知道,首先Packet的Packet Data是PAT信息表,因为其PID为0x0000,并且在包头后需要除去一个字节才是有效数据(payload_unit_start_indicator=”1″),即上面数据中红色部分不属于有效数据包。这样,Packet Data就应该是“ 00 b0 11 00 01 c1 00 00 00 00 e0 1f 00 01 e1 00 24 ac48 84 ff ff …… ff ff ”。
Packet Data分析 |
|||||||||||||||||||||||||
第n个字节 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
… |
||||
Packet Data(除去开头的0x00) |
00 |
b0 |
11 |
00 |
01 |
c1 |
00 |
00 |
00 |
00 |
e0 |
1f |
00 |
01 |
e1 |
00 |
24 |
ac |
48 |
84 |
… |
||||
字段名 |
位 |
具体值 |
次序 |
说明 |
|||||||||||||||||||||
table_id |
8 |
0000 |
第1个字节 0000 0000B(0x00) |
PAT的table_id只能是0x00 |
|||||||||||||||||||||
section_syntax_indicator |
1 |
1 |
第2、3个字节 1011 0000 0001 0001B(0xb0 11) |
段语法标志位,固定为1 |
|||||||||||||||||||||
zero |
1 |
0 |
|||||||||||||||||||||||
reserved |
2 |
11 |
|||||||||||||||||||||||
section_length |
12 |
0000 0001 0001B=0x011=17 |
段长度为17字节 |
||||||||||||||||||||||
transport_stream_id |
16 |
0x0001 |
第4、5个字节 0x00 0x01 |
||||||||||||||||||||||
reserved |
2 |
11 |
第6个字节 1100 0001B(0xc1) |
||||||||||||||||||||||
version_number |
5 |
00000 |
一旦PAT有变化,版本号加1 |
||||||||||||||||||||||
current_next_indicator |
1 |
1 |
当前传送的PAT表可以使用,若为0则要等待下一个表 |
||||||||||||||||||||||
section_number |
8 |
0x00 |
第7个字节0x00 |
||||||||||||||||||||||
last_section_number |
8 |
0x00 |
第8个字节 0x00 |
||||||||||||||||||||||
开始循环,通过这个循环,获得program的个数,计算方法:numProgramBytes = (section_length – 5 /* header */ – 4 /* crc */); |
|||||||||||||||||||||||||
program_number |
16 |
0x0000-第一次 |
2个字节(0x00 00) |
节目号 |
|||||||||||||||||||||
reserved |
3 |
111 |
2个字节 1110 0000 0001 1111B(0xe0 1f) |
||||||||||||||||||||||
network_id(节目号为0时) program_map_PID(节目号为其他时) |
13 |
0 0000 0001 1111B=31 -第一次 |
节目号为0x0000时,表示这是NIT,PID=0x001f,即31 节目号为0x0001时,表示这是PMT,PID=0x100,即256 |
||||||||||||||||||||||
结束循环 |
|||||||||||||||||||||||||
CRC_32 |
32 |
— |
4个字节 |
network_PID(网络PID):仅当program_number为0x00时使用
program_map_PID(节目映射PID):据此找出相应的PMT表
network_PID这个不知道是干嘛用的?大家知道吗?
PID
从这两个图,可以看出,PAT的PID是0。 下表给出了一些表的PID值,这些值是固定的,不允许用于更改。
PAT
PAT表(Program Association Table,节目关联表) ,PAT的PID为0x0000,它的主要作用是针对复用的每一路传输流,提供传输流中包含哪些节目、节目的编号以及对应节目的节目映射表(PMT)的位置,即PMT的TS包的包标识符(PID)的值,同时还提供网络信息表(NIT)的位置,即NIT的TS包的包标识符(PID)的值。
- table_id: 标识一个TS PSI 分段的内容是节目关联分段,条件访问分段还是节目映射分段。对于PAT,置为0x00。
- section_syntax_indicator: 对于PAT,置为0x01。
- section_length: 分段长度字段,其值为从section_length(包括在内)到CRC_32字段的字节数,其值不超过1021。
- transport_stream_id: 区别与其他复用流的标识。
- version_number: PAT的版本号,如果PAT有变,则版本号加1。
- current_next_indicator:置0时,表明该传送的表分段不能使用,下一个表分段才有效。
- section_number: 表明该TS包属于该PAT的第几个分段,分段号从0开始。
- last_section_number: 表明最后一个分段号,同时表明该PAT的最大分段数目。一般,一个PAT表由一个TS包传送。
- program_number: 节目的编号。
- network_PID: NIT表的PID值。
- program_map_PID: PMT表的PID值。
- CRC_32: CRC校验。
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; //表示从下一个字段开始到CRC32(含)之间有用的字节数 unsigned transport_stream_id : 16; //该传输流的ID,区别于一个网络中其它多路复用的流 unsigned reserved_2 : 2;// 保留位 unsigned version_number : 5; //范围0-31,表示PAT的版本号 unsigned current_next_indicator : 1; //发送的PAT是当前有效还是下一个PAT有效 unsigned section_number : 8; //分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段 unsigned last_section_number : 8; //最后一个分段的号码 std::vector<TS_PAT_Program> program; unsigned reserved_3 : 3; // 保留位 unsigned network_PID : 13; //网络信息表(NIT)的PID,节目号为0时对应的PID为network_PID,不为0时,是PID unsigned CRC_32 : 32; //CRC32校验码 } TS_PAT;
从图中可以看到,这个TS里有一个节目,而PMT_PID=0x1000(4096)
PMT
PMT表(Program Map Table,节目映射表)
指明该节目包含的内容,即该节目由哪些流组成,这些流的类型(音频、视频、数据),以及组成该节目的流的位置,即对应的TS包的PID值,每路节目的节目时钟参考(PCR)字段的位置。
PMT表中包含的数据如下:
- 当前节目中所有Video ES流的PID
- 当前节目所有Audio ES流的PID
- 当前节目PCR的PID等。
从图中可以看到这个TS包含一个program,program里包含一路视频和四路音频
主要的字段解析如下:(红色部分是对外有用的,黑色部分仅对当前解析ts有用)
- table_id: 标识一个TS PSI 分段的内容是节目关联分段,条件访问分段还是节目映射分段。对于PMT,置为0x02。
- section_syntax_indicator: 对于PMT,置为0x01。
- section_length: 分段长度字段,其值为从section_length(包括在内)到CRC_32字段的字节数,其值不超过1021。
- program_number: 表明一共有多少个节目。
- version_number: PMT的版本号,如果字段中有关信息有变,则版本号以32为模加1。版本号是对一个节目的定义。
- current_next_indicator:置0时,表明该传送的表分段不能使用,下一个表分段才有效。
- section_number: 总为0x00。
- last_section_number: 总为0x00。
- PCR_PID: 指示含有该节目的PCR字段的TS包的PID。(节目时钟参考)所在TS分组的PID,根据PID可以去搜索相应的TS分组,解出PCR信息
- program_info_length: 表明跟随其后的对节目信息描述的字节数,也就是第一个N loop descriptors的字节数。
- stream_type: 表明PES流的类型。譬如,0x01表明是MPEG-1视频,0X03表明是MPEG-1音频。
- elementary_PID: 表明该负载有该PES流的TS包的PID值。
- ES_info_length: 表明跟随其后的描述相关节目元素的字节数,也就是第二个N loop descriptors的字节数。
- CRC_32: 在CEDARX代码中仅对DVB的场景下作校验。
typedef struct TS_PMT_Stream { unsigned stream_type : 8; //指示特定PID的节目元素包的类型。该处PID由elementary PID指定 unsigned elementary_PID : 13; //该域指示TS包的PID值。这些TS包含有相关的节目元素 unsigned ES_info_length : 12; //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数 unsigned descriptor; }TS_PMT_Stream; //PMT 表结构体 typedef struct TS_PMT { unsigned table_id : 8; //固定为0x02, 表示PMT表 unsigned section_syntax_indicator : 1; //固定为0x01 unsigned zero : 1; //0x01 unsigned reserved_1 : 2; //0x03 unsigned section_length : 12;//首先两位bit置为00,它指示段的byte数,由段长度域开始,包含CRC。 unsigned program_number : 16;// 指出该节目对应于可应用的Program map PID unsigned reserved_2 : 2; //0x03 unsigned version_number : 5; //指出TS流中Program map section的版本号 unsigned current_next_indicator : 1; //当该位置1时,当前传送的Program map section可用; //当该位置0时,指示当前传送的Program map section不可用,下一个TS流的Program map section有效。 unsigned section_number : 8; //固定为0x00 unsigned last_section_number : 8; //固定为0x00 unsigned reserved_3 : 3; //0x07 unsigned PCR_PID : 13; //指明TS包的PID值,该TS包含有PCR域, //该PCR值对应于由节目号指定的对应节目。 //如果对于私有数据流的节目定义与PCR无关,这个域的值将为0x1FFF。 unsigned reserved_4 : 4; //预留为0x0F unsigned program_info_length : 12; //前两位bit为00。该域指出跟随其后对节目信息的描述的byte数。 std::vector<TS_PMT_Stream> PMT_Stream; //每个元素包含8位, 指示特定PID的节目元素包的类型。该处PID由elementary PID指定 unsigned reserved_5 : 3; //0x07 unsigned reserved_6 : 4; //0x0F unsigned CRC_32 : 32; } TS_PMT;
PAT与PMT两张表帮助我们找到该传送流中的所有节目与流,PAT告诉我们,该TS流由哪些节目组成,每个节目的节目映射表PMT的PID是什么,而PMT告诉我们,该节目由哪些流组成,每一路流的类型与PID是什么。
TS流的形成过程:
- 将原始音视频数据压缩之后,压缩结果组成一个基本码流(ES)。
- 对ES(基本码流)进行打包形成PES。
- 在PES包中加入时间戳信息(PTS/DTS)。
- 将PES包内容分配到一系列固定长度的传输包(TS Packet)中。
- 在传输包中加入定时信息(PCR)。
- 在传输包中加入节目专用信息(PSI) 。
- 连续输出传输包形成具有恒定比特率的MPEG-TS流。
- 从复用的MPEG-TS流中解析出TS包;
- 从TS包中获取PAT及对应的PMT(PSI中的表格);
- 从而获取特定节目的音视频PID;
- 通过PID筛选出特定音视频相关的TS包,并解析出PES;
- 从PES中读取到PTS/DTS,并从PES中解析出基本码流ES;
- 将ES交给解码器,获得压缩前的原始音视频数据
分析TS解析过程
ffmpeg对mpeg2-TS详细解析_ChenYuanshen的博客-CSDN博客_ffmpeg mpeg2
FFMpeg对MPEG2 TS流解码的流程分析
FFMpeg对MPEG2 TS流解码的流程分析_iteye_4476的博客-CSDN博客
FFMpeg对MPEG2 TS流解码的流程分析[2]
FFMpeg对MPEG2 TS流解码的流程分析[2] – it610.com
TS流PAT/PMT详解
TS流PAT/PMT详解_rolandz_的博客-CSDN博客_pat pmt
总下简单的说就是,解析ts的过程就是通过找到PAT表,从PAT表中找出对应存在的节目的id,按照这些id找到这些节目的PMT表,从中获到这些节目总的相对的媒体数据id,然后通过这些id,再从ts文件中找到这些文件的es数据,来完成解码或者别的什么操作。
TS流PAT/PMT详解 – rlandj – 博客园
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/137902.html