<什么是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来进行控制;

TS Stream 详解的更多相关文章

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

    本文转载自:<hls之m3u8.ts流格式详解> HLS,Http Live Streaming 是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部 ...

  2. JDK1.8中的Stream详解

    Stream简介 Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML ...

  3. 爱你不容易 —— Stream详解

    作为前端,我们常常会和 Stream 有着频繁的接触.比如使用 gulp 对项目进行构建的时候,我们会使用 gulp.src 接口将匹配到的文件转为 stream(流)的形式,再通过 .pipe() ...

  4. gulp源码解析(一)—— Stream详解

    作为前端,我们常常会和 Stream 有着频繁的接触.比如使用 gulp 对项目进行构建的时候,我们会使用 gulp.src 接口将匹配到的文件转为 stream(流)的形式,再通过 .pipe() ...

  5. 性能篇系列—stream详解

    Stream API Java 8集合中的Stream相当于高级版的Iterator Stream API通过Lambda表达式对集合进行各种非常便利高效的聚合操作,或者大批量数据操作 Stream的 ...

  6. Java8之Stream详解

    Java8中提供了Stream对集合操作作出了极大的简化,学习了Stream之后,我们以后不用使用for循环就能对集合作出很好的操作.   一.流的初始化与转换   Java中的Stream的所有操作 ...

  7. 此流非彼流——Stream详解

    Stream是什么? Java从8开始,不但引入了Lambda表达式,还引入了一个全新的流式API:Stream API.它位于java.util.stream包中. Stream 使用一种类似用 S ...

  8. Java 8 Stream API详解--转

    原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...

  9. Java8的Stream语法详解(转载)

    1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel agg ...

随机推荐

  1. HDU 1846 Brave Game 巴什博奕

    解题报告:Alice和Bob在做一个取石子游戏,有一堆n个石子,然后规定每个人每次最少要去1个石子,最多可以取m个石子,最后一次取完石子的人为胜. 巴什博奕,关键是找到必胜点和必败点,我们可以先列举出 ...

  2. 【leetcode 简单】 第一百一十题 分发饼干

    假设你是一位很棒的家长,想要给你的孩子们一些小饼干.但是,每个孩子最多只能给一块饼干.对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸:并且每块饼干 j ,都有一个尺寸 ...

  3. HDU 3790 最短路径问题 (最短路)

    题目链接 Problem Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的. ...

  4. 【译】第九篇 SQL Server代理了解作业和安全

    本篇文章是SQL Server代理系列的第九篇,详细内容请参考原文 在这一系列的上一篇,学习了如何在SQL Server代理作业步骤启动外部程序.你可以使用过时的ActiveX系统,运行批处理命令脚本 ...

  5. 苹果手机浏览器$(document).on(“click”,function(){})点击无效的问题

    <label class="js_highlight" style="display: inline-block;float: left;width: 50%;&q ...

  6. iOS学习笔记(2)— UIView用户事件响应

    UIView除了负责展示内容给用户外还负责响应用户事件.本章主要介绍UIView用户交互相关的属性和方法. 1.交互相关的属性 userInteractionEnabled 默认是YES ,如果设置为 ...

  7. linux cpu、内存、硬盘空间查询

    [CPU] 算式: CPU总核数 = 物理CPU个数 * 每颗物理CPU的核数 总逻辑CPU数 = 物理CPU个数 * 每颗物理CPU的核数 * 超线程数 #查看CPU型号 cat /proc/cpu ...

  8. Mac上删除不了的文件,Windows上也粉碎不了怎么办?

    推荐一个Mac上的软件:Tuxera Disk Manager 用法很简单:选择删除文件原来所在的文件进行维护就可以了. 维护之后,在废纸篓中清除,成功.

  9. maven package exec 及 maven 配置文件详解

    maven package test包下执行test 的配置文件 生成target目录,编译.测试代码,生成测试报告,生成jar/war文件 maven 配置文件详解 http://blog.csdn ...

  10. Windows 8 应用程序前后台切换事件监听

    在一些情况下,我们需要监听应用程序切换到后台或者从后台切换至前台的事件,从而进行相关处理操作.支付宝应用锁屏(IOS,Android平台)的处理中就需要监听此事件,在用户将应用切换至后台一段时间后再切 ...