关于TS流的解析

简介: TS即是"TransportStream"的缩写。他是分包发送的,每一个包长为188字节。在TS流里可以填入很多类型的数据,如视频、音频、自定义信息等。

TS即是"TransportStream"的缩写。他是分包发送的,每一个包长为188字节。在TS流里可以填入很多类型的数据,如视频、音频、自定义信息等。他的包的结构为,包头为4个字节,负载为184个字节(这184个字节不一定都是有效数据,有一些可能为填充数据)。
工作形式:
因为在TS流里可以填入很多种东西,所以有必要有一种机制来确定怎么来标识这些数据。制定TS流标准的机构就规定了一些数据结构来定义。比如: PSI(ProgramSpecific 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
{
    unsignedsync_byte                       : 8;
    unsignedtransport_error_indicator        : 1;
    unsigned payload_unit_start_indicator    : 1;
    unsignedtransport_priority               : 1;
    unsignedPID                           : 13;
    unsigned transport_scrambling_control    : 2;
    unsignedadaption_field_control           : 2;
    unsignedcontinuity_counter               : 4;
} TS_packet_header;
下面我们来分析,在ISO/IEC 13818-1里有说明,PAT(ProgramAssociation 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进制数就是:4000。现在看看我们的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
{
    unsignedtable_id                       : 8;
    unsignedsection_syntax_indicator        : 1;
    unsigned zero                           : 1;
    unsignedreserved_1                       : 2;
    unsignedsection_length                   : 12;
    unsignedtransport_stream_id           : 16;
    unsignedreserved_2                       : 2;
    unsigned version_number                   : 5;
    unsignedcurrent_next_indicator           : 1;
    unsignedsection_number                   : 8;
    unsignedlast_section_number           : 8;
    unsignedprogram_number                   : 16;
    unsignedreserved_3                       : 3;
    unsignednetwork_PID                   : 13;
    unsignedprogram_map_PID               : 13;
    unsignedCRC_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 0000 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(ProgramMap Table)的结构体:
// PMT table
// Program Map Table
typedef struct TS_PMT
{
    unsignedtable_id                       : 8;
    unsignedsection_syntax_indicator        : 1;
    unsignedzero                           : 1;
    unsignedreserved_1                       : 2;
    unsignedsection_length                   : 12;
    unsignedprogram_number                   : 16;
    unsignedreserved_2                       : 2;
    unsignedversion_number                   : 5;
    unsignedcurrent_next_indicator           : 1;
    unsignedsection_number                   : 8;
    unsignedlast_section_number           : 8;
    unsignedreserved_3                       : 3;
    unsignedPCR_PID                       : 13;
    unsignedreserved_4                       : 4;
    unsignedprogram_info_length           : 12;
   
    unsignedstream_type                   : 8;
    unsignedreserved_5                       : 3;
    unsignedelementary_PID                   : 13;
    unsignedreserved_6                       : 4;
    unsignedES_info_length                   : 12;
    unsignedCRC_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包头定义:

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 0x010xe3 0xe8 0xf0 0x0b 0xd7 0x79 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 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的数据信息。

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

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 0xe90xf0 0x00 0x1b 0xe3 0xe9 0xf0 0x00 0xf0 0xaf 0xb4 0x4f 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff0xff 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

 

目录
相关文章
|
算法 决策智能 C++
干货 |【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
干货 |【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
508 0
关于TS流的解析
<p align="center"><strong><span style="color:#02368D;"></span></strong></p> <div style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25px;"> <span style="font-si
2427 0
[Multimedia][TS]TS流的解析
  TS即是"Transport Stream"的缩写。他是分包发送的,每一个包长为188字节。在TS流里可以填入很多类型的数据,如视频、音频、自定义信息等。他的包的结构为,包头为4个字节,负载为184个字节(这184个字节不一定都是有效数据,有一些可能为填充数据)。
978 0

推荐镜像

更多