PMT 表分析
程序员文章站
2022-03-22 23:23:04
...
PMT表结构
PMT 表实例
在下图中,我们可以看到PMT表携带的基本信息。一共有四个section,是四张PMT表的信息;其中,每个section存储在一个PMT表中,对应了一个节目的信息。 下面,我们以节目号为16398的节目为例进行分析。
下图可以看到,一共有3个单元流,每一个单元流都是组成这个节目的一个 元素(或者说是分量)。 可以看到,这个节目包含一个MPEG2的视频(stream_type=0x02)、一个MPEG2的音频(stream_type=0x04)以及一个私有类型(stream_type=0x06)的数据。
table_id | 8bits | 0x02:对于PMT,该字段置为0x02 |
section_syntax_indicator | 1bits | :对于PMT,该字段置为1 |
0 | 1bits | 0 |
reserved | 2bits | – |
section_length | 12bits | 0000 0001 0111:前两位置为00,该字段指示分段的字节数,由分段长度字段开始,包括CRC,其值不超过1021。 |
Program_number | 16bits | 0x 00 01:对应于PAT中的Program_nmuber。 |
reserved | 2bits | – |
version_number | 5bits | 00000:该字段指出了TS中program_map_section的版本号。 |
current_next_indicator | 1bits | :当该字段置为1时,表示当前传送的program_map_section可用;当该字段置0时,表示当前传送的program_map_section不可用,下一个TS的program_map_section有效。 |
-section_number | 8bits | -0x00:section_number:该字段值总是置0x00. |
last_section_number | 8bits | 0x00:该字段值总是置0x00 |
reserved | 3bits | |
PCR_PID | 13bits | 0x810:该字段指示TS包的PID值。该TS包含有PCR字段,而PCR值对应于有节目好指定的节目。 |
reserved | 4bits | |
Program_info_length | 12bits | 0x000 |
循环开始 | ||
stream_type | 8bits | 1B:表示这个流时h264格式的,通俗点就是视频 |
reserved | 3bits | |
Elementary_pid | 13bits | 0x810:表示PID时810的TS包就是用来装h264数据的 |
reserved | 4bits | |
es_info_length | 12bits | 0x000 |
循环结束 | ||
Crc_32 | 32bits | 校验 |
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
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;
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;
}
上一篇: 【量化投资】策略六(聚宽)
下一篇: Part2-Chapter9-树回归
推荐阅读
-
怎么比较mysql里不同的两张表的差异;还有mysql和postgres之间同表的差异比较?
-
ThinkPHP模板输出display用法分析,thinkphpdisplay_PHP教程
-
PHP中new static()与new self()的区别异同分析_PHP
-
在MySQL中同时查找两张表中的数据的示例_MySQL
-
PHP中spl_autoload_register()和__autoload()区别分析_PHP教程
-
图的深度优先遍历非递归C语言实现(邻接矩阵、邻接表)
-
最短路径—SPFA算法(邻接矩阵+链式前向星+邻接表实现)
-
mysql从某表中查询数据插入到另一表的处理_MySQL
-
Java有向无权图的单源点最短路径-邻接矩阵和邻接表
-
MySQL的性能分析