TS流解析 二

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(unsigned char *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(unsigned char *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;

            }

            unsigned char *pPAT = pTSBuf + iBeginlen;

            packet->table_id                    = pTSBuf[0];

            packet->section_syntax_indicator    = pTSBuf[1] >> 7;

            packet->zero                        = pTSBuf[1] >> 6 & 0x1;

            packet->reserved_1                  = pTSBuf[1] >> 4 & 0x3;

            packet->section_length              = (pTSBuf[1] & 0x0F) << 8 | pTSBuf[2];

            packet->transport_stream_id         = pTSBuf[3] << 8 | pTSBuf[4];

            packet->reserved_2                  = pTSBuf[5] >> 6;

            packet->version_number              = pTSBuf[5] >> 1 &  0x1F;

            packet->current_next_indicator      = (pTSBuf[5] << 7) >> 7;

            packet->section_number              = pTSBuf[6];

            packet->last_section_number         = pTSBuf[7];

            int len = 0;

            len = 3 + packet->section_length;

            packet->CRC_32                      = (pTSBuf[len-4] & 0x000000FF) << 24

                                                | (pTSBuf[len-3] & 0x000000FF) << 16

                                                | (pTSBuf[len-2] & 0x000000FF) << 8

                                                | (pTSBuf[len-1] & 0x000000FF);

            int n = 0;

            for ( n = 0; n < (packet->section_length - 12); n += 4 )

            {

                 packet->program_number = pTSBuf[8 + n ] << 8 | pTSBuf[9 + n ];

                 packet->reserved_3                = pTSBuf[10 + n ] >> 5;

                 if ( packet->program_number == 0x00)

                 {

                     packet->network_PID = (pTSBuf[10 + n ] & 0x1F) << 8 | pTSBuf[11 + n ];

                 }

                 else

                 {

                     // 有效的PMT的PID,然后通过这个PID值去查找PMT包

                     program_map_PID = (pTSBuf[10 + n] & 0x1F) << 8 | pTSBuf[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(unsigned char *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的值为秒单位。

unsigned long long Parse_PTS(unsigned *pBuf)

{

     unsigned long 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数据解析需要参考:2.5.5.1 Syntax of the PES packet syntax for Program Stream directory

5.码流分析工具

5.1 Elecard Stream Analyzer

5.2 EasyICE

分类: 流媒体

时间: 2024-08-26 11:52:05

TS流解析 二的相关文章

TS流解析 四

一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等信息.因此,我们首先需要了解TS流是什么,以及TS流是怎样形成.有着怎样的结构. (一) TS流.PS流.PES流和ES流都是什么? ES流(Elementary Stream):基本码流,不分段的音频.视频或其他信息的连续码流. PES流:把基本流ES分割成段,并加上相应头文件打包成形的打包基本码

TS流解析 三

应该说真正了解TS,还是看了朋友推荐的<数字电视业务信息及其编码>一书之后,MPEG2 TS和数字电视是紧密不可分割的,值得总结一下其中的一些关系. ISO/IEC-13818-1:系统部分:ISO/IEC-13818-2:视频:ISO/IEC-13818-3:音频:ISO/IEC-13818-4:一致性测试:ISO/IEC-13818-5:软件部分:ISO/IEC-13818-6:数字存储媒体命令与控制:ISO/IEC-13818-7:高级音频编码:ISO/IEC-13818-8:系统解码实

ffmpeg解析TS流

介绍:  MPEG的系统层编码为不同的应用场景设计了两种格式: TS(Transport Stream) 和PS(Program Stream), 它们两者之间不具有层级关系, 在逻辑上,它们两者都是由PES(Packetized Elementary Stream)包组成的, 所以可以很方便地实现相互转换. TS(Transport Stream): 是将具有一个或多个独立时间基的一个或多个节目(包括音频和视频)组成一个流, 组成同一个节目的基本流(如一个视频流,多个音频流)的PES包有一个共

关于TS流的解析

TS即是"Transport Stream"的缩写.他是分包发送的,每一个包长为188字节.在TS流里可以填入很多类型的数据,如视频.音频.自定义信息等.他的包的结构为,包头为4个字节,负载为184个字节(这184个字节不一定都是有效数据,有一些可能为填充数据). 工作形式: 因为在TS流里可以填入很多种东西,所以有必要有一种机制来确定怎么来标识这些数据.制定TS流标准的机构就规定了一些数据结构来定义.比如: PSI(Program Specific Information)表,所以解

[视频播放] 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. #

TS流格式(转)

一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等信息.因此,我们首先需要了解TS流是什么,以及TS流是怎样形成.有着怎样的结构. (一) TS流.PS流.PES流和ES流都是什么? ES流(Elementary Stream):基本码流,不分段的音频.视频或其他信息的连续码流. PES流:把基本流ES分割成段,并加上相应头文件打包成形的打包基本码

TS流分析

一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等信息.因此,我们首先需要了解TS流是什么,以及TS流是怎样形成.有着怎样的结构. (一) TS流.PS流.PES流和ES流都是什么? ES流(Elementary Stream):基本码流,不分段的音频.视频或其他信息的连续码流. PES流:把基本流ES分割成段,并加上相应头文件打包成形的打包基本码

TS流之代码分析

代码分析前,先要了解TS流基本概念:TS流之基本概念. VLC解析TS流是通过libts库来分离的,libts库使用libdvbpsi库来解TS表. 1. libts库在加载的时候,会将以下如下两个函数注册下去,当接收到PAT或者PMT的时候,会进行调用.PAT和PMT每隔一段时间就会发送一次,以更新节目信息. static void PATCallBack( void*, dvbpsi_pat_t * ); static void PMTCallBack( void *data, dvbpsi

使用zxing生成和解析二维码

二维码: 是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的: 在代码编制上巧妙的利用构成计算机内部逻辑基础的0和1比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图像输入设备或光电扫描设备自动识读以实现信息自动处理: 二维码能够在横向和纵向两个方位同时表达信息,因此能在很小的面积内表达大量的信息: 二维码相对于条形码的优势就是省空间: zxing简介: zxing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库