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表结构
在SDT表中,我们主要关注的是
service_id->节目的唯一标识号
descriptors_loop_length->当前service_id所有描述子的长度
除以上这两个外,我们还需要关注是什么描述子,在这个任务中,我们主要解析的是Service descriptor,下面是Service descriptor的结构图
描述子里面的所有内容,我们都需要去关注并且了解,找到对应的位置。当我们找到第一个Service descriptor后,后续的描述子就不用管了。
解析过程
我这里只是解析了TABLE_ID = 0x42的SDT表
1 流程图
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;
}