/* * Copyright (C) 2021 Amlogic Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "aml_dec_api" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aml_audio_log.h" #include "aml_dec_api.h" #include "aml_ddp_dec_api.h" #include "aml_dtsx_dec_api.h" #include "aml_pcm_dec_api.h" #include "aml_adpcm_dec_api.h" #include "aml_mpeg_dec_api.h" #include "aml_aac_dec_api.h" #include "aml_flac_dec_api.h" #include "aml_opus_dec_api.h" #include "aml_vorbis_dec_api.h" #include "aml_mpegh_dec_api.h" #include "aml_iamf_dec_api.h" #include "audio_hw_utils.h" #include "aml_dump_debug.h" #ifdef BUILD_LINUX #define DTS_X_LIB_PATH_A "/vendor/lib/libHwAudio_dtsx.so" #define DTS_HD_LIB_PATH_A "/usr/lib/libHwAudio_dtshd.so" #else #define DTS_X_LIB_PATH_A "/odm/lib/libHwAudio_dtsx.so" #define DTS_HD_LIB_PATH_A "/odm/lib/libHwAudio_dtshd.so" #endif static const char* search_paths[] = { "/usr/lib", "/vendor/lib", "/system/lib", NULL }; #define AML_DEC_FRAGMENT_FRAMES (512) #define AML_DEC_MAX_FRAMES (AML_DEC_FRAGMENT_FRAMES * 4) static eDTSLibType_t gDtsLibType = eDTSNull; static aml_dec_func_t * get_decoder_function(audio_format_t format) { switch (format) { case AUDIO_FORMAT_AC3: case AUDIO_FORMAT_E_AC3: { return &aml_dcv_func; } case AUDIO_FORMAT_DOLBY_TRUEHD: case AUDIO_FORMAT_MAT: return NULL; case AUDIO_FORMAT_DTS: case AUDIO_FORMAT_DTS_HD: { if (gDtsLibType == eDTSXLib) { return &aml_dtsx_func; } else if (gDtsLibType == eDTSHDLib) { return &aml_dca_func; } else { ALOGE("[%s:%d] Without any dts library", __func__, __LINE__); return NULL; } } case AUDIO_FORMAT_PCM_16_BIT: case AUDIO_FORMAT_PCM_32_BIT: case AUDIO_FORMAT_PCM_8_BIT: case AUDIO_FORMAT_PCM_8_24_BIT: case AUDIO_FORMAT_PCM_LPCM_DVD: case AUDIO_FORMAT_PCM_LPCM_1394: case AUDIO_FORMAT_PCM_LPCM_BLURAY: { return &aml_pcm_func; } case AUDIO_FORMAT_MP3: case AUDIO_FORMAT_MP2: { return &aml_mad_func; } case AUDIO_FORMAT_AAC: case AUDIO_FORMAT_AAC_LATM: case AUDIO_FORMAT_HE_AAC_V1: case AUDIO_FORMAT_HE_AAC_V2:{ return &aml_faad_func; } case AUDIO_FORMAT_FLAC: { return &aml_flac_func; } case AUDIO_FORMAT_OPUS: { return &aml_opus_func; } case AUDIO_FORMAT_VORBIS: { return &aml_vorbis_func; } case AUDIO_FORMAT_PCM_ADPCM_IMA_WAV: { return &aml_adpcm_func; } case AUDIO_FORMAT_MPEGH: { return &aml_mpegh_func; } case AUDIO_FORMAT_IAMF: { return &aml_iamf_func; } default: ALOGE("[%s:%d] doesn't support decoder format:%#x", __func__, __LINE__, format); return NULL; } return NULL; } int aml_decoder_init(aml_dec_t **ppaml_dec, audio_format_t format, aml_dec_config_t * dec_config) { int ret = -1; aml_dec_func_t *dec_fun = NULL; dec_fun = get_decoder_function(format); aml_dec_t *aml_dec_handel = NULL; if (dec_fun == NULL) { ALOGE("%s got dec_fun as NULL!\n", __func__); return -1; } ALOGD("[%s:%d] dec_fun->f_init=%p, format:%#x", __func__, __LINE__, dec_fun->f_init, format); if (dec_fun->f_init) { ret = dec_fun->f_init(ppaml_dec, dec_config); if (ret < 0) { return -1; } } else { return -1; } aml_dec_handel = *ppaml_dec; aml_dec_handel->frame_cnt = 0; aml_dec_handel->format = format; aml_dec_handel->fragment_left_size = 0; aml_dec_handel->out_frame_pts = -1; aml_dec_handel->last_in_frame_pts = -1; aml_dec_handel->debug_level = get_debug_value(AML_DEBUG_AUDIOHAL_DECODED_INFO); return ret; } int aml_decoder_release(aml_dec_t *aml_dec) { int ret = -1; aml_dec_func_t *dec_fun = NULL; if (aml_dec == NULL) { ALOGE("%s aml_dec is NULL\n", __func__); return -1; } dec_fun = get_decoder_function(aml_dec->format); if (dec_fun == NULL) { return -1; } if (dec_fun->f_release) { dec_fun->f_release(aml_dec); } else { return -1; } if (access(REPORT_DECODED_INFO, F_OK) == 0) { char info_buf[MAX_BUFF_LEN] = {0}; memset(info_buf, 0x00, MAX_BUFF_LEN); int val = 0; sprintf(info_buf, "bitrate %d", val); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "ch_num %d", val); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "samplerate %d", val); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "decoded_frames %d", val); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "decoded_err %d", val); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "decoded_drop %d", val); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf (info_buf, "ch_configuration %d", val); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); } return ret; } int aml_decoder_set_config(aml_dec_t *aml_dec, aml_dec_config_type_t config_type, aml_dec_config_t * dec_config) { int ret = -1; aml_dec_func_t *dec_fun = NULL; if (aml_dec == NULL) { ALOGE("%s aml_dec is NULL\n", __func__); return -1; } dec_fun = get_decoder_function(aml_dec->format); if (dec_fun == NULL) { return -1; } if (dec_fun->f_config) { ret = dec_fun->f_config(aml_dec, config_type, dec_config); } return ret; } int aml_decoder_get_info(aml_dec_t *aml_dec, aml_dec_info_type_t info_type, aml_dec_info_t * dec_info) { int ret = -1; aml_dec_func_t *dec_fun = NULL; if (aml_dec == NULL) { ALOGE("%s aml_dec is NULL\n", __func__); return -1; } dec_fun = get_decoder_function(aml_dec->format); if (dec_fun == NULL) { return -1; } if (dec_fun->f_info) { ret = dec_fun->f_info(aml_dec, info_type, dec_info); } return ret; } int aml_decoder_ad_process(struct audio_stream_out *stream, struct audio_buffer *abuffer, int *used_bytes) { int ret = -1; aml_dec_func_t *dec_fun = NULL; struct aml_stream_out *out = (struct aml_stream_out *)stream; if (!stream) { AM_LOGE("invalid stream:%p", stream); return AML_DEC_RETURN_TYPE_FAIL; } if (false == check_audio_buffer_valid(abuffer)) { AM_LOGE("audio buffer checked fail"); return AML_DEC_RETURN_TYPE_FAIL; } dec_fun = get_decoder_function(abuffer->original_format); *used_bytes = 0; if (dec_fun == NULL) { ALOGW("[%s:%d] get_decoder_function format:%#x is null", __func__, __LINE__, abuffer->original_format); return -1; } if (dec_fun->f_ad_process) { ret = dec_fun->f_ad_process(out->aml_dec, abuffer); } else { ALOGE("[%s:%d] f_ad_process is null", __func__, __LINE__); return -1; } if (ret >= 0 ) { *used_bytes = ret; return AML_DEC_RETURN_TYPE_OK; } else { return ret; } } int aml_system_sound_process(aml_dec_t *aml_dec, struct audio_buffer *abuffer, int *used_bytes) { int ret = -1; aml_dec_func_t *dec_fun = NULL; *used_bytes = 0; if (aml_dec == NULL) { ALOGE("[%s:%d] aml_dec is null", __func__, __LINE__); return -1; } dec_fun = get_decoder_function(aml_dec->format); if (dec_fun == NULL) { ALOGW("[%s:%d] get_decoder_function format:%#x is null", __func__, __LINE__, aml_dec->format); return -1; } if (dec_fun->f_system_sound_process) { ret = dec_fun->f_system_sound_process(aml_dec, abuffer); } else { ALOGE("[%s:%d] f_system_sound_process is null", __func__, __LINE__); return -1; } if (ret >= 0 ) { *used_bytes = ret; return AML_DEC_RETURN_TYPE_OK; } else { AM_LOGE("f_system_sound_process fail"); *used_bytes = abuffer->size; return ret; } } int aml_decoder_process(aml_dec_t *aml_dec, struct audio_buffer *abuffer, int *used_bytes) { int ret = -1; aml_dec_func_t *dec_fun = NULL; int frame_size = 0; int fragment_size = 0; dec_data_info_t * dec_pcm_data = NULL; dec_data_info_t * dec_raw_data = NULL; dec_data_info_t * raw_in_data = NULL; if (aml_dec == NULL) { ALOGE("[%s:%d] aml_dec is null", __func__, __LINE__); return -1; } dec_pcm_data = &aml_dec->dec_pcm_data; dec_raw_data = &aml_dec->dec_raw_data; raw_in_data = &aml_dec->raw_in_data; *used_bytes = 0; dec_fun = get_decoder_function(aml_dec->format); if (dec_fun == NULL) { ALOGW("[%s:%d] get_decoder_function format:%#x is null", __func__, __LINE__, aml_dec->format); return -1; } if ((dec_fun != &aml_dtsx_func) && (dec_fun != &aml_dca_func) && (false == check_audio_buffer_valid(abuffer))) { AM_LOGE("audio buffer checked fail"); return -1; } /*if we have fragment size output*/ if (aml_dec->fragment_left_size > 0) { ALOGI("[%s:%d] fragment_left_size=%d ", __func__, __LINE__, aml_dec->fragment_left_size); frame_size = audio_bytes_per_sample(dec_pcm_data->data_format) * dec_pcm_data->data_ch; fragment_size = AML_DEC_FRAGMENT_FRAMES * frame_size; memmove(dec_pcm_data->buf, (unsigned char *)dec_pcm_data->buf + fragment_size, aml_dec->fragment_left_size); memmove(dec_raw_data->buf, (unsigned char *)dec_raw_data->buf + fragment_size, aml_dec->fragment_left_size); if (aml_dec->fragment_left_size >= fragment_size) { dec_pcm_data->data_len = fragment_size; dec_raw_data->data_len = fragment_size; aml_dec->fragment_left_size -= fragment_size; } else { dec_pcm_data->data_len = aml_dec->fragment_left_size; dec_raw_data->data_len = aml_dec->fragment_left_size; aml_dec->fragment_left_size = 0; } *used_bytes = 0; return 0; } dec_pcm_data->data_len = 0; dec_raw_data->data_len = 0; raw_in_data->data_len = 0; if (dec_fun->f_process) { ret = dec_fun->f_process(aml_dec, abuffer); } else { ALOGE("[%s:%d] f_process is null", __func__, __LINE__); return -1; } if (access(REPORT_DECODED_INFO, F_OK) == 0) { aml_dec_info_t dec_info; memset(&dec_info, 0x00, sizeof(dec_info)); char info_buf[MAX_BUFF_LEN] = {0}; memset(info_buf, 0x00, MAX_BUFF_LEN); aml_decoder_get_info(aml_dec, AML_DEC_STREMAM_INFO, &dec_info); sprintf(info_buf, "bitrate %d", dec_info.dec_info.stream_bitrate); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "ch_num %d", dec_info.dec_info.stream_ch); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "samplerate %d", dec_info.dec_info.stream_sr); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "decoded_frames %d", dec_info.dec_info.stream_decode_num); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "decoded_err %d", dec_info.dec_info.stream_error_num); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "decoded_drop %d", dec_info.dec_info.stream_drop_num); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); memset(info_buf, 0x00, MAX_BUFF_LEN); sprintf(info_buf, "ch_configuration %d", audio_channel_out_mask_from_count(dec_info.dec_info.stream_ch)); sysfs_set_sysfs_str(REPORT_DECODED_INFO, info_buf); } frame_size = audio_bytes_per_sample(dec_pcm_data->data_format) * dec_pcm_data->data_ch; /*one decoded frame length is too big, we need separate it*/ if ((dec_pcm_data->data_len >= AML_DEC_MAX_FRAMES * frame_size) && (dec_raw_data->data_format == AUDIO_FORMAT_IEC61937) && (dec_raw_data->data_len == dec_pcm_data->data_len)) { fragment_size = AML_DEC_FRAGMENT_FRAMES * frame_size; aml_dec->fragment_left_size = dec_pcm_data->data_len - fragment_size; dec_pcm_data->data_len = fragment_size; dec_raw_data->data_len = fragment_size; } if (ret >= 0 ) { *used_bytes = ret; return AML_DEC_RETURN_TYPE_OK; } else { *used_bytes = abuffer->size; return ret; } } eDTSLibType_t detect_dts_lib_type(bool Platform_support) { void *hDTSLibHanle = NULL; // the priority would be "DTSX > DTSHD" lib // DTSX is first priority /*coverity[toctou]: DTS_X_LIB_PATH_A will not change after access*/ if (access(DTS_X_LIB_PATH_A, R_OK) == 0 && Platform_support) { // try to open lib see if it's OK? hDTSLibHanle = dlopen(DTS_X_LIB_PATH_A, RTLD_NOW); if (hDTSLibHanle != NULL) { dlclose(hDTSLibHanle); hDTSLibHanle = NULL; gDtsLibType = eDTSXLib; ALOGI("[%s:%d] Found libHwAudio_dtsx lib", __func__, __LINE__); return eDTSXLib; } } // DTSHD is second priority /*coverity[toctou]: DTS_X_LIB_PATH_A will not change after access*/ if (access(DTS_HD_LIB_PATH_A, R_OK) == 0) { // try to open lib see if it's OK? hDTSLibHanle = dlopen(DTS_HD_LIB_PATH_A, RTLD_NOW); if (hDTSLibHanle != NULL) { dlclose(hDTSLibHanle); hDTSLibHanle = NULL; gDtsLibType = eDTSHDLib; ALOGI("[%s:%d] Found libHwAudio_dtshd lib", __func__, __LINE__); return eDTSHDLib; } } ALOGW("[%s:%d] Failed to find libHwAudio_dtsx.so and libHwAudio_dtshd.so, %s", __FUNCTION__, __LINE__, dlerror()); return eDTSNull; } eDTSLibType_t get_dts_lib_type(void) { return gDtsLibType; } void* aml_decoder_load(const char* lib_name) { char path[128] = {0}; for (int i = 0; search_paths[i] != NULL; i++) { snprintf(path, sizeof(path), "%s/%s", search_paths[i], lib_name); if (access(path, F_OK) == 0) { AM_LOGD("find %s in %s", lib_name, search_paths[i]); void * handle = dlopen(path, RTLD_NOW); if (handle) { return handle; } else { AM_LOGE("failed to open (%s), %s", path, dlerror()); } } } return NULL; }