1.TS格式介绍

TS:全称为MPEG2-TS。TS即"Transport Stream"的缩写。它是分包发送的,每一个包长为188字节(还有192和204个字节的包)。包的结构为,包头为4个字节(第一个字节为0x47),负载为184个字节。在TS流里可以填入很多类型的数据,如视频、音频、自定义信息等。MPEG2-TS主要应用于实时传送的节目,比如实时广播的电视节目。MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。简单地说,将DVD上的VOB文件的前面一截cut掉(或者是数据损坏数据)就会导致整个文件无法解码,而电视节目是任何时候打开电视机都能解码(收看)的。

TS解析需要参考:ISO/IEC 13818-1的2.4 Transport Stream bitstream requirements

2.TS流包含的内容

一段TS流,必须包含PAT包、PMT包、多个音频包、多个视频包、多个PCR包、以及其他信息包。

解析TS流数据的流程:查找PID为0x0的包,解析PAT,PAT包中的program_map_PID表示PMT的PID;查找PMT,PMT包中的elementary_PID表示音视频包的PID,PMT包中的PCR_PID表示PCR的PID,有的时候PCR的PID跟音频或者视频的PID相同,说明PCR会融进音视频的包,注意解析,有的时候PCR是自己单独的包;CAT、NIT、SDT、EIT的PID分别为: 0x01、0x10、0x11、0x12。

3.TS包头解析

TS包头有4个字节

//Transport Stream header
typedef struct TS_header
{
         unsigned sync_byte                    :8;      //同步字节,固定为0x47 ,表示后面的是一个TS分组,当然,后面包中的数据是不会出现0x47的
         unsigned transport_error_indicator       :1;      //传输错误标志位,一般传输错误的话就不会处理这个包了
         unsigned payload_unit_start_indicator    :1;      //有效负载的开始标志,根据后面有效负载的内容不同功能也不同
         // payload_unit_start_indicator为1时,在前4个字节之后会有一个调整字节,它的数值决定了负载内容的具体开始位置。
         unsigned transport_priority              :1;      //传输优先级位,1表示高优先级
         unsigned PID                          :13;     //有效负载数据的类型
         unsigned transport_scrambling_control     :2;      //加密标志位,00表示未加密
         unsigned adaption_field_control          :2;      //调整字段控制,。01仅含有效负载,10仅含调整字段,11含有调整字段和有效负载。为00的话解码器不进行处理。
         unsigned continuity_counter              :4;      //一个4bit的计数器,范围0-15
} TS_header;
    //特殊参数说明:
   //sync_byte:0x47
   //payload_unit_start_indicator:0x01表示含有PSI或者PES头
   //PID:0x0表示后面负载内容为PAT,不同的PID表示不同的负载
   //adaption_field_control:
        // 0x0: // reserved for future use by ISO/IEC
        // 0x1: // 无调整字段,仅含有效负载  
        // 0x2: // 仅含调整字段,无有效负载
        // 0x3: // 调整字段后含有效负载
 
// Parse TS header
int Parse_TS_header(unsignedchar *pTSBuf, TS_header *pheader)
{
    pheader->sync_byte                                     = pTSBuf[0];
    if (pheader->sync_byte != 0x47)
        return -1;
    pheader->transport_error_indicator       = pTSBuf[1] >> 7;
    pheader->payload_unit_start_indicator    = pTSBuf[1] >> 6 & 0x01;
    pheader->transport_priority             = pTSBuf[1] >> 5 & 0x01;
    pheader->PID                         = (pTSBuf[1] & 0x1F) << 8 | pTSBuf[2];
    pheader->transport_scrambling_control   = pTSBuf[3] >> 6;
    pheader->adaption_field_control         = pTSBuf[3] >> 4 & 0x03;
    pheader->continuity_counter            = pTSBuf[3] & 0x0F;
    return 0;
}

TS包头解析需要参考:ISO/IEC 13818-1的2.4.3.2 Transport Stream packet layer

4.TS负载格式解析

4.1 PAT解析

TS_header包头中的PID值为0x0,表示当前负载为PAT(Program Association Table)。PAT数据的信息可以理解为整个TS流包含的节目信息。

// Program Association Table
typedef struct PAT_Packet_tag
{
    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; //最后一个分段的号码
    // for(i=0; i<N; i++)
    // {
    unsigned program_number                  : 16;
    unsigned reserved_3                      : 3;
    unsigned network_PID                     : 16;  // 或者program_map_PID
  // }
    unsigned CRC_32                          : 32;
} PAT_Packet;
 
// Parse PAT
int Parse_PAT(unsignedchar *pTSBuf, PAT_Packet *packet)
{
    TS_header TSheader;
    if (Parse_TS_packet_header(pTSBuf, &TSheader) != 0)
        return -1;
    if (TSheader.payload_unit_start_indicator == 0x01) // 表示含有PSI或者PES头
    {
        if (TSheader.PID == 0x0)  // 表示PAT
        {
             int iBeginlen = 4;
             int adaptation_field_length = pTSBuf[4];
             switch(TSheader.adaption_field_control)
             {
             case 0x0:                                   // reserved for future use by ISO/IEC
                  return -1;
             case 0x1:                                   // 无调整字段,仅含有效负载      
                  iBeginlen += pTSBuf[iBeginlen] + 1;  // + pointer_field
                  break;
             case 0x2:                                    // 仅含调整字段,无有效负载
                  return -1;
             case 0x3:// 调整字段后含有效负载
                 if (adaptation_field_length > 0)
                 {
                      iBeginlen += 1;                   // adaptation_field_length占8位
                      iBeginlen += adaptation_field_length; // + adaptation_field_length
                 }
                 else
                 {
                      iBeginlen += 1;                       // adaptation_field_length占8位
                 }
                 iBeginlen += pTSBuf[iBeginlen] + 1;           // + pointer_field
                 break;
            default:
                 break;
            }
            unsignedchar *pPAT = pTSBuf + iBeginlen;
            packet->table_id                    = pPAT[0];
            packet->section_syntax_indicator    = pPAT[1] >> 7;
            packet->zero                        = pPAT[1] >> 6 & 0x1;
            packet->reserved_1                  = pPAT[1] >> 4 & 0x3;
            packet->section_length              = (pPAT[1] & 0x0F) << 8 |pPAT[2];
            packet->transport_stream_id         = pPAT[3] << 8 | pPAT[4];
            packet->reserved_2                  = pPAT[5] >> 6;
            packet->version_number              = pPAT[5] >> 1 &  0x1F;
            packet->current_next_indicator      = (pPAT[5] << 7) >> 7;
            packet->section_number              = pPAT[6];
            packet->last_section_number         = pPAT[7];
            int len = 0;
            len = 3 + packet->section_length;
            packet->CRC_32                      = (pPAT[len-4] & 0x000000FF) << 24
                                                | (pPAT[len-3] & 0x000000FF) << 16
                                                | (pPAT[len-2] & 0x000000FF) << 8
                                                | (pPAT[len-1] & 0x000000FF);
 
            int n = 0;
            for ( n = 0; n < (packet->section_length - 12); n += 4 )
            {
                 packet->program_number = pPAT[8 + n ] << 8 | pPAT[9 + n ];
                 packet->reserved_3                = pPAT[10 + n ] >> 5;
                 if ( packet->program_number == 0x00)
                 {
                     packet->network_PID = (pPAT[10 + n ] & 0x1F) << 8 |pPAT[11 + n ];
                 }
                 else
                 {
                     // 有效的PMT的PID,然后通过这个PID值去查找PMT包
                     program_map_PID = (pPAT[10 + n] & 0x1F) << 8 |pPAT[11 + n];
                 }
            }
            return 0;
         }
    }
    return -1;
}

  PAT数据解析需要参考:ISO/IEC 13818-1的2.4.4.3 Program Association Table

4.2 PMT解析

由PAT包中的program_map_PID可以确定PMT(Program Map Table)的PID。PMT数据的信息可以理解为这个节目包含的音频和视频信息。

// Program Map Table
typedef struct PMT_Packet_tag
{
     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;
     // for(i=0; i<N; i++)
     // {
     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;
} PMT_Packet;
   // Parse PMT
int Parse_PMT(unsignedchar *pTSBuf, PMT_Packet *packet)
{
    // 参考Parse_PAT()来做就行了
    // ...
     
    return 0;
}

  PMT数据解析需要参考:ISO/IEC 13818-1的2.4.4.8 Program Map Table

4.3 PES解析

根据文档参考PAT、PMT的解析流程就能完成PES的解析了。

需要注意的是PES中PTS的解析,一般来说在90 kHz 中,PTS/9000的值为秒单位。

unsignedlong long Parse_PTS(unsigned *pBuf)
{
     unsignedlong long llpts = (((unsigned long long)(pBuf[0] & 0x0E)) << 29)
         | (unsigned long long)(pBuf[1] << 22)
         | (((unsigned long long)(pBuf[2] & 0xFE)) << 14)
         | (unsigned long long)(pBuf[3] << 7)
         | (unsigned long long)(pBuf[4] >> 1);
     return llpts;
}

PES结构详解
2013年08月05日 ⁄ 编程 ⁄ 共 1100字 ⁄ 评论数 2 ⁄ 被围观 3,562+

PES是Packetized Elementary Stream的简称,是将原始ES流打包后形成的,再将PES经过不同的打包方式可以组成MPEG program stream 和 MPEG transport stream,即PS流和TS流。

PES的组成结构如图,包括6个字节的包头字段,加上3个字节基本流信息字段,根据信息字段的设置可在之后附加其他字段。

<a href="http://www.yunlipiao.com/wp-content/uploads/2013/08/pes.jpg" class="cboxElement" rel="example4" 208"="" style="text-decoration: none; color: rgb(1, 150, 227);">

PES结构

前三字节是包头起始标识字段,内容为0x000001

第四个字节是流ID字段,不同的流ID有不用的意义,如图,音频流ID范围从0xC0到0xDF,视频流ID范围从0xE0到0xEF。

PES流ID字段

第五六个字节是PES包长度,表示PES包头部在该字段之后的长度,单位是字节

接下来的第七八九字节是PES的扩展头部字段,用于设置流的基本信息,结构如图

PES可选扩展

第六字节的高两位是标识位,值为10b

第七字节的高两位是PTS和DTS指示位,00表示无PTS无DTS,01禁止使用,10表示PES头部字段会附加PTS结构

pts结构

11表示PES头部字段会附加PTS和DTS结构

pts和dts结构

其中PTS和DTS使用的是90KHZ时钟单位,即1PTS表示1/90000秒,PTS和DTS虽然是33位,但占用了5个字节

ESCR FLAG字段设为1,会在头部附加6个字节的ESCR结构,ES RATE FLAG字段设置为1,会在头部附加3个字节ES rate结构,其他标识位如果设置为1也会相应的在头部附加对应字段。

ES rate结构

ESCR结构

 

本文地址:http://www.yunlipiao.com/208.html,出自云里飘博客,转载请保留链接

TS格式解析的更多相关文章

  1. 多媒体文件格式(四):TS 格式

    一.TS 格式标准介绍 TS是一种音视频封装格式,全称为MPEG2-TS.其中TS即"Transport Stream"的缩写. 先简要介绍一下什么是MPEG2-TS: DVD的音 ...

  2. 视音频数据处理入门:FLV封装格式解析

    ===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...

  3. TS流解析 二 *****

    1.TS格式介绍 TS:全称为MPEG2-TS.TS即"Transport Stream"的缩写.它是分包发送的,每一个包长为188字节(还有192和204个字节的包).包的结构为 ...

  4. plist文件、NSUserDefault 对文件进行存储的类、json格式解析

    ========================== 文件操作 ========================== Δ一 .plist文件 .plist文件是一个属性字典数组的一个文件: .plis ...

  5. ts 协议解析

    pes : http://wenku.baidu.com/link?url=KjcA0qXqZ1bWVQTa8i1YOmygofldSQL7Pjj-zGRw1e_6_LFmVLo5DIWF0SNwVn ...

  6. MySQL binlog的格式解析

    我搜集到了一些资料,对理解代码比较有帮助. 在头文件中binlog_event.h中,有描述 class Log_event_header class Log_event_footer 参见[Myst ...

  7. JSON格式解析和libjson使用简介(关于cjson的使用示例)

    JSON格式解析和libjson使用简介 在阅读本文之前,请先阅读下<Rss Reader实例开发之系统设计>一文. Rss Reader实例开发中,进行网络数据交换时主要使用到了两种数据 ...

  8. 转:YUV RGB 常见视频格式解析

    转: http://www.cnblogs.com/qinjunni/archive/2012/02/23/2364446.html YUV RGB 常见视频格式解析 I420是YUV格式的一种,而Y ...

  9. 虚拟机VHD格式解析到NTFS文件系统解析

    本来的需求是XEN下的镜像取证,但这篇仅包括他支持的一种格式,就是VHD,此项目从头开始大概用了两周时间,中间遇到了很多让人头大的问题,光是思考的笔记就写了十几页纸,不过实际上并没有那么难,主要是很久 ...

随机推荐

  1. imdisk命令行使用及配置

    imdisk是一个开源的虚拟磁盘软件,集虚拟光驱,文件虚拟光驱,映射物理磁盘,映射物理内存等功能 如果使用devio--Device I/O Service,可以映射网络磁盘等. 通用于windows ...

  2. ESB、SOA、EAI异同【转】

    先说概念:       ESB:企业服务总线(ESB : Enterprise Service Bus):ESB 是一种开放的.基于标准的分布式同步或异步信息传递中间件.通过 XML.Web Serv ...

  3. kernel网址

    http://www.kernel.org HTTP https://www.kernel.org/pub/ FTP ftp://ftp.kernel.org/pub/ http://www.oldl ...

  4. Android ListView 全面优化

    结合昨天学习的多线程,今天又继续对ListView进行了优化,包括异步加载图片,滑动时暂停加载,滑动停止后再加载显示界面中的item. 综合ListView在使用时参考的多篇博客,这里对ListVie ...

  5. CentOS下源码安装Apache2.4+PHP5.4+MySQL5.5

    一.准备(把所有的源文件放在‘/home/yuanjun’目录下) apr http://mirror.bjtu.edu.cn/apache/apr/apr-1.4.6.tar.gz apr-util ...

  6. Yii Listview 更新及搜索

    更新: http://my.oschina.net/shixiaobao17145/blog/130992 http://www.yiiframework.com/forum/index.php/to ...

  7. ios 好去处

    1.王巍的博客(我们都叫它喵神,他很萌哒) 链接:http://onevcat.com/ (难度指数:※※※※※)理由:他的swift的新书讲解的非常好,但不适合入门,进阶的话这是很适合的一本书.其他 ...

  8. iOS开发中使用CIDetector检测人脸

    在iOS5 系统中,苹果就已经有了检测人脸的api,能够检测人脸的位置,包括左右眼睛,以及嘴巴的位置,返回的信息是每个点位置.在 iOS7中,苹果又加入了检测是否微笑的功能.通过使用 CIDetect ...

  9. ubuntu14.04启动提示set_sw_state failed

    安装上ubuntu14.04时,系统启动时一直出现一个问题 kernel: [ 16.465893] [drm:rv770_dpm_set_power_state] *ERROR* rv770_set ...

  10. 在Java项目中整合Scala

    Scala是一个运行在Java JVM上的面向对象的语言.它支持函数编程,在语法上比Java更加灵活,同时通过Akka库,Scala支持强大的基于Actor的多线程编程.具有这些优势,使得我最近很想在 ...