TS流也是由一个或多个PES组合而来的,他们可以具有相同的时间基准,也可以不同。其基本的复用思想是,对具有相同时间基准[color="#000000"]的多个PES现进行节目复用,然后再对相互有独立时间基准的各个PS进行传输复用,最终产生出TS。 TS包由包头和包数据2部分组成,其中包头还可以包括扩展的自适用区。包头长度占4bytes,自使用区和包数据共占184bytes,整个TS包长度相当于4个ATM包长。TS包的包头由如下图摘录所示的同步字节、传输误码指示符、有效载荷单元起始指示符、传输优先、包识别(PID-Packet Identification)、传输加扰控制、自适应区控制和连续计数器8个部分组成。

其中,可用同步字节位串的 自动 相关特性,检测数据流中的包限制,建立包同步;传输误码指示符,是指有不能消除误码时,采用误码校正解码器可表示1bit 的误码,但无法校正;有效载荷单元起始指示符,表示该数据包是否存在确定的起始信息;传输优先,是给 TS 包分配优先权; PID 值是由 用户 确定的,解码器根据PID 将 TS 上从不同 ES 来的 TS 包区别出来,以重建原来的 ES ;传输加扰控制,可指示数据包内容是否加扰,但包头和自适应区永远不加扰;自适应区控制,用 2 bit 表示有否自适应区,即( 01 )表示有有用信息无自适应区,( 10 )表示无有用信息有自适应区,( 11 )表示有有用信息有自适应区,( 00 )无定义;连续计数器可对 PID 包传送顺序计数,据计数器读数,接收端可判断是否有包丢失及包传送顺序错误。显然,包头对 TS 包具有同步、识别、检错及加密功能。
    TS 包自适应区由自适应区长、各种标志指示符、与插入标志有关的信息和填充数据 4 部分组成。其中标志部分由间断指示符、随机存取指示符、 ES 优化指示符、 PCR 标志、接点标志、传输专用数据标志、原始 PCR 标志、自适应区扩展标志 8 个部分组成。重要的是标志部分的 PCR 字段,可给编解码器的 27MHz 时钟提供同步资料,进行同步。其过程是,通过 PLL ,用解码时本地用 PCR 相位与输入的瞬时 PCR 相位锁相比较,确定解码过程是否同步,若不同步,则用这个瞬时 PCR 调整时钟频率。因为,数字图像采用了复杂而不同的压缩编码算法,造成每幅图像的数据各不相同,使直接从压缩编码图像数据的开始部分获取时钟信息成为不可能。为此,选择了某些(而非全部) TS 包的自适应区来传送定时信息。于是,被选中的 TS 包的自适应区,可用于测定包信息的控制 bit 和重要的控制信息。自适应区无须伴随每个包都发送,发送多少主要由选中的 TS 包的传输专用时标参数决定。标志中的随机存取指示符和接点标志,在节目变动时,为随机进入 I 帧压缩的数据流提供随机进入点,也为插入当地节目提供方便。自适应区中的填充数据是由于 PES 包长不可能正好转为 TS 包的整数倍,最后的 TS 包保留一小部分有用容量,通过填充字节加以填补,这样可以防止缓存器下溢,保持总码率恒定不变。

根据前一篇中各数据的定义及数据结构,对数据进行分别解析如下:

TS包头定义:

typedef struct TS_packet_header
{
    unsigned sync_byte                        : 8; //同步字节, 固定为0x47,表示后面的是一个TS分组
    unsigned transport_error_indicator        : 1; //传输误码指示符
    unsigned payload_unit_start_indicator    : 1; //有效荷载单元起始指示符
   
    unsigned transport_priority              : 1; //传输优先, 1表示高优先级,传输机制可能用到,解码用不着
    unsigned PID                            : 13; //PID
    unsigned transport_scrambling_control    : 2; //传输加扰控制 
    unsigned adaption_field_control            : 2; //自适应控制 01仅含有效负载,10仅含调整字段,11含有调整字段和有效负载。为00解码器不进行处理
    unsigned continuity_counter                : 4; //连续计数器 一个4bit的计数器,范围0-15
} TS_packet_header;

TS包头解析代码:

HRESULT CTS_Stream_Parse::adjust_TS_packet_header( TS_packet_header* TS_header )
{
 unsigned char buf[4]; 
 
    memcpy(buf, TS_header, 4);
    TS_header->transport_error_indicator        = buf[1] >> 7;
    TS_header->payload_unit_start_indicator    = buf[1] >> 6 & 0x01;
    TS_header->transport_priority                = buf[1] >> 5 & 0x01;
    TS_header->PID                            = (buf[1] & 0x1F) << 8 | buf[2];
    TS_header->transport_scrambling_control    = buf[3] >> 6;
    TS_header->adaption_field_control            = buf[3] >> 4 & 0x03;
    TS_header->continuity_counter                = buf[3] & 0x0F; // 四位数据,应为0x0F xyy 09.03.18

return 0;
}

如下为一个TS包数据:

0x47 0x40 0x00 0x12 0x00 0x00 0xb0 0x0d 0x00 0x00 0xc1 0x00 0x00 0x00 0x01 0xe3 0xe8 0xf0 0x0b 0xd7 0x79 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff

分析知道前四位0x47 0x40 0x00 0x12TS头部即为TS包头数据,解析如下:

sync_byte   :0x47
transport_error_indicator: 0x00
payload_unit_start_indicator: 0x01
transport_priority  : 0x00

PID                     :0x0000
transport_scrambling_control  :0x00
adaptation_field_control  :0x01

continuity_counter   :0x02

PID = 0x0000,表示此TS包的内容为PSI信息表格的PAT表格数据,在4字节的TS包头之后的第一个字节的Point_field = 0x00, 表示偏移量为0,即紧随其后的即为PAT的数据信息。

TS流解析之PAT表格解析

PAT表格定义如下:

typedef struct TS_PAT_Program
{
 unsigned program_number    :16; //节目号
 unsigned program_map_PID   :13;   //节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个
}TS_PAT_Program;

//PAT表结构体
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

unsigned CRC_32                            : 32;  //CRC32校验码
} TS_PAT;

解析代码如下:

HRESULT CTS_Stream_Parse::adjust_PAT_table( TS_PAT * packet, unsigned char * buffer)
{
    packet->table_id                    = buffer[0];
    packet->section_syntax_indicator    = buffer[1] >> 7;
    packet->zero                        = buffer[1] >> 6 & 0x1;
    packet->reserved_1                    = buffer[1] >> 4 & 0x3;
    packet->section_length                = (buffer[1] & 0x0F) << 8 | buffer[2]; 
 
    packet->transport_stream_id            = buffer[3] << 8 | buffer[4];
 
    packet->reserved_2                    = buffer[5] >> 6;
    packet->version_number                = buffer[5] >> 1 &  0x1F;
    packet->current_next_indicator        = (buffer[5] << 7) >> 7;
    packet->section_number                = buffer[6];
    packet->last_section_number            = buffer[7];

int len = 0;
    len = 3 + packet->section_length;
    packet->CRC_32                        = (buffer[len-4] & 0x000000FF) << 24
  | (buffer[len-3] & 0x000000FF) << 16
  | (buffer[len-2] & 0x000000FF) << 8 
  | (buffer[len-1] & 0x000000FF); 
 
  
 int n = 0;
    for ( n = 0; n < packet->section_length - 12; n += 4 )
    {
  unsigned  program_num = buffer[8 + n ] << 8 | buffer[9 + n ];  
        packet->reserved_3                = buffer[10 + n ] >> 5; 
  
  packet->network_PID = 0x00;
  if ( program_num == 0x00)
  {  
            packet->network_PID = (buffer[10 + n ] & 0x1F) << 8 | buffer[11 + n ];

TS_network_Pid = packet->network_PID; //记录该TS流的网络PID

TRACE(" packet->network_PID %0x \n\n", packet->network_PID );
  }
        else
        {
   TS_PAT_Program PAT_program;
   PAT_program.program_map_PID = (buffer[10 + n] & 0x1F) << 8 | buffer[11 + n];
   PAT_program.program_number = program_num;
   packet->program.push_back( PAT_program );
   
   TS_program.push_back( PAT_program );//向全局PAT节目数组中添加PAT节目信息     
        }         
    }
 return 0;
}

因此,PAT数据解析结果如下:

PAT数据

table_id    :0x00                            //8  
section_syntax_indicator   :0x01           // 1
'0'              :0x00                       // 1
reserved             0x03                // 2
section_length      :0x00d                    // 12
transport_stream_id    :0x0000                 // 16
reserved                        :0x03        // 2
version_number            :0x00              // 5
current_next_indicator   :0x01               // 1
section_number              :0x00            // 8
last_section_number         :0x00            // 8
program_number     :0x0001                    // 16
  reserved                :0x07               // 3
program_map_PID      :0x03e8             // 13
CRC         :0x f0 0b d7 79

由解析结构可知,该PAT表格中没有网络信息包信息,只包含一个节目,其PID为0x03e8

TS流解析之PMT表格解析

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;

解析代码为:

HRESULT CTS_Stream_Parse::adjust_PMT_table ( TS_PMT * packet, unsigned char * buffer )

    packet->table_id                            = buffer[0];
    packet->section_syntax_indicator            = buffer[1] >> 7;
    packet->zero                                = buffer[1] >> 6 & 0x01; 
    packet->reserved_1                            = buffer[1] >> 4 & 0x03;
    packet->section_length                        = (buffer[1] & 0x0F) << 8 | buffer[2];    
    packet->program_number                        = buffer[3] << 8 | buffer[4];
    packet->reserved_2                            = buffer[5] >> 6;
    packet->version_number                        = buffer[5] >> 1 & 0x1F;
    packet->current_next_indicator                = (buffer[5] << 7) >> 7;
    packet->section_number                        = buffer[6];
    packet->last_section_number                    = buffer[7];
    packet->reserved_3                            = buffer[8] >> 5;
    packet->PCR_PID                                = ((buffer[8] << 8) | buffer[9]) & 0x1FFF;

PCRID = packet->PCR_PID;

packet->reserved_4                            = buffer[10] >> 4;
    packet->program_info_length                    = (buffer[10] & 0x0F) << 8 | buffer[11]; 
    // Get CRC_32
 int len = 0;
    len = packet->section_length + 3;    
    packet->CRC_32                = (buffer[len-4] & 0x000000FF) << 24
  | (buffer[len-3] & 0x000000FF) << 16
  | (buffer[len-2] & 0x000000FF) << 8
  | (buffer[len-1] & 0x000000FF);

int pos = 12;
    // program info descriptor
    if ( packet->program_info_length != 0 )
        pos += packet->program_info_length;    
    // Get stream type and PID    
    for ( ; pos <= (packet->section_length + 2 ) -  4; )
    {
  TS_PMT_Stream pmt_stream;
  pmt_stream.stream_type =  buffer[pos];
  packet->reserved_5  =   buffer[pos+1] >> 5;
  pmt_stream.elementary_PID =  ((buffer[pos+1] << 8) | buffer[pos+2]) & 0x1FFF;
  packet->reserved_6     =   buffer[pos+3] >> 4;
  pmt_stream.ES_info_length =   (buffer[pos+3] & 0x0F) << 8 | buffer[pos+4];
  
  pmt_stream.descriptor = 0x00;
  if (pmt_stream.ES_info_length != 0)
  {
   pmt_stream.descriptor = buffer[pos + 5];
   
   for( int len = 2; len <= pmt_stream.ES_info_length; len ++ )
   {
    pmt_stream.descriptor = pmt_stream.descriptor<< 8 | buffer[pos + 4 + len];
   }
   pos += pmt_stream.ES_info_length;
  }
  pos += 5;
  packet->PMT_Stream.push_back( pmt_stream );
  TS_Stream_type.push_back( pmt_stream );
    }
 return 0;
}

举例如下:

0x47 0x43 0xe8 0x12 0x00 0x02 0xb0 0x12 0x00 0x01 0xc1 0x00 0x00 0xe3 0xe9 0xf0 0x00  0x1b 0xe3 0xe9 0xf0 0x00 0xf0 0xaf 0xb4 0x4f 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff

TS头部

sync_byte   :0x47
transport_error_indicator: 0x00
payload_unit_start_indicator: 0x01
transport_priority  : 0x00

PID                     :0x03e8
transport_scrambling_control  :0x00
adaptation_field_control  :0x01

continuity_counter   :0x02

PMT数据

table_id     :0x02                          // 8
section_syntax_indicator  :0x01            //  1
'0'                :0x00                   //  1
reserved       :0x03                       //  2
section_length :      0x012                 //  12
program_number    :0x00 01                    //  16
reserved               :0x03               //  2
version_number    :0x00                    //  5
current_next_indicator   0x01             //  1
section_number      :0x00                  //  8
last_section_number    :0x00               //  8 
reserved                   0x07           //  3
PCR_PID           :0x03 e9   // PCR(节目参考时钟)所在TS分组的PID          //  13
reserved       :0x0f                 //4
program_info_length     :0x000              //  12
stream_type       :0x1b                    //  8
reserved            0x07                  //  3
elementary_PID        :0x03 e9    //  13//该节目中包括的视频流,音频流等对应的TS分组的PID
reserved                    :0x0f          //  4
ES_info_length         :0x000               //  12
CRC        : 0xf0 af b4 4f

TS流结构分析(PAT和PMT)相关推荐

  1. 【PSI/SI学习系列】1.从TS流到PAT和PMT

    [PSI/SI学习系列]1.从TS流到PAT和PMT   前言 欢迎到我的网站阅读:http://www.onelib.biz/blog/stb 一 从TS流开始 最近开始学习数字电视机顶盒的开发,从 ...

  2. RTSP中TS流结构分析

    RTSP中TS流结构分析 UDP数据包整体结构 RTP Header结构 TS Header结构 PAT结构 PMT结构 PES Header结构 ES层 Wireshark抓取TS包 UDP数据包整 ...

  3. TS流PAT/PMT详解

    原文 :http://www.cnblogs.com/shakin/p/3714848.html 一 从TS流开始 从MPEG-2到DVB,看着看着突然就出现了一大堆表格,什么PAT.PMT.CAT- ...

  4. hls之m3u8、ts流格式详解

    HLS,Http Live Streaming 是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部分,一是M3U8描述文件,二是TS媒体文件. 1.M3U8文件 ...

  5. 网络流媒体(四)———TS流

    1. 数字视频压缩MPEG-2标准 MPEG-2是MPEG(Moving Picture Experts Group,运动图像专家组)组织制定的视频和音频有损压缩标准之一,它的正式名称为"基 ...

  6. PS-TS-PES-ES流结构分析

    相关链接:https://blog.csdn.net/knowledgebao/article/details/84776869 目录 概念普及: TS层(ts header+adaption+PAT ...

  7. TS流讲解--什么是ts流

    一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等 ...

  8. hls中ts流格式简介

    1.ts简介      ts流最早应用于数字电视领域,其格式非常复杂包含的配置信息表多大十几个,视频格式主要是mpeg2.苹果公司发明的http live stream流媒体是基于ts文件的,不过他大 ...

  9. (原)关于MEPG-2中的TS流数据格式学习

    关于MEPG-2中的TS流数据格式学习 Author:lihaiping1603 原创:http://www.cnblogs.com/lihaiping/p/8572997.html 本文主要记录了, ...

最新文章

  1. UC阿里鱼卡全网免流活动正在进行
  2. 大数据集群启停shell脚本:hadoop(hdfs、yarn)、hbase集群启停
  3. Fikker反向代理服务器的网站缓存加速/网站加速基础教程
  4. ASP.NET Core Docker部署
  5. shiro学习(1):shiro简介
  6. 剖析 Promise 之基础篇
  7. 数据中台 VS 传统大数据平台,这 8 点区别要了解
  8. 导入ansys的实体怎么进行parameter_ANSYS在线缆线束设计中的仿真应用
  9. Fedora 10下应用网络模拟器NS心得
  10. 数据科学 IPython 笔记本 9.2 NumPy 简介
  11. MUI+Htmlplus开发APP实现页面之间传值
  12. linux中完全卸载oracle,Linux 完整卸载oracle和grid软件
  13. 音乐外链php修复版源码
  14. Rails博客软件 Enki
  15. reference pics
  16. 山沟沟里的技术脱贫:阿里工程师助平武蜂农物联网养蜂...
  17. Keras的Model模型使用
  18. C语言|职工工资管理系统
  19. html中word wrap,HTML的断行word-wrap: break-word 和 word-break: break-all 到底有啥区别?
  20. dataframe 赋值

热门文章

  1. 手把手带用宝塔面板发布前端项目
  2. Postman光标错位问题
  3. 自助建站有什么优势?建站宝盒“三站合一”火爆来袭!!
  4. LeetCode 803. Bricks Falling When Hit
  5. gta5ol什么时候修复服务器,【图片】Rockstar感谢GTA玩家修复了线上的加载时间,官方更新即将到来。【gta5吧】_百度贴吧...
  6. my server与mysql_my sql和sql server有什么区别?
  7. 单片机AT指令控制WiFi模块联网及远程控制LED灯
  8. java之JVM学习全过程学习记录
  9. android 仿美团联动,仿美团弹出分类选择框(左右两个listview联动)
  10. 百度地图高德地图横向评测nbsp;出…