blob: 20684a4c97e047f7a2b0b506a54230f2ecbf89df [file] [log] [blame]
/*
* 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, &timestamp[0], 1);
tmp --;
if (timestamp[0] == 'd') {
pcm_read(pcm_read_ctx, &timestamp[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;
}