TS文件格式详解及解封装过程

三篇相关联的文章: 

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流的相关业务,也不能提供节目的类型、节目名称、开始时间、节目简介等信息。

SI:Specific Information 特定信息,PSI中无法提供的相关信息,SI定义了NIT、SDT、EIT和TDT等9张表,方便用户查看多种信息。
 

结构图

TS文件格式详解及解封装过程_第1张图片

通过av_read_frame获取到原始的es数据流对比可以看出.和ts原始数据缺少了ts和pes的头.左边为.ts文件,右边为.264文件。 

TS文件格式详解及解封装过程_第2张图片

流程图

TS文件格式详解及解封装过程_第3张图片

                                                        编码过程

TS解析图

先看下数据ts,这张图是借用别人的图,之前忘记分析这个图,觉得挺好的

TS文件格式详解及解封装过程_第4张图片

下面开始分析

TS文件格式详解及解封装过程_第5张图片

这个图主要解析的是流的基本信息:format,filesize,duration,bitrate以及音视频的Count

TS文件格式详解及解封装过程_第6张图片

  PAT和PMT的相关基本信息

TS文件格式详解及解封装过程_第7张图片

下面图是多音轨的TS

TS文件格式详解及解封装过程_第8张图片

 TS文件格式详解及解封装过程_第9张图片

 各种流的PID,索引及数量占的百分比,可以看到PAT和PMT是一一对应的,同时对应多个音频或者视频数据

分析

TS层的packet都是固定等长的188字节包,由ts header、adaptation field、payload组成,其中ts header固定4个字节(32位);adaptation field可能存在也可能不存在,主要作用是给不足188字节的数据做填充;payload是pes数据。结构图如下

TS文件格式详解及解封装过程_第10张图片

Ts header部分

TS文件格式详解及解封装过程_第11张图片

这里我们分析一段TS流其中一个Packet的Packet Data部分:
        首先给出一个数据包,其数据如下: 

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

固定同步字节

transport_error_indicator

“0”

没有传输错误

payload_unit_start_indicator

“1”

负载单元开始标识

在前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。

对于空包的包,payload_unit_start_indicator应该置为0。
 

transport_priority

“0”

传输优先级低

PID

0x0000

PID=0x0000说明数据包是PAT表信息,共13bit

transport_scrambling_control

“00”

未加密/传输扰乱控制

adaptation_field_control

“01”

附加区域控制/自适应区域控制

00:是保留值。
01:负载中只有有效载荷。
10:负载中只有自适应字段。
11:先有自适应字段,再有有效载荷。

continuity_counte

“0000”

包递增计数器

如上表所示,我们可以知道,首先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  

  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这个不知道是干嘛用的?大家知道吗?

TS文件格式详解及解封装过程_第12张图片

PID


       PID是TS流中唯一识别标志,Packet Data是什么内容就是由PID决定的。如果一个TS流中的一个Packet的Packet Header中的PID是0x0000,那么这个Packet的Packet Data就是DVB的PAT表而非其他类型数据(如Video、Audio或其他业务信息)。 

TS文件格式详解及解封装过程_第13张图片

TS文件格式详解及解封装过程_第14张图片

 从这两个图,可以看出,PAT的PID是0。 下表给出了一些表的PID值,这些值是固定的,不允许用于更改。

TS文件格式详解及解封装过程_第15张图片

PAT

PAT表(Program Association Table,节目关联表) ,PAT的PID为0x0000,它的主要作用是针对复用的每一路传输流,提供传输流中包含哪些节目、节目的编号以及对应节目的节目映射表(PMT)的位置,即PMT的TS包的包标识符(PID)的值,同时还提供网络信息表(NIT)的位置,即NIT的TS包的包标识符(PID)的值。

TS文件格式详解及解封装过程_第16张图片

TS文件格式详解及解封装过程_第17张图片

  •  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 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文件格式详解及解封装过程_第18张图片

从图中可以看到,这个TS里有一个节目,而PMT_PID=0x1000(4096)

PMT

PMT表(Program Map Table,节目映射表)

指明该节目包含的内容,即该节目由哪些流组成,这些流的类型(音频、视频、数据),以及组成该节目的流的位置,即对应的TS包的PID值,每路节目的节目时钟参考(PCR)字段的位置。

PMT表中包含的数据如下:

  • 当前节目中所有Video ES流的PID
  • 当前节目所有Audio ES流的PID
  • 当前节目PCR的PID等。

TS文件格式详解及解封装过程_第19张图片

 从图中可以看到这个TS包含一个program,program里包含一路视频和四路音频

TS文件格式详解及解封装过程_第20张图片

 主要的字段解析如下:(红色部分是对外有用的,黑色部分仅对当前解析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。
  • 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的场景下作校验。

TS文件格式详解及解封装过程_第21张图片

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 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流。


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 - 博客园

你可能感兴趣的:(FFMPEG,流媒体,TS解析)