#include "proc_get_table.h" #include #include #include #include #include #include #include #include #include #include "uapi_demux.h" #include "uapi_acodec.h" #include "securec.h" #include "uapi_system.h" #ifdef ANDROID #include #endif #ifdef ANDROID #define LOG_MAX_LEN 1024 void log_print(const char *format, ...) { char log_str[LOG_MAX_LEN]; va_list args; td_s32 ret; va_start(args, format); ret = vsnprintf_s(log_str, LOG_MAX_LEN, LOG_MAX_LEN - 1, format, args); va_end(args); if (ret < 0) { printf("call vsnprintf_s failed.\n"); return; } android_printLog(ANDROID_LOG_ERROR, "SAMPLE", "%s", log_str); } #endif #define proc_api_run(api, ret) do { \ td_s32 _err_code; \ _err_code = api; \ if (_err_code != 0) { \ (ret) |= _err_code; \ SAMPLE_COMMON_PRINTF("\033[0;31m" "[Function: %s line: %d] %s failed ret = 0x%x \n" "\033[0m", \ __FUNCTION__, __LINE__, # api, _err_code); \ } \ } while (0) #define dmx_proc_dofunc_goto(func, ret, switch_point) do { \ (ret) = (func); \ if ((ret) != TD_SUCCESS) { \ SAMPLE_COMMON_PRINTF("call %s failed, ret = 0x%x\n", # func, (ret)); \ goto switch_point; \ } \ } while (0) static td_u8 g_lang_ch_table[16][16] = { /* 16: Number of line/column in language character table */ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ {' ', ' ', ' ', '0', '@', 'P', '`', 'p', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 0 */ {' ', ' ', '!', '1', 'A', 'Q', 'a', 'q', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 1 */ {' ', ' ', '"', '2', 'B', 'R', 'b', 'r', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 2 */ {' ', ' ', '#', '3', 'C', 'S', 'c', 's', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 3 */ {' ', ' ', '$', '4', 'D', 'T', 'd', 't', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 4 */ {' ', ' ', '%', '5', 'E', 'U', 'e', 'u', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 5 */ {' ', ' ', '&', '6', 'F', 'V', 'f', 'v', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 6 */ {' ', ' ', '\'', '7', 'G', 'W', 'g', 'w', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 7 */ {' ', ' ', '(', '8', 'H', 'X', 'h', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 8 */ {' ', ' ', ')', '9', 'I', 'Y', 'i', 'y', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* 9 */ {' ', ' ', '*', ':', 'J', 'Z', 'j', 'z', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* A */ {' ', ' ', '+', ';', 'K', '[', 'k', '{', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* B */ {' ', ' ', ',', '<', 'L', '\\', 'l', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* C */ {' ', ' ', '-', '=', 'M', ']', 'm', '}', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* D */ {' ', ' ', '.', '>', 'N', '^', 'n', '~', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /* E */ {' ', ' ', '/', '?', 'O', '_', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '} /* F */ }; static td_s32 dmx_section_config_filter_attr(const dmx_data_filter *data_filter, uapi_dmx_filter_attr *attr) { td_s32 ret; attr->filter_depth = data_filter->filter_depth; ret = memcpy_s(attr->match, sizeof(attr->match), data_filter->match, DMX_FILTER_MAX_DEPTH); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memcpy_s fail 0x%x", ret); return ret; } ret = memcpy_s(attr->mask, sizeof(attr->mask), data_filter->mask, DMX_FILTER_MAX_DEPTH); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memcpy_s fail 0x%x", ret); return ret; } ret = memcpy_s(attr->negate, sizeof(attr->negate), data_filter->negate, DMX_FILTER_MAX_DEPTH); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memcpy_s fail 0x%x", ret); return ret; } return TD_SUCCESS; } static td_void dmx_config_chan_attr(uapi_dmx_chan_attr *chan_attr, td_bool tee_enable) { chan_attr->buffer_size = (tee_enable == TD_TRUE) ? (2 * 1024 * 1024) : /* 2*1024*1024: buffer size is 2M */ (64 * 1024); /* 64*1024: buffer size is 64K */ chan_attr->secure_mode = (tee_enable == TD_TRUE) ? UAPI_DMX_SECURE_MODE_TEE : chan_attr->secure_mode; chan_attr->chan_type = UAPI_DMX_CHAN_TYPE_SEC; chan_attr->crc_mode = UAPI_DMX_CHAN_CRC_MODE_FORCE_AND_DISCARD; } static td_s32 dmx_section_start_data_filter_ext(td_u32 dmx_id, const dmx_data_filter *data_filter, td_bool tee_enable) { td_u32 i; td_u8 *p = TD_NULL; uapi_dmx_chan_attr chan_attr = { 0 }; td_handle h_chan, h_filter; td_s32 ret; uapi_dmx_filter_attr filter_attr = { 0 }; sample_dmx_acquire_info info = { 0 }; if (data_filter == TD_NULL) { SAMPLE_COMMON_PRINTF("null ptr!\n"); return TD_FAILURE; } info.buf = (td_u8 *)malloc(sizeof(td_u8) * MAX_SECTION_LEN * MAX_SECTION_NUM); if (info.buf == TD_NULL) { SAMPLE_COMMON_PRINTF("malloc data_buf failed!\n"); return TD_FAILURE; } dmx_proc_dofunc_goto(dmx_section_config_filter_attr(data_filter, &filter_attr), ret, DMX_EXIT); uapi_dmx_get_play_chan_default_attr(&chan_attr); dmx_config_chan_attr(&chan_attr, tee_enable); dmx_proc_dofunc_goto(uapi_dmx_create_play_chan(dmx_id, &chan_attr, &h_chan), ret, DMX_EXIT); dmx_proc_dofunc_goto(uapi_dmx_set_play_chan_pid(h_chan, data_filter->tspid), ret, DMX_DESTROY); dmx_proc_dofunc_goto(uapi_dmx_create_filter(dmx_id, &filter_attr, &h_filter), ret, DMX_DESTROY); dmx_proc_dofunc_goto(uapi_dmx_set_filter_attr(h_filter, &filter_attr), ret, DMX_FILTER_DESTROY); dmx_proc_dofunc_goto(uapi_dmx_attach_filter(h_filter, h_chan), ret, DMX_FILTER_DESTROY); dmx_proc_dofunc_goto(uapi_dmx_open_play_chan(h_chan), ret, DMX_FILTER_DETACH); ret = dmx_data_read(h_chan, data_filter->time_out, &info); if (ret == TD_SUCCESS) { /* multi-SECTION parse */ p = info.buf; for (i = 0; i < info.acquired_num; i++) { data_filter->fun_section_fun_callback(p, (td_s32)info.buf_size[i], data_filter->section_struct); p = p + MAX_SECTION_LEN; } } proc_api_run(uapi_dmx_close_play_chan(h_chan), ret); DMX_FILTER_DETACH: proc_api_run(uapi_dmx_detach_filter(h_filter, h_chan), ret); DMX_FILTER_DESTROY: proc_api_run(uapi_dmx_destroy_filter(h_filter), ret); DMX_DESTROY: proc_api_run(uapi_dmx_destroy_play_chan(h_chan), ret); DMX_EXIT: if (info.buf != TD_NULL) { free((void *)info.buf); info.buf = TD_NULL; } return ret; } static td_s32 srh_parse_pat(const td_u8 *section_data, td_s32 length, td_u8 *section_struct) { td_u16 program_number; td_u16 pid; td_u16 ts_id; pat_tb *pat_tab = (pat_tb *)section_struct; pat_info *pat_info = TD_NULL; if ((section_data == TD_NULL) || (section_struct == TD_NULL)) { return TD_FAILURE; } #ifdef SRCH_DEBUG td_s32 index; SAMPLE_COMMON_PRINTF("\n"); for (index = 0; index < length; index++) { } SAMPLE_COMMON_PRINTF("\n"); #endif if (section_data[0] != PAT_TABLE_ID) { return TD_FAILURE; } length = (td_s32)(((section_data[1] << 8) | section_data[2]) & 0x0fff); /* 8, 2: section len size is 12bits */ ts_id = (td_u16)((section_data[3] << 8) | section_data[4]); /* 3, 4, 8: ts id field size is 16bits */ pat_tab->ts_id = ts_id; section_data += 8; /* Skipping 8 bytes to program number. */ length -= 9; /* has pased 9 bytes section data */ while (length >= 4) { /* 4: program number 16 bits, reserved 3 bits and PID 13 bits */ pat_info = &(pat_tab->pat_info[pat_tab->prog_num]); program_number = (td_u16)((section_data[0] << 8) | section_data[1]); /* 8:size of program number is 16 bits */ pid = (td_u16)(((section_data[2] & 0x1F) << 8) | section_data[3]); /* 2 3 8: Size of PID is 13 bits */ if (program_number != 0x0000) { pat_info->service_id = program_number; pat_info->pmt_pid = pid; pat_tab->prog_num++; #ifdef SRCH_DEBUG SAMPLE_COMMON_PRINTF(" parser PAT get PmtPid %d(0x%x) ServiceID %d(0x%x) index %d\n", pat_info->pmt_pid, pat_info->pmt_pid, pat_info->service_id, pat_info->service_id, index); #endif } section_data += 4; /* 4: Skip to next program number. */ length -= 4; /* 4: Skip to next program number. */ } return (TD_SUCCESS); } /* Description: get Pat table */ static td_s32 srh_pat_request_ext(td_u32 dmx_id, pat_tb *pat_tab, td_bool tee_enable) { td_s32 ret; dmx_data_filter data_filter; #ifdef SRCH_DEBUG printf("\n ++++ PAT Request dmxid = %d \n", dmx_id); #endif ret = memset_s(data_filter.match, sizeof(data_filter.match), 0, DMX_FILTER_MAX_DEPTH * sizeof(td_u8)); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memset_s failed.\n"); return TD_FAILURE; } ret = memset_s(data_filter.mask, sizeof(data_filter.mask), 0, DMX_FILTER_MAX_DEPTH * sizeof(td_u8)); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memset_s failed.\n"); return TD_FAILURE; } ret = memset_s(data_filter.negate, sizeof(data_filter.negate), 0, DMX_FILTER_MAX_DEPTH * sizeof(td_u8)); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memset_s failed.\n"); return TD_FAILURE; } data_filter.tspid = PAT_TSPID; data_filter.time_out = PGPAT_TIMEOUT; data_filter.filter_depth = PAT_FILTER_DEPTH; data_filter.crcflag = 0; data_filter.match[0] = PAT_TABLE_ID; data_filter.mask[0] = 0x0; /* set call back func */ data_filter.fun_section_fun_callback = &srh_parse_pat; data_filter.section_struct = (td_u8 *)pat_tab; /* start data filter */ ret = dmx_section_start_data_filter_ext(dmx_id, &data_filter, tee_enable); if (ret != TD_SUCCESS) { SAMPLE_COMMON_PRINTF("\n No PAT received \n"); } return ret; } static long long get_bits48(const td_u8 *buff, const td_s32 byte_offset, td_s32 start_bit, const td_s32 bit_len) { const td_u8 *p_tmp = TD_NULL; unsigned long long v; unsigned long long mask; unsigned long long tmp; if (bit_len > 48) { /* 48: The max length pased */ return 0x7EFEFEFEFEFEFEFELL; } if (buff == (unsigned char *)0) { return 0x7EFEFEFEFEFEFEFELL; } if (bit_len == 0) { return 0; } p_tmp = &buff[(td_u32)byte_offset + ((td_u32)start_bit >> 3)]; /* >>3: bit -> byte */ start_bit %= 8; /* %8: start bit after offset byte */ tmp = (unsigned long long)(*(p_tmp + 6) + /* 6: The 7th byte pased */ (*(p_tmp + 5) << 8) + /* 5 8: The 6th byte pased */ (*(p_tmp + 4) << 16) + /* 4 16: The 5th byte pased */ ((unsigned long long) *(p_tmp + 3) << 24) + /* 3 24: The 4th byte pased */ ((unsigned long long) *(p_tmp + 2) << 32) + /* 2 32: The 3th byte pased */ ((unsigned long long) *(p_tmp + 1) << 40) + /* 1 40: The 2nd byte pased */ ((unsigned long long) *(p_tmp) << 48)); /* 48: The 1st byte pased */ start_bit = 56 - start_bit - bit_len; /* 56: bit size of data cuted */ tmp = tmp >> (td_u32)start_bit; mask = (1ULL << (td_u32)bit_len) - 1; v = tmp & mask; return (long long)v; } static unsigned long get_bits(const td_u8 *buff, const td_s32 byte_offset, td_s32 start_bit, const td_s32 bit_len) { const td_u8 *tmp = TD_NULL; unsigned long v; unsigned long mask; unsigned long tmp_long = 0; td_s32 bit_high = 0; if (bit_len > 32) { /* 32: The max length pased */ return (td_u32)0xFEFEFEFE; } if (buff == (unsigned char *)0) { return (td_u32)0xFEFEFEFE; } if (bit_len == 0) { return 0; } tmp = &buff[(td_u32)byte_offset + ((td_u32)start_bit >> 3)]; /* >>3: bit -> byte */ start_bit %= 8; /* %8: start bit after offset byte */ switch (((td_u32)bit_len - 1) >> 3) { /* >>3: Bytes number - 1 */ case 3: /* 3: 4 bytes */ return (unsigned long)get_bits48(tmp, 0, start_bit, bit_len); case 2: /* 2: 4 bytes be cuted */ tmp_long = (unsigned long)(*(tmp + 3) + (*(tmp + 2) << 8) + /* 3 2 8: 3bytes */ (*(tmp + 1) << 16) + (*(tmp) << 24)); /* 16 24: 3bytes */ bit_high = 32; /* 32: 4 bytes be cuted */ break; case 1: /* 1: 3 bytes be cuted */ tmp_long = (unsigned long)(*(tmp + 2) + (*(tmp + 1) << 8) + (*(tmp) << 16)); /* 2 8 16: 3bytes */ bit_high = 24; /* 24: 3 bytes be cuted */ break; case 0: /* 0: 2 bytes be cuted */ tmp_long = (unsigned long)((*(tmp) << 8) + *(tmp + 1)); /* 8: 2bytes */ bit_high = 16; /* 16: 2 bytes be cuted */ break; case -1: /* -1: No bytes need be cuted */ return 0L; default: return (unsigned long)0xFEFEFEFE; } start_bit = bit_high - start_bit - bit_len; tmp_long = tmp_long >> (td_u32)start_bit; mask = (1ULL << (td_u32)bit_len) - 1; v = tmp_long & mask; return v; } static td_void dmx_data_proc_table_id(const uapi_dmx_data *section, td_u32 *sec_num, td_u32 *sec_total_num) { td_u8 table_id = section->data[0]; if (((table_id >= EIT_TABLE_ID_SCHEDULE_ACTUAL_LOW) && (table_id <= EIT_TABLE_ID_SCHEDULE_ACTUAL_HIGH)) || ((table_id >= EIT_TABLE_ID_SCHEDULE_OTHER_LOW) && (table_id <= EIT_TABLE_ID_SCHEDULE_OTHER_HIGH))) { *sec_num = section->data[0x6] >> 0x3; *sec_total_num = (section->data[0x7] >> 0x3) + 1; } else if ((table_id == TDT_TABLE_ID) || (table_id == TOT_TABLE_ID)) { *sec_num = 0; *sec_total_num = 1; } else { *sec_num = section->data[0x6]; *sec_total_num = section->data[0x7] + 1; } return; } td_s32 dmx_data_read(td_handle h_channel, td_u32 time_outms, sample_dmx_acquire_info *info) { uapi_dmx_data section[32] = {{0}}; /* section data num is 32 */ td_u32 num, i; td_u32 count = 0; td_u32 times = 10; /* attempt to acquire 10 times */ td_u32 sec_total_num = 0; td_u32 sec_num; const td_u32 request_num = 32; /* each time, 32 sections are obtained */ td_u8 sec_got_flag[MAX_SECTION_NUM] = {0}; uapi_dmx_data *tmp = section; while ((--times) != 0) { num = 0; if ((uapi_dmx_acquire_buffer(h_channel, request_num, &num, section, time_outms) != TD_SUCCESS) || (num == 0)) { SAMPLE_COMMON_PRINTF("uapi_dmx_acquire_buffer time out\n"); continue; } for (i = 0; i < num; i++) { if (section[i].data_type != UAPI_DMX_DATA_TYPE_WHOLE) { continue; } dmx_data_proc_table_id(§ion[i], &sec_num, &sec_total_num); if (sec_num >= MAX_SECTION_NUM) { return TD_FAILURE; } if (sec_got_flag[sec_num] != 0) { continue; } if (memcpy_s((void *)(info->buf + sec_num * MAX_SECTION_LEN), MAX_SECTION_LEN, section[i].data, section[i].size) != EOK) { SAMPLE_COMMON_PRINTF("call memcpy_s failed!\n"); } sec_got_flag[sec_num] = 1; info->buf_size[sec_num] = section[i].size; count++; } uapi_dmx_release_buffer(h_channel, num, tmp); /* to check if all sections are received */ if (sec_total_num == count) { break; } } if (times == 0) { SAMPLE_COMMON_PRINTF("uapi_dmx_acquire_buffer time out\n"); return TD_FAILURE; } info->acquired_num = sec_total_num; return TD_SUCCESS; } static td_void parse_audio_language_code_trans(const td_u8 iso639_language_code[LANG_CODE_LEN], td_u8 str_buf_len, td_u8 *str_buf) { td_u32 i; td_u8 first_nibble; td_u8 second_nibble; if ((str_buf == TD_NULL) || (str_buf_len < LANG_CODE_LEN)) { return; } for (i = 0; i < LANG_CODE_LEN; i++) { first_nibble = (iso639_language_code[i] & 0xF0) >> 4; /* >> 4: fist nibble */ second_nibble = iso639_language_code[i] & 0x0F; if ((first_nibble > 0xf) || (second_nibble > 0xF)) { return; } str_buf[i] = g_lang_ch_table[second_nibble][first_nibble]; } return; } static td_void parse_audio_language(const td_u8 *des_data, td_u32 buf_len, pmt_desc_iso639_language *data) { td_u8 *buff = (td_u8 *)des_data; td_u8 length; td_u8 str_code[LANG_CODE_LEN] = {0}; td_s32 ret; if ((buff == TD_NULL) || (data == TD_NULL)) { return; } if (buff[0] != LANGUAGE_DESCRIPTOR) { return; } if (buf_len != (buff[1] + 2)) { /* 2: Value buf_len contains descriptor tag and descriptor length */ return; } length = buff[1]; buff += 2; /* 2: Size of descriptor tag field and descriptor length field */ data->language_ele_num = 0; while (length >= 4) { /* 4: lang code * 3 + type *1 */ if (data->language_ele_num >= MAX_LANGUAGE_ELENUM) { return; } data->ast_language_info[data->language_ele_num].iso639_language_code[0] = /* The 1st language code */ (td_u8)get_bits(buff, 0, 0, 8); /* 0/0/8: offset/start/length */ data->ast_language_info[data->language_ele_num].iso639_language_code[1] = /* 1: The 2nd language code */ (td_u8)get_bits(buff, 0, 8, 8); /* 0/8/8: offset/start/length */ data->ast_language_info[data->language_ele_num].iso639_language_code[2] = /* 2: The 3th language code */ (td_u8)get_bits(buff, 0, 16, 8); /* 0/16/8: offset/start/length */ data->ast_language_info[data->language_ele_num].audio_type = (td_u8)get_bits(buff, 0, 24, 8); /* 0/24/8: offset/start/length */ ret = memset_s(str_code, sizeof(str_code), 0x00, sizeof(str_code)); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memset_s failed.\n"); return; } parse_audio_language_code_trans(data->ast_language_info[data->language_ele_num].iso639_language_code, LANG_CODE_LEN, str_code); data->ast_language_info[data->language_ele_num].iso639_language_code[0] = str_code[0]; /* The 1st stringcode */ data->ast_language_info[data->language_ele_num].iso639_language_code[1] = str_code[1]; /* 1: The 2nd code */ data->ast_language_info[data->language_ele_num].iso639_language_code[2] = str_code[2]; /* 2: The 3th code */ data->language_ele_num++; buff += 4; /* has pased 4 bytes */ length -= 4; /* has pased 4 bytes */ } return; } static td_void parse_pmt_desc_lang(pmt_tb *pstru_prog, const td_bool parse_audio, const td_u8 *data, const td_u8 length) { td_s32 ret; pmt_desc_iso639_language audio_lang; if (parse_audio == TD_FALSE) { return; } ret = memset_s(&audio_lang, sizeof(audio_lang), 0x00, sizeof(audio_lang)); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memset_s failed.\n"); return; } parse_audio_language(data, length, &audio_lang); pstru_prog->audio_info[pstru_prog->audo_num].aud_lang[0] = audio_lang.ast_language_info[0].iso639_language_code[0]; pstru_prog->audio_info[pstru_prog->audo_num].aud_lang[1] = audio_lang.ast_language_info[0].iso639_language_code[1]; pstru_prog->audio_info[pstru_prog->audo_num].aud_lang[2] = /* 2: The 3th audio language Code */ audio_lang.ast_language_info[0].iso639_language_code[2]; /* 2: The 3th audio language Code */ if (audio_lang.ast_language_info[0].audio_type == 3) { pstru_prog->audio_info[pstru_prog->audo_num].ad_type = 1; } } static td_void parse_pmt_desc_teletext(const td_u8 *desc_data, const td_s32 desc_length, pmt_tb *pstru_prog, const td_u8 length) { td_u16 i; td_u8 cnt_index; td_u16 ttx_index = pstru_prog->ttx_num; if ((ttx_index >= TTX_MAX) || (length > TTX_MAX * 5)) { /* A TTX dexcriptor field is 5 bytes */ printf("The parameter out of range\n"); return; } for (i = 0; i < length; i += 5) { /* A TTX dexcriptor field is 5 bytes */ cnt_index = pstru_prog->ttx_info[ttx_index].des_info_cnt; if ((desc_length >= 5) && cnt_index < TTX_DES_MAX) { /* A TTX dexcriptor field is 5 bytes */ /* 8859-1 language code */ pstru_prog->ttx_info[ttx_index].ttx_des[cnt_index].iso639_language_code = (desc_data[i + 0] << 16) | (desc_data[i + 1] << 8) | (desc_data[i + 2]); /* 16 [1] 8 [2], Size: 24b */ pstru_prog->ttx_info[ttx_index].ttx_des[cnt_index].ttx_type = (desc_data[i + 3] >> 3) & 0x1f; /* [3]>>3 &0x1f: teletext_type, 5bits */ pstru_prog->ttx_info[ttx_index].ttx_des[cnt_index].ttx_magazine_number = desc_data[i + 3] & 0x7; /* [3] & 0x7: teletext_magazine_number, 3bits */ pstru_prog->ttx_info[ttx_index].ttx_des[cnt_index].ttx_page_number = desc_data[i + 4]; /* [4]: teletext_page_number, 8bits */ pstru_prog->ttx_info[ttx_index].des_info_cnt++; } } return; } static td_void parse_pmt_desc_subtitling(const td_u8 *desc_data, const td_s32 desc_length, pmt_tb *pstru_prog, const td_u8 length) { td_u16 i; td_u8 cnt_index; td_u16 subt_index = pstru_prog->subtitling_num; if (subt_index >= SUBTITLING_MAX) { printf("The parameter out of range\n"); return; } for (i = 0; i < length; i += 8) { /* 8: A descriptor field is 8 bytes */ cnt_index = pstru_prog->subtiting_info[subt_index].des_info_cnt; #ifdef SRCH_DEBUG printf("Subtitle tag desc_length:%u.............pstru_prog->subtitling_num = %d, cnt_index = %d\n", desc_length, pstru_prog->subtitling_num, cnt_index); #endif if ((desc_length >= 8) && cnt_index < SUBTDES_INFO_MAX) { /* 8: A descriptor field is 8 bytes */ /* 8859-1 language code */ pstru_prog->subtiting_info[subt_index].des_info[cnt_index].lang_code = (desc_data[i + 0] << 16) | (desc_data[i + 1] << 8) | (desc_data[i + 2]); /* 16 [1] 8 [2], Size: 24b */ /* page id */ pstru_prog->subtiting_info[subt_index].des_info[cnt_index].page_id = (desc_data[i + 4] << 8) | (desc_data[i + 5]); /* [+4]<<8 [+5]: This id size is 16bits */ /* ancilary page id */ pstru_prog->subtiting_info[subt_index].des_info[cnt_index].ancillary_page_id = (desc_data[i + 6] << 8) | (desc_data[i + 7]); /* [+6]<<8 [+7]: This id size is 16bits */ pstru_prog->subtiting_info[subt_index].des_info_cnt++; #ifdef SRCH_DEBUG SAMPLE_COMMON_PRINTF("[%d]lang code:%#x\n", pstru_prog->subtitling_num, pstru_prog->subtiting_info[pstru_prog->subtitling_num].des_info[cnt_index].lang_code); SAMPLE_COMMON_PRINTF("[%d]page id :%u\n", pstru_prog->subtitling_num, pstru_prog->subtiting_info[pstru_prog->subtitling_num].des_info[cnt_index].page_id); SAMPLE_COMMON_PRINTF("[%d]ancilary page id : %u\n", pstru_prog->subtitling_num, pstru_prog->subtiting_info[pstru_prog->subtitling_num].des_info[cnt_index].ancillary_page_id); SAMPLE_COMMON_PRINTF("[%d]count is %u\n\n", pstru_prog->subtitling_num, pstru_prog->subtiting_info[pstru_prog->subtitling_num].des_info_cnt); SAMPLE_COMMON_PRINTF("[%d]pid is 0x%x\n\n", pstru_prog->subtitling_num, pstru_prog->subtiting_info[pstru_prog->subtitling_num].subtitling_pid); #endif } } return; } #if defined(STREAM_TYPE_CAPTURE_86) static td_void parse_pmt_desc_caption_service(const td_u8 *desc_data, const td_s32 desc_length, pmt_tb *pstru_prog, const td_u8 length) { td_u8 service_num; td_u8 index; td_u32 lang_code; td_u8 j = 0; /* Ref : 6.9.2 Caption Service Descriptor in ATSC a/65 */ service_num = desc_data[0] & 0x1f; pstru_prog->closed_caption_num = service_num; j++; while (j < length) { for (index = 0; index < service_num; index++) { lang_code = (desc_data[j] << 16) | (desc_data[j + 1] << 8) | desc_data[j + 2]; /* 2 8 16, Size: 24bits */ j += 3; /* has pased 3 bytes */ pstru_prog->closed_caption[index].is_digital_cc = desc_data[j] & 0x80; if (pstru_prog->closed_caption[index].is_digital_cc) { pstru_prog->closed_caption[index].lang_code = lang_code; pstru_prog->closed_caption[index].service_number = desc_data[j] & 0x3f; j += 1; /* has pased 1 bytes */ pstru_prog->closed_caption[index].is_easy_reader = desc_data[j] & 0x80; pstru_prog->closed_caption[index].is_wide_aspect_ratio = desc_data[j] & 0x40; j += 2; /* has pased 2 bytes */ } else { j += 3; /* has pased 3 bytes */ } } } return; } #endif static td_void parse_pmt_desc_extension(const td_u8 *desc_data, td_s32 desc_length, pmt_tb *pstru_prog) { td_u8 extension_tag; TD_UNUSED(desc_length); extension_tag = desc_data[0]; if (extension_tag == SUPPLEMENTARY_AUDIO_DESCRIPTOR) { if ((desc_data[1] >> 7) == 0x0) { /* [1]>>7: size of mix type is 1bits */ pstru_prog->audio_info[pstru_prog->audo_num].ad_type = 1; } } if (extension_tag == AC4_DESCRIPTOR) { pstru_prog->audio_info[pstru_prog->audo_num].audio_enc_type = UAPI_ACODEC_ID_MS12_AC4; } } static td_void parse_pmt_desc(const td_u8 *desc_data, td_s32 desc_length, pmt_tb *program, td_bool parse_audio) { td_u8 tag; td_u8 length; const td_u8 *data = TD_NULL; if ((desc_data == TD_NULL) || (program == TD_NULL)) { return; } while (desc_length > 0) { data = desc_data; tag = *desc_data++; length = *desc_data++; if (length == 0) { return; } switch (tag) { case LANGUAGE_DESCRIPTOR: parse_pmt_desc_lang(program, parse_audio, data, length + 2); /* 2: Contains size of tag and length */ break; case CA_DESCRIPTOR: if (program->ca_num >= PROG_MAX_CA) { return; } program->ca_system[program->ca_num].ca_system_id = (desc_data[0] << 8) | desc_data[1]; /* 8:16b */ program->ca_system[program->ca_num].cap_id = (desc_data[2] << 8) | desc_data[3]; /* 2 3 8:16bits */ program->ca_num++; break; case TELETEXT_DESCRIPTOR: parse_pmt_desc_teletext(desc_data, desc_length, program, length); break; case SUBTITLING_DESCRIPTOR: parse_pmt_desc_subtitling(desc_data, desc_length, program, length); break; #if defined(STREAM_TYPE_CAPTURE_86) case CAPTION_SERVICE_DESCRIPTOR: parse_pmt_desc_caption_service(desc_data, desc_length, program, length); break; #endif case EXTENSION_DESCRIPTOR: parse_pmt_desc_extension(desc_data, desc_length, program); break; /* The following case uses the default branch. */ /* AC3_DESCRIPTOR */ /* AC3_PLUS_DESCRIPTOR */ /* COPYRIGHT_DESCRIPTOR */ /* MOSAIC_DESCRIPTOR */ /* STREAM_IDENTIFIER_DESCRIPTOR */ /* PRIVATE_DATA_SPECIFIER_DESCRIPTOR */ /* SERVICE_MOVE_DESCRIPTOR */ /* CA_SYSTEM_DESCRIPTOR */ /* DATA_BROADCAST_ID_DESCRIPTOR */ default: break; } desc_data += length; desc_length -= (td_s32)(length + 2); /* 2: tag and length filed. */ } return; } static td_void pase_pmt_video_descriptor(const td_u8 *section_data, const td_u16 desc_len, pmt_tb *pmt_tab, const td_u16 pid, const td_u8 stream_type) { #ifdef SRCH_DEBUG printf("video stream type is %#x, pid=%#x\n", stream_type, pid); #endif pmt_tab->video_info[pmt_tab->video_num].video_pid = pid; if (stream_type == STREAM_TYPE_14496_10_VIDEO) { pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_H264; } else if (stream_type == STREAM_TYPE_14496_2_VIDEO) { pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_MPEG4; } else if (stream_type == STREAM_TYPE_AVS_VIDEO) { pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_AVS; } else if (stream_type == STREAM_TYPE_AVS2_VIDEO) { pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_AVS2; } else if (stream_type == STREAM_TYPE_AVS3_VIDEO) { pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_AVS3; } else if (stream_type == STREAM_TYPE_HEVC_VIDEO) { pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_H265; } else { pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_MPEG2; } if (desc_len > 0) { parse_pmt_desc(section_data, desc_len, pmt_tab, TD_FALSE); } pmt_tab->video_num++; } static td_void srh_parse_pmt_stream_dts_ma(pmt_tb *pmt_tab, const td_u8 stream_type, td_u16 desc_len, td_u16 pid) { pmt_tab->audio_info[pmt_tab->audo_num].audio_pid = pid; TD_UNUSED(desc_len); #ifdef SRCH_DEBUG SAMPLE_COMMON_PRINTF(" audio type = 0x%x \n", stream_type); #endif if ((stream_type == STREAM_TYPE_13818_7_AUDIO) || (stream_type == STREAM_TYPE_14496_3_AUDIO)) { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_AAC; } else if (stream_type == STREAM_TYPE_AC3_AUDIO || stream_type == STREAM_TYPE_EAC3_AUDIO) { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_DOLBY_PLUS; } else if (stream_type == STREAM_TYPE_DOLBY_TRUEHD_AUDIO) { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_DOLBY_TRUEHD; } else if (stream_type == STREAM_TYPE_DTS_AUDIO || #if !defined(STREAM_TYPE_CAPTURE_86) (stream_type == STREAM_TYPE_DTS_MA) #else TD_FALSE #endif ) { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_DTSHD; } else { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_MP3; } pmt_tab->audo_num++; } static td_bool is_subtitle_stream(const td_u8 *data, td_s32 length) { td_bool ret = TD_FALSE; int n_len = length; td_u8 *data_tmp = (td_u8 *)data; td_u8 tag; td_u8 length_tmp; while (n_len > 0) { tag = *data_tmp++; length_tmp = *data_tmp++; if (tag == SUBTITLING_DESCRIPTOR) { ret = TD_TRUE; break; } data_tmp += length_tmp; n_len -= (td_s32)(length_tmp + 2); /* 2: tag and length filed. */ } return ret; } static td_bool is_aribcc_stream(const td_u8 *data, td_s32 length) { td_bool ret = TD_FALSE; td_s32 n_len = length; td_u8 *data_tmp = (td_u8 *)data; td_u8 tag; td_u8 length_tmp; td_u8 component_tag; while (n_len > 0) { tag = *data_tmp++; length_tmp = *data_tmp++; /* Ref ARIB-TR-B14v2_8-vol3-p3-2-E2.pdf P3-107 */ if (tag == STREAM_IDENTIFIER_DESCRIPTOR) { component_tag = *data_tmp; if ((component_tag == 0x30) || (component_tag == 0x87)) { ret = TD_TRUE; } break; } data_tmp += length_tmp; n_len -= (td_s32)(length_tmp + 2); /* 2: tag and length filed. */ } return ret; } static td_bool is_ttx_stream(const td_u8 *data, td_s32 length) { td_bool ret = TD_FALSE; td_s32 n_len = length; td_u8 *data_tmp = (td_u8 *)data; td_u8 tag; td_u8 length_tmp; while (n_len > 0) { tag = *data_tmp++; length_tmp = *data_tmp++; if (tag == TELETEXT_DESCRIPTOR) { ret = TD_TRUE; break; } data_tmp += length_tmp; n_len -= (td_s32)(length_tmp + 2); /* 2: tag and length filed. */ } return ret; } static td_bool is_dts_stream(const td_u8 *buf, td_u32 buf_len) { td_u32 cur_tag, cur_tag_len; while (buf_len >= 2) { /* 2: It's not at end while length >= 2 bytes */ cur_tag = *buf++; cur_tag_len = *buf++; buf_len -= 2; /* 2: tag and length filed. */ if (cur_tag == REGISTRATION_DESCRIPTOR) { if ((htonl(*((td_u32*)buf)) == STREAM_TYPE_DTS1_AUDIO_IDENTIFY) || (htonl(*((td_u32*)buf)) == STREAM_TYPE_DTS2_AUDIO_IDENTIFY) || (htonl(*((td_u32*)buf)) == STREAM_TYPE_DTS3_AUDIO_IDENTIFY)) { return TD_TRUE; } } else { buf += cur_tag_len; buf_len = (cur_tag_len >= buf_len) ? 0 : (buf_len - cur_tag_len); } } return TD_FALSE; } static td_bool is_dra_stream(const td_u8 *buf, td_u32 buf_len) { td_u32 cur_tag, cur_tag_len; while (buf_len >= 2) { /* 2: It's not at end while length >= 2 bytes */ cur_tag = *buf++; cur_tag_len = *buf++; buf_len -= 2; /* 2: tag and length filed. */ if (cur_tag == DRA_DESCRIPTOR) { return TD_TRUE; } else { buf += cur_tag_len; buf_len = (cur_tag_len >= buf_len) ? 0 : (buf_len - cur_tag_len); } } return TD_FALSE; } static td_bool is_ac3_stream(const td_u8 *buf, td_u32 buf_len) { td_u32 cur_tag, cur_tag_len; while (buf_len >= 2) { /* 2: It's not at end while length >= 2 bytes */ cur_tag = *buf++; cur_tag_len = *buf++; buf_len -= 2; /* 2: tag and length filed. */ if (cur_tag == AC3_DESCRIPTOR || cur_tag == AC3_PLUS_DESCRIPTOR || cur_tag == AC3_EXT_DESCRIPTOR) { return TD_TRUE; } else { buf += cur_tag_len; buf_len = (cur_tag_len >= buf_len) ? 0 : (buf_len - cur_tag_len); } } return TD_FALSE; } static td_bool is_265_stream(const td_u8 *data, td_s32 length) { td_bool ret = TD_FALSE; int n_len = length; td_u8 *data_tmp = (td_u8 *)data; td_u8 tag; td_u8 length_tmp; while (n_len > 0) { tag = *data_tmp++; length_tmp = *data_tmp++; if (tag == REGISTRATION_DESCRIPTOR) { td_u32 identify = htonl(*((td_u32 *)data_tmp)); if (identify == STREAM_TYPE_HEVC_VIDEO_IDENTIFY) { ret = TD_TRUE; break; } } data_tmp += length_tmp; n_len -= (td_s32)(length_tmp + 2); /* 2: tag and length filed. */ } return ret; } static td_void pase_pmt_audio_descriptor(const td_u8 *section_data, const td_u16 desc_len, pmt_tb *pmt_tab, const td_u16 pid, const td_u8 stream_type) { #ifdef SRCH_DEBUG printf("audio stream type is %#x, pid = %#x\n", stream_type, pid); #endif if (pmt_tab->audo_num >= PROG_MAX_AUDIO) { return; } srh_parse_pmt_stream_dts_ma(pmt_tab, stream_type, desc_len, pid); if (desc_len > 0) { parse_pmt_desc(section_data, desc_len, pmt_tab, TD_TRUE); } } static td_void pase_pmt_private_stream_descriptor(const td_u8 *section_data, const td_u16 desc_len, pmt_tb *pmt_tab, const td_u16 pid) { #ifdef SRCH_DEBUG printf("private stream...........pid=%#x\n", pid); #endif if (desc_len <= 0) { /* subtitling stream info */ return; } if (is_subtitle_stream(section_data, desc_len)) { if (pmt_tab->subtitling_num < SUBTITLING_MAX) { pmt_tab->subtiting_info[pmt_tab->subtitling_num].subtitling_pid = pid; #ifdef SRCH_DEBUG printf("using pmt_tb->subtitling_num = %d to parse description\n", pmt_tab->subtitling_num); #endif parse_pmt_desc(section_data, desc_len, pmt_tab, TD_FALSE); pmt_tab->subtitling_num++; } else { SAMPLE_COMMON_PRINTF("Subtitle language is over than the max number:%d\n", SUBTITLING_MAX); } } else if (is_aribcc_stream(section_data, desc_len)) { pmt_tab->aribcc_pid = pid; } else if (is_ttx_stream(section_data, desc_len)) { if (pmt_tab->ttx_num < TTX_MAX) { pmt_tab->ttx_info[pmt_tab->ttx_num].ttx_pid = pid; parse_pmt_desc(section_data, desc_len, pmt_tab, TD_FALSE); pmt_tab->ttx_num++; } } else if (is_265_stream(section_data, desc_len)) { pmt_tab->video_info[pmt_tab->video_num].video_pid = pid; pmt_tab->video_info[pmt_tab->video_num].video_enc_type = UAPI_VCODEC_TYPE_H265; pmt_tab->video_num++; } else { if (pmt_tab->audo_num < PROG_MAX_AUDIO) { pmt_tab->audio_info[pmt_tab->audo_num].audio_pid = pid; /* dolby parse */ if (is_ac3_stream(section_data, desc_len)) { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_DOLBY_PLUS; } else if (is_dts_stream(section_data, desc_len)) { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_DTSHD; } else if (is_dra_stream(section_data, desc_len)) { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_DRA; } else { pmt_tab->audio_info[pmt_tab->audo_num].audio_enc_type = UAPI_ACODEC_ID_MP3; } parse_pmt_desc(section_data, desc_len, pmt_tab, TD_TRUE); pmt_tab->audo_num++; } } return; } #ifdef STREAM_TYPE_SCTE_82H static td_void pase_pmt_scte_stream_descriptor(const td_u8 *section_data, const td_u16 desc_len, pmt_tb *pmt_tab, const td_u16 pid) { if (desc_len > 0) { parse_pmt_desc(section_data, desc_len, pmt_tab, TD_FALSE); } pmt_tab->scte_subt_info.scte_subt_pid = pid; } #endif static void pase_pmt_other_stream_descriptor(const td_u8 *section_data, const td_u16 desc_len, pmt_tb *pmt_tab) { if (desc_len > 0) { parse_pmt_desc(section_data, desc_len, pmt_tab, TD_FALSE); } } static td_void pase_pmt_es_descriptor(const td_u8 *section_data, const td_u16 desc_len, pmt_tb *pmt_tab, const td_u16 pid, const td_u8 stream_type) { switch (stream_type) { /* video stream */ case STREAM_TYPE_14496_10_VIDEO: case STREAM_TYPE_14496_2_VIDEO: case STREAM_TYPE_11172_VIDEO: case STREAM_TYPE_13818_VIDEO: case STREAM_TYPE_AVS_VIDEO: case STREAM_TYPE_AVS2_VIDEO: case STREAM_TYPE_AVS3_VIDEO: case STREAM_TYPE_HEVC_VIDEO: pase_pmt_video_descriptor(section_data, desc_len, pmt_tab, pid, stream_type); break; /* audio stream */ case STREAM_TYPE_11172_AUDIO: case STREAM_TYPE_13818_AUDIO: case STREAM_TYPE_14496_3_AUDIO: case STREAM_TYPE_13818_7_AUDIO: case STREAM_TYPE_AC3_AUDIO: case STREAM_TYPE_EAC3_AUDIO: #ifndef STREAM_TYPE_SCTE_82H case STREAM_TYPE_DTS_AUDIO: #endif case STREAM_TYPE_DOLBY_TRUEHD_AUDIO: #if !defined(STREAM_TYPE_CAPTURE_86) case STREAM_TYPE_DTS_MA: #endif pase_pmt_audio_descriptor(section_data, desc_len, pmt_tab, pid, stream_type); break; case 0x8b: /* one special SCTE stream contains error subt info,skip it, not parse */ break; case STREAM_TYPE_PRIVATE: pase_pmt_private_stream_descriptor(section_data, desc_len, pmt_tab, pid); break; #ifdef STREAM_TYPE_SCTE_82H case STREAM_TYPE_SCTE: pase_pmt_scte_stream_descriptor(section_data, desc_len, pmt_tab, pid); break; #endif default: pase_pmt_other_stream_descriptor(section_data, desc_len, pmt_tab); break; } return; } static td_void proc_seach_pase_pmt_all_descriptor(const td_u8 *section_data, td_s32 *length, pmt_tb *pmt_tab) { td_u8 stream_type; td_u16 desc_len; td_u16 pid; if ((section_data == TD_NULL) || (length == TD_NULL) || (pmt_tab == TD_NULL)) { return; } desc_len = (td_u16)(((section_data[2] & 0x0F) << 8) | section_data[3]); /* 2 3 8: program info length is 12bits */ section_data += 4; /* Skipping 4-byte to program info descriptor */ #ifdef SRCH_DEBUG printf("pcr pid = %#x, desclength:%d, length = %d\n", pmt_tab->pcr_pid, desc_len, *length); #endif if (desc_len > 0) { parse_pmt_desc(section_data, desc_len, pmt_tab, TD_FALSE); section_data += desc_len; *length -= desc_len; } while (*length > 4) { /* 4: Every ES info data is at least 5 bytes. it's not at end while *length > 4 bytes */ stream_type = section_data[0]; pid = (((section_data[1] & 0x1F) << 8) | section_data[2]); /* 1 2 8: PCR PID, 13-bits */ desc_len = (((section_data[3] & 0x0F) << 8) | section_data[4]); /* [3]4bits [4]8bits: len field is 12bit */ section_data += 5; /* Skipping 5-byte to ES info descriptor */ *length -= 5; /* Skipping 5-byte to ES info descriptor */ #ifdef SRCH_DEBUG printf("stream type : %#x, pid:%#x, length:%d, desc_len = %d\n", stream_type, pid, *length, desc_len); #endif pase_pmt_es_descriptor(section_data, desc_len, pmt_tab, pid, stream_type); if (desc_len > 0) { section_data += desc_len; *length -= desc_len; } } return; } static td_s32 srh_parse_pmt(const td_u8 *section_data, td_s32 length, td_u8 *section_struct) { pmt_tb *pmt_tab = (pmt_tb *)section_struct; td_s32 ret; if ((section_data == TD_NULL) || (section_struct == TD_NULL)) { return TD_FAILURE; } if (section_data[0] != PMT_TABLE_ID) { return TD_FAILURE; } ret = memcpy_s(pmt_tab->pmt_data, sizeof(pmt_tab->pmt_data), section_data, (size_t)length); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memcpy_s failed.\n"); return TD_FAILURE; } pmt_tab->pmt_len = (td_u32)(length); #ifdef SRCH_DEBUG printf("enter length : %d\n", length); #endif length = (td_s32)(((section_data[1] << 8) | section_data[2]) & 0x0fff); // [1]4bits [2]8bits: len field is 12bit #ifdef SRCH_DEBUG printf("length = %d, %#x:%#x\n", length, section_data[1], section_data[2]); /* [1] [2]: length field */ #endif pmt_tab->service_id = (td_u16)((section_data[3] << 8) | section_data[4]); /* 3 8 4: service id is a 16bit field */ section_data += 8; /* skip 8-byte to PCR_PID */ pmt_tab->pcr_pid = (td_u16)(((section_data[0] & 0x1F) << 8) | section_data[1]); /* 8: PCR PID heigh 8-bits */ length -= 9; /* has prased 9-byte since service_id */ (td_void)proc_seach_pase_pmt_all_descriptor(section_data, &length, pmt_tab); return TD_SUCCESS; } static td_s32 srh_pmt_request_ext(td_u32 dmx_id, pmt_tb *pmt_tab, td_u16 pmt_pid, td_u16 service_id, td_bool tee_enable) { td_s32 ret; dmx_data_filter data_filter = { 0 }; #ifdef SRCH_DEBUG SAMPLE_COMMON_PRINTF("+++++PMT PID %d(0x%x) ServiceID %d(0x%x)+++++\n", pmt_pid, pmt_pid, service_id, service_id); #endif ret = memset_s(data_filter.mask, sizeof(data_filter.mask), 0xff, DMX_FILTER_MAX_DEPTH * sizeof(td_u8)); if (ret != EOK) { SAMPLE_COMMON_PRINTF("call memset_s failed.\n"); return TD_FAILURE; } data_filter.tspid = pmt_pid; data_filter.time_out = PGPMT_TIMEOUT; data_filter.filter_depth = PMT_FILTER_DEPTH; data_filter.crcflag = 0; data_filter.match[0] = PMT_TABLE_ID; data_filter.mask[0] = 0x0; /* set service id */ data_filter.match[1] = (td_u8)((service_id >> 8) & 0x00ff); /* match[1]: service id high 8 bits field */ data_filter.mask[1] = 0; /* mask[1]: service id mask high 8 bits field */ data_filter.match[2] = (td_u8)(service_id & 0x00ff); /* match[2]: service id low 8 bit field */ data_filter.mask[2] = 0; /* mask[2]: service id mask low 8 bit field */ /* set call back func */ data_filter.fun_section_fun_callback = &srh_parse_pmt; data_filter.section_struct = (td_u8 *)pmt_tab; /* start data filter */ ret = dmx_section_start_data_filter_ext(dmx_id, &data_filter, tee_enable); if (ret == TD_FAILURE) { SAMPLE_COMMON_PRINTF("DMX_SectionStartDataFilter failed to receive PMT\n"); } #ifdef SRCH_DEBUG td_s32 i; SAMPLE_COMMON_PRINTF("ServiceID %d PcrPID %#x VideoNum %d AudioNum %d\n", pmt_tab->service_id, pmt_tab->pcr_pid, pmt_tab->video_num, pmt_tab->audo_num); for (i = 0; i < pmt_tab->video_num; i++) { SAMPLE_COMMON_PRINTF("Video[%d] PID %#x Vtype %#x\n", i, pmt_tab->video_info[i].video_pid, pmt_tab->video_info[i].video_enc_type); } for (i = 0; i < pmt_tab->audo_num; i++) { SAMPLE_COMMON_PRINTF("Audio[%d] PID %#x Atype %#x\n", i, pmt_tab->audio_info[i].audio_pid, pmt_tab->audio_info[i].audio_enc_type); } SAMPLE_COMMON_PRINTF("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); #endif return ret; } static td_s32 proc_search_get_pmt_prog_data(pmt_compact_prog *proginfo, const pat_info *pat_info, const pmt_tb *pmt_tb) { td_s32 ret; proginfo->prog_id = pat_info->service_id; proginfo->pmt_pid = pat_info->pmt_pid; proginfo->pcr_pid = pmt_tb->pcr_pid; proginfo->video_type = pmt_tb->video_info[0].video_enc_type; proginfo->v_element_num = pmt_tb->video_num; proginfo->v_element_pid = pmt_tb->video_info[0].video_pid; proginfo->audio_type = pmt_tb->audio_info[0].audio_enc_type; proginfo->a_element_num = pmt_tb->audo_num; proginfo->a_element_pid = pmt_tb->audio_info[0].audio_pid; proginfo->subtitling_num = pmt_tb->subtitling_num; proginfo->scte_subt_info.scte_subt_pid = pmt_tb->scte_subt_info.scte_subt_pid; proginfo->closed_caption_num = pmt_tb->closed_caption_num; ret = memcpy_s(proginfo->closed_caption, sizeof(proginfo->closed_caption), pmt_tb->closed_caption, sizeof(pmt_tb->closed_caption)); if (ret != EOK) { printf("call memcpy_s failed.\n"); return TD_FAILURE; } proginfo->aribcc_pid = pmt_tb->aribcc_pid; proginfo->ttx_num = pmt_tb->ttx_num; ret = memcpy_s(proginfo->ttx_info, sizeof(proginfo->ttx_info), pmt_tb->ttx_info, sizeof(pmt_ttx)*TTX_MAX); if (ret != EOK) { printf("call memcpy_s failed.\n"); return TD_FAILURE; } ret = memcpy_s(proginfo->pmt_data, sizeof(proginfo->pmt_data), pmt_tb->pmt_data, pmt_tb->pmt_len); if (ret != EOK) { printf("call memcpy_s failed.\n"); return TD_FAILURE; } proginfo->pmt_len = pmt_tb->pmt_len; return TD_SUCCESS; } static td_void proc_search_get_pmt_subtiting(pmt_compact_prog *prog_info, const pmt_tb *pmt_tb) { td_u32 i; td_u32 j; if (prog_info->subtitling_num > SUBTITLING_MAX) { printf("receive subtitling_num(%u) are over than the max num:%u\n", prog_info->subtitling_num, SUBTITLING_MAX); prog_info->subtitling_num = SUBTITLING_MAX; } /* parse and deal with subtitling info */ for (i = 0; i < prog_info->subtitling_num; i++) { prog_info->subtiting_info[i].subtitling_pid = pmt_tb->subtiting_info[i].subtitling_pid; prog_info->subtiting_info[i].des_info_cnt = pmt_tb->subtiting_info[i].des_info_cnt; if (prog_info->subtiting_info[i].des_info_cnt > SUBTDES_INFO_MAX) { printf("receive des_info_cnt(%hhu) are over than the max number:%u\n", prog_info->subtiting_info[i].des_info_cnt, SUBTDES_INFO_MAX); prog_info->subtiting_info[i].des_info_cnt = SUBTDES_INFO_MAX; } #ifdef SRCH_DEBUG printf("prog_info->subtiting_info[%d].des_info_cnt = %d\n", i, prog_info->subtiting_info[i].des_info_cnt); #endif for (j = 0; j < prog_info->subtiting_info[i].des_info_cnt; j++) { prog_info->subtiting_info[i].des_info[j].lang_code = pmt_tb->subtiting_info[i].des_info[j].lang_code; prog_info->subtiting_info[i].des_info[j].page_id = pmt_tb->subtiting_info[i].des_info[j].page_id; prog_info->subtiting_info[i].des_info[j].ancillary_page_id = pmt_tb->subtiting_info[i].des_info[j].ancillary_page_id; #if SRCH_DEBUG printf("pid:0x%02x,desp:%u, page id:%u, ancilary page id:%u, lang code: %#x\n", prog_info->subtiting_info[i].subtitling_pid, j, prog_info->subtiting_info[i].des_info[j].page_id, prog_info->subtiting_info[i].des_info[j].ancillary_page_id, prog_info->subtiting_info[i].des_info[j].lang_code); #endif } } if (pmt_tb->subtitling_num > 0) { prog_info->subt_type |= SUBT_TYPE_DVB; printf("\tDVB subtitle NUM = 0x%x\n", pmt_tb->subtitling_num); } return; } static td_void proc_search_print_pmt_prog_info(pmt_compact_prog *prog_info, const pmt_tb *pmt_tb) { td_u32 i; for (i = 0; i < pmt_tb->audo_num; i++) { printf("\tAudio Stream PID = 0x%x\n", pmt_tb->audio_info[i].audio_pid); } for (i = 0; i < pmt_tb->video_num; i++) { printf("\tVideo Stream PID = 0x%x\n", pmt_tb->video_info[i].video_pid); } if (pmt_tb->scte_subt_info.scte_subt_pid != 0) { prog_info->subt_type |= SUBT_TYPE_SCTE; printf("\tSCTE subtitle PID = 0x%x\n", pmt_tb->scte_subt_info.scte_subt_pid); } if (prog_info->closed_caption_num > 0) { for (i = 0; i < prog_info->closed_caption_num; i++) { if (prog_info->closed_caption[i].is_digital_cc != 0) { printf("\tClosed Captioning 708, language : %#x, service num : %hhu\n", prog_info->closed_caption[i].lang_code, prog_info->closed_caption[i].service_number); } else { printf("\tClosed Captioning 608\n"); } } } if (prog_info->aribcc_pid != 0) { printf("\tARIB CC PID = 0x%x\n", prog_info->aribcc_pid); } if (prog_info->ttx_num > 0) { printf("\tTeletext NUM = 0x%x\n", pmt_tb->ttx_num); for (i = 0; i < prog_info->ttx_num; i++) { printf("\tTeletext%u PID = 0x%x\n", i, pmt_tb->ttx_info[i].ttx_pid); } } return; } static td_s32 proc_search_get_prog_info(pmt_compact_prog *prog_info, const pat_info *pat_info, pmt_tb *pmt_table, td_u32 dmx_id, td_bool tee_enable) { td_s32 j; td_s32 ret; ret = memset_s(pmt_table, sizeof(pmt_tb), 0, sizeof(pmt_tb)); if (ret != EOK) { printf("call memset_s failed.\n"); return TD_FAILURE; } ret = srh_pmt_request_ext(dmx_id, pmt_table, pat_info->pmt_pid, pat_info->service_id, tee_enable); if (ret != TD_SUCCESS) { printf("failed to search PMT\n"); return TD_FAILURE; } ret = proc_search_get_pmt_prog_data(prog_info, pat_info, pmt_table); if (ret != TD_SUCCESS) { printf("proc_search_get_pmt_prog_data failed\n"); return TD_FAILURE; } td_u32 audio_num = pmt_table->audo_num < PROG_MAX_AUDIO ? pmt_table->audo_num : PROG_MAX_AUDIO; ret = memcpy_s(&prog_info->audio_info[0], sizeof(pmt_audio) * PROG_MAX_AUDIO, &pmt_table->audio_info[0], sizeof(pmt_audio) * audio_num); if (ret != TD_SUCCESS) { printf("call memcpy_s failed\n"); return TD_FAILURE; } prog_info->ca_num = pmt_table->ca_num; for (j = 0; j < pmt_table->ca_num; j++) { if (j < PROG_MAX_CA) { prog_info->ca_system[j].ca_system_id = pmt_table->ca_system[j].ca_system_id; prog_info->ca_system[j].cap_id = pmt_table->ca_system[j].cap_id; } } #ifdef SRCH_DEBUG printf("prog_table->proginfo[%d].subtitling_num = %d\n", promnum, prog_info->subtitling_num); #endif proc_search_get_pmt_subtiting(prog_info, pmt_table); printf("Program ID = %u PMT PID = 0x%x,\n", pat_info->service_id, pat_info->pmt_pid); proc_search_print_pmt_prog_info(prog_info, pmt_table); return TD_SUCCESS; } static td_s32 proc_search_malloc_pmt_prog_table(pmt_compact_tbl **prog_table, const pat_tb *pat_tb) { pmt_compact_tbl *prog_tab = TD_NULL; td_s32 ret; if (pat_tb->prog_num == 0 || pat_tb->prog_num > PMT_PROG_MAX) { printf("PMT program num failed. \n"); return TD_FAILURE; } prog_tab = (pmt_compact_tbl *)malloc(sizeof(pmt_compact_tbl)); if (prog_tab == TD_NULL) { printf("have no memory for pat\n"); return TD_FAILURE; } prog_tab->prog_num = pat_tb->prog_num; prog_tab->proginfo = (pmt_compact_prog *)malloc(pat_tb->prog_num * sizeof(pmt_compact_prog)); if (prog_tab->proginfo == TD_NULL) { printf("have no memory for pat\n"); free(prog_tab); return TD_FAILURE; } ret = memset_s(prog_tab->proginfo, pat_tb->prog_num * sizeof(pmt_compact_prog), 0, pat_tb->prog_num * sizeof(pmt_compact_prog)); if (ret != EOK) { printf("call memset_s failed.\n"); free(prog_tab->proginfo); prog_tab->proginfo = TD_NULL; free(prog_tab); return TD_FAILURE; } *prog_table = prog_tab; return TD_SUCCESS; } /* get PMT table */ static td_s32 proc_search_get_all_pmt_ext(td_u32 dmx_id, pmt_compact_tbl **pp_prog_table, td_bool tee_enable) { td_s32 i, ret; pat_tb pat_tb = { 0 }; pmt_tb *pmt_tab = TD_NULL; pmt_compact_tbl *prog_table = TD_NULL; td_u32 promnum = 0; td_u32 cnt = 0; if (pp_prog_table == TD_NULL) { printf("para is null pointer!\n"); return TD_FAILURE; } pmt_tab = (pmt_tb *)malloc(sizeof(pmt_tb)); if (pmt_tab == TD_NULL) { printf("malloc pmt table failed!\n"); return TD_FAILURE; } ret = memset_s(pmt_tab, sizeof(pmt_tb), 0, sizeof(pmt_tb)); if (ret != EOK) { printf("memset_s pmt table failed!\n"); goto out; } do { ret = srh_pat_request_ext(dmx_id, &pat_tb, tee_enable); if (ret != TD_SUCCESS) { printf("failed to search PAT\n"); goto out; } if (pat_tb.prog_num != 0) { break; } usleep(5000); /* 5000: sleep microseconds. */ cnt += 5; /* 5: Incremental value. */ } while (cnt < 5000); /* 5000: Request PAT number of times. */ ret = proc_search_malloc_pmt_prog_table(&prog_table, &pat_tb); if (ret != TD_SUCCESS) { printf("failed to search PAT\n"); goto out; } printf("\n\nALL Program Infomation[%u]:\n", pat_tb.prog_num); for (i = 0; i < pat_tb.prog_num; i++) { if ((pat_tb.pat_info[i].service_id == 0) || (pat_tb.pat_info[i].pmt_pid == 0x1fff)) { continue; } ret = proc_search_get_prog_info(&(prog_table->proginfo[promnum]), &(pat_tb.pat_info[i]), pmt_tab, dmx_id, tee_enable); if (ret != TD_SUCCESS) { printf("failed to proc_search_get_prog_info, search PMT[%d]\n", i); continue; } if ((pmt_tab->video_num > 0) || (pmt_tab->audo_num > 0)) { promnum++; } } prog_table->prog_num = promnum; printf("\n"); *pp_prog_table = prog_table; ret = ((promnum != 0) ? TD_SUCCESS : TD_FAILURE); out: free(pmt_tab); pmt_tab = TD_NULL; return ret; } td_s32 proc_search_free_all_pmt(pmt_compact_tbl *prog_table) { if (prog_table != TD_NULL) { if (prog_table->proginfo != TD_NULL) { free(prog_table->proginfo); prog_table->proginfo = TD_NULL; } free(prog_table); prog_table = TD_NULL; } return TD_SUCCESS; } td_s32 proc_search_get_all_pmt(td_u32 dmx_id, pmt_compact_tbl **pp_prog_table) { return proc_search_get_all_pmt_ext(dmx_id, pp_prog_table, TD_FALSE); }