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.
822 lines
28 KiB
822 lines
28 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved.
|
|
* Description: adec thread function
|
|
* Author: audio
|
|
* Create: 2019-12-30
|
|
*/
|
|
|
|
#include "adec_thread.h"
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <sys/syscall.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
|
|
#include "soc_math.h"
|
|
#include "mpi_adec_debug.h"
|
|
#include "adec_pts.h"
|
|
#include "adec_volume.h"
|
|
#include "adec_common.h"
|
|
#include "adec_lock.h"
|
|
#include "adec_fault_check.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif /* __cplusplus */
|
|
|
|
#define NANO_SLEEP_MS 1000000
|
|
#define DDP_STATIC_OUTPUT_DELAY 6
|
|
|
|
static td_void adec_sw_decode(adec_chan *adec);
|
|
|
|
static td_void adec_check_scrambler(adec_chan *adec, td_s32 consume_bytes)
|
|
{
|
|
td_u32 mute = 0;
|
|
adec_proc_item *adec_info = adec->adec_info;
|
|
|
|
if (adec->adec_info == TD_NULL) {
|
|
soc_log_err("adec->adec_info is null\n");
|
|
return;
|
|
}
|
|
|
|
if (adec_info->last_correct_frame_num == adec_info->framn_nm) {
|
|
adec_info->frame_consumed_bytes += (td_u32)consume_bytes;
|
|
|
|
/* mute the adec if the frame comsumed bytes more than ADEC_MAX_FRAME_CONSUME_THD */
|
|
if (adec_info->frame_consumed_bytes > ADEC_MAX_FRAME_CONSUME_THD) {
|
|
mute = 1;
|
|
}
|
|
} else {
|
|
if ((adec_info->last_correct_frame_num + 1) == adec_info->framn_nm) {
|
|
if ((adec_info->frame_consumed_bytes + consume_bytes) > ADEC_MAX_FRAME_CONSUME_THD) {
|
|
mute = 1;
|
|
}
|
|
}
|
|
|
|
/* detect again */
|
|
adec_info->last_correct_frame_num = adec_info->framn_nm;
|
|
adec_info->frame_consumed_bytes = 0;
|
|
}
|
|
|
|
/* should not invoke adec_set_volume */
|
|
if (mute != 0) {
|
|
adec_set_volume(adec, 0);
|
|
} else {
|
|
adec_set_volume(adec, ADEC_MAX_VOLUME);
|
|
}
|
|
|
|
adec->bs_consume_bytes = 0;
|
|
}
|
|
|
|
static td_void adec_thread_schedule(const adec_chan *adec, td_u32 time_ms)
|
|
{
|
|
td_u32 i;
|
|
struct timespec time = {
|
|
.tv_sec = 0,
|
|
.tv_nsec = NANO_SLEEP_MS,
|
|
};
|
|
|
|
if (time_ms == 0) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < time_ms; i++) {
|
|
if (adec->adec_thread_run == TD_FALSE) {
|
|
/* shorten the exit time of adec thread */
|
|
return;
|
|
}
|
|
|
|
if (nanosleep(&time, TD_NULL) != 0) {
|
|
soc_log_err("call nanosleep failed\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* dynamically change sleep time */
|
|
static td_void adec_calculate_sleep_time(adec_proc_item *adec_proc)
|
|
{
|
|
td_u32 frame_time;
|
|
|
|
/* bluray lpcm decoder need to wake up decoder thread in 1ms */
|
|
if (adec_proc->codec_id == UAPI_ACODEC_ID_BLYRAYLPCM) {
|
|
adec_proc->adec_system_sleep_time = ADEC_MIN_SLEEP_TIME;
|
|
return;
|
|
}
|
|
|
|
/* stream info not sure, use default sleep time */
|
|
if (adec_proc->sample_rate == 0) {
|
|
adec_proc->adec_system_sleep_time = ADEC_SYS_SLEEP_TIME;
|
|
return;
|
|
}
|
|
|
|
/* passthrough only decoder use default sleep time */
|
|
if (adec_proc->pcm_samples_per_frame == 0) {
|
|
adec_proc->adec_system_sleep_time = ADEC_SYS_SLEEP_TIME;
|
|
return;
|
|
}
|
|
|
|
/* sleep at least 1ms and at most 10ms */
|
|
frame_time = adec_samples_to_time(adec_proc->pcm_samples_per_frame, adec_proc->sample_rate);
|
|
frame_time = max2(ADEC_MIN_SLEEP_TIME, frame_time);
|
|
adec_proc->adec_system_sleep_time = min2(ADEC_SYS_SLEEP_TIME, frame_time);
|
|
}
|
|
|
|
static inline td_bool adec_decoder_ready(const adec_chan *adec)
|
|
{
|
|
return ((adec->dec_attr.decoder != TD_NULL) && (adec_be_work(adec->state) == TD_TRUE));
|
|
}
|
|
|
|
static td_void adec_thread_check_schedule_start(adec_proc_item *adec_proc)
|
|
{
|
|
adec_proc->thread_begin_time = adec_get_time_stamp();
|
|
|
|
if (adec_proc->thread_end_time == 0) {
|
|
return;
|
|
}
|
|
|
|
if (adec_proc->thread_begin_time - adec_proc->thread_end_time > ADEC_SCHE_THREADTIME_LIMIT) {
|
|
adec_proc->thread_sched_time_out_cnt++;
|
|
}
|
|
}
|
|
|
|
static td_void adec_thread_check_schedule_stop(adec_proc_item *adec_proc)
|
|
{
|
|
adec_proc->thread_end_time = adec_get_time_stamp();
|
|
if (adec_proc->thread_end_time - adec_proc->thread_begin_time > ADEC_EXE_THREADTIME_LIMIT) {
|
|
adec_proc->thread_exe_time_out_cnt++;
|
|
}
|
|
}
|
|
|
|
td_void *adec_dec_thread(td_void *arg)
|
|
{
|
|
adec_chan *adec = (adec_chan *)arg;
|
|
adec_proc_item *adec_proc = TD_NULL;
|
|
|
|
if (adec == TD_NULL) {
|
|
soc_log_err("adec is null!\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
adec_proc = adec->adec_info;
|
|
if (adec_proc == TD_NULL) {
|
|
soc_log_err("adec(%d) proc is null!\n", adec->ch_id);
|
|
return TD_NULL;
|
|
}
|
|
|
|
adec_proc->thread_id = (td_u32)syscall(__NR_gettid);
|
|
|
|
while (adec->adec_thread_run == TD_TRUE) {
|
|
adec_thread_check_schedule_start(adec_proc);
|
|
adec_data_lock(adec->ch_id);
|
|
if (adec_decoder_ready(adec) == TD_FALSE) {
|
|
adec_data_unlock(adec->ch_id);
|
|
adec_thread_schedule(adec, ADEC_SYS_SLEEP_TIME);
|
|
continue;
|
|
}
|
|
|
|
adec_sw_decode(adec);
|
|
if (adec->packet_decoder == TD_FALSE) {
|
|
/* pop sound only in non-packet sw-decode mode */
|
|
adec_check_scrambler(adec, adec->bs_consume_bytes);
|
|
}
|
|
adec_data_unlock(adec->ch_id);
|
|
|
|
adec_thread_check_schedule_stop(adec_proc);
|
|
adec_calculate_sleep_time(adec_proc);
|
|
adec_thread_schedule(adec, adec_proc->adec_system_sleep_time);
|
|
}
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
td_u32 adec_get_input_data_size(adec_chan_input_buf *in_buf)
|
|
{
|
|
if (in_buf == TD_NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (in_buf->buf_read_pos <= (td_s32)in_buf->buf_write_pos) {
|
|
return in_buf->buf_write_pos - in_buf->buf_read_pos;
|
|
} else {
|
|
return in_buf->buf_size - in_buf->buf_read_pos + in_buf->buf_write_pos;
|
|
}
|
|
}
|
|
|
|
static td_void adec_update_bs_read_pos(adec_chan_input_buf *in_buf, td_u32 consume_bytes)
|
|
{
|
|
in_buf->buf_read_pos += (td_s32)consume_bytes;
|
|
if (in_buf->buf_read_pos >= (td_s32)in_buf->buf_size) {
|
|
in_buf->buf_read_pos -= (td_s32)in_buf->buf_size;
|
|
}
|
|
|
|
in_buf->buf_free += consume_bytes;
|
|
}
|
|
|
|
/* deal with buffer wrap, only at last little data */
|
|
static td_void adec_update_bs_wrap(adec_chan_input_buf *in_buf)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 read;
|
|
td_u32 wrap_size;
|
|
|
|
if (in_buf->buf_read_pos <= 0) {
|
|
return;
|
|
}
|
|
|
|
read = (td_u32)in_buf->buf_read_pos;
|
|
if (in_buf->buf_write_pos >= read) {
|
|
return;
|
|
}
|
|
|
|
wrap_size = in_buf->buf_size - read;
|
|
if (wrap_size > in_buf->buf_padding_size) {
|
|
return;
|
|
}
|
|
|
|
ret = memcpy_s(in_buf->data - wrap_size, wrap_size + in_buf->buf_size,
|
|
in_buf->data + read, wrap_size);
|
|
if (ret != EOK) {
|
|
soc_err_print_call_fun_err(memcpy_s, ret);
|
|
return;
|
|
}
|
|
|
|
in_buf->buf_read_pos = (td_s32)(0 - wrap_size);
|
|
}
|
|
|
|
static td_u32 adec_get_stream_read_pos(adec_chan_input_buf *in_buf)
|
|
{
|
|
td_u32 data_size = adec_get_input_data_size(in_buf);
|
|
if (in_buf->stream_write_pos >= data_size) {
|
|
return in_buf->stream_write_pos - data_size;
|
|
} else {
|
|
return in_buf->boundary + in_buf->stream_write_pos - data_size;
|
|
}
|
|
}
|
|
|
|
static td_u32 adec_fix_stream_read_pos(const adec_chan *adec, td_u32 stream_read_pos, td_u32 backward_bytes)
|
|
{
|
|
td_u32 fix_pos;
|
|
td_u32 border = adec->in_stream_buf.boundary;
|
|
|
|
if (stream_read_pos < backward_bytes) {
|
|
return 0;
|
|
}
|
|
|
|
fix_pos = stream_read_pos - backward_bytes;
|
|
if (fix_pos >= border) {
|
|
fix_pos -= border;
|
|
}
|
|
|
|
return fix_pos;
|
|
}
|
|
|
|
static td_s32 adec_get_input_buf(adec_chan *adec, uapi_acodec_dec_in_packet *avpkt)
|
|
{
|
|
td_s32 ret;
|
|
adec_chan_input_buf *in_buf = &adec->in_stream_buf;
|
|
adec_packet_que *packet_que = adec->packet_que;
|
|
adec_packet *packet = TD_NULL;
|
|
td_s32 bs_left_bytes;
|
|
|
|
ret = memset_s(avpkt, sizeof(*avpkt), 0, sizeof(uapi_acodec_dec_in_packet));
|
|
if (ret != EOK) {
|
|
soc_err_print_call_fun_err(memset_s, ret);
|
|
return ret;
|
|
}
|
|
|
|
if (adec->packet_decoder == TD_TRUE) {
|
|
packet = &packet_que->packet_arry[packet_que->packet_read];
|
|
if (packet->packet_eos_flag == TD_TRUE) {
|
|
/* deal with buffer wrap before decode at packet mode */
|
|
if (packet->beg_pos > (td_s32)packet->end_pos) {
|
|
adec_update_bs_wrap(in_buf);
|
|
packet->beg_pos = in_buf->buf_read_pos;
|
|
}
|
|
|
|
avpkt->data = in_buf->data + in_buf->buf_read_pos;
|
|
avpkt->size = (td_s32)packet->end_pos - in_buf->buf_read_pos;
|
|
}
|
|
} else {
|
|
/* get linear-buffer unread data length */
|
|
if ((td_s32)in_buf->buf_write_pos < in_buf->buf_read_pos) {
|
|
bs_left_bytes = (td_s32)(in_buf->buf_size) - in_buf->buf_read_pos;
|
|
} else {
|
|
bs_left_bytes = (td_s32)(in_buf->buf_write_pos - in_buf->buf_read_pos);
|
|
}
|
|
|
|
avpkt->data = in_buf->data + in_buf->buf_read_pos;
|
|
avpkt->size = bs_left_bytes;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static adec_decode_output *adec_get_out_buf(adec_chan_output_buf *out_buf)
|
|
{
|
|
td_u32 next_tail;
|
|
adec_decode_output *dec_output = out_buf->out_buf;
|
|
|
|
/* check availability of output buffer */
|
|
next_tail = adec_sat_add(out_buf->write, 1, out_buf->buf_num);
|
|
if ((next_tail == out_buf->read) || (dec_output[out_buf->write].flag == TD_TRUE)) {
|
|
return TD_NULL;
|
|
}
|
|
|
|
return &dec_output[out_buf->write];
|
|
}
|
|
|
|
static td_void adec_update_frame_info(adec_chan *adec)
|
|
{
|
|
adec_proc_item *adec_info = adec->adec_info;
|
|
|
|
if (((adec->frame_info.sample_rate != adec_info->sample_rate) ||
|
|
(adec->frame_info.channel != adec_info->out_channels) ||
|
|
(adec->frame_info.bit_depth != adec_info->bit_width)) &&
|
|
((adec->frame_info.sample_rate != EXT_SAMPLE_RATE_MAX) &&
|
|
(adec->frame_info.channel != 0) &&
|
|
(adec->frame_info.bit_depth != EXT_BIT_DEPTH_MAX))) {
|
|
soc_log_warn("frame information change!\n");
|
|
adec->frame_info.frame_info_change = TD_TRUE;
|
|
adec_event_report(&adec->event, EXT_ADEC_EVENT_FRAME_INFO_CHANGE, TD_NULL, 0);
|
|
}
|
|
|
|
adec->frame_info.sample_rate = adec_info->sample_rate;
|
|
adec->frame_info.channel = adec_info->out_channels;
|
|
adec->frame_info.bit_depth = adec_info->bit_width;
|
|
}
|
|
|
|
static td_void adec_get_codec_output_delay(adec_chan *adec)
|
|
{
|
|
td_s32 ret;
|
|
td_void *decoder = adec->dec_attr.decoder;
|
|
uapi_acodec_decode *dev = adec->dec_attr.codec_dev;
|
|
uapi_acodec_output_delay_get_param output_delay = {
|
|
.cmd = UAPI_ACODEC_OUTPUT_DELAY_GET_CMD,
|
|
.output_delay = 0,
|
|
};
|
|
|
|
switch (adec->codec_id) {
|
|
case UAPI_ACODEC_ID_AAC:
|
|
ret = dev->set_config(decoder, (td_void *)&output_delay);
|
|
if (ret != TD_SUCCESS) {
|
|
adec->output_delay = 0;
|
|
return;
|
|
}
|
|
|
|
adec->output_delay = output_delay.output_delay;
|
|
break;
|
|
|
|
case UAPI_ACODEC_ID_DOLBY_PLUS:
|
|
adec->output_delay = DDP_STATIC_OUTPUT_DELAY;
|
|
break;
|
|
|
|
default:
|
|
adec->output_delay = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static td_void adec_update_input_buf(adec_chan *adec, td_u32 consume_bytes)
|
|
{
|
|
adec_chan_input_buf *in_buf = &adec->in_stream_buf;
|
|
adec_packet_que *packet_que = adec->packet_que;
|
|
adec_packet *packet = &packet_que->packet_arry[packet_que->packet_read];
|
|
|
|
if ((adec->packet_decoder == TD_TRUE) &&
|
|
(packet->packet_eos_flag == TD_TRUE)) {
|
|
adec_update_bs_read_pos(in_buf, consume_bytes);
|
|
if ((td_u32)in_buf->buf_read_pos == packet->end_pos) {
|
|
packet->packet_eos_flag = TD_FALSE;
|
|
packet_que->packet_read = (packet_que->packet_read + 1) % ADEC_MAX_STORED_PACKET_NUM;
|
|
if (packet->packet_eos_flag == TD_TRUE) {
|
|
}
|
|
}
|
|
} else {
|
|
if (consume_bytes != 0) {
|
|
adec_update_bs_read_pos(in_buf, consume_bytes);
|
|
} else {
|
|
/* only sw decoder need to wrap buffer */
|
|
adec_update_bs_wrap(in_buf);
|
|
}
|
|
}
|
|
|
|
adec->adec_info->buf_read = in_buf->buf_read_pos;
|
|
}
|
|
|
|
static td_void adec_update_out_buf(adec_chan *adec)
|
|
{
|
|
adec_chan_output_buf *out_stream_buf = &adec->out_stream_buf;
|
|
adec_proc_item *adec_info = adec->adec_info;
|
|
|
|
out_stream_buf->out_buf[out_stream_buf->write].buf_status = ADEC_OUTPUT_EMPTY_THIS_BUF;
|
|
out_stream_buf->write = adec_sat_add(out_stream_buf->write, 1, out_stream_buf->buf_num);
|
|
adec_info->frame_write = out_stream_buf->write;
|
|
}
|
|
|
|
static td_void adec_report_event_eos(adec_chan *adec)
|
|
{
|
|
if (adec->eos_flag == TD_TRUE) {
|
|
adec->adec_info->not_enough_buf_cnt++;
|
|
} else {
|
|
adec->adec_info->not_enough_buf_cnt = 0;
|
|
}
|
|
|
|
/* out buffer is empty and decoder report SOC_ERROR_NOT_ENOUGHDATA for 5 times */
|
|
if (adec->out_stream_buf.read == adec->out_stream_buf.write &&
|
|
adec->adec_info->not_enough_buf_cnt >= ADEC_EOS_LIMIT_COUNT) {
|
|
adec_event_report(&adec->event, EXT_ADEC_EVENT_EOS, TD_NULL, 0);
|
|
adec->adec_info->report_eos_event = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
static td_void adec_decode_get_in_pkt(adec_chan *adec, adec_in_packet *in_pkt)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 read_pos;
|
|
|
|
in_pkt->ready = TD_FALSE;
|
|
|
|
ret = adec_get_input_buf(adec, &in_pkt->pkt);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(adec_get_input_buf, ret);
|
|
return;
|
|
}
|
|
|
|
if (in_pkt->pkt.size < 0) {
|
|
return;
|
|
}
|
|
|
|
read_pos = adec_get_stream_read_pos(&adec->in_stream_buf);
|
|
read_pos = adec_fix_stream_read_pos(adec, read_pos, adec->sw_decoder_bytes_left);
|
|
in_pkt->read_pos = read_pos;
|
|
|
|
in_pkt->input_size = (td_u32)in_pkt->pkt.size;
|
|
in_pkt->total_input_size = in_pkt->pkt.size + adec->sw_decoder_bytes_left;
|
|
in_pkt->output_size = 0;
|
|
in_pkt->consume_size = 0;
|
|
in_pkt->ready = TD_TRUE;
|
|
}
|
|
|
|
static td_void adec_out_packet_process_volume(adec_chan *adec, uapi_acodec_dec_out_packet *pkt)
|
|
{
|
|
if (adec->volume == ADEC_MAX_VOLUME) {
|
|
return;
|
|
}
|
|
|
|
if (pkt->pcm_out_samples == 0) {
|
|
return;
|
|
}
|
|
|
|
adec_process_volume(pkt->pcm_out_buf,
|
|
(td_s32)pkt->pcm_out_samples,
|
|
(td_s32)pkt->bit_per_sample,
|
|
(td_s32)pkt->out_channels,
|
|
adec->volume_frac);
|
|
}
|
|
|
|
/* adjust pts by interpolation error */
|
|
static td_u32 adec_adjust_pts_by_ie(adec_chan *adec, const uapi_acodec_dec_out_packet *pkt,
|
|
td_bool interpolated, const td_u32 cur_frame_pts, td_u32 cur_frame_time)
|
|
{
|
|
/* to avoid decimal being ignored (caused by integer division), we scale it up by 1000 */
|
|
td_u32 actual_samples = pkt->pcm_out_samples * ADEC_TIME_RATE;
|
|
td_u32 frame_time_samples;
|
|
td_u32 adjusted_pts = cur_frame_pts;
|
|
|
|
if ((interpolated != TD_TRUE) || (cur_frame_pts == ADEC_INVALID_PTS) ||
|
|
(actual_samples == 0) || (pkt->out_sample_rate == 0)) {
|
|
adec->ie_samples = 0;
|
|
return cur_frame_pts;
|
|
}
|
|
|
|
frame_time_samples = cur_frame_time * pkt->out_sample_rate;
|
|
if (actual_samples > frame_time_samples) {
|
|
adec->ie_samples += (td_s32)(actual_samples - frame_time_samples);
|
|
} else {
|
|
adec->ie_samples -= (td_s32)(frame_time_samples - actual_samples);
|
|
}
|
|
if ((adec->ie_samples > (td_s32)pkt->out_sample_rate) || (adec->ie_samples < (0 - (td_s32)pkt->out_sample_rate))) {
|
|
if (adec->ie_samples > 0) {
|
|
adjusted_pts += 1; /* compensate 1 ms */
|
|
adec->ie_samples -= (td_s32)pkt->out_sample_rate;
|
|
} else if (cur_frame_pts >= 1) { /* >=1 for non negative */
|
|
adjusted_pts -= 1; /* compensate 1 ms */
|
|
adec->ie_samples += (td_s32)pkt->out_sample_rate;
|
|
}
|
|
}
|
|
|
|
if (adjusted_pts != cur_frame_pts) {
|
|
soc_log_dbg("adjust frame[%u] pts(%u->%u),samples*1000(ie=%u,frm=%u,frametimeToSamples=%u),rate=%u\n",
|
|
adec->dfx.out_frame_num, cur_frame_pts, adjusted_pts, adec->ie_samples, actual_samples, frame_time_samples,
|
|
pkt->out_sample_rate);
|
|
}
|
|
|
|
return adjusted_pts;
|
|
}
|
|
|
|
/* convert decoder out packet adec out buffer */
|
|
static td_void adec_out_pkt_to_out_buf(adec_chan *adec, adec_in_packet *in_pkt, adec_out_packet *out_pkt)
|
|
{
|
|
td_u32 pts;
|
|
td_u32 adjusted_pts;
|
|
td_u32 frame_time = adec_out_packet_get_frame_time(&out_pkt->pkt);
|
|
adec_pts_find_info find_pts_info;
|
|
memset_s(&find_pts_info, sizeof(find_pts_info), 0, sizeof(adec_pts_find_info));
|
|
|
|
find_pts_info.pts_que = &adec->pts_que;
|
|
find_pts_info.read_pos = in_pkt->read_pos;
|
|
find_pts_info.frame_time = frame_time;
|
|
pts = adec_find_pts(&find_pts_info);
|
|
out_pkt->out_buf->org_pts = find_pts_info.out_org_pts;
|
|
adjusted_pts = adec_adjust_pts_by_ie(adec, &out_pkt->pkt, find_pts_info.out_pts_interpolated, pts, frame_time);
|
|
if (adjusted_pts != pts) {
|
|
pts = adjusted_pts;
|
|
adec->pts_que.last_pts_ms = adjusted_pts;
|
|
}
|
|
if (pts == ADEC_INVALID_PTS) {
|
|
td_u32 end_pos = 0;
|
|
adec_chan_input_buf *in_buf = &adec->in_stream_buf;
|
|
|
|
end_pos += in_pkt->total_input_size - in_pkt->total_output_size;
|
|
if (end_pos > in_buf->boundary) {
|
|
end_pos -= in_buf->boundary;
|
|
}
|
|
|
|
/*
|
|
* 1. begin_pos pts is -1
|
|
* 2. begin_pos ~ end_pos cover a valid pts
|
|
* then report the next valid pts
|
|
*/
|
|
pts = adec_find_fix_pts(&adec->pts_que, in_pkt->read_pos, frame_time, &out_pkt->out_buf->org_pts);
|
|
}
|
|
|
|
/* pts fix: if the decoder output delay exist */
|
|
/* the output pts should minus it */
|
|
if ((pts < adec->output_delay) || (pts == ADEC_INVALID_PTS)) {
|
|
out_pkt->out_buf->pts = ADEC_INVALID_PTS;
|
|
} else {
|
|
out_pkt->out_buf->pts = pts - adec->output_delay;
|
|
}
|
|
|
|
out_pkt->out_buf->pcm_out_samples_per_frame = out_pkt->pkt.pcm_out_samples;
|
|
out_pkt->out_buf->bits_out_bytes_per_frame = out_pkt->pkt.bits_out_bytes;
|
|
out_pkt->out_buf->md_and_obj_out_bytes_per_frame = out_pkt->pkt.md_and_obj_out_bytes;
|
|
out_pkt->out_buf->out_channels = out_pkt->pkt.out_channels;
|
|
out_pkt->out_buf->out_sample_rate = out_pkt->pkt.out_sample_rate;
|
|
out_pkt->out_buf->interleaved = out_pkt->pkt.interleaved;
|
|
out_pkt->out_buf->bit_per_sample = out_pkt->pkt.bit_per_sample;
|
|
out_pkt->out_buf->pcm_out_buf = out_pkt->pkt.pcm_out_buf;
|
|
out_pkt->out_buf->bits_out_buf = out_pkt->pkt.bits_out_buf;
|
|
out_pkt->out_buf->md_and_obj_out_buf = out_pkt->pkt.md_and_obj_out_buf;
|
|
adec_chan_dfx_check_pts(adec, in_pkt, out_pkt, &find_pts_info);
|
|
adec_out_packet_process_volume(adec, &out_pkt->pkt);
|
|
soc_log_info("adec%02u in_pkt(org_pts=%u,pos=%u,size=%u,consumed=%u), "
|
|
"out_pkt(pts=%u,samples=%u,rate=%u), codec_delay=%u, err_frames=%u\n",
|
|
adec->ch_id, find_pts_info.out_org_pts, in_pkt->read_pos, in_pkt->input_size, in_pkt->consume_size,
|
|
out_pkt->out_buf->pts, out_pkt->pkt.pcm_out_samples, out_pkt->pkt.out_sample_rate, adec->output_delay,
|
|
adec->adec_info->err_frame_num);
|
|
}
|
|
|
|
/* convert adec out buffer to decoder out packet */
|
|
static td_void adec_out_buf_to_out_pkt(adec_chan *adec, adec_out_packet *out_pkt)
|
|
{
|
|
td_u32 size;
|
|
|
|
/* setup pcm out buffer */
|
|
size = adec_get_max_pcm_out_size(adec->dec_attr.codec_dev, adec->dec_attr.decoder);
|
|
out_pkt->pkt.pcm_out_buf = (td_s32 *)(out_pkt->out_buf->buf);
|
|
out_pkt->pkt.pcm_out_buf_size = size;
|
|
|
|
/* setup bits out buffer */
|
|
size = adec_get_max_bits_out_size(adec->dec_attr.codec_dev, adec->dec_attr.decoder);
|
|
out_pkt->pkt.bits_out_buf = (td_s32 *)(out_pkt->out_buf->buf + out_pkt->pkt.pcm_out_buf_size);
|
|
out_pkt->pkt.bits_out_buf_size = size;
|
|
|
|
/* setup md and obj out buffer */
|
|
size = adec_get_max_pcm_out_size(adec->dec_attr.codec_dev, adec->dec_attr.decoder);
|
|
out_pkt->pkt.md_and_obj_out_buf = (td_s32 *)(out_pkt->out_buf->buf +
|
|
out_pkt->pkt.bits_out_buf_size + out_pkt->pkt.pcm_out_buf_size);
|
|
out_pkt->pkt.md_and_obj_out_buf_size = size;
|
|
}
|
|
|
|
static td_void adec_decode_get_out_pkt(adec_chan *adec, adec_out_packet *out_pkt)
|
|
{
|
|
out_pkt->out_buf = adec_get_out_buf(&adec->out_stream_buf);
|
|
if (out_pkt->out_buf == TD_NULL) {
|
|
out_pkt->ready = TD_FALSE;
|
|
return;
|
|
}
|
|
adec_out_buf_to_out_pkt(adec, out_pkt);
|
|
out_pkt->ready = TD_TRUE;
|
|
}
|
|
|
|
static td_void adec_decode_process_again(adec_chan *adec, adec_in_packet *in_pkt, adec_out_packet *out_pkt)
|
|
{
|
|
if ((in_pkt->consume_size == 0) && (in_pkt->pkt.size != 0)) {
|
|
adec->not_consume_byte_cnt++;
|
|
if (adec->packet_decoder == TD_TRUE) {
|
|
/* can't decode, packet audio error */
|
|
soc_log_warn("FMT_PACKET discard crrupt packet bytes(%d)!\n", in_pkt->pkt.size);
|
|
in_pkt->consume_size = (td_u32)in_pkt->pkt.size;
|
|
}
|
|
} else {
|
|
adec->not_consume_byte_cnt = 0;
|
|
}
|
|
|
|
/* about 1s time & can not decode one frame, notify unsupport format */
|
|
if ((adec->not_consume_byte_cnt >= ADEC_MAX_UNCONSUMEBYTECNT) &&
|
|
(adec->adec_info->framn_nm == 0) && (adec->adec_info->report_eos == TD_FALSE)) {
|
|
/* discard bytes */
|
|
in_pkt->consume_size = min2(in_pkt->pkt.size, ADEC_BYTES_DISCARD_THD);
|
|
adec->adec_info->codec_unsupport_num++;
|
|
adec_event_report(&adec->event, EXT_ADEC_EVENT_UNSUPPORT_STREAM, TD_NULL, 0);
|
|
adec_chan_dfx_check_report_frame_err(adec, EXT_ADEC_EVENT_UNSUPPORT_STREAM);
|
|
}
|
|
|
|
adec->sw_decoder_bytes_left = out_pkt->pkt.pts_info.un_pts.sw_decoder_bytes_left;
|
|
|
|
adec_update_input_buf(adec, in_pkt->consume_size);
|
|
if (adec_is_pts_full(&adec->pts_que) == TD_TRUE) {
|
|
adec_discard_pts(&adec->pts_que, in_pkt->read_pos);
|
|
}
|
|
|
|
/* use for check whether end of decode the input buffer */
|
|
adec_report_event_eos(adec);
|
|
}
|
|
|
|
static td_void adec_decode_process_success(adec_chan *adec, adec_in_packet *in_pkt, adec_out_packet *out_pkt)
|
|
{
|
|
/* when decode audio frame success, clear not_enough_buf_cnt */
|
|
adec->adec_info->not_enough_buf_cnt = 0;
|
|
adec->not_consume_byte_cnt = 0;
|
|
|
|
if ((out_pkt->pkt.out_sample_rate == 0) ||
|
|
(out_pkt->pkt.out_sample_rate > EXT_SAMPLE_RATE_192K)) {
|
|
soc_log_warn("invalid sample_rate(%d)! \n", out_pkt->pkt.out_sample_rate);
|
|
adec_update_input_buf(adec, in_pkt->consume_size);
|
|
return;
|
|
}
|
|
|
|
adec->sw_decoder_bytes_left = out_pkt->pkt.pts_info.un_pts.sw_decoder_bytes_left;
|
|
in_pkt->total_output_size = in_pkt->pkt.size + adec->sw_decoder_bytes_left;
|
|
|
|
adec_get_codec_output_delay(adec);
|
|
adec_out_pkt_to_out_buf(adec, in_pkt, out_pkt);
|
|
|
|
/* move the tail of output buffer */
|
|
adec_update_input_buf(adec, in_pkt->consume_size);
|
|
adec->mid_state.continue_err_num = 0;
|
|
adec->adec_info->framn_nm++;
|
|
adec->adec_info->sample_rate = (ext_sample_rate)out_pkt->pkt.out_sample_rate;
|
|
adec->adec_info->bit_width = (ext_bit_depth)out_pkt->pkt.bit_per_sample;
|
|
adec->adec_info->out_channels = out_pkt->pkt.out_channels;
|
|
adec->adec_info->org_channels = out_pkt->pkt.org_channels;
|
|
adec->adec_info->pcm_samples_per_frame = adec_pcm_samples(out_pkt->pkt.pcm_out_samples);
|
|
adec->adec_info->bit_rate = out_pkt->pkt.bit_rate;
|
|
adec->dfx.out_frame_num++;
|
|
|
|
adec_update_out_buf(adec);
|
|
adec_update_frame_info(adec);
|
|
adec_event_report(&adec->event, EXT_ADEC_EVENT_NEW_FRAME, TD_NULL, 0);
|
|
if ((adec->dfx.passthrough_only != TD_TRUE) &&
|
|
(adec->dfx.acquire_start_time != 0)) {
|
|
fc_ud_generate_data(&adec->dfx.ud_output, out_pkt->pkt.pcm_out_samples);
|
|
}
|
|
|
|
if ((adec->report_decode_event == TD_FALSE) && (adec->codec_id != UAPI_ACODEC_ID_PASSTHROUGH)) {
|
|
adec_event_report(&adec->event, EXT_ADEC_EVENT_FIRST_DECODE_FRAME,
|
|
(td_u8 *)&adec->codec_id, sizeof(adec->codec_id));
|
|
adec->report_decode_event = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
static td_void adec_decode_process_fail(adec_chan *adec, adec_in_packet *in_pkt, const adec_out_packet *out_pkt)
|
|
{
|
|
/* when decode audio frame failure, clear not_enough_buf_cnt */
|
|
adec->adec_info->not_enough_buf_cnt = 0;
|
|
adec->not_consume_byte_cnt = 0;
|
|
|
|
if (in_pkt->consume_size == 0) {
|
|
/* decode holding, discard bytes */
|
|
in_pkt->consume_size = min2(in_pkt->pkt.size, ADEC_BYTES_DISCARD_THD);
|
|
}
|
|
|
|
adec->adec_info->err_frame_num++;
|
|
adec->sw_decoder_bytes_left = out_pkt->pkt.pts_info.un_pts.sw_decoder_bytes_left;
|
|
|
|
adec_update_input_buf(adec, in_pkt->consume_size);
|
|
if (adec_is_pts_full(&adec->pts_que) == TD_TRUE) {
|
|
adec_discard_pts(&adec->pts_que, in_pkt->read_pos);
|
|
}
|
|
}
|
|
|
|
static td_void adec_decode_report_errno(adec_chan *adec, td_s32 error)
|
|
{
|
|
if (error == SOC_ERR_ADEC_NOT_SUPPORT) {
|
|
adec->adec_info->codec_unsupport_num++;
|
|
adec_event_report(&adec->event, EXT_ADEC_EVENT_UNSUPPORT_STREAM, TD_NULL, 0);
|
|
} else if (error == SOC_ERR_ADEC_STREAM_CORRUPT) {
|
|
adec->adec_info->stream_corrupt_num++;
|
|
adec_event_report(&adec->event, EXT_ADEC_EVENT_ERROR_FRAME, TD_NULL, 0);
|
|
}
|
|
adec_chan_dfx_check_report_frame_err(adec, error);
|
|
}
|
|
|
|
static td_void adec_decode_prepare(adec_chan *adec, adec_in_packet *in_pkt, adec_out_packet *out_pkt)
|
|
{
|
|
adec_decode_get_in_pkt(adec, in_pkt);
|
|
adec_decode_get_out_pkt(adec, out_pkt);
|
|
}
|
|
|
|
static td_void adec_decode_finish(adec_chan *adec, adec_in_packet *in_pkt)
|
|
{
|
|
if (in_pkt->pkt.size < 0) {
|
|
soc_log_err("decoder abnormal\n");
|
|
return;
|
|
}
|
|
|
|
if (in_pkt->pkt.size > (td_s32)in_pkt->input_size) {
|
|
soc_log_err("input pkt size before decode: 0x%x\n", in_pkt->input_size);
|
|
soc_log_err("input pkt size after decode: 0x%x\n", in_pkt->pkt.size);
|
|
in_pkt->consume_size = 0;
|
|
} else {
|
|
in_pkt->consume_size = in_pkt->input_size - in_pkt->pkt.size;
|
|
}
|
|
|
|
/* for adec_check_scrambler */
|
|
adec->bs_consume_bytes += (td_s32)in_pkt->consume_size;
|
|
}
|
|
|
|
static td_void adec_codec_check_schedule_start(adec_proc_item *adec_proc)
|
|
{
|
|
adec_proc->codec_begin_time = adec_get_time_stamp();
|
|
|
|
if (adec_proc->codec_end_time == 0) {
|
|
return;
|
|
}
|
|
|
|
if (adec_proc->codec_begin_time - adec_proc->codec_end_time > ADEC_SCHE_THREADTIME_LIMIT) {
|
|
adec_proc->codec_sched_time_out_cnt++;
|
|
}
|
|
}
|
|
|
|
static td_void adec_codec_check_schedule_stop(adec_proc_item *adec_proc)
|
|
{
|
|
adec_proc->codec_end_time = adec_get_time_stamp();
|
|
if (adec_proc->codec_end_time - adec_proc->codec_begin_time > ADEC_EXE_THREADTIME_LIMIT) {
|
|
adec_proc->codec_exe_time_out_cnt++;
|
|
}
|
|
}
|
|
|
|
static td_void adec_sw_decode(adec_chan *adec)
|
|
{
|
|
td_s32 ret;
|
|
adec_in_packet in_pkt;
|
|
adec_out_packet out_pkt;
|
|
|
|
memset_s(&in_pkt, sizeof(adec_in_packet), 0, sizeof(adec_in_packet));
|
|
memset_s(&out_pkt, sizeof(adec_out_packet), 0, sizeof(adec_out_packet));
|
|
|
|
adec_io_lock(adec->ch_id);
|
|
adec->adec_info->dbg_decode_entry_count++;
|
|
while (1) {
|
|
adec_chan_dfx_check_eos_missed(adec);
|
|
adec_decode_prepare(adec, &in_pkt, &out_pkt);
|
|
if ((in_pkt.ready == TD_FALSE) || (out_pkt.ready == TD_FALSE)) {
|
|
break;
|
|
}
|
|
adec->adec_info->dbg_try_decode_count++;
|
|
|
|
adec_io_unlock(adec->ch_id);
|
|
adec_codec_check_schedule_start(adec->adec_info);
|
|
ret = adec_decode_frame(adec->dec_attr.codec_dev, adec->dec_attr.decoder,
|
|
&in_pkt.pkt, &out_pkt.pkt);
|
|
adec_codec_check_schedule_stop(adec->adec_info);
|
|
adec_io_lock(adec->ch_id);
|
|
adec_decode_finish(adec, &in_pkt);
|
|
if ((ret == TD_SUCCESS) || (ret == HA_ERR_NONE)) {
|
|
/* decoder output one frame success */
|
|
adec_decode_process_success(adec, &in_pkt, &out_pkt);
|
|
continue;
|
|
} else if ((ret == SOC_ERR_ADEC_NOT_ENOUGH_DATA) || (ret == HA_ERR_NOT_ENOUGH_DATA)) {
|
|
/* not enough input data, try again later */
|
|
adec_decode_process_again(adec, &in_pkt, &out_pkt);
|
|
break;
|
|
} else {
|
|
/* decoder report other error */
|
|
adec_decode_process_fail(adec, &in_pkt, &out_pkt);
|
|
adec_decode_report_errno(adec, ret);
|
|
break;
|
|
}
|
|
}
|
|
if ((adec->dfx.passthrough_only != TD_TRUE) &&
|
|
(adec->dfx.acquire_start_time != 0)) {
|
|
fc_ud_scheduled(&adec->dfx.ud_output);
|
|
}
|
|
adec_io_unlock(adec->ch_id);
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /* __cplusplus */
|