TS Stream 详解

<什么是TS>

TS(transport stream) , TS流文件,是一种DVD的文件格式,TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的,这种特性就决定了TS流文件主要用来实时传送的节目,比如实时广播的电视节目。与之相互对应的是PS(Program Stream),PS主要应用于存储的具有固定时长的节目,如DVD电影,将DVD上的VOB文件的前面一截剪掉(或者干脆就是数据损坏),那么就会导致整个文件无法解码。

<TS码流数据封装格式>

网络上常见的TS码流结构图:

由上图可知,TS流主要由header 和 payload 组成,其中header 部分相对来说比较简单一些,payload部分成分比较复杂,其中payload 可以是PSI(其中包括PAT , PMT),可以是PES(从摄像头采集的数据经过压缩算法后的数据被成为ES , 一般是在一帧的ES数据前加上点头信息,其中最主要的是PTS和DTS信息,就形成了PES),可以是一些自适应数据(没一包TS码流长度是固定的188字节,视频数据不够188个字节,使用0xFF填充)。

?TS header

TS header 的结构:

TS header结构图如图所示, 各个部分的含义如下:

?sync_byte:同步字节,固定为0x47 ,表示后面的是一个TS分组。

?transport_error_indicator:错误标志位,占位1bit,置为1表示此分组中至少有一个不可纠正的错误

?payload_unit_start_indicator:负载开始标志位,针对不同的负载,有不同的含义

●PES:

置为1,标识TS包的有效净荷以PES包的第一个字节开始,即此TS包为PES包的起始包,且此TS分组中有且只有一个PES包的起始字段;置为0,表示TS包不是PES包的起始包,是后面的数据包。

●PSI:

置为1,表示TS包中带有PSI数据分段的第一个字节,即这个TS包是PSI
Section的起始包,则此TS包的负载(payload)的第一个字节带有pointer_field,用来指示PSI数据的在payload 中的位置;置为0,表示TS包不带有PSI
Section的第一个字节,即此TS包不是PSI的起始包,即在有效负载中没有point_field,有效负载的开始就是PSI的数据内容。point_field的定义将在下面的PSI节中进行介绍;对于空包的包,payload_unit_start_indicator应该置为0。

例如:若TS包载荷为PAT,则当接收到的TS包的payload_unit_start_indicator为1时,表明这个TS包包含了PAT头信息,从这个包里面解析出section_length和continuity_counter,然后继续收集后面的payload_unit_start_indicator
= 0的TS包,并判断continuity_counter的连续性,不断读出TS包中的净载荷(也就是PAT数据),用section_length作为收集TS包结束条件。

?transport_priority:发送优先级,置1则表示此包比其他相同PID置0的包有高的优先级

PID:指示有效负载中的数据类型

●0x0000代表PAT

●0x0001代表CAT

●0x0002-0x000F保留

●0x1FFF表示空包

transport_scrambling_control:有效负载加密模式标志,占位2bit,00表示未加密

adaption_field_control:调整字段标志,表示此TS首部是否跟随调整字段还是负载数据,占位2bit,其中00位保留,01表示无调整字段,只有有效负载数据,10表示只有调整字段,无有效负载,11表示有调整字段,且其后跟有有效负载;空分组此字段应为01;

●总结

如果adaptation_field_control == 1x,表示后面跟有自适应字段;

如果adaptation_field_control == x1,表示后面跟有没有自适应字段;

continuity_counter:连续性计数,随每一个相同PID的TS分组增加,达到最大值后又归为0;占位4bit,如果adaptation_field_control值为00或01,此值不应增加;若调整字段的标志位discontinuity_indicator值为1,则此值也不连续。

?自适应调整字段

调整字段,一般在以下两种情况会在TS流中添加自适应段,并且此时的TS header 中的 adaptation_field_control == 1x时,以下字段才会存在 :

(1) 封装TS数据的时候,视频或者音频数据不够184个字节的时候,使用该段来指明调整字段0xFF的长度,此时的自适应的区的PCR_flag 标志为0;

(2)对于每一帧视频数据进行封装的开始,需要并且是必须在TS header 之后添加自适应区间,此时,自适应区间中最重要的部分是PCR相关数据,PCR主要用来实现解码端的时钟同步,具有很重要的意义。此时的自适应区的PCT_flag 标志为1;

?  adaptation_field_length:调整字段长度标示,标示此字节后面调整字段的长度,占位8bit;值为0时,表示在TS分组中插入一个调整字节,后面没有调整字段,紧跟着的是有效负载;adaptation_field_control ==
‘11’时,此值在0~182之间,adaptation_field_control == ‘10’时,此值为183,若字段没这么长则填充0xFF字段;后面的字段都是在adaptation_field_length>0的时候才会出现,顺序如下:

discontinuity_indicator:不连续状态指示符,占位1bit,置位1时表示此TS分组的不连续状态为真;
random_access_indicator:随机访问指示符,占位1bit;
elementary_stream_priority_indicator:原始流数据优先级指示符,占位1bit,置位1表示此原始流数据比相同PID的TS包中的其他原始流优先级高;

?后面是5个flags,对应的flag 如果被置1 , 就在flags字段追加相应的数据
PCR_flag:PCR标志位,占位1bit,置位1表示调整字段中包含PCR字段,置位0则没有PCR字段;

PCR字段:当PCR_flag == 1时,此字段才存在,占位48bit,依次顺序为:

●program_clock_reference_base字段:         占位33bit;

●reserved字段:                                                占位6bit;

●program_clock_reference_extension字段:占位9bit;

OPCR_flag:OPCR标志位,占位1bit,置位1表示调整字段中包含OPCR字段,置位0则没有OPCR字段;

OPCR字段:当OPCR_flag == 1时,此字段才存在,占位48bit,依次顺序为:

original_program_clock_reference_base字段:         占位33bit;

reserved字段:                                                               占位6bit;

original_program_clock_reference_extension字段:占位9bit;

splicing_point_flag:splice_countdown标志位,占位1bit,置位1表示调整字段中包含splice_countdown字段,置位0则没有splice_countdown字段;

splice_countdown字段:当splicing_point_flag == 1时此字段存在,占位8bit;

transport_private_data_flag:transport_private_data标志位,占位1bit,置位1时表示调整字段中含有1个或者多个私有数据字节,置位0则无此字节;

transport_private_data字段:私有数据字段,当transport_private_data_flag == 1时此字段存在,占位N*8bit,字节顺序为:

transport_private_data_length:表明私有数据的字节长度,占位8bit;

private_data_byte:私有数据,长度由前面的长度字段确定;

adaptation_field_extension_flag:调整字段扩展标志位,占位1bit,置位1表示含有调整字段扩展字段,置位0则无扩展字段;

adaptation_field_extension字段:调整字段扩展字段,占用长度不确定,当adaptation_field_extension_flag == 1时此字段存在,字段中也有3个标志位,来确定一些字段存不存在,其具体字节顺序如下:

adaptation_field_extension_length:调整字段扩展字段的长度,占位8bit;

ltw_flag:ltw字段标志位,置位1时表示此字段存在,占位1bit;

piecewise_rate_flag:piecewise_rate字段标志位,置位1时此字段存在,占位1bit;

seamless_splice_flag:seamless_splice标志位,置位1时此字段存在,占位1bit;

Reserved:保留字段,占位5bit;

Ltw字段:当ltw_flag == 1时此字段存在,占位16bit,其由以下两个字段组成

ltw_valid_flag:占位1bit,当ltw_valid_flag == 1时,ltw_offset才有效;

ltw_offset:占位15bit;

piecewise_rate字段:当piecewise_rate_flag == 1时此字段存在,占位24bit,其字节顺序如下:

reserved字段:保留字段,占位2bit;

piecewise_rate字段:占位22bit;此字段只有在当ltw_flag == 1和ltw_valid_flag == 1时才有定义,有定义时此字段是一个正整数;

seamless_splice字段:当seamless_splice_flag == 1时此字段存在,占位40bit;字节顺序依次为:

splice_type字段:占位4bit;标识delay和rate值;

DTS_next_AU[32..30]:占位3bit;

marker_bit字段:占位1bit;

DTS_next_AU[29..15]字段:占位15bit;

marker_bit:占位1bit;

DTS_next_AU[14..0]:占位15bit;

marker_bit:占位1bit;

stuffing_byte:填充字段,固定为0xFF

?Payload_bytes:有效负载字段,字节来自PES包,PSI部分等;

?PES头

PES流是对原始ES流进行的第一层封装,PES流的基本单位是PES包,由包头和payload组成,ES流即音视频裸流,是从编码器里面出来的原始视频音频流;ES流只包含一种内容,里面是视频或者音频;封装时不对其进行改变,只在前面添加头部,如私有头,解码时,将私有头剥掉,将原始ES码流送进解码器解码,这也是解码通用性,若是修改了,则其他解码器就没法解码了;PES和ES一样,都是单一原始码流,一般我遇到的是一帧数据放在一个PES包里面,但是一个PES包的最大长度为65535字节,因此一帧数据有可能被分为多个PES;其包头格式如下。

可以看出,PES包是由固定包头,可选包头和负载三部分组成,其中固定包头固定6个字节;PES包长度字段占位16bit,最大值为65536,故一帧可能会分为多个PES包;下面依次介绍其每个字段的含义:

?Packet start code prefix:包头起始码,固定为0x000001,占位24bit;

?Stream id:(UI)PES包中的负载流类型,一般视频为0xe0,音频为0xc0,占位8bit;

?PES packet length:(UI)PES包长度,包括此字节后的可选包头和负载的长度,占位16bit;

 Optional PES Header,顺序依次为:

?‘10‘字段:占位2bit;

?PES scrambling control:加密模式,占2bit;00未加密,01或10或11由用户定义;

?PES priority:有效负载的优先级,占位1bit;值为1比值为0的负载优先级高;

?Data alignment indicator:数据定位指示器,占位1bit;

?Copyright:版权信息,1为有版权,0无版权,占位1bit;

?Original or copy:原始或备份,1为原始,0为备份,占位1bit;

? 后面是7个flags,对应的flag 如果被置1 , 就在PES header data length字段后追加相应的数据(一般我们关注的就是PTS
DTS的标志位):

?PTS_DTS_flags:PTS和DTS标志位,占位2bit;10表示首部有PTS字段,11表示有PTS和DTS字段,00表示都没有,01被禁止,不会出现此种情况;

PTS/DTS字段:显示时间戳/解码时间戳,占位40bit,当PTS_DTS_flags == 1x时此字段存在;时间占用33个bit,PTS和DTS的内容是在这40bit中取33位,方式相同;

PTS(presentation time stamp)显示时间戳和DTS(Decoding Time
Stamp)解码时间戳,是用来音视频同步的,是打在PES包的包头里面的,PTS/DTS是相对SCR(系统参考)的时间戳,是以90000为单位的,PTS/DTS到ms的转换公式是PTS/90,系统时钟频率(H264采样频率?)为90Khz,所以转换到秒为PTS/90000,所以如果是以ms为单位的播放器,PTS/DTS是要使用公式ms=pts/90来转换才行的,而如果是以时钟频率为单位的话,则直接将PTS/DTS送进去解码即可;如果没有B帧,PTS和DTS的顺序应该是一致的,如果有B帧,则需要先解码P帧,才能解出来B帧,所以需要PTS和DTS来控制解码时间和显示时间;

字节顺序依次:

start_code:起始码,占位4bit;若PTS_DTS_flags == ‘10’,则说明只有PTS,起始码为0010;若PTS_DTS_flags == ‘11’,则PTS和DTS都存在,PTS的起始码为0011,DTS的起始码为0001;(PTS的起始码后2个bit与flag相同)

PTS[32..30]:占位3bit;

marker_bit:占位1bit;

PTS[29..15]:占位15bit;

marker_bit:占位1bit;

PTS[14..0]:占位15bit;

marker_bit:占位1bit;

PTS/DTS  = (PTS1 & 0x0e) << 29 + (PTS2 & 0xfffe) << 14 + (PTS3 & 0xfffe ) >> 1;

?ESCR_flag:ESCR标志,占位1bit;1表示首部有ESCR字段,0则无此字段

ESCR字段:此字段占位48bit,由33bit的ESCR_base字段和9bit的ESCR_extension字段组成,ESCR_flag == 1时此字段存在;数据依次顺序:

Reserved:保留字段,占位2bit;

ESCR_base[32..30]:占位3bit;

marker_bit:占位1bit;

ESCR_base[29..15]:占位15bit;

marker_bit:占位1bit;

ESCR_base[14..0]:占位15bit;

marker_bit:占位1bit;

ESCR_extension:(UI)占位9bit;周期数,取值范围0~299;循环一次,base+1;

marker_bit:占位1bit;

?ES_rate_flag:ES_rate字段,占位1bit;1表示首部有此字段,0无此字段;

ES rate字段:目标解码器接收PES分组字节速率,禁止为0,占位24bit,ES_rate_flag == 1时此字段存在;数据顺序为:

marker_bit:占位1bit;

ES_rate:占位22bit;

marker_bit:占位1bit;

?DSM_trick_mode_flag:占位1bit;1表示有8位的DSM_trick_mode_flag字段,0无此字段;

Trick mode control字段:表示哪种trick mode被应用于相应的视频流,占位8个bit,DSM_ trick_mode_flag == 1时此字段存在;其中trick_mode_control占前3个bit,根据其值后面有5个bit的不同内容;

如果trick_mode_control == ‘000’,依次字节顺序为:

field_id:占位2bit;

intra_slice_refresh :占位1bit;

frequency_truncation:占位2bit;

如果trick_mode_control == ‘001’,依次字节顺序为:

rep_cntrl:占位5bit;

如果trick_mode_control == ‘010’,依次字节顺序为:

field_id:占位2bit;

Reserved:占位3bit;

如果trick_mode_control == ‘011’,依次字节顺序为:

field_id:占位2bit;

intra_slice_refresh:占位1bit;

frequency_truncation:占位2bit;

如果trick_mode_control== ‘100’,依次字节顺序为:

rep_cntrl:占位5bit;

其他情况,字节顺序为:

reserved :占位5bit;

?Additional_copy_info_flag:占位1bit;1表示首部有此字段,0表示无此字段;

Additional copy info字段8个bit,Additional_copy_info_flag == 1时此字段存在;数据顺序为:

marker_bit:占位1bit;

copy info字段:占位7bit;表示和版权相关的私有数据;

?PES_CRC_flag:占位1bit;置1表示PES分组有CRC字段,0无此字段;

Previous PES CRC字段:占位16bit字段,包含CRC值,PES_CRC_flag == 1时此字段存在;

?PES_extension_flag:占位1bit;扩展标志位,置1表示有扩展字段,0无此字段

PES exten sion字段:PES扩展字段,PES_extension_flag == 1时此字段存在;内容如下,字节顺序依次为:

PES_private_data_flag:占位1bit,置1表示有私有数据,0则无;

PES_private_data字段:私有数据内容,占位128bit,PES_private_data_flag == 1时此字段存在;

Pack_header_field_flag:占位1bit,置1表示有Pack_header_field字段,0则无;

Pack_header_field字段:Pack_header_field_flag == 1时此字段存在;字段组成顺序如下:

Pack_field_length字段:(UI)指定后面的field的长度,占位8bit;

pack_header_field()长度为Pack_field_length指定;

Program_packet_sequence_counter_flag:占位1bit,置1表示有此字段,0则无;

Program_packet_sequence_counter字段:计数器字段,16个bit;当flag字段Program_packet_sequence_counter_flag == 1时此字段存在;字节顺序依次为:

marker_bit:占位1bit;

packet_sequence_counter字段:(UI)占位7bit;

marker_bit占位1bit;

MPEG1_MPEG2_identifier:占位1bit;置位1表示此PES包的负载来自MPEG1流,置位0表示此PES包的负载来自PS流;

original_stuff_length:(UI)占位6bit;表示PES头部填充字节长度;

P-STD_buffer_flag:占位1bit,置1表示有P-STD_buffer字段,0则无此字段;

P-STD_buffer字段:表示P-STD_buffer内容,占位16bit;P-STD_buffer_flag == ‘1‘时此字段存在;字节顺序依次为:

’01’字段:占位2bit;

P-STD_buffer_scale:占位1bit;表示用来解释后面P-STD_buffer_size字段的比例因子;如果之前的stream_id表示音频流,则此值应为0,若之前的stream_id表示视频流,则此值应为1,对于其他stream类型,此值可以0或1;

P-STD_buffer_size:占位13bit;无符号整数;大于或等于所有P-STD输入缓冲区大小BSn的最大值;若P-STD_buffer_scale == 0,则P-STD_buffer_size以128字节为单位;若P-STD_buffer_scale == 1,则P-STD_buffer_size以1024字节为单位;

Reserved字段:3个bit;

PES_extension_flag_2:占位1bit,置1表示有扩展字段,0则无此字段;

PES_extension2字段:扩展字段的扩展字段;占用N*8个bit,PES_extension_flag_2 == ‘1‘时此字段存在;字节顺序依次为:

marker_bit占位1bit;

PES_extension_field_length:占位7bit,表示扩展区域的长度;

Reserved字段:占位8*PES_extension_field_length个bit;

Stuffing bytes:填充字段,固定为0xFF;不能超过32个字节;

PES_packet_data_bytePES包负载中的数据,即ES原始流数据

?PES header data length:(UI)PES首部中可选字段和填充字段的长度;占位8bit;可选字段的内容由上面7个flags来进行控制;

原文地址:https://www.cnblogs.com/big-devil/p/8589377.html

时间: 2024-07-30 19:28:34

TS Stream 详解的相关文章

[视频播放] HLS协议之M3U8、TS流详解

本文转载自:<hls之m3u8.ts流格式详解> HLS,Http Live Streaming 是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部分,一是M3U8描述文件,二是TS媒体文件. 1.M3U8文件 用文本方式对媒体文件进行描述,由一系列标签组成. #EXTM3U #EXT-X-TARGETDURATION:5 #EXTINF:5, ./0.ts #EXTINF:5, ./1.ts #EXTM3U:每个M3U8文件第一行必须是这个tag. #

爱你不容易 —— Stream详解

作为前端,我们常常会和 Stream 有着频繁的接触.比如使用 gulp 对项目进行构建的时候,我们会使用 gulp.src 接口将匹配到的文件转为 stream(流)的形式,再通过 .pipe() 接口对其进行链式加工处理: 或者比如我们通过 http 模块创建一个 HTTP 服务: const http = require('http'); http.createServer( (req, res) => { //... }).listen(3000); 此处的 req 和 res 也属于

Java8之Stream详解

Java8中提供了Stream对集合操作作出了极大的简化,学习了Stream之后,我们以后不用使用for循环就能对集合作出很好的操作. 一.流的初始化与转换 Java中的Stream的所有操作都是针对流的,所以,使用Stream必须要得到Stream对象: 1.初始化一个流 Stream stream = Stream.of("a", "b", "c"); 2.数组转换为一个流 String [] strArray = new String[]

Java8初体验(二)Stream语法详解

原文链接:http://ifeve.com/stream/ 1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel aggregate operations. 我们来解读一下上面的那句话: Stream是元素的集合,这点让Stream看起来用些类似Iterator: 可以支持顺序和并行的对原Stream进行汇聚的操作: 大家可以把Stream当成一个高级版本的

Node.js开发入门—Stream用法详解

Stream是Node.js中非常重要的一个模块,应用广泛.一个流是一个具备了可读.可写或既可读又可写能力的接口,通过这些接口,我们可以和磁盘文件.套接字.HTTP请求来交互,实现数据从一个地方流动到另一个地方的功能. 所有的流都实现了EventEmitter的接口,具备事件能力,通过发射事件来反馈流的状态.比如有错误发生时会发射"error"事件,有数据可被读取时发射"data"事件.这样我们就可以注册监听器来处理某个事件,达到我们的目的. Node.js定义了R

JAVA8之lambda表达式详解,及stream中的lambda使用

原文:http://blog.csdn.net/jinzhencs/article/details/50748202 lambda表达式详解 一.问题 1.什么是lambda表达式? 2.lambda表达式用来干什么的? 3.lambda表达式的优缺点? 4.lambda表达式的使用场景? 5.lambda只是一个语法糖吗? 二.概念 lambda表达式是JAVA8中提供的一种新的特性,它支持Java也能进行简单的"函数式编程". 它是一个匿名函数,Lambda表达式基于数学中的λ演算

【转】Java8初体验(二)Stream语法详解

原文链接 http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 [email protected]上篇文章Java8初体验(一)lambda表达式语法比较详细的介绍了lambda表达式的方方面面,细心的读者会发现那篇文章的例子中有很多Stream的例子.这些Stream的例子可能让你产生疑惑,本文将会详细讲解Stream的使用方法(不会涉及Stream的原理,因为这个系列的文章还是一个快速学习如何使用的). 1. Str

Java 8 Stream API详解

Java 8 Stream API详解 一.Stream API介绍 Java 8引入了全新的Stream API,此Stream与Java I/O包里的InputStream和OutputStream是完全不同的概念,它不同于StAX对XML解析的Stream,也不同于Amazon Kinesis对大数据实时处理的Stream.Stream API更像具有Iterable的集合类,但行为和集合类又有所不同,它是对集合对象功能的增强,专注于对集合对象进行各种非常便捷.高效的聚合操作或大批量数据操

Storm 第三章 Storm编程案例及Stream Grouping详解

1 功能说明 设计一个topology,来实现对文档里面的单词出现的频率进行统计.整个topology分为三个部分: SentenceSpout:数据源,在已知的英文句子中,随机发送一条句子出去. SplitBolt:负责将单行文本记录(句子)切分成单词 CountBolt:负责对单词的频率进行累加 2 代码实现 1 package com.ntjr.bigdata; 2 3 import org.apache.storm.Config; 4 import org.apache.storm.Lo