欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TS码流解析-4-解析PMT表

程序员文章站 2022-03-05 12:17:17
...

任务四

根据解析PAT表的PMT_PID列表,获取所有的相关的PMT表,并且解析出包含的节目信息,主要是指音频和视频的pid。

相关知识

相信解码流解到这一步的人,对表的解析多多少少有一些了解,在这先放张PMT表的结构图,方便大家了解。PMT表示的是节目映射表的简称,可由PAT表查找到相应的PID,里面存储着音频、视频以及其他一些与节目相关的信息。解到这一步后,可以尝试着把音频视频的PID对应的ts_package找出来,并且另存一个文件,用播放器打开,可以看到对应的节目,会对解码流的任务有更深的理解,知道我们的目的是什么。
TS码流解析-4-解析PMT表
前八个字节就不用赘述了,descriptor对目前阶段来说,用处不大,也用不着管,知道它占多大空间就行了,我们要关注的字段有
program_info_length->后面描述子的总长度,stream_type前面的那个描述子
stream_type->媒体流的类型,判断是音频还是视频的重要标志
elementary_PID->媒体流类型对应的PID,可通过此PID找到对应的信息
ES_info_length->后续descriptor的长度

解析过程

这里的解析过程会比较麻烦,因为pmt的table有很多个,每解一个节目需要获取一遍table

1 流程图

TS码流解析-4-解析PMT表

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 运行结果

TS码流解析-4-解析PMT表
能把对应的信息存储起来,这个任务就算完成了