| /* |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| * * Description: |
| * adpcm decoder |
| */ |
| #define LOG_TAG "AdpcmDecoder" |
| |
| #include <stdio.h> |
| #include <stdint.h> |
| //#include <syslog.h> |
| #include "adpcm.h" |
| #include "adec-armdec-mgt.h" |
| #include <sys/time.h> |
| #include <stdint.h> |
| #include <string.h> |
| //#include <android/log.h> |
| #include <cutils/log.h> |
| #include <cutils/properties.h> |
| |
| #define LOG_TAG "AdpcmDecoder" |
| //#define PRINTF(...) //__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) |
| #define PRINTF( ...) //syslog(LOG_ERR, ##__VA_ARGS__) |
| |
| |
| typedef struct { |
| int ValidDataLen; |
| int UsedDataLen; |
| unsigned char *BufStart; |
| unsigned char *pcur; |
| } pcm_read_ctl_t; |
| |
| |
| static int pcm_read_init(pcm_read_ctl_t *pcm_read_ctx, unsigned char* inbuf, int size) |
| { |
| pcm_read_ctx->ValidDataLen = size; |
| pcm_read_ctx->UsedDataLen = 0; |
| pcm_read_ctx->BufStart = inbuf; |
| pcm_read_ctx->pcur = inbuf; |
| return 0; |
| } |
| |
| static int pcm_read(pcm_read_ctl_t *pcm_read_ctx, unsigned char* outbuf, int size) |
| { |
| int bytes_read = 0; |
| if (size <= pcm_read_ctx->ValidDataLen) { |
| memcpy(outbuf, pcm_read_ctx->pcur, size); |
| pcm_read_ctx->ValidDataLen -= size; |
| pcm_read_ctx->UsedDataLen += size; |
| pcm_read_ctx->pcur += size; |
| bytes_read = size; |
| } |
| return bytes_read; |
| } |
| |
| struct t_wave_buf { |
| void *addr; |
| unsigned size; |
| }; |
| static unsigned wave_timestamplen = 0; |
| static unsigned wave_timestamp = 0; |
| |
| static int adpcm_step[89] = { |
| 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, |
| 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, |
| 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, |
| 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, |
| 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, |
| 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, |
| 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, |
| 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, |
| 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 |
| }; |
| |
| static int adpcm_index[16] = { |
| -1, -1, -1, -1, 2, 4, 6, 8, |
| -1, -1, -1, -1, 2, 4, 6, 8 |
| }; |
| |
| // useful macros |
| // clamp a number between 0 and 88 |
| #define CLAMP_0_TO_88(x) if ((x) < 0) (x) = 0; else if ((x) > 88) (x) = 88; |
| #define CLAMP_0_TO_88_2(x) if ((x) < 0) return 0; else if ((x) > 88) return 88; return (x); |
| |
| // clamp a number within a signed 16-bit range |
| #define CLAMP_S16(x) if (x < -32768) x = -32768; \ |
| else if (x > 32767) x = 32767; |
| #define CLAMP_S16_2(x) if ((x) < -32768) return -32768; \ |
| else if ((x) > 32767) return 32767; \ |
| return (x); |
| // clamp a number above 16 |
| #define CLAMP_ABOVE_16(x) if (x < 16) x = 16; |
| // sign extend a 16-bit value |
| #define SE_16BIT(x) if (x & 0x8000) x -= 0x10000; |
| // sign extend a 4-bit value |
| #define SE_4BIT(x) if (x & 0x8) x -= 0x10; |
| static t_adpcm_output_buf_manager g_mgr; |
| static int block_align = 0; |
| static int offset = 0; |
| //extern unsigned char buffer[1024*64]; |
| static unsigned char *pwavebuf = NULL; |
| static struct t_wave_buf wave_decoder_buffer[] = {{0, 0}, {0, 0}}; // 0 - stream, 1 - pcm |
| |
| #define CHECK_DATA_ENOUGH_SUB(Ctl,NeedBytes,UsedSetIfNo) { \ |
| if ((Ctl)->ValidDataLen < (NeedBytes)) { \ |
| PRINTF("[%s %d]NOTE--> no enough data\n",__FUNCTION__,__LINE__);\ |
| (Ctl)->UsedDataLen-=(UsedSetIfNo); \ |
| return -1; \ |
| } \ |
| } |
| |
| #define CHECK_DATA_ENOUGH_SET(Ctl,NeedBytes,UsedSetIfNo) { \ |
| if ((Ctl)->ValidDataLen < (NeedBytes)) { \ |
| PRINTF("[%s %d]NOTE--> no enough data\n",__FUNCTION__,__LINE__);\ |
| (Ctl)->UsedDataLen=(UsedSetIfNo); \ |
| return -1; \ |
| } \ |
| } |
| |
| static int refill(audio_decoder_operations_t *adec_ops, pcm_read_ctl_t *pcm_read_ctx, unsigned char* buf, int len) |
| { |
| static unsigned refill_timestamp_len = 0; |
| unsigned char *pbuf = buf; |
| unsigned char tmp_a = 0; |
| unsigned char tmp_p = 0; |
| unsigned char tmp_t = 0; |
| unsigned char tmp_s = 0; |
| int len_bak = len; |
| int tmp = 0; |
| if (wave_timestamplen == 0) { // when no apts found |
| unsigned char timestamp[4] = {0}; |
| unsigned char block_length[4] = {0}; |
| |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, 4, 0) |
| pcm_read(pcm_read_ctx, &tmp_a, 1); |
| pcm_read(pcm_read_ctx, &tmp_p, 1); |
| pcm_read(pcm_read_ctx, &tmp_t, 1); |
| pcm_read(pcm_read_ctx, &tmp_s, 1); |
| |
| if (tmp_a == 'A' && tmp_p == 'P' && tmp_t == 'T' && tmp_s == 'S') { |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, 8, 0) |
| pcm_read(pcm_read_ctx, timestamp, 4); |
| wave_timestamp = (timestamp[0] << 24) | (timestamp[1] << 16) | (timestamp[2] << 8) | (timestamp[3]); |
| pcm_read(pcm_read_ctx, block_length, 4); |
| wave_timestamplen = (block_length[0] << 24) | (block_length[1] << 16) | (block_length[2] << 8) | (block_length[3]); |
| refill_timestamp_len = wave_timestamplen; |
| |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, refill_timestamp_len, 0) |
| |
| } else if (tmp_a == 'R' && tmp_p == 'I' && tmp_t == 'F' && tmp_s == 'F') { |
| if ((adec_ops->nAudioDecoderType == CODEC_ID_ADPCM_IMA_WAV) || (adec_ops->nAudioDecoderType == CODEC_ID_ADPCM_MS)) { |
| tmp = len; |
| while (tmp) { |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, 8, 0) |
| pcm_read(pcm_read_ctx, ×tamp[0], 1); |
| tmp --; |
| if (timestamp[0] == 'd') { |
| pcm_read(pcm_read_ctx, ×tamp[1], 3); |
| tmp -= 3; |
| if ((timestamp[0] == 'd') && (timestamp[1] == 'a') && (timestamp[2] == 't') && (timestamp[3] == 'a')) { |
| break; |
| } |
| } |
| } |
| pcm_read(pcm_read_ctx, timestamp, 4); |
| wave_timestamplen = 0; |
| wave_timestamp = 0xffffffff; |
| |
| CHECK_DATA_ENOUGH_SUB(pcm_read_ctx, len, 0) |
| } else { |
| *pbuf++ = tmp_a; |
| *pbuf++ = tmp_p; |
| *pbuf++ = tmp_t; |
| *pbuf++ = tmp_s; |
| len -= 4; |
| wave_timestamplen = 0; |
| wave_timestamp = 0xffffffff; |
| |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, len, 0) |
| } |
| } else { |
| *pbuf++ = tmp_a; |
| *pbuf++ = tmp_p; |
| *pbuf++ = tmp_t; |
| *pbuf++ = tmp_s; |
| len -= 4; |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, len, 0) |
| wave_timestamplen = 0; |
| wave_timestamp = 0xffffffff; |
| } |
| } |
| |
| if (wave_timestamplen) { |
| pcm_read(pcm_read_ctx, pbuf, refill_timestamp_len); |
| return refill_timestamp_len; |
| } else { |
| pcm_read(pcm_read_ctx, pbuf, len); |
| return len_bak; |
| } |
| |
| } |
| |
| /*IMA ADPCM*/ |
| #define le2me_16(x) (x) |
| #define MS_IMA_ADPCM_PREAMBLE_SIZE 4 |
| #define LE_16(x) (le2me_16(*(unsigned short *)(x))) |
| |
| static void decode_nibbles(unsigned short *output, |
| int output_size, int channels, |
| int predictor_l, int index_l, |
| int predictor_r, int index_r) |
| { |
| int step[2]; |
| int predictor[2]; |
| int index[2]; |
| int diff; |
| int i; |
| int sign; |
| int delta; |
| int channel_number = 0; |
| |
| step[0] = adpcm_step[index_l]; |
| step[1] = adpcm_step[index_r]; |
| predictor[0] = predictor_l; |
| predictor[1] = predictor_r; |
| index[0] = index_l; |
| index[1] = index_r; |
| |
| for (i = 0; i < output_size; i++) { |
| delta = output[i]; |
| |
| index[channel_number] += adpcm_index[delta]; |
| CLAMP_0_TO_88(index[channel_number]); |
| |
| sign = delta & 8; |
| delta = delta & 7; |
| |
| diff = step[channel_number] >> 3; |
| if (delta & 4) { |
| diff += step[channel_number]; |
| } |
| if (delta & 2) { |
| diff += step[channel_number] >> 1; |
| } |
| if (delta & 1) { |
| diff += step[channel_number] >> 2; |
| } |
| |
| if (sign) { |
| predictor[channel_number] -= diff; |
| } else { |
| predictor[channel_number] += diff; |
| } |
| |
| CLAMP_S16(predictor[channel_number]); |
| output[i] = predictor[channel_number]; |
| step[channel_number] = adpcm_step[index[channel_number]]; |
| |
| // toggle channel |
| channel_number ^= channels - 1; |
| |
| } |
| } |
| |
| static int ima_adpcm_decode_block(unsigned short *output, |
| unsigned char *input, int channels, int block_size) |
| { |
| int predictor_l = 0; |
| int predictor_r = 0; |
| int index_l = 0; |
| int index_r = 0; |
| int i; |
| int channel_counter; |
| int channel_index; |
| int channel_index_l; |
| int channel_index_r; |
| |
| predictor_l = LE_16(&input[0]); |
| SE_16BIT(predictor_l); |
| index_l = input[2]; |
| if (channels == 2) { |
| predictor_r = LE_16(&input[4]); |
| SE_16BIT(predictor_r); |
| index_r = input[6]; |
| } |
| |
| if (channels == 1) |
| for (i = 0; i < (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels); i++) { |
| output[i * 2 + 0] = input[MS_IMA_ADPCM_PREAMBLE_SIZE + i] & 0x0F; |
| output[i * 2 + 1] = input[MS_IMA_ADPCM_PREAMBLE_SIZE + i] >> 4; |
| } |
| else { |
| // encoded as 8 nibbles (4 bytes) per channel; switch channel every |
| // 4th byte |
| channel_counter = 0; |
| channel_index_l = 0; |
| channel_index_r = 1; |
| channel_index = channel_index_l; |
| for (i = 0; |
| i < (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels); i++) { |
| output[channel_index + 0] = |
| input[MS_IMA_ADPCM_PREAMBLE_SIZE * 2 + i] & 0x0F; |
| output[channel_index + 2] = |
| input[MS_IMA_ADPCM_PREAMBLE_SIZE * 2 + i] >> 4; |
| channel_index += 4; |
| channel_counter++; |
| if (channel_counter == 4) { |
| channel_index_l = channel_index; |
| channel_index = channel_index_r; |
| } else if (channel_counter == 8) { |
| channel_index_r = channel_index; |
| channel_index = channel_index_l; |
| channel_counter = 0; |
| } |
| } |
| } |
| |
| decode_nibbles(output, |
| (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2, |
| channels, |
| predictor_l, index_l, |
| predictor_r, index_r); |
| |
| return (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2; |
| } |
| #define MSADPCM_ADAPT_COEFF_COUNT 7 |
| static int AdaptationTable [] = { |
| 230, 230, 230, 230, 307, 409, 512, 614, |
| 768, 614, 512, 409, 307, 230, 230, 230 |
| } ; |
| |
| /* TODO : The first 7 coef's are are always hardcode and must |
| appear in the actual WAVE file. They should be read in |
| in case a sound program added extras to the list. */ |
| |
| static int AdaptCoeff1 [MSADPCM_ADAPT_COEFF_COUNT] = { |
| 256, 512, 0, 192, 240, 460, 392 |
| } ; |
| |
| static int AdaptCoeff2 [MSADPCM_ADAPT_COEFF_COUNT] = { |
| 0, -256, 0, 64, 0, -208, -232 |
| } ; |
| |
| static int ms_adpcm_decode_block(short *pcm_buf, unsigned char *buf, int channel, int block) |
| { |
| int sampleblk = 2036; |
| short bpred[2]; |
| short idelta[2]; |
| int blockindx = 0; |
| int sampleindx = 0; |
| short bytecode = 0; |
| int predict = 0; |
| int current = 0; |
| int delta = 0; |
| int i = 0; |
| int j = 0; |
| short s0 = 0; |
| short s1 = 0; |
| short s2 = 0; |
| short s3 = 0; |
| short s4 = 0; |
| short s5 = 0; |
| |
| //sampleblk = sample_block; |
| j = 0; |
| if (channel == 1) { |
| bpred[0] = buf[0]; |
| bpred[1] = 0; |
| if (bpred[0] >= 7) { |
| //printf("sync error\n"); |
| //goto _exit; |
| } |
| idelta[0] = buf[1] | buf[2] << 8; |
| idelta[1] = 0; |
| |
| s1 = buf[3] | buf[4] << 8; |
| s0 = buf[5] | buf[6] << 8; |
| |
| blockindx = 7; |
| sampleindx = 2; |
| } else if (channel == 2) { |
| bpred[0] = buf[0]; |
| bpred[1] = buf[1]; |
| if (bpred[0] >= 7 || bpred[1] >= 7) { |
| //printf("sync error\n"); |
| //goto _exit; |
| } |
| idelta[0] = buf[2] | buf[3] << 8; |
| idelta[1] = buf[4] | buf[5] << 8; |
| |
| s2 = buf[6] | buf[7] << 8; |
| s3 = buf[8] | buf[9] << 8; |
| s0 = buf[10] | buf[11] << 8; |
| s1 = buf[12] | buf[13] << 8; |
| blockindx = 14; |
| sampleindx = 4; |
| } |
| |
| /*-------------------------------------------------------- |
| This was left over from a time when calculations were done |
| as ints rather than shorts. Keep this around as a reminder |
| in case I ever find a file which decodes incorrectly. |
| |
| if (chan_idelta [0] & 0x8000) |
| chan_idelta [0] -= 0x10000 ; |
| if (chan_idelta [1] & 0x8000) |
| chan_idelta [1] -= 0x10000 ; |
| --------------------------------------------------------*/ |
| |
| /* Pull apart the packed 4 bit samples and store them in their |
| ** correct sample positions. |
| */ |
| |
| /* Decode the encoded 4 bit samples. */ |
| int chan; |
| |
| for (i = channel * 2;/*i<channel*sampleblk&&*/(blockindx < block); i++) { |
| if (sampleindx <= i) { |
| if (blockindx < block) { |
| bytecode = buf[blockindx++]; |
| |
| |
| if (channel == 1) { |
| s2 = (bytecode >> 4) & 0x0f; |
| s3 = bytecode & 0x0f; |
| } else if (channel == 2) { |
| s4 = (bytecode >> 4) & 0x0f; |
| s5 = bytecode & 0x0f; |
| } |
| sampleindx++; |
| sampleindx++; |
| |
| } |
| } |
| chan = (channel > 1) ? (i % 2) : 0; |
| |
| if (channel == 1) { |
| bytecode = s2 & 0x0f; |
| } else if (channel == 2) { |
| bytecode = s4 & 0x0f; |
| } |
| /* Compute next Adaptive Scale Factor (ASF) */ |
| delta = idelta[chan]; |
| |
| /* => / 256 => FIXED_POINT_ADAPTATION_BASE == 256 */ |
| idelta[chan] = (AdaptationTable[bytecode] * delta) >> 8; |
| |
| if (idelta[chan] < 16) { |
| idelta[chan] = 16; |
| } |
| if (bytecode & 0x8) { |
| bytecode -= 0x10; |
| } |
| /* => / 256 => FIXED_POINT_COEFF_BASE == 256 */ |
| |
| if (channel == 1) { |
| predict = s1 * AdaptCoeff1[bpred[chan]]; |
| predict += s0 * AdaptCoeff2[bpred[chan]]; |
| } else if (channel == 2) { |
| predict = s2 * AdaptCoeff1[bpred[chan]]; |
| predict += s0 * AdaptCoeff2[bpred[chan]]; |
| } |
| |
| predict >>= 8; |
| current = bytecode * delta + predict; |
| #if 1 |
| if (current > 32767) { |
| current = 32767 ; |
| } else if (current < -32768) { |
| current = -32768 ; |
| } |
| #else |
| current = _min(current, 32767); |
| current = _max(current, -32768); |
| #endif |
| if (channel == 1) { |
| s2 = current; |
| } else if (channel == 2) { |
| s4 = current; |
| } |
| |
| pcm_buf[j++] = s0; |
| |
| if (channel == 1) { |
| s0 = s1; |
| s1 = s2; |
| s2 = s3; |
| } else if (channel == 2) { |
| s0 = s1; |
| s1 = s2; |
| s2 = s3; |
| s3 = s4; |
| s4 = s5; |
| } |
| } |
| |
| if (channel == 1) { |
| pcm_buf[j++] = s0; |
| pcm_buf[j++] = s1; |
| } else if (channel == 2) { |
| pcm_buf[j++] = s0; |
| pcm_buf[j++] = s1; |
| pcm_buf[j++] = s2; |
| pcm_buf[j++] = s3; |
| } |
| |
| return j; |
| } |
| |
| static void dump_data(void *buffer, int size, char *file_name) |
| { |
| int flen = 0; |
| |
| if (property_get_bool("vendor.media.adec.adpcm", 0)) { |
| FILE *fp = fopen(file_name, "a+"); |
| if (fp) { |
| flen = fwrite((char *)buffer, 1, size, fp); |
| ALOGV("%s[%d]: buffer=%p, need dump data size=%d, actual dump size=%d\n", __FUNCTION__, __LINE__, buffer, size, flen); |
| fclose(fp); |
| } |
| } |
| } |
| |
| /* |
| * u-law, A-law and linear PCM conversions. |
| */ |
| |
| #define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ |
| #define QUANT_MASK (0xf) /* Quantization field mask. */ |
| #define NSEGS (8) /* Number of A-law segments. */ |
| #define SEG_SHIFT (4) /* Left shift for segment number. */ |
| #define SEG_MASK (0x70) /* Segment field mask. */ |
| //static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; |
| #define BIAS (0x84) /* Bias for linear code. */ |
| |
| /* |
| * alaw2linear() - Convert an A-law value to 16-bit linear PCM |
| * |
| */ |
| int alaw2linear(unsigned char a_val) |
| { |
| int t; |
| int seg; |
| a_val ^= 0x55; |
| t = (a_val & QUANT_MASK) << 4; |
| seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; |
| switch (seg) { |
| case 0: |
| t += 8; |
| break; |
| case 1: |
| t += 0x108; |
| break; |
| default: |
| t += 0x108; |
| t <<= seg - 1; |
| } |
| return ((a_val & SIGN_BIT) ? t : -t); |
| } |
| /* |
| * ulaw2linear() - Convert a u-law value to 16-bit linear PCM |
| * |
| * First, a biased linear code is derived from the code word. An unbiased |
| * output can then be obtained by subtracting 33 from the biased code. |
| * |
| * Note that this function expects to be passed the complement of the |
| * original code word. This is in keeping with ISDN conventions. |
| */ |
| int ulaw2linear(unsigned char u_val) |
| { |
| int t; |
| /* Complement to obtain normal u-law value. */ |
| u_val = ~u_val; |
| /* |
| * Extract and bias the quantization bits. Then |
| * shift up by the segment number and subtract out the bias. |
| */ |
| t = ((u_val & QUANT_MASK) << 3) + BIAS; |
| t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; |
| return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); |
| } |
| |
| int runalawdecoder(audio_decoder_operations_t *adec_ops, pcm_read_ctl_t *pcm_read_ctx, unsigned char *buf, int len) |
| { |
| int i = 0; |
| int tmp = 0; |
| short *pcm_buf = (short*)wave_decoder_buffer[1].addr; |
| |
| tmp = refill(adec_ops, pcm_read_ctx, pwavebuf, WAVE_BLOCK_SIZE); |
| if (tmp < 0) { |
| return -1; |
| } |
| for (i = 0; i < tmp; i++) { |
| pcm_buf[i] = alaw2linear(pwavebuf[i]); |
| } |
| memcpy(buf, (char*)pcm_buf, 2 * WAVE_BLOCK_SIZE); |
| return (WAVE_BLOCK_SIZE) * 2; |
| } |
| int runulawdecoder(audio_decoder_operations_t *adec_ops, pcm_read_ctl_t *pcm_read_ctx, unsigned char *buf, int len) |
| { |
| int i = 0; |
| short *pcm_buf = (short*)wave_decoder_buffer[1].addr; |
| int tmp = 0; |
| |
| tmp = refill(adec_ops, pcm_read_ctx, pwavebuf, WAVE_BLOCK_SIZE); |
| if (tmp < 0) { |
| return -1; |
| } |
| for (i = 0; i < tmp; i++) { |
| pcm_buf[i] = ulaw2linear(pwavebuf[i]); |
| } |
| memcpy(buf, (char*)pcm_buf, 2 * WAVE_BLOCK_SIZE); |
| return (WAVE_BLOCK_SIZE) * 2; |
| |
| } |
| static short |
| read_sample (const char * data) |
| { |
| unsigned short val = data[0] | (data[1] << 8); |
| return *((short *) & val); |
| } |
| #define MIN(a,b) (((a) < (b)) ? (a) : (b)) |
| short Clamp(int x, int min, int max) |
| { |
| if (x > max) |
| return max; |
| if (x < min) |
| return min; |
| return x; |
| } |
| |
| int adpcmdec_decode_ima_block (int channels, int n_samples, const char * data, |
| short * samples) |
| { |
| short stepindex[2]; |
| int channel; |
| int idx; |
| int i, j; |
| int sample; |
| |
| if ((n_samples - channels) % 8 != 0) { |
| ALOGE("[%s:%d] Input not correct size", __func__, __LINE__); |
| return 0; |
| } |
| |
| for (channel = 0; channel < channels; channel++) { |
| samples[channel] = read_sample (data + channel * 4); |
| stepindex[channel] = MIN (data[channel * 4 + 2], 88); |
| |
| if (data[channel * 4 + 3] != 0) { |
| ALOGE("[%s:%d] Synchronisation error", __func__, __LINE__); |
| return 0; |
| } |
| } |
| |
| i = channels; |
| idx = 4 * channels; |
| |
| while (i < n_samples) { |
| for (channel = 0; channel < channels; channel++) { |
| sample = i + channel; |
| for (j = 0; j < 8; j++) { |
| int bytecode; |
| int step; |
| int diff; |
| |
| if (j % 2 == 0) { |
| bytecode = data[idx] & 0x0F; |
| } else { |
| bytecode = (data[idx] >> 4) & 0x0F; |
| idx++; |
| } |
| step = adpcm_step[stepindex[channel]]; |
| diff = (2 * (bytecode & 0x7) * step + step) / 8; |
| if (bytecode & 8) |
| diff = -diff; |
| |
| samples[sample] = |
| Clamp(samples[sample - channels] + diff, -32768, 32767); |
| stepindex[channel] = |
| Clamp (stepindex[channel] + adpcm_index[bytecode], 0, 88); |
| sample += channels; |
| } |
| } |
| i += 8 * channels; |
| } |
| return 1; |
| } |
| |
| int runimaadpcmdecoder(audio_decoder_operations_t *adec_ops, pcm_read_ctl_t *pcm_read_ctx, unsigned char *buf, int len) |
| { |
| short *pcm_buf = (short*)wave_decoder_buffer[1].addr; |
| int Output_Size = 0, samples; |
| int tmp = 0; |
| char buffer[5]; |
| unsigned block_size = 0; |
| int UsedDataLenSave = 0; |
| if (!block_align) { |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, 4, 0) |
| pcm_read(pcm_read_ctx, buffer, 4); |
| while (1) { |
| if ((buffer[0] == 0x11) && (buffer[1] == 0x22) && (buffer[2] == 0x33) && (buffer[3] == 0x44)) { //sync word |
| break; |
| } |
| CHECK_DATA_ENOUGH_SUB(pcm_read_ctx, 1, 3) |
| pcm_read(pcm_read_ctx, &buffer[4], 1); |
| memmove(buffer, &buffer[1], 4); |
| } |
| CHECK_DATA_ENOUGH_SUB(pcm_read_ctx, 2, 4) |
| pcm_read(pcm_read_ctx, buffer, 2); |
| |
| block_size = (buffer[0] << 8) | buffer[1]; |
| CHECK_DATA_ENOUGH_SUB(pcm_read_ctx, block_size, 6) |
| } else { |
| block_size = block_align; |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, block_size, 0) |
| } |
| |
| if (block_size < 4) { |
| PRINTF("[%s %d]imaadpcm block align not valid: %d\n", __FUNCTION__, __LINE__, block_size); |
| return 0; |
| } |
| |
| UsedDataLenSave = pcm_read_ctx->UsedDataLen; |
| tmp = refill(adec_ops, pcm_read_ctx, pwavebuf, block_size); |
| if (tmp < 0) { |
| pcm_read_ctx->UsedDataLen = UsedDataLenSave; |
| return -1; |
| } |
| |
| if (tmp != block_size) { |
| PRINTF("[%s %d]imaadpcm: data missalign\n", __FUNCTION__, __LINE__); |
| } |
| |
| //Output_Size = ima_adpcm_decode_block((unsigned short *)pcm_buf, pwavebuf, g_mgr.ch, block_size); |
| samples = (block_align - 4 * g_mgr.ch) * 2 + g_mgr.ch; |
| //dump_data(pwavebuf, block_size, "/data/adpcm_in.pcm"); |
| adpcmdec_decode_ima_block(g_mgr.ch, samples, pwavebuf, pcm_buf); |
| memcpy(buf, (char*)pcm_buf, 2 * samples); |
| //return Output_Size * 2; |
| return samples * 2; |
| } |
| |
| int runmsadpcmdecoder(audio_decoder_operations_t *adec_ops, pcm_read_ctl_t *pcm_read_ctx, unsigned char *buf, int len) |
| { |
| short *pcm_buf = (short*)wave_decoder_buffer[1].addr; |
| int Output_Size = 0; |
| unsigned tmp = 0; |
| char buffer[5]; |
| unsigned block_size = 0; |
| int UsedDataLenSave = 0; |
| if (!block_align) { |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, 4, 0) |
| pcm_read(pcm_read_ctx, buffer, 4); |
| while (1) { |
| if ((buffer[0] == 0x11) && (buffer[1] == 0x22) && (buffer[2] == 0x33) && (buffer[3] == 0x44)) { //sync word |
| break; |
| } |
| CHECK_DATA_ENOUGH_SUB(pcm_read_ctx, 1, 3) |
| pcm_read(pcm_read_ctx, &buffer[4], 1); |
| memmove(buffer, &buffer[1], 4); |
| } |
| |
| CHECK_DATA_ENOUGH_SUB(pcm_read_ctx, 2, 4) |
| pcm_read(pcm_read_ctx, buffer, 2); |
| block_size = (buffer[0] << 8) | buffer[1]; |
| CHECK_DATA_ENOUGH_SUB(pcm_read_ctx, block_size, 6) |
| } else { |
| block_size = block_align; |
| CHECK_DATA_ENOUGH_SET(pcm_read_ctx, block_size, 0) |
| } |
| |
| if (block_size < 4) { |
| PRINTF("[%s %d]msadpcm block align not valid: %d\n", __FUNCTION__, __LINE__, block_size); |
| return 0; |
| } |
| |
| UsedDataLenSave = pcm_read_ctx->UsedDataLen; |
| tmp = refill(adec_ops, pcm_read_ctx, pwavebuf, block_size); |
| if (tmp < 0) { |
| pcm_read_ctx->UsedDataLen = UsedDataLenSave; |
| return -1; |
| |
| } |
| if (tmp != block_size) { |
| PRINTF("[%s %d]msadpcm: data missalign\n", __FUNCTION__, __LINE__); |
| } |
| |
| Output_Size = ms_adpcm_decode_block(pcm_buf, pwavebuf, g_mgr.ch, block_size); |
| Output_Size = Output_Size - Output_Size % g_mgr.ch; |
| memcpy(buf, (char*)pcm_buf, 2 * Output_Size); |
| return Output_Size * 2; |
| |
| } |
| |
| |
| enum SampleFormat { |
| SAMPLE_FMT_NONE = -1, |
| SAMPLE_FMT_U8, ///< unsigned 8 bits |
| SAMPLE_FMT_S16, ///< signed 16 bits |
| SAMPLE_FMT_S32, ///< signed 32 bits |
| SAMPLE_FMT_FLT, ///< float |
| SAMPLE_FMT_DBL, ///< double |
| SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if dynamically linking to libavcodec |
| }; |
| |
| int runpcmdecoder(audio_decoder_operations_t *adec_ops, pcm_read_ctl_t *pcm_read_ctx, unsigned char *buf, int len) |
| { |
| int i/*, j*/; |
| short *pcm_buf = (short*)wave_decoder_buffer[1].addr; |
| int tmp = 0; |
| offset = 0; |
| if (g_mgr.bps == SAMPLE_FMT_U8) { |
| tmp = refill(adec_ops, pcm_read_ctx, pwavebuf, WAVE_BLOCK_SIZE); |
| if (tmp < 0) { |
| return -1; |
| } |
| for (i = 0; i < tmp;) { |
| pcm_buf[i] = (pwavebuf[i] - 0x80) << 8; |
| i++; |
| pcm_buf[i] = (pwavebuf[i] - 0x80) << 8; |
| i++; |
| pcm_buf[i] = (pwavebuf[i] - 0x80) << 8; |
| i++; |
| pcm_buf[i] = (pwavebuf[i] - 0x80) << 8; |
| i++; |
| } |
| return (WAVE_BLOCK_SIZE) * 2; |
| } else { |
| if (refill(adec_ops, pcm_read_ctx, pwavebuf, WAVE_BLOCK_SIZE) < 0) { |
| return -1; |
| }; |
| return ((WAVE_BLOCK_SIZE >> 1) * 2); |
| } |
| } |
| |
| static int adpcm_decode_frame(audio_decoder_operations_t *adec_ops, pcm_read_ctl_t *pcm_read_ctx, unsigned char *buf, int len) |
| { |
| int buf_size = 0; |
| pwavebuf = (unsigned char*)wave_decoder_buffer[0].addr; |
| |
| switch (adec_ops->nAudioDecoderType) { |
| case CODEC_ID_PCM_ALAW: |
| buf_size = runalawdecoder(adec_ops, pcm_read_ctx, buf, len); |
| break; |
| |
| case CODEC_ID_PCM_MULAW: |
| buf_size = runulawdecoder(adec_ops, pcm_read_ctx, buf, len); |
| break; |
| |
| case CODEC_ID_ADPCM_IMA_WAV: |
| buf_size = runimaadpcmdecoder(adec_ops, pcm_read_ctx, buf, len); |
| break; |
| |
| case CODEC_ID_ADPCM_MS: |
| buf_size = runmsadpcmdecoder(adec_ops, pcm_read_ctx, buf, len); |
| break; |
| default: |
| buf_size = runpcmdecoder(adec_ops, pcm_read_ctx, buf, len); |
| break; |
| } |
| return buf_size; |
| } |
| |
| |
| |
| int audio_dec_decode(audio_decoder_operations_t *adec_ops, char *outbuf, int *outlen, char *inbuf, int inlen) |
| { |
| //ALOGV("[%s:%d] in %p, inlen %d", __func__, __LINE__, inbuf, inlen); |
| pcm_read_ctl_t pcm_read_ctl = {0}; |
| pcm_read_init(&pcm_read_ctl, inbuf, inlen); |
| |
| *outlen = adpcm_decode_frame(adec_ops, &pcm_read_ctl, outbuf, *outlen); |
| //dump_data(outbuf, *outlen, "/data/adpcm_out.pcm"); |
| //ALOGV("[%s:%d] outlen %d. used %d", __func__, __LINE__, *outlen, pcm_read_ctl.UsedDataLen); |
| |
| return pcm_read_ctl.UsedDataLen; |
| |
| } |
| int audio_dec_init(audio_decoder_operations_t *adec_ops) |
| { |
| ALOGD("\n\n[%s]BuildDate--%s BuildTime--%s", __FUNCTION__, __DATE__, __TIME__); |
| ALOGD("[%s] samplerate/%d channels/%d\n", __FUNCTION__, adec_ops->samplerate, adec_ops->channels); |
| |
| wave_decoder_buffer[0].addr = malloc(WAVE_BLOCK_SIZE); |
| if (wave_decoder_buffer[0].addr == 0) { |
| PRINTF("[%s %d]Error: malloc adpcm buffer failed!\n", __FUNCTION__, __LINE__); |
| return -1; |
| } |
| wave_decoder_buffer[0].size = WAVE_BLOCK_SIZE; |
| wave_decoder_buffer[1].addr = malloc(WAVE_BLOCK_SIZE * 1 * 4); |
| if (wave_decoder_buffer[1].addr == 0) { |
| PRINTF("[%s %d]Error: malloc adpcm buffer failed!\n", __FUNCTION__, __LINE__); |
| return -1; |
| } |
| adec_ops->nInBufSize = WAVE_BLOCK_SIZE; |
| adec_ops->nOutBufSize = 0; |
| wave_decoder_buffer[1].size = WAVE_BLOCK_SIZE * 1 * 4; // 2byte, 2ch, compress ratio 4 |
| g_mgr.start = 0; |
| g_mgr.size = 0; |
| g_mgr.bps = SAMPLE_FMT_S16; |
| g_mgr.ch = adec_ops->channels; |
| g_mgr.sr = adec_ops->samplerate; |
| g_mgr.wr = 0; |
| g_mgr.last_rd = 0; |
| g_mgr.totalSample = 0; |
| g_mgr.totalSamplePlayed = 0; |
| g_mgr.totalSampleDecoded = 0; |
| g_mgr.last_pts = 0; |
| g_mgr.blk = 0; |
| |
| block_align = adec_ops->block_size;//512; |
| wave_timestamplen = 0; |
| ALOGD("[%s %d]block_align/%d codec_id/0x%x\n", __FUNCTION__, __LINE__, block_align, adec_ops->nAudioDecoderType); |
| return 0; |
| } |
| |
| int audio_dec_release(audio_decoder_operations_t *adec_ops) |
| { |
| if (wave_decoder_buffer[0].addr) { |
| free(wave_decoder_buffer[0].addr); |
| wave_decoder_buffer[0].addr = 0; |
| wave_decoder_buffer[0].size = 0; |
| } |
| if (wave_decoder_buffer[1].addr) { |
| free(wave_decoder_buffer[1].addr); |
| wave_decoder_buffer[1].addr = 0; |
| wave_decoder_buffer[1].size = 0; |
| } |
| return 0; |
| } |
| |
| int audio_dec_getinfo(audio_decoder_operations_t *adec_ops, void *pAudioInfo) |
| { |
| return 0; |
| } |
| |
| |