TS码流解析-4-解析PMT表
程序员文章站
2022-03-05 12:17:17
...
任务四
根据解析PAT表的PMT_PID列表,获取所有的相关的PMT表,并且解析出包含的节目信息,主要是指音频和视频的pid。
相关知识
相信解码流解到这一步的人,对表的解析多多少少有一些了解,在这先放张PMT表的结构图,方便大家了解。PMT表示的是节目映射表的简称,可由PAT表查找到相应的PID,里面存储着音频、视频以及其他一些与节目相关的信息。解到这一步后,可以尝试着把音频视频的PID对应的ts_package找出来,并且另存一个文件,用播放器打开,可以看到对应的节目,会对解码流的任务有更深的理解,知道我们的目的是什么。
前八个字节就不用赘述了,descriptor对目前阶段来说,用处不大,也用不着管,知道它占多大空间就行了,我们要关注的字段有
program_info_length->后面描述子的总长度,stream_type前面的那个描述子
stream_type->媒体流的类型,判断是音频还是视频的重要标志
elementary_PID->媒体流类型对应的PID,可通过此PID找到对应的信息
ES_info_length->后续descriptor的长度
解析过程
这里的解析过程会比较麻烦,因为pmt的table有很多个,每解一个节目需要获取一遍table
1 流程图
2 数据结构定义
typedef struct stream_message
{
unsigned int stream_type :8;
unsigned int elementary_pid :13;
struct stream_message *next;
}STREAM_MESSAGE;
typedef struct pmt_info
{
unsigned short program_number;
STREAM_MESSAGE *stream_message;
struct pmt_info *next;
}PMT_INFO;
typedef int(*CHECK_TYPE)(STREAM_MESSAGE message_node);
3 解析代码
/*****************************************************************************
* Function Name: check_stream_type_callback
* Description : according the condition then get the specify message
* Parameters : STREAM_MESSAGE message_node
* Returns : static int
* -1 check error
* other check success
*****************************************************************************/
static int check_stream_type_callback(STREAM_MESSAGE message_node)
{
if (0x0b == message_node.stream_type)
{
return 3;
}
if (0x06 == message_node.stream_type)
{
return 2;
}
if ((0x03==message_node.stream_type) || (0x04==message_node.stream_type))
{
return 1;
}
if ((0x01==message_node.stream_type) || (0x02==message_node.stream_type))
{
return 0;
}
return -1;
}
/*****************************************************************************
* Function Name: add_node_to_stream_message_link
* Description : add the message node to the link
* Parameters : PMT_INFO *pmt_info
* STREAM_MESSAGE message_node
* CHECK_TYPE check_stream_type
* Returns : static void
*****************************************************************************/
static void add_node_to_stream_message_link(PMT_INFO *pmt_info, STREAM_MESSAGE message_node, CHECK_TYPE check_stream_type)
{
STREAM_MESSAGE *new_stream_message_node = NULL;
new_stream_message_node = (STREAM_MESSAGE*)malloc(sizeof(STREAM_MESSAGE));
if (NULL == new_stream_message_node)
{
log("malloc memory error!\n");
return;
}
new_stream_message_node->stream_type = message_node.stream_type;
new_stream_message_node->elementary_pid = message_node.elementary_pid;
new_stream_message_node->next = NULL;
if (check_stream_type != NULL)
{
if (-1 == check_stream_type(message_node))
{
log("check type error!\n");
return;
}
}
//tail insert
if (NULL == pmt_info->stream_message)
{
pmt_info->stream_message = new_stream_message_node;
}else
{
new_stream_message_node->next = pmt_info->stream_message;
pmt_info->stream_message = new_stream_message_node;
}
}
/*****************************************************************************
* Function Name: parse_pmt_section
* Description : after get the one section and parse it
* Parameters : SECTION *stream_table
* PMT_INFO *pat_info_link_head
* unsigned int program_number
* Returns : static PMT_INFO *
* success return the messsage head
* error return NULL
*****************************************************************************/
static PMT_INFO *parse_pmt_section(SECTION *stream_table, PMT_INFO *pmt_info_link_head, unsigned int program_number)
{
unsigned int current_read_position = 0;
STREAM_MESSAGE swap_stream_message_node = {0};
PMT_INFO *pmt_info_node = NULL;
if (NULL == stream_table)
{
log("Section is NULL!\n");
return pmt_info_link_head;
}
pmt_info_node = (PMT_INFO*)malloc(sizeof(PMT_INFO));
if (NULL == pmt_info_node)
{
log("malloc memory error!\n");
return pmt_info_link_head;
}
memset(pmt_info_node, 0, sizeof(PMT_INFO));
pmt_info_node->program_number = program_number;
//head insert
pmt_info_node->next = pmt_info_link_head;
while(stream_table != NULL)
{
current_read_position = PMT_SECTION_HEAD_LENGTH + stream_table->section_buffer[PMT_SECTION_HEAD_LENGTH - 1];
while (current_read_position < (stream_table->section_length - 4))
{
swap_stream_message_node.stream_type = stream_table->section_buffer[current_read_position];
swap_stream_message_node.elementary_pid = ((stream_table->section_buffer[current_read_position + 1] & 0x1f) << 8) | stream_table->section_buffer[current_read_position + 2];
//add_node_to_stream_message_link(pmt_info_node, swap_stream_message_node, check_stream_type_callback);
add_node_to_stream_message_link(pmt_info_node, swap_stream_message_node, NULL);
current_read_position += 5 + stream_table->section_buffer[current_read_position + 4];
}
stream_table = stream_table->next;
}
return pmt_info_node;
}
/*****************************************************************************
* Function Name: create_pmt_info_link
* Description : input ts file get all the pmt information
* Parameters : FILE *ts_file
* unsigned int package_length
* int first_sync_position
* PROGRAM_INFO *pat_info_link_head
* Returns : PMT_INFO *
* success return the pmt information link head
* error return NULL
*****************************************************************************/
PMT_INFO *create_pmt_info_link(FILE *ts_file, unsigned int package_length, int first_sync_position, PAT_INFO *pat_info_link_head)
{
SECTION *stream_table = NULL;
PMT_INFO *pmt_info_link_head = NULL;
if ((NULL==ts_file) || (first_sync_position<0) || (0==package_length) || (NULL==pat_info_link_head))
{
log("function parse_pmt parameter error");
return NULL;
}
while (pat_info_link_head != NULL)
{
stream_table = create_section_link(ts_file, package_length, first_sync_position, PMT_TABLE_ID, pat_info_link_head->program_number_pid, NULL);
pmt_info_link_head = parse_pmt_section(stream_table, pmt_info_link_head, pat_info_link_head->program_number);
pat_info_link_head = pat_info_link_head->next;
destroy_section_link(stream_table);
stream_table = NULL;
}
return pmt_info_link_head;
}
4 运行结果
能把对应的信息存储起来,这个任务就算完成了
下一篇: Simplify Path