[Mplayer-cvslog] CVS: main/libmpcodecs ad.c,1.3,1.4 ad_imaadpcm.c,1.1,1.2 ad_msadpcm.c,1.2,1.3 ad_dk3adpcm.c,1.1,1.2 Makefile,1.18,1.19
Mike Melanson
melanson at mplayer.dev.hu
Sat Mar 30 23:27:47 CET 2002
Update of /cvsroot/mplayer/main/libmpcodecs
In directory mplayer:/var/tmp.root/cvs-serv6419/libmpcodecs
Modified Files:
ad.c ad_imaadpcm.c ad_msadpcm.c ad_dk3adpcm.c Makefile
Log Message:
reworked ADPCM decoders; changes include:
* fixed MS IMA ADPCM
* dissolved adpcm.c/.h into appropriate ad_* decoders
* DK4 audio is handled directly by IMA ADPCM decoder (this obsoletes
ad_dk4adpcm.c)
Index: ad.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/ad.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ad.c 26 Mar 2002 15:53:18 -0000 1.3
+++ ad.c 30 Mar 2002 22:27:44 -0000 1.4
@@ -25,7 +25,6 @@
extern ad_functions_t mpcodecs_ad_alaw;
extern ad_functions_t mpcodecs_ad_imaadpcm;
extern ad_functions_t mpcodecs_ad_msadpcm;
-extern ad_functions_t mpcodecs_ad_dk4adpcm;
extern ad_functions_t mpcodecs_ad_dk3adpcm;
extern ad_functions_t mpcodecs_ad_roqaudio;
extern ad_functions_t mpcodecs_ad_dshow;
@@ -47,7 +46,6 @@
&mpcodecs_ad_alaw,
&mpcodecs_ad_imaadpcm,
&mpcodecs_ad_msadpcm,
- &mpcodecs_ad_dk4adpcm,
&mpcodecs_ad_dk3adpcm,
&mpcodecs_ad_roqaudio,
&mpcodecs_ad_msgsm,
Index: ad_imaadpcm.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/ad_imaadpcm.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ad_imaadpcm.c 25 Mar 2002 21:06:01 -0000 1.1
+++ ad_imaadpcm.c 30 Mar 2002 22:27:44 -0000 1.2
@@ -1,11 +1,71 @@
+/*
+ IMA ADPCM Decoder for MPlayer
+ by Mike Melanson
+
+ This file is in charge of decoding all of the various IMA ADPCM data
+ formats that various entities have created. Details about the data
+ formats can be found here:
+ http://www.pcisys.net/~melanson/codecs/
+
+ So far, this file handles these formats:
+ 'ima4': IMA ADPCM found in QT files
+ 0x11: IMA ADPCM found in MS AVI/ASF/WAV files
+ 0x61: DK4 ADPCM found in certain AVI files on Sega Saturn CD-ROMs;
+ note that this is a 'rogue' format number in that it was
+ never officially registered with Microsoft
+*/
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "config.h"
+#include "bswap.h"
#include "ad_internal.h"
-#include "../adpcm.h"
+#define MS_IMA_ADPCM_PREAMBLE_SIZE 4
+
+#define QT_IMA_ADPCM_PREAMBLE_SIZE 2
+#define QT_IMA_ADPCM_BLOCK_SIZE 0x22
+#define QT_IMA_ADPCM_SAMPLES_PER_BLOCK 64
+
+#define BE_16(x) (be2me_16(*(unsigned short *)(x)))
+#define BE_32(x) (be2me_32(*(unsigned int *)(x)))
+#define LE_16(x) (le2me_16(*(unsigned short *)(x)))
+#define LE_32(x) (le2me_32(*(unsigned int *)(x)))
+
+// pertinent tables for IMA ADPCM
+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;
+// clamp a number within a signed 16-bit range
+#define CLAMP_S16(x) if (x < -32768) x = -32768; \
+ else if (x > 32767) x = 32767;
+// 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 ad_info_t info =
{
@@ -14,32 +74,52 @@
AFM_IMAADPCM,
"Nick Kurshev",
"Mike Melanson",
- "ima4 (MOV files)"
+ ""
};
LIBAD_EXTERN(imaadpcm)
+static int preinit(sh_audio_t *sh_audio)
+{
+ // not exactly sure what this field is for
+ sh_audio->audio_out_minsize = 8192;
+
+ // if format is "ima4", assume the audio is coming from a QT file which
+ // indicates constant block size, whereas an AVI/ASF/WAV file will fill
+ // in this field with 0x11
+ if ((sh_audio->format == 0x11) || (sh_audio->format == 0x61))
+ {
+ sh_audio->ds->ss_div = (sh_audio->wf->nBlockAlign -
+ (MS_IMA_ADPCM_PREAMBLE_SIZE * sh_audio->wf->nChannels)) * 2;
+ sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign;
+ }
+ else
+ {
+ sh_audio->ds->ss_div = QT_IMA_ADPCM_SAMPLES_PER_BLOCK;
+ sh_audio->ds->ss_mul = QT_IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels;
+ }
+ return 1;
+}
+
static int init(sh_audio_t *sh_audio)
{
/* IMA-ADPCM 4:1 audio codec:*/
sh_audio->channels=sh_audio->wf->nChannels;
sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
/* decodes 34 byte -> 64 short*/
- sh_audio->i_bps=IMA_ADPCM_BLOCK_SIZE*(sh_audio->channels*sh_audio->samplerate)/
- IMA_ADPCM_SAMPLES_PER_BLOCK; /* 1:4 */
- return 1;
-}
+ sh_audio->i_bps =
+ (sh_audio->ds->ss_mul * sh_audio->samplerate) / sh_audio->ds->ss_div;
+
+ if ((sh_audio->a_in_buffer =
+ (unsigned char *)malloc(sh_audio->ds->ss_mul)) == NULL)
+ return 0;
-static int preinit(sh_audio_t *sh_audio)
-{
- sh_audio->audio_out_minsize=4096;
- sh_audio->ds->ss_div=IMA_ADPCM_SAMPLES_PER_BLOCK;
- sh_audio->ds->ss_mul=IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels;
return 1;
}
-static void uninit(sh_audio_t *sh)
+static void uninit(sh_audio_t *sh_audio)
{
+ free(sh_audio->a_in_buffer);
}
static int control(sh_audio_t *sh,int cmd,void* arg, ...)
@@ -48,12 +128,247 @@
return CONTROL_UNKNOWN;
}
+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 qt_ima_adpcm_decode_block(unsigned short *output,
+ unsigned char *input, int channels)
+{
+ int initial_predictor_l = 0;
+ int initial_predictor_r = 0;
+ int initial_index_l = 0;
+ int initial_index_r = 0;
+ int i;
+
+ initial_predictor_l = BE_16(&input[0]);
+ initial_index_l = initial_predictor_l;
+
+ // mask, sign-extend, and clamp the predictor portion
+ initial_predictor_l &= 0xFF80;
+ SE_16BIT(initial_predictor_l);
+ CLAMP_S16(initial_predictor_l);
+
+ // mask and clamp the index portion
+ initial_index_l &= 0x7F;
+ CLAMP_0_TO_88(initial_index_l);
+
+ // handle stereo
+ if (channels > 1)
+ {
+ initial_predictor_r = BE_16(&input[QT_IMA_ADPCM_BLOCK_SIZE]);
+ initial_index_r = initial_predictor_r;
+
+ // mask, sign-extend, and clamp the predictor portion
+ initial_predictor_r &= 0xFF80;
+ SE_16BIT(initial_predictor_r);
+ CLAMP_S16(initial_predictor_r);
+
+ // mask and clamp the index portion
+ initial_index_r &= 0x7F;
+ CLAMP_0_TO_88(initial_index_r);
+ }
+
+ // break apart all of the nibbles in the block
+ if (channels == 1)
+ for (i = 0; i < QT_IMA_ADPCM_SAMPLES_PER_BLOCK / 2; i++)
+ {
+ output[i * 2 + 0] = input[2 + i] & 0x0F;
+ output[i * 2 + 1] = input[2 + i] >> 4;
+ }
+ else
+ for (i = 0; i < QT_IMA_ADPCM_SAMPLES_PER_BLOCK / 2 * 2; i++)
+ {
+ output[i * 4 + 0] = input[2 + i] & 0x0F;
+ output[i * 4 + 1] = input[2 + QT_IMA_ADPCM_BLOCK_SIZE + i] & 0x0F;
+ output[i * 4 + 2] = input[2 + i] >> 4;
+ output[i * 4 + 3] = input[2 + QT_IMA_ADPCM_BLOCK_SIZE + i] >> 4;
+ }
+
+ decode_nibbles(output,
+ QT_IMA_ADPCM_SAMPLES_PER_BLOCK * channels, channels,
+ initial_predictor_l, initial_index_l,
+ initial_predictor_r, initial_index_r);
+
+ return QT_IMA_ADPCM_SAMPLES_PER_BLOCK * channels;
+}
+
+static int ms_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) / 2; 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;
+}
+
+static int dk4_ima_adpcm_decode_block(unsigned short *output,
+ unsigned char *input, int channels, int block_size)
+{
+ int i;
+ int output_ptr;
+ int predictor_l = 0;
+ int predictor_r = 0;
+ int index_l = 0;
+ int index_r = 0;
+
+ // the first predictor value goes straight to the output
+ predictor_l = output[0] = LE_16(&input[0]);
+ SE_16BIT(predictor_l);
+ index_l = input[2];
+ if (channels == 2)
+ {
+ predictor_r = output[1] = LE_16(&input[4]);
+ SE_16BIT(predictor_r);
+ index_r = input[6];
+ }
+
+ output_ptr = channels;
+ for (i = MS_IMA_ADPCM_PREAMBLE_SIZE * channels; i < block_size; i++)
+ {
+ output[output_ptr++] = input[i] >> 4;
+ output[output_ptr++] = input[i] & 0x0F;
+ }
+
+ decode_nibbles(&output[channels],
+ (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2 - channels,
+ channels,
+ predictor_l, index_l,
+ predictor_r, index_r);
+
+ return (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2 - channels;
+}
+
static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
{
- unsigned char ibuf[IMA_ADPCM_BLOCK_SIZE * 2]; /* bytes / stereo frame */
- if (demux_read_data(sh_audio->ds, ibuf,
- IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) !=
- IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels)
- return -1;
- return 2*ima_adpcm_decode_block((unsigned short*)buf,ibuf, sh_audio->wf->nChannels);
+ if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,
+ sh_audio->ds->ss_mul) !=
+ sh_audio->ds->ss_mul)
+ return -1;
+
+ if (sh_audio->format == 0x11)
+ {
+ return 2 * ms_ima_adpcm_decode_block(
+ (unsigned short*)buf, sh_audio->a_in_buffer, sh_audio->wf->nChannels,
+ sh_audio->ds->ss_mul);
+ }
+ else if (sh_audio->format == 0x61)
+ {
+ return 2 * dk4_ima_adpcm_decode_block(
+ (unsigned short*)buf, sh_audio->a_in_buffer, sh_audio->wf->nChannels,
+ sh_audio->ds->ss_mul);
+ }
+ else
+ {
+ return 2 * qt_ima_adpcm_decode_block(
+ (unsigned short*)buf, sh_audio->a_in_buffer, sh_audio->wf->nChannels);
+ }
}
Index: ad_msadpcm.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/ad_msadpcm.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ad_msadpcm.c 26 Mar 2002 04:41:43 -0000 1.2
+++ ad_msadpcm.c 30 Mar 2002 22:27:44 -0000 1.3
@@ -1,8 +1,18 @@
+/*
+ MS ADPCM Decoder for MPlayer
+ by Mike Melanson
+
+ This file is responsible for decoding Microsoft ADPCM data.
+ Details about the data format can be found here:
+ http://www.pcisys.net/~melanson/codecs/
+*/
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "config.h"
+#include "bswap.h"
#include "ad_internal.h"
static ad_info_t info =
@@ -17,8 +27,40 @@
LIBAD_EXTERN(msadpcm)
+static int ms_adapt_table[] =
+{
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+};
+
+static int ms_adapt_coeff1[] =
+{
+ 256, 512, 0, 192, 240, 460, 392
+};
+
+static int ms_adapt_coeff2[] =
+{
+ 0, -256, 0, 64, 0, -208, -232
+};
+
#define MS_ADPCM_PREAMBLE_SIZE 7
+#define LE_16(x) (le2me_16(*(unsigned short *)(x)))
+#define LE_32(x) (le2me_32(*(unsigned int *)(x)))
+
+// 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;
+// clamp a number within a signed 16-bit range
+#define CLAMP_S16(x) if (x < -32768) x = -32768; \
+ else if (x > 32767) x = 32767;
+// 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 int preinit(sh_audio_t *sh_audio)
{
sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 4;
@@ -54,14 +96,110 @@
return CONTROL_UNKNOWN;
}
+static int ms_adpcm_decode_block(unsigned short *output, unsigned char *input,
+ int channels, int block_size)
+{
+ int current_channel = 0;
+ int idelta[2];
+ int sample1[2];
+ int sample2[2];
+ int coeff1[2];
+ int coeff2[2];
+ int stream_ptr = 0;
+ int out_ptr = 0;
+ int upper_nibble = 1;
+ int nibble;
+ int snibble; // signed nibble
+ int predictor;
+
+ // fetch the header information, in stereo if both channels are present
+ if (input[stream_ptr] > 6)
+ mp_msg(MSGT_DECAUDIO, MSGL_WARN,
+ "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n",
+ input[stream_ptr]);
+ coeff1[0] = ms_adapt_coeff1[input[stream_ptr]];
+ coeff2[0] = ms_adapt_coeff2[input[stream_ptr]];
+ stream_ptr++;
+ if (channels == 2)
+ {
+ if (input[stream_ptr] > 6)
+ mp_msg(MSGT_DECAUDIO, MSGL_WARN,
+ "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n",
+ input[stream_ptr]);
+ coeff1[1] = ms_adapt_coeff1[input[stream_ptr]];
+ coeff2[1] = ms_adapt_coeff2[input[stream_ptr]];
+ stream_ptr++;
+ }
+
+ idelta[0] = LE_16(&input[stream_ptr]);
+ stream_ptr += 2;
+ SE_16BIT(idelta[0]);
+ if (channels == 2)
+ {
+ idelta[1] = LE_16(&input[stream_ptr]);
+ stream_ptr += 2;
+ SE_16BIT(idelta[1]);
+ }
+
+ sample1[0] = LE_16(&input[stream_ptr]);
+ stream_ptr += 2;
+ SE_16BIT(sample1[0]);
+ if (channels == 2)
+ {
+ sample1[1] = LE_16(&input[stream_ptr]);
+ stream_ptr += 2;
+ SE_16BIT(sample1[1]);
+ }
+
+ sample2[0] = LE_16(&input[stream_ptr]);
+ stream_ptr += 2;
+ SE_16BIT(sample2[0]);
+ if (channels == 2)
+ {
+ sample2[1] = LE_16(&input[stream_ptr]);
+ stream_ptr += 2;
+ SE_16BIT(sample2[1]);
+ }
+
+ while (stream_ptr < block_size)
+ {
+ // get the next nibble
+ if (upper_nibble)
+ nibble = snibble = input[stream_ptr] >> 4;
+ else
+ nibble = snibble = input[stream_ptr++] & 0x0F;
+ upper_nibble ^= 1;
+ SE_4BIT(snibble);
+
+ predictor = (
+ ((sample1[current_channel] * coeff1[current_channel]) +
+ (sample2[current_channel] * coeff2[current_channel])) / 256) +
+ (snibble * idelta[current_channel]);
+ CLAMP_S16(predictor);
+ sample2[current_channel] = sample1[current_channel];
+ sample1[current_channel] = predictor;
+ output[out_ptr++] = predictor;
+
+ // compute the next adaptive scale factor (a.k.a. the variable idelta)
+ idelta[current_channel] =
+ (ms_adapt_table[nibble] * idelta[current_channel]) / 256;
+ CLAMP_ABOVE_16(idelta[current_channel]);
+
+ // toggle the channel
+ current_channel ^= channels - 1;
+ }
+
+ return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2;
+}
+
static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
{
if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,
- sh_audio->ds->ss_mul) !=
- sh_audio->ds->ss_mul)
- return -1; /* EOF */
+ sh_audio->ds->ss_mul) !=
+ sh_audio->ds->ss_mul)
+ return -1; /* EOF */
return 2 * ms_adpcm_decode_block(
- (unsigned short*)buf, sh_audio->a_in_buffer,
- sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign);
+ (unsigned short*)buf, sh_audio->a_in_buffer,
+ sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign);
}
Index: ad_dk3adpcm.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/ad_dk3adpcm.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ad_dk3adpcm.c 25 Mar 2002 21:06:01 -0000 1.1
+++ ad_dk3adpcm.c 30 Mar 2002 22:27:44 -0000 1.2
@@ -1,8 +1,19 @@
+/*
+ DK3 ADPCM Decoder for MPlayer
+ by Mike Melanson
+
+ This file is responsible for decoding audio data encoded with
+ Duck Corp's DK3 ADPCM algorithm. Details about the data format
+ can be found here:
+ http://www.pcisys.net/~melanson/codecs/
+*/
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "config.h"
+#include "bswap.h"
#include "ad_internal.h"
static ad_info_t info =
@@ -17,27 +28,70 @@
LIBAD_EXTERN(dk3adpcm)
-#include "adpcm.h"
+#define DK3_ADPCM_PREAMBLE_SIZE 16
-static int init(sh_audio_t *sh_audio)
+#define LE_16(x) (le2me_16(*(unsigned short *)(x)))
+#define LE_32(x) (le2me_32(*(unsigned int *)(x)))
+
+// 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;
+// clamp a number within a signed 16-bit range
+#define CLAMP_S16(x) if (x < -32768) x = -32768; \
+ else if (x > 32767) x = 32767;
+// 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;
+
+// pertinent tables
+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] =
{
- sh_audio->channels=sh_audio->wf->nChannels;
- sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
- sh_audio->i_bps=DK3_ADPCM_BLOCK_SIZE*
- (sh_audio->channels*sh_audio->samplerate) / DK3_ADPCM_SAMPLES_PER_BLOCK;
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+static int preinit(sh_audio_t *sh_audio)
+{
+ sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 6;
+ sh_audio->ds->ss_div =
+ (sh_audio->wf->nBlockAlign - DK3_ADPCM_PREAMBLE_SIZE) * 8 / 3;
+ sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign;
return 1;
}
-static int preinit(sh_audio_t *sh_audio)
+static int init(sh_audio_t *sh_audio)
{
- sh_audio->audio_out_minsize=DK3_ADPCM_SAMPLES_PER_BLOCK * 4;
- sh_audio->ds->ss_div=DK3_ADPCM_SAMPLES_PER_BLOCK;
- sh_audio->ds->ss_mul=DK3_ADPCM_BLOCK_SIZE;
+ sh_audio->channels = sh_audio->wf->nChannels;
+ sh_audio->samplerate = sh_audio->wf->nSamplesPerSec;
+ sh_audio->i_bps =
+ (sh_audio->ds->ss_mul * sh_audio->samplerate) / sh_audio->ds->ss_div;
+
+ if ((sh_audio->a_in_buffer =
+ (unsigned char *)malloc(sh_audio->ds->ss_mul)) == NULL)
+ return 0;
+
return 1;
}
-static void uninit(sh_audio_t *sh)
+static void uninit(sh_audio_t *sh_audio)
{
+ free(sh_audio->a_in_buffer);
}
static int control(sh_audio_t *sh,int cmd,void* arg, ...)
@@ -46,15 +100,143 @@
return CONTROL_UNKNOWN;
}
+#define DK3_GET_NEXT_NIBBLE() \
+ if (decode_top_nibble_next) \
+ { \
+ nibble = (last_byte >> 4) & 0x0F; \
+ decode_top_nibble_next = 0; \
+ } \
+ else \
+ { \
+ last_byte = input[in_ptr++]; \
+ nibble = last_byte & 0x0F; \
+ decode_top_nibble_next = 1; \
+ }
+
+// note: This decoder assumes the format 0x62 data always comes in
+// stereo flavor
+static int dk3_adpcm_decode_block(unsigned short *output, unsigned char *input,
+ int block_size)
+{
+ int sum_pred;
+ int diff_pred;
+ int sum_index;
+ int diff_index;
+ int diff_channel;
+ int in_ptr = 0x10;
+ int out_ptr = 0;
+
+ unsigned char last_byte = 0;
+ unsigned char nibble;
+ int decode_top_nibble_next = 0;
+
+ // ADPCM work variables
+ int sign;
+ int delta;
+ int step;
+ int diff;
+
+ sum_pred = LE_16(&input[10]);
+ diff_pred = LE_16(&input[12]);
+ SE_16BIT(sum_pred);
+ SE_16BIT(diff_pred);
+ diff_channel = diff_pred;
+ sum_index = input[14];
+ diff_index = input[15];
+
+ while (in_ptr < block_size)
+// while (in_ptr < 2048)
+ {
+ // process the first predictor of the sum channel
+ DK3_GET_NEXT_NIBBLE();
+
+ step = adpcm_step[sum_index];
+
+ sign = nibble & 8;
+ delta = nibble & 7;
+
+ diff = step >> 3;
+ if (delta & 4) diff += step;
+ if (delta & 2) diff += step >> 1;
+ if (delta & 1) diff += step >> 2;
+
+ if (sign)
+ sum_pred -= diff;
+ else
+ sum_pred += diff;
+
+ CLAMP_S16(sum_pred);
+
+ sum_index += adpcm_index[nibble];
+ CLAMP_0_TO_88(sum_index);
+
+ // process the diff channel predictor
+ DK3_GET_NEXT_NIBBLE();
+
+ step = adpcm_step[diff_index];
+
+ sign = nibble & 8;
+ delta = nibble & 7;
+
+ diff = step >> 3;
+ if (delta & 4) diff += step;
+ if (delta & 2) diff += step >> 1;
+ if (delta & 1) diff += step >> 2;
+
+ if (sign)
+ diff_pred -= diff;
+ else
+ diff_pred += diff;
+
+ CLAMP_S16(diff_pred);
+
+ diff_index += adpcm_index[nibble];
+ CLAMP_0_TO_88(diff_index);
+
+ // output the first pair of stereo PCM samples
+ diff_channel = (diff_channel + diff_pred) / 2;
+ output[out_ptr++] = sum_pred + diff_channel;
+ output[out_ptr++] = sum_pred - diff_channel;
+
+ // process the second predictor of the sum channel
+ DK3_GET_NEXT_NIBBLE();
+
+ step = adpcm_step[sum_index];
+
+ sign = nibble & 8;
+ delta = nibble & 7;
+
+ diff = step >> 3;
+ if (delta & 4) diff += step;
+ if (delta & 2) diff += step >> 1;
+ if (delta & 1) diff += step >> 2;
+
+ if (sign)
+ sum_pred -= diff;
+ else
+ sum_pred += diff;
+
+ CLAMP_S16(sum_pred);
+
+ sum_index += adpcm_index[nibble];
+ CLAMP_0_TO_88(sum_index);
+
+ // output the second pair of stereo PCM samples
+ output[out_ptr++] = sum_pred + diff_channel;
+ output[out_ptr++] = sum_pred - diff_channel;
+ }
+
+ return out_ptr;
+}
+
static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
{
- int len=-1;
- unsigned char ibuf[DK3_ADPCM_BLOCK_SIZE * 2]; /* bytes / stereo frame */
- if (demux_read_data(sh_audio->ds, ibuf,
- DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) !=
- DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels)
- return len; /* EOF */
- len = 2 * dk3_adpcm_decode_block(
- (unsigned short*)buf,ibuf);
- return len;
+ if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,
+ sh_audio->ds->ss_mul) !=
+ sh_audio->ds->ss_mul)
+ return -1; /* EOF */
+
+ return 2 * dk3_adpcm_decode_block(
+ (unsigned short*)buf, sh_audio->a_in_buffer,
+ sh_audio->wf->nBlockAlign);
}
Index: Makefile
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/Makefile,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- Makefile 26 Mar 2002 15:53:18 -0000 1.18
+++ Makefile 30 Mar 2002 22:27:44 -0000 1.19
@@ -3,7 +3,7 @@
LIBNAME = libmpcodecs.a
-AUDIO_SRCS=dec_audio.c ad.c ad_a52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dk4adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c
+AUDIO_SRCS=dec_audio.c ad.c ad_a52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c
VIDEO_SRCS=dec_video.c vd.c vd_null.c vd_cinepak.c vd_qtrpza.c vd_ffmpeg.c vd_dshow.c vd_vfw.c vd_odivx.c vd_divx4.c vd_raw.c vd_xanim.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_nuv.c vd_libmpeg2.c vd_msrle.c vd_huffyuv.c vd_zlib.c
ifeq ($(PNG),yes)
More information about the MPlayer-cvslog
mailing list