http://blog.csdn.net/tuan891205/article/details/8557661

TS即是"Transport Stream"的缩写。他是分包发送的,每一个包长为188字节。在TS流里可以填入很多类型的数据,如视频、音频、自定义信息等。他的包的结构为,包头为4个字节,负载为184个字节(这184个字节不一定都是有效数据,有一些可能为填充数据)。
工作形式: 
因为在TS流里可以填入很多种东西,所以有必要有一种机制来确定怎么来标识这些数据。制定TS流标准的机构就规定了一些数据结构来定义。比如: PSI(Program Specific Information)表,所以解析起来就像这样: 先接收一个负载里为PAT的数据包,在整个数据包里找到一个PMT包的ID。然后再接收一个含有PMT的数据包,在这个数据包里找到有关填入数据类型的ID。之后就在接收到的TS包里找含有这个ID的负载内容,这个内容就是填入的信息。根据填入的数据类型的ID的不同,在TS流复合多种信息是可行的。关键就是找到标识的ID号。
现在以一个例子来说明具体的操作:
在开始之前先给出一片实际TS流例子: 
0000f32ch: 47 40 00 17 00 00 B0 0D 00 01 C1 00 00 00 01 E0 ; G@....?..?...? 
0000f33ch: 20 A2 C3 29 41 FF FF FF FF FF FF FF FF FF FF FF ;  ⒚)A
0000f34ch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f35ch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f36ch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f37ch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f38ch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f39ch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f3ach: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f3bch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f3cch: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 
0000f3dch: FF FF FF FF FF FF FF FF FF FF FF FF 47 40 20 17 ; G@ .
0000f3ech: 00 02 B0 1B 00 01 C1 00 00 E0 21 F0 00 1B E0 21 ; ..?..?.??.?
0000f3fch: F0 04 2A 02 7E 1F 03 E0 22 F0 00 5D 16 BD 48    ; ?*.~..??].紿
具体的分析就以这个例子来分析。
// Adjust TS packet header
void adjust_TS_packet_header(TS_packet_header* pheader)
{
    unsigned char buf[4];
    memcpy(buf, pheader, 4);
    pheader->transport_error_indicator        = buf[1] >> 7;
    pheader->payload_unit_start_indicator    = buf[1] >> 6 & 0x01;
    pheader->transport_priority                = buf[1] >> 5 & 0x01;
    pheader->PID                            = (buf[1] & 0x1F) << 8 | buf[2];
    pheader->transport_scrambling_control    = buf[3] >> 6;
    pheader->adaption_field_control            = buf[3] >> 4 & 0x03;
    pheader->continuity_counter                = buf[3] & 0x03;
}
这是一个调整TS流数据包头的函数,这里牵扯到位段调整的问题。现在看一下TS流数据包头的结构的定义:
// Transport packet header
typedef struct TS_packet_header
{
    unsigned sync_byte                        : 8;
    unsigned transport_error_indicator        : 1;
    unsigned payload_unit_start_indicator    : 1;
    unsigned transport_priority                : 1;
    unsigned PID                            : 13;
    unsigned transport_scrambling_control    : 2;
    unsigned adaption_field_control            : 2;
    unsigned continuity_counter                : 4;
} TS_packet_header;
下面我们来分析,在ISO/IEC 13818-1里有说明,PAT(Program Association Table)的PID值为0x00,TS包的标识(即sync_byte)为0x47,并且为了确保这个TS包里的数据有效,所以我们一开始查找47 40 00这三组16进制数,为什么这样?具体的奥秘在TS包的结构上,前面已经说了sync_byte固定为0x47。现在往下看transport_error_indicator、payload_unit_start_indicator、transport_priority和PID这四个元素,PID为0x00,这是PAT的标识。transport_error_indicator为0,transport_priority为0。把他们看成是两组8位16进制数就是:40 00。现在看看我们的TS流片断例子,看来正好是47 40 00开头的,一个TS流的头部占据了4个字节。剩下的负载部分的内容由PID来决定,例子看来就是一个PAT表。在这里有个地方需要注意一下,payload_unit_start_indicator为1时,在前4个字节之后会有一个调整字节,它的数值决定了负载内容的具体开始位置。现在看例子中的数据47 40 00 17 00第五个字节是00,说明紧跟着00之后就是具体的负载内容。
下面给出PAT表的结构体:
// PAT table
// Programm Association Table
typedef struct TS_PAT
{
    unsigned table_id                        : 8;
    unsigned section_syntax_indicator        : 1;
    unsigned zero                            : 1;
    unsigned reserved_1                        : 2;
    unsigned section_length                    : 12;
    unsigned transport_stream_id            : 16;
    unsigned reserved_2                        : 2;
    unsigned version_number                    : 5;
    unsigned current_next_indicator            : 1;
    unsigned section_number                    : 8;
    unsigned last_section_number            : 8;
    unsigned program_number                    : 16;
    unsigned reserved_3                        : 3;
    unsigned network_PID                    : 13;
    unsigned program_map_PID                : 13;
    unsigned CRC_32                            : 32;
} TS_PAT;
再给出PAT表字段调整函数:
// Adjust PAT table
void adjust_PAT_table ( TS_PAT * packet, char * buffer )
{
    int n = 0, i = 0;
    int len = 0;
    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];
    // Get CRC_32
    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);
    // Parse network_PID or program_map_PID
    for ( n = 0; n < packet->section_length - 4; n ++ )
    {
        packet->program_number            = buffer[8] << 8 | buffer[9];
        packet->reserved_3                = buffer[10] >> 5;
        if ( packet->program_number == 0x0 )
            packet->network_PID = (buffer[10] << 3) << 5 | buffer[11];
        else
        {
            packet->program_map_PID = (buffer[10] << 3) << 5 | buffer[11];
        }
        n += 5;
    }
}
通过上面的分析,例子中的数据00 B0 0D 00 01 C1 00 00 00 01 E0 20 A2 C3 29 41就是具体的PAT表的内容,然后根据PAT结构体来具体分析PAT表。但是我们需要注意的是在PAT表里有program_number、network_PID的元素不只有一个,这两个元素是通过循环来确定的。循环的次数通过section_length元素的确定。在这个例子中program_map_PID为20,所以下面来PMT分析时,就是查找47 40 20的开头的TS包。
下面来分析PMT表,先给出PMT(Program Map Table)的结构体:
// PMT table
// Program Map Table
typedef struct TS_PMT
{
    unsigned table_id                        : 8;
    unsigned section_syntax_indicator        : 1;
    unsigned zero                            : 1;
    unsigned reserved_1                        : 2;
    unsigned section_length                    : 12;
    unsigned program_number                    : 16;
    unsigned reserved_2                        : 2;
    unsigned version_number                    : 5;
    unsigned current_next_indicator            : 1;
    unsigned section_number                    : 8;
    unsigned last_section_number            : 8;
    unsigned reserved_3                        : 3;
    unsigned PCR_PID                        : 13;
    unsigned reserved_4                        : 4;
    unsigned program_info_length            : 12;
   
    unsigned stream_type                    : 8;
    unsigned reserved_5                        : 3;
    unsigned elementary_PID                    : 13;
    unsigned reserved_6                        : 4;
    unsigned ES_info_length                    : 12;
    unsigned CRC_32                            : 32;
} TS_PMT;
在给出调整字段函数:
// Adjust PMT table
void adjust_PMT_table ( TS_PMT * packet, char * buffer )
{
    int pos = 12, len = 0;
    int i = 0;
    packet->table_id                            = buffer[0];
    packet->section_syntax_indicator            = buffer[1] >> 7;
    packet->zero                                = buffer[1] >> 6;
    packet->reserved_1                            = buffer[1] >> 4;
    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;
    packet->reserved_4                            = buffer[10] >> 4;
    packet->program_info_length                    = (buffer[10] & 0x0F) << 8 | buffer[11];
    // Get CRC_32
    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);
    // 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; )
    {
        packet->stream_type                            = buffer[pos];
        packet->reserved_5                            = buffer[pos+1] >> 5;
        packet->elementary_PID                        = ((buffer[pos+1] << 8) | buffer[pos+2]) & 0x1FFF;
        packet->reserved_6                            = buffer[pos+3] >> 4;
        packet->ES_info_length                        = (buffer[pos+3] & 0x0F) << 8 | buffer[pos+4];
        // Store in es
        es[i].type = packet->stream_type;
        es[i].pid = packet->elementary_PID;
        if ( packet->ES_info_length != 0 )
        {
            pos = pos+5;
            pos += packet->ES_info_length;
        }
        else
        {
            pos += 5;
        }
        i++;
    }
}
TS流可以复合很多的节目的视频和音频,但是解码器是怎么来区分的呢?答案就在PMT表里,如其名节目映射表。他就是来解决这个问题的。现在看PMT结构体里的stream_type、elementary_PID这两个元素,前一个用来确定后一个作为标识PID的内容具体是什么,音频或视频等。还有要注意他们不只有一个,所以他们是通过循环读取来确保所有的值都被读取了,当然循环也是有规定的(具体看调整函数上)。从例子上来看,我们在倒数第三行找到了上面分析来的PMT表的PID为0x20的TS包。然后就可以把数据是用调整函数填入结构中。然后得到具体节目的PID为视频0x21, 音频0x22。
PS. 文章里的PID是用来判断具体TS包是什么包的。分析每个包得到的PID值,都可以复合在TS头部结构体的PID里。

TS结构解析(详细的PAT和PMT解析代码)相关推荐

  1. TS流PAT、PMT、ES、PES分析及解析代码

    TS流即是我们所熟知的传输流,其是由定长的TS包组成(188字节),包括包头和负载数据.其中包头固定为4字节,用来指明包的起始位置.负载的PID以及各种标志位:负载则由各种表及基础流组成: PAT表给 ...

  2. 从mpeg ts文件中提取I帧(2):pat pmt解析

    一.PAT用途 1.描述当前传输流中 PMT 的 PID 信息. 2.描述PMT,与SDT的对应关系. 3.program_number=0时为network pid即nit的pid,接收pmt时注意 ...

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

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

  4. TS流结构分析(PAT和PMT)

    TS流也是由一个或多个PES组合而来的,他们可以具有相同的时间基准,也可以不同.其基本的复用思想是,对具有相同时间基准[color="#000000"]的多个PES现进行节目复用, ...

  5. TS流PAT、PMT、SDT内容

    TS流: TS流.PS流.PES流和ES流都是什么? ES流(ElementaryStream):基本码流,不分段的音频.视频或其他信息的连续码流. PES流:把基本流ES分割成段,并加上相应头文件打 ...

  6. PAT、PMT、SDT详解

    http://blog.chinaunix.NET/uid-24322243-id-2620180.html 下面针对解复用程序详细分析一下PAT,PMT和SDT三类表格的格式. PAT---Prog ...

  7. PAT、PMT、SDT详解 MPEG2-TS流的分析

    下面针对解复用程序详细分析一下PAT,PMT和SDT三类表格的格式. PAT---Program Association Table,节目关联表.PAT表携带以下信息: (1) TS流ID--- tr ...

  8. 结构感知图像修复:ICCV2019论文解析

    结构感知图像修复:ICCV2019论文解析 StructureFlow: Image Inpainting via Structure-aware Appearance Flow 论文链接: http ...

  9. 【算法】超详细的遗传算法(Genetic Algorithm)解析

    转自:https://www.jianshu.com/p/ae5157c26af9 [算法]超详细的遗传算法(Genetic Algorithm)解析 00 目录 遗传算法定义 生物学术语 问题导入 ...

最新文章

  1. java动态url_使用url Param的动态主题
  2. python 异常处理模块_扩展Python模块系列(五)----异常和错误处理
  3. AAC ADTS格式分析
  4. Map.Entry如何使用?
  5. Teradata 金融数据模型FS-LDM
  6. 高质量C /C编程指南---序言
  7. htaccess 伪静态的规则
  8. Java实现简单图书管理系统
  9. LDAP DirectoryEntry access AD User
  10. 有源医疗器械电磁兼容入门知识汇总
  11. Week 8 CSP M2 HRZ学英语
  12. 更换鼠标垫(鼠标)的心路历程
  13. 无盘服务器文件管理,云图管家文档图纸管理软件
  14. 华三模拟器命令(陆续更新)
  15. 嵌入式系统之实时系统调度算法
  16. android 点击震动,Android 实现为点击事件添加震动效果
  17. IOS m3u8格式视频流截图
  18. Eclipse折叠代码插件folding 推荐
  19. Teamviewer退出锁定远程计算机
  20. PMP笔记-项目干系人管理要点总结

热门文章

  1. 家长怎样让孩子不在沉迷手机
  2. Java研发工程师知识点总结
  3. centos8 yum问题
  4. denied 虚拟机access_彻底解决Ubuntu SSH 无法远程登录及root 登录ACCESS Denied 问题
  5. 互联网对证券业务的影响 发展证券电子商务将是券商的必然选择
  6. 一个富翁试图与陌生人做一笔生意用python_2009年青岛市程序设计试题
  7. xmind右键无法创建
  8. 直播录屏神器Camtasia 2023屏幕录制和视频编辑的软件
  9. [架构漫谈]软件架构师如何工作
  10. apache启动失败故障排除