天天看點

TS碼流解析-6-解析EIT表任務六

任務六

利用之前編寫的函數,從碼流中解析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表結構

TS碼流解析-6-解析EIT表任務六

在這裡,需要重點關注的字段有

start_time:表示這個事件的開始時間是什麼

duration:表示事件持續的時間,可以計算出結束時間

running:運作狀态

Short event descriptor的結構

TS碼流解析-6-解析EIT表任務六

在這個描述子中,我們重點關注的字段有

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中在子表和段中插入了一個節的層次。關于節有如下約定:

  1. 一個EIT子表被分成32個節
  2. 每個節最多有8個段
  3. 一個EIT子表最多有256個段
  4. 每個節所包含的時間資訊最長不能超過3個小時
  5. 如果在節中小于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
  6. 節中包含所有的段,那麼字段segment_last_section_number值算法為s0+7
  7. 如果節中包含所有的段是空段,那麼字段segment_last_section_number值算法為s0+0
  8. 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的原因了

TS碼流解析-6-解析EIT表任務六

EIT表解析

1-流程圖

TS碼流解析-6-解析EIT表任務六

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表的解析過程,如果有什麼問題或者不懂的,歡迎留言指出!!!!!

繼續閱讀