/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved. * Description: adec channel function * Author: audio * Create: 2019-12-30 */ #include "adec_chan.h" #include #include #include #include #include #include #include #include "securec.h" #include "mpi_memory_ext.h" #include "mpi_adec_debug.h" #include "mpi_adec_imple.h" #include "drv_ioctl_adec.h" #include "adec_common.h" #include "adec_thread.h" #include "adec_fault_check.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ static inline td_s32 adec_open_device(adec_chan *adec) { adec->adec_dev_fd = open(ADEC_DEVICE_NAME, O_RDWR, 0); if (adec->adec_dev_fd < 0) { soc_log_fatal("cannot open '%s'!\n", ADEC_DEVICE_NAME); return SOC_ERR_ADEC_DEV_NOT_OPEN; } return TD_SUCCESS; } static td_s32 adec_close_device(adec_chan *adec) { td_s32 ret; if (adec->adec_dev_fd < 0) { return TD_SUCCESS; } ret = close(adec->adec_dev_fd); if (ret != TD_SUCCESS) { soc_log_warn("adec device close failed(0x%x)\n", ret); } adec->adec_dev_fd = -1; return ret; } td_u32 adec_get_max_out_buf_size(adec_chan *adec) { uapi_acodec_decode *codec = adec->dec_attr.codec_dev; td_void *decoder = adec->dec_attr.decoder; return adec_get_max_pcm_out_size(codec, decoder) * 2 + /* 2 pcm buffer size to store object pcm */ adec_get_max_bits_out_size(codec, decoder); } static inline td_s32 adec_find_decoder(adec_chan *adec) { uapi_acodec_decode *codec = adec_find_ha_decoder_imple(adec->codec_id); if (codec == TD_NULL) { soc_err_print_h32(adec->codec_id); soc_err_print_str(adec_get_decoder_lib_name_imple(adec->codec_id)); return SOC_ERR_ADEC_NOT_SUPPORT; } adec->dec_attr.codec_dev = codec; return TD_SUCCESS; } static td_s32 adec_init_decoder(adec_chan *adec) { td_s32 ret; ret = adec_find_decoder(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_find_decoder, ret); return ret; } ret = adec_init_decoder_imple(&adec->dec_attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_init_decoder_imple, ret); return ret; } return TD_SUCCESS; } static inline td_void adec_deinit_decoder(adec_chan *adec) { return adec_deinit_decoder_imple(&adec->dec_attr); } static td_s32 adec_init_out_buf(adec_chan_output_buf *out_buf, td_u32 max_frame_size) { td_u32 i; td_u8 *buf = TD_NULL; if ((max_frame_size == 0) || (out_buf->buf_num <= 0x1) || (out_buf->buf_num >= ADEC_MAX_WORK_BUFFER_NUMBER)) { return SOC_ERR_ADEC_INVALID_PARA; } /* allocate out_buffer */ buf = (td_u8 *)malloc(out_buf->buf_num * max_frame_size); if (buf == TD_NULL) { soc_log_fatal("call malloc( failed\n"); return SOC_ERR_ADEC_ALLOC_MEM_FAILED; } /* assigning buffer */ for (i = 0; i < out_buf->buf_num; i++) { out_buf->out_buf[i].buf = buf + i * max_frame_size; out_buf->out_buf[i].flag = TD_FALSE; out_buf->out_buf[i].buf_status = ADEC_OUTPUT_FILL_THIS_BUF; } /* reset output buffer pointer */ out_buf->base_addr = buf; out_buf->read = 0; out_buf->write = 0; return TD_SUCCESS; } static td_void adec_deinit_out_buf(adec_chan_output_buf *out_buf) { td_u32 i; if (out_buf->base_addr != TD_NULL) { free(out_buf->base_addr); out_buf->base_addr = TD_NULL; } for (i = 0; i < out_buf->buf_num; i++) { out_buf->out_buf[i].buf = TD_NULL; out_buf->out_buf[i].flag = TD_FALSE; out_buf->out_buf[i].buf_status = ADEC_OUTPUT_FILL_THIS_BUF; } out_buf->read = 0; out_buf->write = 0; } static td_void adec_deinit_in_buf(adec_chan_input_buf *in_buf) { if (in_buf->data != TD_NULL) { free(in_buf->data - in_buf->buf_padding_size); in_buf->data = TD_NULL; } in_buf->buf_free = 0; in_buf->buf_read_pos = 0; in_buf->buf_write_pos = 0; in_buf->stream_write_pos = 0; in_buf->buf_padding_size = 0; } static td_s32 adec_init_in_buf(adec_chan_input_buf *in_buf, td_u32 padding_size) { if ((in_buf->buf_size < ADEC_MIN_INPUT_BUFFER_SIZE) || (in_buf->buf_size > ADEC_MAX_INPUT_BUFFER_SIZE)) { soc_log_err(" invalid input buffer size(%d) minsize(%d) maxsize(%d)!\n", in_buf->buf_size, ADEC_MIN_INPUT_BUFFER_SIZE, ADEC_MAX_INPUT_BUFFER_SIZE); return SOC_ERR_ADEC_INVALID_PARA; } in_buf->buf_free = in_buf->buf_size; in_buf->buf_read_pos = 0; in_buf->buf_write_pos = 0; in_buf->stream_write_pos = 0; in_buf->boundary = in_buf->buf_size; while ((in_buf->boundary << 1) <= (ADEC_PTS_BOUNDARY_SIZE - in_buf->buf_size)) { in_buf->boundary <<= 1; } in_buf->buf_padding_size = padding_size; in_buf->data = (td_u8 *)malloc(in_buf->buf_size + padding_size); if (in_buf->data == TD_NULL) { soc_log_fatal("call malloc( failed\n"); return SOC_ERR_ADEC_ALLOC_MEM_FAILED; } in_buf->data += padding_size; return TD_SUCCESS; } static td_void adec_free_buffer(adec_chan *adec) { adec_deinit_out_buf(&adec->out_stream_buf); adec_deinit_in_buf(&adec->in_stream_buf); } static td_s32 adec_alloc_buffer(adec_chan *adec) { td_s32 ret; td_u32 padding_size; if (adec->packet_decoder == TD_TRUE) { padding_size = PACKET_ADEC_INPUTBUF_PADDING_SIZE; } else { padding_size = ADEC_INPUTBUF_PADDING_SIZE; } ret = adec_init_in_buf(&adec->in_stream_buf, padding_size); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_init_in_buf, ret); return ret; } ret = adec_init_out_buf(&adec->out_stream_buf, adec_get_max_out_buf_size(adec)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_init_out_buf, ret); adec_deinit_in_buf(&adec->in_stream_buf); return ret; } return TD_SUCCESS; } static td_void adec_free_packet_queue(adec_chan *adec) { if (adec->packet_que == TD_NULL) { return; } adec_free(adec->packet_que); adec->packet_que = TD_NULL; } static td_s32 adec_alloc_packet_queue(adec_chan *adec) { /* only sw decoder support packet audio */ adec->packet_que = (adec_packet_que *)adec_malloc(sizeof(adec_packet_que)); if (adec->packet_que == TD_NULL) { soc_log_err("adec_malloc adec_packet_que failed\n"); return SOC_ERR_ADEC_ALLOC_MEM_FAILED; } return TD_SUCCESS; } static td_void adec_reset_chan(adec_chan *adec) { td_s32 ret; adec->sw_decoder_bytes_left = 0; adec->output_delay = 0; adec->ie_samples = 0; adec->mid_state.continue_err_num = 0; adec->mid_state.last_frame_channels = EXT_AUDIO_CH_STEREO; adec->mid_state.last_frame_sample_rate = EXT_SAMPLE_RATE_48K; /* reset PTS */ ret = memset_s(&adec->pts_que, sizeof(adec->pts_que), 0, sizeof(adec_pts_que)); if (ret != EOK) { soc_err_print_call_fun_err(memset_s, ret); return; } adec->pts_que.last_pts_ms = ADEC_INVALID_PTS; adec->pts_que.last_store_pts_ms = ADEC_INVALID_PTS; adec->pts_que.dfx.first_valid_pts = ADEC_INVALID_PTS; adec->pts_que.dfx.expect_pts = ADEC_INVALID_PTS; ret = memset_s(&adec->dfx, sizeof(adec->dfx), 0, sizeof(adec_chan_dfx)); if (ret != EOK) { soc_err_print_call_fun_err(memset_s, ret); return; } adec->dfx.speed.speed_integer = 1; } static td_s32 adec_init_channel(adec_chan *adec) { td_s32 ret; ret = adec_init_decoder(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_init_decoder, ret); return ret; } ret = adec_alloc_packet_queue(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_alloc_packet_queue, ret); goto out0; } ret = adec_alloc_buffer(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_alloc_buffer, ret); goto out1; } ret = adec_event_init(&adec->event); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_event_init, ret); goto out2; } adec_reset_chan(adec); adec_chan_dfx_create_ud(adec); return TD_SUCCESS; out2: adec_free_buffer(adec); out1: adec_free_packet_queue(adec); out0: adec_deinit_decoder(adec); return ret; } static td_s32 adec_deinit_channel(adec_chan *adec) { adec_chan_dfx_destroy_ud(adec); adec_event_deinit(&adec->event); adec_free_buffer(adec); adec_free_packet_queue(adec); adec_deinit_decoder(adec); return TD_SUCCESS; } static td_void adec_get_decoder_name(adec_chan *adec) { td_s32 ret; adec_proc_item *adec_proc = adec->adec_info; uapi_acodec_decode *codec = adec->dec_attr.codec_dev; if (codec == TD_NULL) { return; } ret = snprintf_s(adec_proc->codec_type, sizeof(adec_proc->codec_type), sizeof(adec_proc->codec_type) - 1, "%s", (codec->name != TD_NULL) ? codec->name : "UNKNOWN"); if (ret < 0) { soc_err_print_call_fun_err(snprintf_s, ret); return; } ret = snprintf_s(adec_proc->codec_description, sizeof(adec_proc->codec_description), sizeof(adec_proc->codec_description) - 1, "%s", (codec->description != TD_NULL) ? codec->description : "UNKNOWN"); if (ret < 0) { soc_err_print_call_fun_err(snprintf_s, ret); return; } } static td_void adec_reset_proc_info(adec_chan *adec) { adec_proc_item *adec_proc = adec->adec_info; if (adec_proc == TD_NULL) { return; } adec_proc->codec_id = adec->codec_id; adec_proc->fmt = adec->packet_decoder; adec_proc->adec_work_enable = adec_be_work(adec->state); adec_proc->frame_size = adec->out_stream_buf.buf_num; adec_proc->buf_size = adec->in_stream_buf.buf_size; adec_proc->frame_read = 0; adec_proc->frame_write = 0; adec_proc->frame_read_wrap = 0; adec_proc->frame_write_wrap = 0; adec_proc->out_channels = 0; adec_proc->bits_out_bytes_per_frame = 0; adec_proc->pcm_samples_per_frame = 0; adec_proc->buf_read = 0; adec_proc->buf_write = 0; adec_proc->pts_lost = 0; adec_proc->framn_nm = 0; adec_proc->err_frame_num = 0; adec_proc->frame_consumed_bytes = 0; adec_proc->last_correct_frame_num = 0; adec_proc->codec_unsupport_num = 0; adec_proc->stream_corrupt_num = 0; adec->total_dec_duration_ms = 0.0f; adec_get_decoder_name(adec); } static td_void adec_init_proc_info(adec_proc_item *adec_info) { td_s32 ret; ret = memset_s(adec_info, sizeof(*adec_info), 0, sizeof(adec_proc_item)); if (ret != EOK) { soc_err_print_call_fun_err(memset_s, ret); return; } adec_info->sample_rate = EXT_SAMPLE_RATE_UNKNOWN; adec_info->bit_width = EXT_BIT_DEPTH_UNKNOWN; adec_info->pcm_ctrl_state = ADEC_CMD_CTRL_STOP; adec_info->es_ctrl_state = ADEC_CMD_CTRL_STOP; adec_info->volume = ADEC_MAX_VOLUME; } static td_s32 adec_proc_init(adec_chan *adec) { td_s32 ret; adec_proc_param adec_proc = {0, -1, 0}; ret = adec_open_device(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_open_device, ret); return ret; } ret = ioctl(adec->adec_dev_fd, DRV_ADEC_PROC_INIT, &adec_proc); if (ret != TD_SUCCESS) { soc_log_err("ioctl DRV_ADEC_PROC_INIT failed(0x%x)\n", ret); goto out1; } adec->adec_info = (adec_proc_item *)mmap((td_void *)0, sizeof(adec_proc_item), PROT_READ | PROT_WRITE, MAP_SHARED, adec_proc.map_fd, 0); if (adec->adec_info == MAP_FAILED) { soc_log_err("mmap adec_proc_item failed\n"); goto out2; } adec->adec_proc_map_fd = adec_proc.map_fd; adec_init_proc_info(adec->adec_info); return TD_SUCCESS; out2: ret = ioctl(adec->adec_dev_fd, DRV_ADEC_PROC_EXIT); if (ret != TD_SUCCESS) { soc_log_err("ioctl DRV_ADEC_PROC_EXIT failed(0x%x)\n", ret); } out1: ret = adec_close_device(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_close_device, ret); } return TD_FAILURE; } static td_void adec_free_private_data(adec_chan *adec) { if (adec->dec_attr.private_data != TD_NULL) { free(adec->dec_attr.private_data); adec->dec_attr.private_data = TD_NULL; adec->dec_attr.private_data_size = 0; } } static td_void adec_proc_deinit(adec_chan *adec) { td_s32 ret; if (adec->adec_info != TD_NULL) { ret = munmap(adec->adec_info, sizeof(adec_proc_item)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(munmap, ret); return; } adec->adec_proc_map_fd = TD_INVALID_HANDLE; adec->adec_info = TD_NULL; } if (adec->adec_dev_fd >= 0) { ret = ioctl(adec->adec_dev_fd, DRV_ADEC_PROC_EXIT); if (ret != TD_SUCCESS) { soc_log_err("ioctl DRV_ADEC_PROC_EXIT failed(0x%x)\n", ret); return; } ret = adec_close_device(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_close_device, ret); return; } } adec_free_private_data(adec); } td_s32 adec_chan_stop_dec_thread(adec_chan *adec) { td_s32 ret; if (adec == TD_NULL) { return TD_SUCCESS; } adec->adec_thread_run = TD_FALSE; ret = pthread_join(adec->adec_thread_inst, TD_NULL); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pthread_join, ret); return ret; } return TD_SUCCESS; } td_s32 adec_chan_close(adec_chan *adec) { td_s32 ret; if (adec == TD_NULL) { return TD_SUCCESS; } if (adec_be_work(adec->state) == TD_TRUE) { ret = adec_deinit_channel(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_deinit_channel, ret); return ret; } adec->state = ADEC_STATE_STOP; } adec_proc_deinit(adec); return TD_SUCCESS; } td_s32 adec_chan_open(adec_chan *adec) { td_s32 ret; check_adec_null_ptr(adec); ret = adec_proc_init(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_proc_init, ret); return ret; } adec->adec_thread_run = TD_TRUE; ret = pthread_create(&adec->adec_thread_inst, TD_NULL, adec_dec_thread, (td_void *)adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pthread_create, ret); adec_proc_deinit(adec); return ret; } adec->start_time = 0; return TD_SUCCESS; } td_s32 adec_chan_start(adec_chan *adec) { td_s32 ret; check_adec_null_ptr(adec); if (adec_be_work(adec->state) == TD_TRUE) { return TD_SUCCESS; } ret = adec_init_channel(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_init_channel, ret); return ret; } adec->state = ADEC_STATE_START; adec_reset_proc_info(adec); adec->start_time = 0; soc_log_info("adec%02u start\n", adec->ch_id); return TD_SUCCESS; } td_s32 adec_chan_stop(adec_chan *adec) { td_s32 ret; check_adec_null_ptr(adec); if (adec_be_work(adec->state) == TD_FALSE) { return TD_SUCCESS; } ret = adec_deinit_channel(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_deinit_channel, ret); return ret; } adec->state = ADEC_STATE_STOP; adec->eos_flag = TD_FALSE; adec->report_decode_event = TD_FALSE; adec_reset_proc_info(adec); soc_log_info("adec%02u stop\n", adec->ch_id); return TD_SUCCESS; } td_s32 adec_chan_pause(adec_chan *adec) { check_adec_null_ptr(adec); if (adec_be_work(adec->state) == TD_FALSE) { return SOC_ERR_ADEC_NOT_SUPPORT; } if (adec->state == ADEC_STATE_PAUSE) { return TD_SUCCESS; } adec_chan_dfx_pause(adec); adec->state = ADEC_STATE_PAUSE; return TD_SUCCESS; } td_s32 adec_chan_resume(adec_chan *adec) { check_adec_null_ptr(adec); if (adec_be_work(adec->state) == TD_FALSE) { return SOC_ERR_ADEC_NOT_SUPPORT; } if (adec->state != ADEC_STATE_PAUSE) { return TD_SUCCESS; } adec_chan_dfx_resume(adec); adec->state = ADEC_STATE_START; return TD_SUCCESS; } td_s32 adec_chan_set_speed(adec_chan *adec, const ext_adec_speed *speed) { td_s32 ret; check_adec_null_ptr(adec); check_adec_null_ptr(speed); if (adec_be_work(adec->state) == TD_FALSE || (speed->speed_integer == 0 && speed->speed_decimal == 0)) { return SOC_ERR_ADEC_NOT_SUPPORT; } if (adec->state == ADEC_STATE_PAUSE) { adec_chan_dfx_resume(adec); adec->state = ADEC_STATE_START; } ret = adec_chan_dfx_set_speed(adec, speed); return ret; } td_s32 adec_chan_get_speed(adec_chan *adec, ext_adec_speed *speed) { check_adec_null_ptr(adec); check_adec_null_ptr(speed); if (adec_be_work(adec->state) == TD_FALSE) { return SOC_ERR_ADEC_DECODE_MODE; } return adec_chan_dfx_get_speed(adec, speed); } static td_s32 adec_store_decode_private_data(adec_chan *adec, const ext_adec_attr *adec_attr) { td_s32 ret; td_void *private = TD_NULL; td_u32 size = adec_attr->open_param.private_data_size; ret = memcpy_s(&adec->dec_attr.dec_param, sizeof(adec->dec_attr.dec_param), &adec_attr->open_param, sizeof(uapi_acodec_dec_param)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } if ((adec_attr->open_param.private_data == TD_NULL) || (size == 0)) { return TD_SUCCESS; } if ((adec->dec_attr.private_data_size >= size) && (adec->dec_attr.private_data != TD_NULL)) { private = adec->dec_attr.private_data; } else { adec_free_private_data(adec); private = malloc(size); if (private == TD_NULL) { soc_log_err("call malloc( fail\n"); return SOC_ERR_ADEC_ALLOC_MEM_FAILED; } } ret = memcpy_s(private, size, adec_attr->open_param.private_data, adec_attr->open_param.private_data_size); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); if (adec->dec_attr.private_data == TD_NULL) { free(private); } else { adec_free_private_data(adec); } return ret; } adec->dec_attr.dec_param.private_data = private; adec->dec_attr.dec_param.private_data_size = size; adec->dec_attr.private_data = private; adec->dec_attr.private_data_size = size; return TD_SUCCESS; } static td_void adec_check_packet_decode(adec_chan *adec) { td_s32 ret; uapi_acodec_packet_decoder_query_param packet_decode = { .cmd = UAPI_ACODEC_PACKET_DECODER_QUERY_CMD, .packet_decoder = TD_FALSE, }; if (adec->codec_id == 0xFFFFFFFF) { return; } ret = adec_set_config_decoder(adec->codec_id, &packet_decode); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_set_config_decoder, ret); adec->packet_decoder = TD_FALSE; return; } adec->packet_decoder = packet_decode.packet_decoder; } td_s32 adec_chan_get_attr(adec_chan *adec, ext_adec_attr *adec_attr) { td_s32 ret; ret = memcpy_s(&adec_attr->open_param, sizeof(adec_attr->open_param), &adec->dec_attr.dec_param, sizeof(uapi_acodec_dec_param)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } adec_attr->codec_id = adec->codec_id; adec_attr->in_buf_size = adec->in_stream_buf.buf_size; adec_attr->out_buf_num = adec->out_stream_buf.buf_num; adec_attr->enable = adec_be_work(adec->state); adec_attr->eos = adec->eos_flag; if ((adec_attr->codec_id == UAPI_ACODEC_ID_DOLBY_PLUS) || (adec_attr->codec_id == UAPI_ACODEC_ID_DTSM6)) { adec->output_channel_num = adec_attr->open_param.pcm_attr.desired_out_channels; soc_log_notice("set adec_channel->output_channel_num:%d\n", adec->output_channel_num); } return TD_SUCCESS; } td_s32 adec_chan_set_attr(adec_chan *adec, const ext_adec_attr *adec_attr) { td_s32 ret; ret = adec_chan_stop(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_chan_stop, ret); return ret; } ret = adec_store_decode_private_data(adec, adec_attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_store_decode_private_data, ret); return ret; } adec->in_stream_buf.buf_size = adec_attr->in_buf_size; adec->out_stream_buf.buf_num = adec_attr->out_buf_num; adec->codec_id = adec_attr->codec_id; adec->eos_flag = adec_attr->eos; if (adec_attr->enable == TD_TRUE) { ret = adec_chan_start(adec); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(adec_chan_start, ret); return ret; } } adec_check_packet_decode(adec); return TD_SUCCESS; } #ifdef __cplusplus } #endif /* __cplusplus */