TS协议解析第二部分(PMT)
2016-06-05 17:07
585 查看
1. PMT:
PMT(Program Map Table):节目映射表,该表的PID是由PAT提供给出的。通过该表可以得到一路节目中包含的信息,例如,该路节目由哪些流构成和这些流的类型(视频,音频,数据),指定节目中各流对应的PID,以及该节目的PCR所对应的PID。
PMT表中包含的数据如下:
(1) 当前频道中包含的所有Video数据的PID
(2) 当前频道中包含的所有Audio数据的PID
(3) 和当前频道关联在一起的其他数据的PID(如数字广播,数据通讯等使用的PID)
2. 分析MPT包:
2.1 PMT包数据:
2.2 包头:
TS包头只有4个字节(47 60 81 10),除掉第一个字节0x47,剩下就3个,重新分组如下:
0 1 1 0000010000001 00 01 0000
2.3 TS包:
1) 在payload_unit_start_indicator为1时,在前4个字节后会有一个调整字节。所以实际数据应该为去除第一个字节00后的数据。(47 60 81 10 00 02
B0 17 00 01 C1 00 00 E8 10 F0 00 1B E8 10 F0 00 03 E8 14 F0 00 66 74 A4 2D)
2) 02 B0 17:0000 0010 1011 0000 0001 0111
section_length:23 (47
60 81 10 00 02 B0 17 00 01 C1 00 00 E8 10
F0 00 1B E8 10 F0 00 03 E8 14 F0 00 66 74 A4 2D)
3)
00 01:0000 0000 0000 0001
C1:1100 0001
00 00:0000 0000 0000 0000
E8 10:1110 1000 0001 0000
F0 00:1111 0000 0000 0000
1B E8 10 F0 00:0001 1011 1110 1000 0001 0000 1111 0000 0000 0000
03 E8 14 F0 00:0000 0011 1110 1000 0001 0100 1111 0000 0000 0000
[align=center]
[/align]
PMT
[align=center]
[/align]
3. 实现:
3.1 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;
3.2 PMT表结构体:
3.3 解析代码:
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;
}
PMT(Program Map Table):节目映射表,该表的PID是由PAT提供给出的。通过该表可以得到一路节目中包含的信息,例如,该路节目由哪些流构成和这些流的类型(视频,音频,数据),指定节目中各流对应的PID,以及该节目的PCR所对应的PID。
PMT表中包含的数据如下:
(1) 当前频道中包含的所有Video数据的PID
(2) 当前频道中包含的所有Audio数据的PID
(3) 和当前频道关联在一起的其他数据的PID(如数字广播,数据通讯等使用的PID)
2. 分析MPT包:
2.1 PMT包数据:
2.2 包头:
TS包头只有4个字节(47 60 81 10),除掉第一个字节0x47,剩下就3个,重新分组如下:
0 1 1 0000010000001 00 01 0000
sync_byte | 同步字节 | 0x47: |
transport_error_indicator | 传输错误标识 | 0: |
payload_unit_start_indicator | 负载单元开始标识 | 1: |
transport_priority | 传输优先级 | 1: |
pid | PID | 0x81:因为在PAT中查找到program_map_PID为0x81,因此就查找到PMT。 |
transport_scrambling_control | 传输扰乱控制 | 00: |
adaptation_field_control | 自适应区域控制 | 01: 00:是保留值。 01:负载中只有有效载荷。 10:负载中只有自适应字段。 11:先有自适应字段,再有有效载荷。 |
continuity_counter | 连续计数器 | 0x0: |
1) 在payload_unit_start_indicator为1时,在前4个字节后会有一个调整字节。所以实际数据应该为去除第一个字节00后的数据。(47 60 81 10 00 02
B0 17 00 01 C1 00 00 E8 10 F0 00 1B E8 10 F0 00 03 E8 14 F0 00 66 74 A4 2D)
2) 02 B0 17:0000 0010 1011 0000 0001 0111
section_length:23 (47
60 81 10 00 02 B0 17 00 01 C1 00 00 E8 10
F0 00 1B E8 10 F0 00 03 E8 14 F0 00 66 74 A4 2D)
3)
00 01:0000 0000 0000 0001
C1:1100 0001
00 00:0000 0000 0000 0000
E8 10:1110 1000 0001 0000
F0 00:1111 0000 0000 0000
1B E8 10 F0 00:0001 1011 1110 1000 0001 0000 1111 0000 0000 0000
03 E8 14 F0 00:0000 0011 1110 1000 0001 0100 1111 0000 0000 0000
[align=center]
[/align]
table_id | 0x02:对于PMT,该字段置为0x02 |
section_syntax_indicator | 1:对于PMT,该字段置为1 |
0 | 0: |
reserved | 11: |
section_length | 0000 0001 0111:前两位置为00,该字段指示分段的字节数,由分段长度字段开始,包括CRC,其值不超过1021。 |
Program_number | 0x 00 01:对应于PAT中的Program_nmuber。 |
reserved | 11: |
version_number | 00000:该字段指出了TS中program_map_section的版本号。 |
current_next_indicator | 1:当该字段置为1时,表示当前传送的program_map_section可用;当该字段置0时,表示当前传送的program_map_section不可用,下一个TS的program_map_section有效。 |
section_number | 0x00:section_number:该字段值总是置0x00 |
last_section_number | 0x00:该字段值总是置0x00 |
reserved | 111: |
PCR_PID | 0x810:该字段指示TS包的PID值。该TS包含有PCR字段,而PCR值对应于有节目好指定的节目。 |
reserved | 1111: |
Program_info_length | 0x000: |
stream_type | 1B:表示这个流时h264格式的,通俗点就是视频 |
reserved | 111: |
Elementary_pid | 0x810:表示PID时810的TS包就是用来装h264数据的 |
reserved | 1111: |
es_info_length | 0x000: |
Stream_type: | 0x03: |
reserved: | 111: |
Elementary_pid | 0x814 |
reserved | 1111: |
Es_info_lenth | 0x000: |
Crc_32 | 0x 03 E8 14 F0 00: |
table_id | 8 | 1个字节 |
section_syntax_indicator | 1 | 2个字节 |
‘0’ | 1 | |
reserved | 2 | |
section_length | 12 | |
program_number | 16 | 2个字节 |
reserved | 2 | 1个字节 |
version_number | 5 | |
current_next_indicator | 1 | |
section_number | 8 | 1个字节 |
last_section_number | 8 | 1个字节 |
reserved | 3 | 2个字节 |
PCR_PID | 13 | |
reserved | 4 | 2个字节 |
program_info_length | 12 | |
循环:descriptor()(0-N) | ||
循环开始(0-N1) | ||
stream_type | 8 | 1个字节 |
reserved | 3 | 2个字节 |
elementary_PID | 13 | |
reserved | 4 | 2个字节 |
ES_info_length | 12 | |
循环:descriptor()(0-N2) | ||
循环结束 | ||
CRC_32 | 32 | 4个字节 |
[/align]
3. 实现:
3.1 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;
3.2 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 nsigned 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;
3.3 解析代码:
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;
}
相关文章推荐
- PHP中VC6、VC9、TS、NTS版本的区别与用法详解
- Ten printing rules with Citrix XenApp
- 获取各个TS内存
- Table_id、PID分配
- ts 码流结构分析
- PMT表的结构和流类型
- 从dvbsnoop到ts demux的设计
- pes时处理PTS和DTS的方法
- TS流
- Live555转发DVB实时流数据
- MPEG2-TS 简单理解
- 什么是 音轨 声道 与 ES TS 关系 通道
- ffmpeg 常用转码命令和格式
- MPEG2 TS小结
- MPEG2-TS音视频同步原理
- TS协议解析第一部分(PAT)
- 信源编码与信道编码
- MPEG & MPEG-2 system
- 基于Live555的封装H264裸流为Ts流笔记(H264转ts流最简单方法)
- 使用FFmpeg将mp4转为ts(代码实现)