You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1596 lines
58 KiB

#include "proc_get_table.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "uapi_demux.h"
#include "uapi_acodec.h"
#include "securec.h"
#include "uapi_system.h"
#ifdef ANDROID
#include <utils/Log.h>
#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(&section[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);
}