/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2019. All rights reserved. * Description: IEC61937 data parser function * Author: audio * Create: 2012-05-30 */ #include #include "mpi_ai_debug.h" #include "iec61937_parser.h" #include "soc_math.h" #include "mpi_memory_ext.h" #include "mpi_system_ext.h" #include "securec.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ static td_void ai_free(td_void *buf) { if (buf == TD_NULL) { return; } free(buf); } static td_void *ai_malloc(td_u32 size) { td_s32 ret; td_void *buf = TD_NULL; if (size == 0) { soc_log_err("invalid size\n"); return TD_NULL; } buf = malloc(size); if (buf == TD_NULL) { soc_log_err("call malloc( failed\n"); return TD_NULL; } ret = memset_s(buf, size, 0, size); if (ret != EOK) { soc_err_print_call_fun_err(memset_s, ret); free(buf); return TD_NULL; } return buf; } /* when sync not found, return pos = (bytes - 3) */ static td_bool iec61937_parser_find_sync_word(const td_u8 *buf, td_u32 bytes, td_u32 *pos, td_bool *dtscd) { td_u32 state; td_u32 i; td_bool big_endian = TD_FALSE; /* find IEC SYNC */ for (i = 0; i < (bytes - 3); i++) { /* 3 is a number */ state = (buf[i] << 24) | (buf[i + 1] << 16) | /* 24 and 16 is shift number */ (buf[i + 2] << 8) | buf[i + 3]; /* 8 is a shift number, 2 and 3 is serial number */ if ((state == IEC61937_SYNCWORD_LE) || (state == IEC61937_SYNCWORD_BE)) { big_endian = (state == IEC61937_SYNCWORD_BE) ? TD_TRUE : TD_FALSE; *dtscd = TD_FALSE; *pos = i; return big_endian; } } /* find DTSCD */ for (i = 0; i < (bytes - 3); i++) { /* 3 is a number */ state = (buf[i] << 24) | (buf[i + 1] << 16) | /* 24 and 16 is shift number */ (buf[i + 2] << 8) | buf[i + 3]; /* 8 is a shift number, 2 and 3 is serial number */ if ((state == DCA_MARKER_RAW_BE) || (state == DCA_MARKER_RAW_LE) || (state == DCA_MARKER_14B_BE) || (state == DCA_MARKER_14B_LE)) { *dtscd = TD_TRUE; break; } } *pos = i; return big_endian; } static td_void iec61937_parser_get_frame_len(iec61937_parser_stream_type stream_type, const td_u16 *buf, td_u32 *bytes) { td_u32 frame_len = 0; switch (stream_type) { case IEC61937_PARSER_STREAM_DD: frame_len = buf[3] >> 3; /* 3 is a shift number */ break; case IEC61937_PARSER_STREAM_DDP: frame_len = buf[3]; /* 3 is a number */ break; case IEC61937_PARSER_STREAM_DTS: frame_len = buf[3] >> 3; /* 3 is a shift number */ frame_len = ((frame_len + 3) >> 2) << 2; /* 2 is a shift number, 3 is a number */ break; case IEC61937_PARSER_STREAM_DTSHD: frame_len = buf[9]; /* 9 is a number */ frame_len = ((frame_len + 3) >> 2) << 2; /* 2 is a shift number, 3 is a number */ break; case IEC61937_PARSER_STREAM_MAT: frame_len = buf[3]; /* 3 is a number */ break; default: soc_log_err("invalid iec61937 stream type!\n"); break; } *bytes = frame_len; } static td_void iec61937_parser_move_buf_to_head(iec61937_parser_state *state, const td_u8 *src_buf) { td_s32 ret; ret = memmove_s(state->buffer, IEC61937_PARSER_LENGTH_MAX, src_buf, state->filled_len); if (ret != EOK) { soc_log_err("memmove_s failed,err = 0x%x\n", ret); return; } state->free_len = state->alloc_len - state->filled_len; } static td_s32 iec61937_parser_build_burst_info_default(iec61937_parser_state *state, const td_u8 *src_buf, td_u32 data_type) { state->filled_len -= LENGTH_OF_PA_AND_PB; iec61937_parser_move_buf_to_head(state, src_buf + LENGTH_OF_PA_AND_PB); soc_log_err("invalid IEC61937 data type!\n"); soc_err_print_u32(data_type); if (data_type == IEC61937_DATATYPE_NULL) { return SOC_ERR_AI_BITS_INVALID_DATA; } else if (data_type == IEC61937_DATATYPE_PAUSE) { return SOC_ERR_AI_BITS_PAUSE_DATA; } return SOC_ERR_AI_PARSERBUF_EMPTY; } static const struct { td_u32 data_type; const td_char *str; td_u32 stream_type; td_u32 len; } g_iec61937_parser[] = { { IEC61937_DATATYPE_AC3, "IEC61937_DATATYPE_AC3", IEC61937_PARSER_STREAM_DD, BITS_BURSTLENGTH_AC3 }, { IEC61937_DATATYPE_EAC3, "IEC61937_DATATYPE_EAC3", IEC61937_PARSER_STREAM_DDP, BITS_BURSTLENGTH_EAC3 }, { IEC61937_DATATYPE_DTS_TYPE_I, "IEC61937_DATATYPE_DTS_TYPE_I", IEC61937_PARSER_STREAM_DTS, BITS_BURSTLENGTH_DTS_TYPE_I }, { IEC61937_DATATYPE_DTS_TYPE_II, "IEC61937_DATATYPE_DTS_TYPE_II", IEC61937_PARSER_STREAM_DTS, BITS_BURSTLENGTH_DTS_TYPE_II }, { IEC61937_DATATYPE_DTS_TYPE_III, "IEC61937_DATATYPE_DTS_TYPE_III", IEC61937_PARSER_STREAM_DTS, BITS_BURSTLENGTH_DTS_TYPE_III }, { IEC61937_DATATYPE_MAT, "IEC61937_DATATYPE_MAT", IEC61937_PARSER_STREAM_MAT, BITS_BURSTLENGTH_MAT }, }; static td_s32 iec61937_parser_build_burst_info(iec61937_parser_state *state, td_u8 *src_buf) { /* data type: value of PC bit 0-4 */ td_u32 data_type = (td_u16)src_buf[4] & 0x1f; /* 4 is a serial number */ td_u32 i; for (i = 0; i < (sizeof(g_iec61937_parser) / sizeof(g_iec61937_parser[0])); i++) { if (data_type == g_iec61937_parser[i].data_type) { soc_log_dbg("g_iec61937_parser[%d].data_type %s!\n", i, g_iec61937_parser[i].str); state->stream_type = g_iec61937_parser[i].stream_type; state->burst_len = g_iec61937_parser[i].len; return TD_SUCCESS; } } if (data_type == IEC61937_DATATYPE_DTS_TYPE_IV) { soc_log_dbg("IEC61937_DATATYPE_DTS_TYPE_IV\n"); state->stream_type = IEC61937_PARSER_STREAM_DTSHD; state->burst_len = (BITS_BURSTLENGTH_DTS_TYPE_I << ((td_u16)src_buf[5] & 0x7)); /* 5 is a serial number */ return TD_SUCCESS; } return iec61937_parser_build_burst_info_default(state, src_buf, data_type); } static td_s32 iec61937_parser_continual_dtscd(iec61937_parser_state *state) { td_bool dtscd = TD_FALSE; td_u32 sync_skip = 0; if (state->stream_type != IEC61937_PARSER_STREAM_DTS) { if (state->filled_len < BITS_BURSTLENGTH_DTSCD + IEC61937_PARSER_LENGTH_MIN) { return SOC_ERR_AI_PARSERBUF_EMPTY; } (td_void)iec61937_parser_find_sync_word(state->buffer + BITS_BURSTLENGTH_DTSCD, state->filled_len - BITS_BURSTLENGTH_DTSCD, &sync_skip, &dtscd); if ((sync_skip != 0) || (dtscd != TD_TRUE)) { state->filled_len -= (BITS_BURSTLENGTH_DTSCD + sync_skip); state->total_discard_len += (BITS_BURSTLENGTH_DTSCD + sync_skip); iec61937_parser_move_buf_to_head(state, state->buffer + BITS_BURSTLENGTH_DTSCD + sync_skip); return SOC_ERR_AI_PARSERBUF_EMPTY; } } return TD_SUCCESS; } static td_bool iec61937_check_is_empty_frame(const td_u8 *buffer, td_u32 size) { td_u32 i; for (i = 0; i < size; i++) { if (*(buffer + i) != 0) { return TD_FALSE; } } return TD_TRUE; } static td_s32 iec61937_parser_handup_dtscd(iec61937_parser_state *state) { td_s32 ret; soc_log_dbg("IEC61937_DATATYPE_DTSCD\n"); ret = iec61937_parser_continual_dtscd(state); if (ret != TD_SUCCESS) { soc_log_warn("iec61937_parser_continual_dtscd failed\n"); soc_err_print_err_code(ret); return ret; } state->burst_len = BITS_BURSTLENGTH_DTSCD; state->stream_type = IEC61937_PARSER_STREAM_DTS; return TD_SUCCESS; } static td_s32 iec61937_parser_avoid_handup_dtscd(iec61937_parser_state *state) { td_s32 ret; td_u32 cur_sys_time_ms; /* avoid handup when getframelen */ if (state->filled_len < LENGTH_OF_PREAMBLE + DTSHD_HEADER_SIZE) { ext_mpi_sys_get_time_stamp_ms(&cur_sys_time_ms); if (state->first_empty_time == 0) { state->first_empty_time = cur_sys_time_ms; } if (state->total_discard_len >= IEC61937_PARSER_LENGTH_MAX * 2) { /* 2 is a number */ return SOC_ERR_AI_FIND_SYNC_FAILED; } else if (cur_sys_time_ms > state->first_empty_time + 1000) { /* 1000 means 1 second */ return SOC_ERR_AI_BITS_INVALID_DATA; } else { return SOC_ERR_AI_PARSERBUF_EMPTY; } } ret = iec61937_parser_build_burst_info(state, state->buffer); if (ret != TD_SUCCESS) { soc_log_err("iec61937_parser_build_burst_info failed\n"); soc_err_print_err_code(ret); return ret; } if (state->stream_type != IEC61937_PARSER_STREAM_MAT) { state->big_endian = TD_FALSE; /* only for turehd or mat */ } return TD_SUCCESS; } static td_s32 iec61937_parser_build_burst_data(iec61937_parser_state *state, td_bool *dtscd) { td_s32 ret; td_u32 sync_skip = 0; state->big_endian = iec61937_parser_find_sync_word(state->buffer, state->filled_len, &sync_skip, dtscd); if (sync_skip != 0) { state->filled_len -= sync_skip; state->total_discard_len += sync_skip; iec61937_parser_move_buf_to_head(state, state->buffer + sync_skip); } if (*dtscd == TD_TRUE) { ret = iec61937_parser_handup_dtscd(state); if (ret != TD_SUCCESS) { return ret; } } else { /* avoid handup when getframelen */ ret = iec61937_parser_avoid_handup_dtscd(state); if (ret != TD_SUCCESS) { soc_log_warn("iec61937_parser_handup_dtscd failed\n"); return ret; } } /* if successfully find sync, reset first_empty_time */ state->first_empty_time = 0; state->total_discard_len = 0; /* ensure release frame including the stuffing */ if (state->filled_len < state->burst_len) { soc_log_warn("state->filled_len < state->burst_len\n"); soc_warn_print_u32(state->filled_len); soc_warn_print_u32(state->burst_len); return SOC_ERR_AI_PARSERBUF_EMPTY; } return TD_SUCCESS; } #define IEC61937_PARSER_MAX_TIMES 150 static td_s32 iec61937_parser_build_burst_data_inner(iec61937_parser_state *state, td_bool *dtscd) { td_s32 ret; td_u32 i; ret = iec61937_parser_build_burst_data(state, dtscd); /* PAUSE data should be consumed timely. */ if (ret == SOC_ERR_AI_BITS_PAUSE_DATA) { for (i = 0; i < IEC61937_PARSER_MAX_TIMES; i++) { ret = iec61937_parser_build_burst_data(state, dtscd); if ((ret == TD_SUCCESS) || (ret == SOC_ERR_AI_PARSERBUF_EMPTY)) { break; } } } if (ret != TD_SUCCESS) { soc_warn_print_call_fun_err(iec61937_parser_build_burst_data, ret); return ret; } return TD_SUCCESS; } static td_u32 iec61937_calc_frame_size(td_u32 ch, td_u32 bit_depth) { switch (bit_depth) { case EXT_BIT_DEPTH_16: return ch * sizeof(td_u16); case EXT_BIT_DEPTH_24: return ch * sizeof(td_u32); default: return 0; } } td_s32 iec61937_parser_create(ext_parser_handle *parser) { iec61937_parser_state *state = TD_NULL; check_ai_null_ptr(parser); state = (iec61937_parser_state *)ai_malloc(sizeof(iec61937_parser_state)); if (state == TD_NULL) { soc_log_err("malloc parser instance failed\n"); return SOC_ERR_AI_INSUFFICIENT_RESOURCES; } state->buffer = (td_u8 *)ai_malloc(IEC61937_PARSER_LENGTH_MAX); if (state->buffer == TD_NULL) { soc_log_err("malloc parser inner buffer failed\n"); ai_free(state); return SOC_ERR_AI_INSUFFICIENT_RESOURCES; } state->free_len = IEC61937_PARSER_LENGTH_MAX; state->alloc_len = IEC61937_PARSER_LENGTH_MAX; state->stream_type = IEC61937_PARSER_STREAM_TYPE_MAX; *parser = (ext_parser_handle)state; return TD_SUCCESS; } td_void iec61937_parser_destroy(ext_parser_handle parser) { iec61937_parser_state *state = (iec61937_parser_state *)parser; if (state == TD_NULL) { return; } if (state->buffer != TD_NULL) { /* no need to set state->buffer to NULL, because state is going to be free next */ ai_free(state->buffer); } ai_free(state); } td_s32 iec61937_parser_get_buf(ext_parser_handle parser, td_u32 request_size, iec61937_parser_stream_buf *stream) { iec61937_parser_state *state = TD_NULL_PTR; td_u32 actual_req_size; td_u32 frame_size; check_ai_null_ptr(parser); check_ai_null_ptr(stream); state = (iec61937_parser_state *)parser; stream->size = 0; if (request_size == 0) { return TD_SUCCESS; } frame_size = iec61937_calc_frame_size(state->channel, state->bit_depth); if (frame_size == 0) { soc_log_err("invalid parameter!\n"); soc_err_print_u32(state->channel); soc_err_print_u32(state->bit_depth); return SOC_ERR_AI_INVALID_PARA; } /* ensure actual_req_size - filled_len is aligned with frame_size */ actual_req_size = request_size; if ((state->stream_type == IEC61937_PARSER_STREAM_PCM) || (state->stream_type == IEC61937_PARSER_STREAM_UNKNOWN) || (state->stream_type == IEC61937_PARSER_STREAM_TYPE_MAX)) { actual_req_size += (state->filled_len % frame_size); } if (actual_req_size > IEC61937_PARSER_LENGTH_MAX) { soc_log_err("request_size is too big!\n"); soc_err_print_u32(request_size); soc_err_print_u32(actual_req_size); return SOC_ERR_AI_INVALID_PARA; } if (request_size > state->filled_len) { stream->data = state->buffer + state->filled_len; stream->size = actual_req_size - state->filled_len; } return TD_SUCCESS; } td_s32 iec61937_parser_put_buf(ext_parser_handle parser, iec61937_parser_stream_buf *stream) { iec61937_parser_state *state = TD_NULL_PTR; check_ai_null_ptr(parser); check_ai_null_ptr(stream); check_ai_null_ptr(stream->data); if (stream->size == 0) { return TD_SUCCESS; } state = (iec61937_parser_state *)parser; if (stream->size > state->free_len) { soc_log_err("size is bigger then free_len\n"); soc_err_print_u32(stream->size); soc_err_print_u32(state->free_len); return SOC_ERR_AI_INVALID_PARA; } state->free_len -= stream->size; state->filled_len += stream->size; return TD_SUCCESS; } static inline td_u16 swapbit_16(td_u16 x) { td_u16 res = (x >> 8) | (x << 8); /* shift right 8 bits, shift left 8 bits */ return res; } static td_void big_endian2_little_endian(td_u8 *io, td_s32 bytes) { td_s32 i; td_u16 *data = (td_u16 *)io; td_u16 pcm_data; for (i = 0; i < bytes / 2; i++) { /* 2 is a number */ pcm_data = *data; *data++ = swapbit_16(pcm_data); } } static td_void iec61937_parser_acquire_dtscd_frame(iec61937_parser_state *state) { state->frame_buf = state->buffer; state->frame_len = BITS_BURSTLENGTH_DTSCD; } static td_s32 iec61937_parser_acquire_mat_frame(iec61937_parser_state *state) { state->frame_buf = state->buffer; state->frame_len = BITS_BURSTLENGTH_MAT; if (state->filled_len < state->frame_len) { soc_log_warn("frame_len < filled_len"); soc_warn_print_u32(state->frame_len); soc_warn_print_u32(state->filled_len); return SOC_ERR_AI_PARSERBUF_EMPTY; } if (state->big_endian == TD_TRUE) { big_endian2_little_endian(state->buffer, BITS_BURSTLENGTH_MAT); } return TD_SUCCESS; } static td_s32 iec61937_parser_acquire_other_frame(iec61937_parser_state *state) { iec61937_parser_get_frame_len(state->stream_type, (td_u16 *)state->buffer, &state->frame_len); if ((state->frame_len == 0) || (state->frame_len > BITS_BURSTLENGTH_MAT)) { state->filled_len -= LENGTH_OF_PA_AND_PB; iec61937_parser_move_buf_to_head(state, state->buffer + LENGTH_OF_PA_AND_PB); soc_log_err("invalid frame_len!\n"); soc_err_print_u32(state->frame_len); return SOC_ERR_AI_BITS_INVALID_DATA; } if (state->filled_len < state->frame_len) { soc_log_warn("frame_len < filled_len\n"); soc_warn_print_u32(state->frame_len); soc_warn_print_u32(state->filled_len); return SOC_ERR_AI_PARSERBUF_EMPTY; } if ((state->stream_type == IEC61937_PARSER_STREAM_DTSHD) || (state->stream_type == IEC61937_PARSER_STREAM_MAT)) { state->frame_buf = state->buffer + LENGTH_OF_PREAMBLE + DTSHD_HEADER_SIZE; } else { state->frame_buf = state->buffer + LENGTH_OF_PREAMBLE; } return TD_SUCCESS; } td_s32 iec61937_parser_acquire_frame(ext_parser_handle parser, td_void *dst_buf, td_u32 *frame_len) { td_s32 ret; td_bool dtscd = TD_FALSE; td_u8 **pp_dst_buf = TD_NULL_PTR; iec61937_parser_state *state = TD_NULL_PTR; check_ai_null_ptr(parser); check_ai_null_ptr(dst_buf); check_ai_null_ptr(frame_len); state = (iec61937_parser_state *)parser; pp_dst_buf = (td_u8 **)dst_buf; /* avoid acquire frame much times without release frame */ if (state->frame_is_ready == TD_TRUE) { soc_log_warn("call iec61937_parser_acquire_frame continuously many times!\n"); *pp_dst_buf = state->frame_buf; *frame_len = state->frame_len; return TD_SUCCESS; } *frame_len = 0; /* avoid acquire fail and do release */ if ((state->filled_len < IEC61937_PARSER_LENGTH_MIN) || (state->filled_len > IEC61937_PARSER_LENGTH_MAX)) { soc_log_warn("state->filled_len is not fit!\n"); soc_warn_print_u32(state->filled_len); return SOC_ERR_AI_PARSERBUF_EMPTY; } ret = iec61937_parser_build_burst_data_inner(state, &dtscd); if (ret != TD_SUCCESS) { soc_log_warn("iec61937_parser_build_burst_data_inner failed\n"); soc_warn_print_h32(ret); return ret; } check_ai_null_ptr(state->buffer); if (dtscd == TD_TRUE) { iec61937_parser_acquire_dtscd_frame(state); } else if (state->stream_type == IEC61937_PARSER_STREAM_MAT) { ret = iec61937_parser_acquire_mat_frame(state); if (ret != TD_SUCCESS) { return ret; } } else { ret = iec61937_parser_acquire_other_frame(state); if (ret != TD_SUCCESS) { return ret; } } *pp_dst_buf = state->frame_buf; *frame_len = state->frame_len; state->frame_is_ready = TD_TRUE; return TD_SUCCESS; } td_s32 iec61937_parser_release_frame(ext_parser_handle parser, td_u32 frame_len) { iec61937_parser_state *state = TD_NULL_PTR; check_ai_null_ptr(parser); if (frame_len == 0) { return TD_SUCCESS; } state = (iec61937_parser_state *)parser; /* avoid release frame much times without acquire frame */ if (state->frame_is_ready == TD_FALSE) { soc_log_warn("call iec61937_parser_release_frame continuously many times!"); return TD_SUCCESS; } if (state->filled_len < state->burst_len) { soc_log_err("filled_len < burst_len, release failed!"); soc_err_print_u32(state->filled_len); soc_err_print_u32(state->burst_len); return SOC_ERR_AI_INVALID_PARA; } state->frame_is_ready = TD_FALSE; state->filled_len -= state->burst_len; iec61937_parser_move_buf_to_head(state, state->buffer + state->burst_len); return TD_SUCCESS; } td_s32 iec61937_parser_get_stream_type(ext_parser_handle parser, iec61937_parser_stream_type *stream_type) { td_s32 ret; td_bool dtscd = TD_FALSE; iec61937_parser_state *state = TD_NULL_PTR; check_ai_null_ptr(parser); check_ai_null_ptr(stream_type); state = (iec61937_parser_state *)parser; *stream_type = state->stream_type; if ((state->stream_type != IEC61937_PARSER_STREAM_UNKNOWN) && (state->stream_type != IEC61937_PARSER_STREAM_TYPE_MAX)) { *stream_type = state->stream_type; return TD_SUCCESS; } if ((state->filled_len < IEC61937_PARSER_LENGTH_MIN) || (state->filled_len > IEC61937_PARSER_LENGTH_MAX)) { soc_log_warn("state->filled_len is not fit!\n"); soc_warn_print_u32(state->filled_len); return SOC_ERR_AI_PARSERBUF_EMPTY; } ret = iec61937_parser_build_burst_data_inner(state, &dtscd); if (ret != TD_SUCCESS) { soc_log_warn("iec61937_parser_build_burst_data_inner failed\n"); soc_err_print_err_code(ret); return ret; } *stream_type = state->stream_type; return TD_SUCCESS; } td_s32 iec61937_parser_get_burst_len(ext_parser_handle parser, td_u32 *burst_len) { iec61937_parser_state *state = TD_NULL_PTR; check_ai_null_ptr(parser); check_ai_null_ptr(burst_len); state = (iec61937_parser_state *)parser; if ((state->stream_type == IEC61937_PARSER_STREAM_UNKNOWN) || (state->stream_type == IEC61937_PARSER_STREAM_TYPE_MAX)) { /* A proper value enough to parse all stream type and to synchronize. */ *burst_len = BITS_BURSTLENGTH_DTS_TYPE_III; return TD_SUCCESS; } if ((state->burst_len) > BITS_BURSTLENGTH_MAT) { soc_log_err("burst length is too big!"); soc_err_print_u32(state->burst_len); return SOC_ERR_AI_BITS_INVALID_DATA; } else { *burst_len = state->burst_len; return TD_SUCCESS; } } td_bool iec61937_check_is_empty(ext_parser_handle parser) { iec61937_parser_state *state = (iec61937_parser_state *)parser; if ((state == TD_NULL) || (state->buffer == TD_NULL)) { return TD_FALSE; } if (iec61937_check_is_empty_frame(state->buffer, state->filled_len) == TD_TRUE) { state->filled_len = 0; state->free_len = state->alloc_len; return TD_TRUE; } return TD_FALSE; } #ifdef __cplusplus } #endif /* __cplusplus */