项目中要用到ADPCM_DVI4音频格式,需要对DVI4做编解码,在windows环境海思提供了库,可以直接调用,近期需要移植到linux,海思没有提供相关库,只能自己想办法了。找了很多资料,终于在RFC3551中找到DVI4的描述,见https://tools.ietf.org/html/rfc3551 4.5.1 。
总结下来只需要将IMA_ADPCM算法改两部分就可以:
1.解码代码
/**************************************************************************************
* Function: adpcm_decoder
*
* Description: decode ADPCM data in a long word to 8 16-bit PCM
*
* Argument: char *outdata; [I] ADPCM output
* short *indata; [0] PCM input
* adpcm_state *state; [I/O] save previous info (output value and index into stepsize table)
*
* Return: void
*
* Notes: quantize the difference (diff)
* predict the valpred for next sample
**************************************************************************************/
void adpcm_decoder(char *indata, short *outdata, struct adpcm_state *state, int input_len)
{
// signed char *inp; /* Input buffer pointer */
// short *outp; /* output buffer pointer */
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int step; /* Stepsize */
int valpred; /* Predicted value */
int vpdiff; /* Current change to valpred */
int index; /* Current step change index */
int inputbuffer; /* place to keep next 4-bit value */
int bufferstep; /* toggle between inputbuffer/input */
int len;
// outp = outdata;
// inp = (signed char *)indata;
valpred = (int)state->valprev;
index = state->index;
step = stepsizeTable[index];
bufferstep = 0;
inputbuffer = 0;
//int i = 0;
for (len = 0; len < input_len * 2; len++) {
/* Step 1 - get the delta value */
if (bufferstep) {
//delta = (inputbuffer >> 4) & 0xf;
//再解低4bit
delta = (inputbuffer) & 0xf;
}
else {
inputbuffer = *indata++;
//delta = (inputbuffer) & 0xf;
//先解高4bit
delta = (inputbuffer >> 4) & 0xf;
}
bufferstep = !bufferstep;
/* Step 2 - Find new index value (for later) */
index += indexTable[delta];
if (index < 0) index = 0;
if (index > 88) index = 88;
/* Step 3 - Separate sign and magnitude */
sign = delta & 8;
delta = delta & 7;
/* Step 4 - Compute difference and new predicted value */
/*
** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
** in adpcm_coder.
*/
vpdiff = step >> 3;
if (delta & 4) vpdiff += step;
if (delta & 2) vpdiff += step >> 1;
if (delta & 1) vpdiff += step >> 2;
if (sign)
valpred -= vpdiff;
else
valpred += vpdiff;
/* Step 5 - clamp output value */
if (valpred > 32767)
valpred = 32767;
else if (valpred < -32768)
valpred = -32768;
/* Step 6 - Update step value */
step = stepsizeTable[index];
/* Step 7 - Output value */
*outdata++ = (valpred >> TRUCATE_BIT); // convert to 15 bit output
}
state->valprev = valpred;
state->index = index;
}
修改部分 主要是对调了每个字节的4bit顺序
if (bufferstep) {
//delta = (inputbuffer >> 4) & 0xf;
//再解低4bit
delta = (inputbuffer) & 0xf;
}
else {
inputbuffer = *indata++;
//delta = (inputbuffer) & 0xf;
//先解高4bit
delta = (inputbuffer >> 4) & 0xf;
}
2.调用与IMA不同的是 前4个字节是predict和index 也就是上面方法中的adpcm_state
pst->valprev = ((short)data[1] << 8) + data[0];
//pst->index = ((short)data[3] << 8) + data[2];
pst->index = data[2];
data += 4;
adpcm_decoder(data, outdata, pst, data_len);