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

TS码流解析-5-解析SDT表

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

任务五

解析SDT表,解出相关的节目信息,主要是service_id和节目名字以及供应商的名字等

相关知识

SDT是服务描述表的简称,描述了业务内容及信息,连接了NIT、EIT和PMT(PSI),所谓业务也就是我们所理解的频道。
SDT:
PID = 0x0011
TABLE_ID = 0x42 (discribe actual TS,现行TS)
TABLE_ID = 0x46 (discribe not actual TS,非现行TS)
SDT表结构
TS码流解析-5-解析SDT表
在SDT表中,我们主要关注的是
service_id->节目的唯一标识号
descriptors_loop_length->当前service_id所有描述子的长度
除以上这两个外,我们还需要关注是什么描述子,在这个任务中,我们主要解析的是Service descriptor,下面是Service descriptor的结构图
TS码流解析-5-解析SDT表
描述子里面的所有内容,我们都需要去关注并且了解,找到对应的位置。当我们找到第一个Service descriptor后,后续的描述子就不用管了。

解析过程

我这里只是解析了TABLE_ID = 0x42的SDT表

1 流程图

TS码流解析-5-解析SDT表

2 数据结构的定义

#define SDT_PID                0x11
#define SDT_ACTUAL_TABLE_ID    0x42
#define SDT_SECTION_HEAD_LEN   11
#define SDT_CRC_LEN            4
#define SERVICE_DESCRIPTOR     0x48

typedef struct sdt_info
{
    unsigned short service_id;
    unsigned char service_type;
    char *service_provider_name;
    char *service_name;
    struct sdt_info *next;
}SDT_INFO;

3 相关代码

/*****************************************************************************
*   Function Name: add_sdt_info_to_link
*   Description  : add the sdt node to the sdt link
*   Parameters   : SDT_INFO *sdt_info_link_head  
*                  SDT_INFO node            
*   Returns : static SDT_INFO *
*               return the sdt_info_link_head node
*****************************************************************************/
static SDT_INFO *add_sdt_info_to_link(SDT_INFO *sdt_info_link_head, SDT_INFO node)
{
    SDT_INFO *new_sdt_info_node = NULL;

    new_sdt_info_node = (SDT_INFO*)malloc(sizeof(SDT_INFO));
    if (NULL == new_sdt_info_node)
    {
        log("malloc memory error!\n");
        return sdt_info_link_head;
    }

    new_sdt_info_node->service_id = node.service_id;
    new_sdt_info_node->service_type = node.service_type;
    new_sdt_info_node->service_name = node.service_name;
    new_sdt_info_node->service_provider_name = node.service_provider_name;
    //insert to the head of the link
    new_sdt_info_node->next = sdt_info_link_head;
    
    return new_sdt_info_node;
}


/*****************************************************************************
*   Function Name: get_service_descriptor_info
*   Description  : create the descriptor link and save the descriptor message
                   
*   Parameters   : SECTION *sdt_section           
*                  int descriptor_start_position  
*                  int descriptor_end_position    
*                  SDT_INFO *sdt_info_temp        
*   Returns : static void 
*****************************************************************************/
static void get_service_descriptor_info(SECTION *sdt_section, int descriptor_start_position, int descriptor_end_position, SDT_INFO *sdt_info_temp)
{
    int service_provider_name_length = 0;
    int service_name_length = 0;
    while (descriptor_start_position < descriptor_end_position)
    {
        if (SERVICE_DESCRIPTOR != sdt_section->section_buffer[descriptor_start_position])
        {
            descriptor_start_position += sdt_section->section_buffer[descriptor_start_position + 1];
            continue;
        }
        sdt_info_temp->service_type = sdt_section->section_buffer[descriptor_start_position + 2];
        service_provider_name_length = sdt_section->section_buffer[descriptor_start_position + 3];
        service_name_length = sdt_section->section_buffer[descriptor_start_position + 4 + service_provider_name_length];
        sdt_info_temp->service_provider_name = (unsigned char*)malloc((sizeof(char) * service_provider_name_length) + 1);
        if (NULL == sdt_info_temp->service_provider_name)
        {
            log("malloc memory error!\n");
            return;
        }
        sdt_info_temp->service_name = (unsigned char*)malloc((sizeof(char) * service_name_length) + 1);
        if (NULL == sdt_info_temp->service_name)
        {
            log("malloc memory error!\n");
            free(sdt_info_temp->service_provider_name);
            return;
        }

        memcpy(sdt_info_temp->service_provider_name, sdt_section->section_buffer + descriptor_start_position + 4, service_provider_name_length);
        sdt_info_temp->service_provider_name[service_provider_name_length] = 0;
        memcpy(sdt_info_temp->service_name, sdt_section->section_buffer + descriptor_start_position + 5 + service_provider_name_length, service_name_length);
        sdt_info_temp->service_name[service_name_length] = 0;

        descriptor_start_position += sdt_section->section_buffer[descriptor_start_position + 1];
    }
}

/*****************************************************************************
*   Function Name: parse_sdt_section
*   Description  : parse the section 
*   Parameters   : SECTION *sdt_section     
*                  SDT_INFO *sdt_info_link_head  
*   Returns : static SDT_INFO *
*               return the sdt info link head
*****************************************************************************/
static SDT_INFO *parse_sdt_section(SECTION *sdt_section, SDT_INFO *sdt_info_link_head)
{
    unsigned int read_position = SDT_SECTION_HEAD_LEN;
    int descriptor_position = 0;
    int descriptor_end_position = 0;
    int descriptor_start_position = 0;
    int descriptors_loop_length = 0;
    char *service_name = NULL;
    SDT_INFO sdt_info_temp = {0};
    
    while (read_position < (sdt_section->section_length - SDT_CRC_LEN))
    {
        sdt_info_temp.service_id = (sdt_section->section_buffer[read_position] << 8) | sdt_section->section_buffer[read_position + 1];
        descriptor_start_position = read_position + 5;
        descriptors_loop_length = ((sdt_section->section_buffer[read_position + 3] & 0x0f) << 8) | sdt_section->section_buffer[read_position + 4];
        descriptor_end_position = descriptor_start_position + descriptors_loop_length;
        get_service_descriptor_info(sdt_section, descriptor_start_position, descriptor_end_position, &sdt_info_temp);
        sdt_info_temp.next = NULL;
        sdt_info_link_head = add_sdt_info_to_link(sdt_info_link_head, sdt_info_temp);
        read_position += descriptors_loop_length + 5;
    }

    return sdt_info_link_head;
}

/*****************************************************************************
*   Function Name: create_sdt_info_link
*   Description  : create the sdt info link
*   Parameters   : FILE *ts_file                
*                  unsigned int package_length  
*                  int first_sync_position                                 
*   Returns : SDT_INFO *
*               return the sdt info link head
*****************************************************************************/
SDT_INFO *create_sdt_info_link(FILE *ts_file, unsigned int package_length, int first_sync_position)
{
    SECTION *sdt_actual_table = NULL;
    SECTION *current_handle_section = NULL;
    SDT_INFO *sdt_info_link_head = NULL;
    
    if ((NULL==ts_file) || (first_sync_position<0) || (0==package_length))
    {
        log("function parse_pmt parameter error");
        return NULL;
    }
    sdt_actual_table = create_section_link(ts_file, package_length, first_sync_position, SDT_ACTUAL_TABLE_ID, SDT_PID, NULL);
    if (NULL == sdt_actual_table)
    {
        log("get sdt_actual_section error!\n");
        return sdt_info_link_head;
    }
    
    current_handle_section = sdt_actual_table;

    while (current_handle_section != NULL)
    {
        sdt_info_link_head = parse_sdt_section(current_handle_section, sdt_info_link_head);
        current_handle_section = current_handle_section->next;
    }
    
    destroy_section_link(sdt_actual_table);
    sdt_actual_table = NULL;
    log("-----------------------------------SDT-----------------------------------\n");
    return sdt_info_link_head;
}

4 运行结果

TS码流解析-5-解析SDT表