任务六
利用之前编写的函数,从码流中解析EIT表,主要是获取对应的service_id和EPG标题,时间段等。
相关知识
简述
EIT表按照时间顺序提供每一个业务所包含的事件信息,是事件信息表的简称,它是EPG中绝大部分信息的携带者。我们看电视的时候,节目预告之类的内容,就是通过这个表来获取的。另外,EIT主要的信息是通过插入的描述符来实现的。根据table_id的不同,一共分为四类EIT表
传输流 | 信息 | table_id |
---|---|---|
当前TS流 | 当前/后续事件信息 | 0x4E |
其他TS流 | 当前/后续事件信息 | 0x4F |
当前TS流 | 事件时间信息 | 0x50-0x5F |
其他TS流 | 事件时间信息 | 0x60-0x6F |
相同的EIT子表具有相同的transport和original_stream_id
EIT表结构

在这里,需要重点关注的字段有
start_time:表示这个事件的开始时间是什么
duration:表示事件持续的时间,可以计算出结束时间
running:运行状态
Short event descriptor的结构
在这个描述子中,我们重点关注的字段有
ISO_639_language_code:语言代码,说明后续文本字段的语言
event_name_char:事件名称字符
text_char:文本字符,对事件的简单描述
对 EIT schedule的解释
EIT schedule用来发送大量的event信息,也就是EPG的节目单。EIT schedule 被分成16个table_id来传送,0x50-0x5F代表的是当前流的schedule,0x60-0x6F代表的是其他流的schedule,也就是说一个节目最多可以用16个字表来发送节目预告,这16个EIT是按照时间顺序排列的。
注意下,在EIT子表中引入了节(segment)的概念,刚开始接触的时候有点模糊,知道是什么,但不知道为什么,在这里简单解释是什么。
在普通的子表中分段使用段(section),每个子表语法结构中都有个8bit字段的last_section_number,用来表示一个子表由多少个段来组成。由字长我们可以看出,一个子表最多有256个段。而EIT中在子表和段中插入了一个节的层次。关于节有如下约定:
- 一个EIT子表被分成32个节
- 每个节最多有8个段
- 一个EIT子表最多有256个段
- 每个节所包含的时间信息最长不能超过3个小时
- 如果在节中小于8个段在使用,就需要 靠字段segment_ last_section_ number 标识节中有哪些有效的段。EIT 中传送的字段segment last section_number 值算法为s0+n-1。这里s0的值是节中的第一个段号,n表示该节中段的个数。举个例子:如果某个EIT子表中第二个节只包含2个段,那么在这2个段中字段segment_last_section_number的值就是:8 + 2 -1 = 9
- 节中包含所有的段,那么字段segment_last_section_number值算法为s0+7
- 如果节中包含所有的段是空段,那么字段segment_last_section_number值算法为s0+0
- EIT Table_id=0x50(或 者0x60)的第一个节包含着今天00:00-02:59:59 UTC时间的三个小时的事件信息,第二个节包含了03:00:00 and 05:59:59 UTC时间的三个小时的事件信息,依次类推下去,一个子表最多能包含4天的事件信息;
根据以上,我想就可以解释为什么在EIT ACTUAL SCHEDULE中section number的跨度为8的原因了
EIT表解析
1-流程图
2-数据结构定义
typedef struct program_time
{
int hour;
int minute;
int second;
}PROGRAM_TIME;
typedef struct event_node
{
unsigned short event_id;
unsigned char start_time[START_TIME_LEN];
unsigned char duration[DURATION_LEN];
unsigned char running_status :3;
unsigned char *event_name;
unsigned char *text;
struct event_node *next;
}EVENT_NODE;
typedef struct eit_info_node
{
unsigned short service_id;
unsigned short transport_stream_id;
unsigned short original_network_id;
struct event_node *event_link_head;
struct eit_info_node *next;
}EIT_INFO;
typedef int(*EIT_TAG_CHECK)(unsigned char tag);
3-相关代码
/*****************************************************************************
* Function Name: eit_tag_check_callback
* Description : check the eit tag type whether we want
* Parameters : unsigned char tag
* Returns : static int
* return 1 we want
* return 0 we don't
*****************************************************************************/
static int eit_tag_check_callback(unsigned char tag)
{
if(SHORT_EVENT_DESCRIPTOR_TAG == tag)
{
return 1;
}
return 0;
}
/*****************************************************************************
* Function Name: get_short_descriptor_message
* Description : get the short event descriptor message
* Parameters : SECTION *eit_actual_section
* unsigned int *eit_descriptors_read_position
* unsigned int eit_descriptors_end_position
* EVENT_NODE *new_event_node
* EIT_TAG_CHECK eit_tag_check
* Returns : static void
*****************************************************************************/
static void get_short_descriptor_message(SECTION *eit_actual_section, unsigned int *eit_descriptors_read_position, unsigned int eit_descriptors_end_position, EVENT_NODE *new_event_node, EIT_TAG_CHECK eit_tag_check)
{
int descriptor_length;
int event_name_length = 0;
int text_length = 0;
while (*eit_descriptors_read_position < eit_descriptors_end_position)
{
if (eit_tag_check != NULL)
{
if (eit_tag_check(eit_actual_section->section_buffer[*eit_descriptors_read_position]) != 1)
{
*eit_descriptors_read_position += eit_actual_section->section_buffer[*eit_descriptors_read_position + 1] + 2;
continue;
}
}
descriptor_length = eit_actual_section->section_buffer[*eit_descriptors_read_position + 1];
event_name_length = eit_actual_section->section_buffer[*eit_descriptors_read_position + 2 + 3];
text_length = eit_actual_section->section_buffer[*eit_descriptors_read_position + 2 + 4 + event_name_length];
new_event_node->event_name = (unsigned char*)malloc(sizeof(char) * event_name_length + 1);
if (NULL == new_event_node->event_name)
{
log("new_event_node->event_name malloc error!\n");
return;
}
memset(new_event_node->event_name, 0, sizeof(char) * event_name_length + 1);
memcpy(new_event_node->event_name, eit_actual_section->section_buffer + *eit_descriptors_read_position + 2 + 4, event_name_length);
new_event_node->text = (unsigned char*)malloc(sizeof(char) * text_length + 1);
if (NULL == new_event_node->text)
{
log("new_event_node->text malloc error!\n");
return;
}
memset(new_event_node->text, 0, sizeof(char) * text_length + 1);
memcpy(new_event_node->text, eit_actual_section->section_buffer + *eit_descriptors_read_position + 2 + 5 + event_name_length, text_length);
*eit_descriptors_read_position += descriptor_length + 2;
}
}
/*****************************************************************************
* Function Name: create_event_link
* Description : create the event link
* Parameters : SECTION *eit_actual_section
* unsigned int event_read_position
* unsigned int event_end_position
* Returns : static EVENT_NODE *
* return the event link head
*****************************************************************************/
static EVENT_NODE *create_event_link(SECTION *eit_actual_section, unsigned int event_read_position, unsigned int event_end_position)
{
EVENT_NODE *event_link_head = NULL;
EVENT_NODE *new_event_node = NULL;
EVENT_NODE *temp_handle_node = NULL;
unsigned int eit_descriptors_end_position = 0;
unsigned int descriptors_loop_length = 0;
while (event_read_position < event_end_position)
{
new_event_node = (EVENT_NODE*)malloc(sizeof(EVENT_NODE));
if (NULL == new_event_node)
{
log("eit event malloc fail!\n");
return event_link_head;
}
descriptors_loop_length = ((eit_actual_section->section_buffer[event_read_position + 10] & 0x0f) << 8) | eit_actual_section->section_buffer[event_read_position + 11];
eit_descriptors_end_position = event_read_position + 12 + descriptors_loop_length;
new_event_node->event_id = (eit_actual_section->section_buffer[event_read_position] << 8) | eit_actual_section->section_buffer[event_read_position + 1];
memcpy(new_event_node->start_time, eit_actual_section->section_buffer + event_read_position + 2, sizeof(new_event_node->start_time));
memcpy(new_event_node->duration, eit_actual_section->section_buffer + event_read_position + 2 + sizeof(new_event_node->start_time), sizeof(new_event_node->duration));
new_event_node->running_status = eit_actual_section->section_buffer[event_read_position + 2 + sizeof(new_event_node->start_time) + sizeof(new_event_node->duration)] >> 5;
event_read_position = event_read_position + 12;
get_short_descriptor_message(eit_actual_section, &event_read_position, eit_descriptors_end_position, new_event_node, eit_tag_check_callback);
new_event_node->next = NULL;
//tail insert
if (NULL == event_link_head)
{
event_link_head = new_event_node;
temp_handle_node = event_link_head;
}else
{
temp_handle_node->next = new_event_node;
temp_handle_node = new_event_node;
}
}
return event_link_head;
}
/*****************************************************************************
* Function Name: parse_eit_section
* Description : input the eit table section then parse it
* Parameters : SECTION *eit_actual_section
* EIT_INFO *eit_info_link_head
* Returns : static EIT_INFO *
* return the eit info link head
*****************************************************************************/
static EIT_INFO *parse_eit_section(SECTION *eit_actual_section, EIT_INFO *eit_info_link_head)
{
EIT_INFO *new_eit_info_node = NULL;
new_eit_info_node = (EIT_INFO*)malloc(sizeof(EIT_INFO));
if (NULL == new_eit_info_node)
{
log("eit information malloc fail!\n");
return eit_info_link_head;
}
new_eit_info_node->service_id = (eit_actual_section->section_buffer[SERVICE_ID_OFFSET] << 8) | eit_actual_section->section_buffer[SERVICE_ID_OFFSET + 1];
new_eit_info_node->original_network_id = (eit_actual_section->section_buffer[ORIGINAL_NETWORK_ID_OFFSET] << 8) | eit_actual_section->section_buffer[ORIGINAL_NETWORK_ID_OFFSET + 1];
new_eit_info_node->transport_stream_id = (eit_actual_section->section_buffer[TRANSPORT_STREAM_ID_OFFSET] << 8) | eit_actual_section->section_buffer[TRANSPORT_STREAM_ID_OFFSET + 1];
new_eit_info_node->event_link_head = create_event_link(eit_actual_section, EVENT_START_POSITION, eit_actual_section->section_length - CRC_LENGTH);
new_eit_info_node->next = eit_info_link_head;
return new_eit_info_node;
}
/*****************************************************************************
* Function Name: create_eit_info_link
* Description : create eit info link then return the link head
* Parameters : FILE *ts_file
* unsigned int package_length
* int first_sync_position
* Returns : EIT_INFO *
* return the eit link head
*****************************************************************************/
EIT_INFO *create_eit_info_link(FILE *ts_file, unsigned int package_length, int first_sync_position)
{
SECTION *eit_actual_table = NULL;
SECTION *current_handle_section = NULL;
unsigned char loop_table_id = 0;
EIT_INFO *eit_info_link_head = NULL;
unsigned short eit_table_id_array[EIT_TABLE_ID_MAX_LEN] = {0};
FILE *temp = ts_file;
if ((NULL==ts_file) || (first_sync_position<0) || (0==package_length))
{
log("function parse_pmt parameter error");
return NULL;
}
eit_actual_table = create_section_link(temp, package_length, first_sync_position, loop_table_id, EIT_PID, eit_table_id_array, eit_check);
destroy_section_link(eit_actual_table);
eit_actual_table = NULL;
for (loop_table_id; loop_table_id<EIT_TABLE_ID_MAX_LEN; loop_table_id++)
{
if (eit_table_id_array[loop_table_id] != 1)
{
continue;
}
eit_actual_table = create_section_link(ts_file, package_length, first_sync_position, loop_table_id + 0x4e, EIT_PID, NULL, eit_check);
current_handle_section = eit_actual_table;
while (current_handle_section != NULL)
{
eit_info_link_head = parse_eit_section(current_handle_section, eit_info_link_head);
current_handle_section = current_handle_section->next;
}
destroy_section_link(eit_actual_table);
eit_actual_table = NULL;
}
log("-----------------------------------EIT-----------------------------------\n");
return eit_info_link_head;
}
上面通过一个记录eit table id 的数组来遍历TS文件,为的就是在获取eit table的时候,流中没有的table id就不用去遍历了,这样效率更高。
以上就是EIT表的解析过程,如果有什么问题或者不懂的,欢迎留言指出!!!!!