aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec
diff options
context:
space:
mode:
authorMarco Gerards <mgerards@xs4all.nl>2007-04-07 16:03:23 +0000
committerDiego Biurrun <diego@biurrun.de>2007-04-07 16:03:23 +0000
commitd1e0d21f9492215b324fe7872e050b2d48a55c1d (patch)
tree3e67a6ef88f4f739cdf795e07399202e72a9fd89 /libavcodec
parentefd2afc2aef18e9c8d43a18dccc792d901528992 (diff)
downloadffmpeg-d1e0d21f9492215b324fe7872e050b2d48a55c1d.tar.gz
THP PCM decoder, used on the Nintendo GameCube.
patch by Marco Gerards, mgerards xs4all nl Originally committed as revision 8646 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/Makefile1
-rw-r--r--libavcodec/adpcm.c68
-rw-r--r--libavcodec/allcodecs.c1
-rw-r--r--libavcodec/avcodec.h2
4 files changed, 72 insertions, 0 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 175755eb90..a07879e962 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -250,6 +250,7 @@ OBJS-$(CONFIG_ADPCM_SBPRO_4_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_SBPRO_4_ENCODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_SWF_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_SWF_ENCODER) += adpcm.o
+OBJS-$(CONFIG_ADPCM_THP_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_XA_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_XA_ENCODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 8800c3a20c..cf282f1071 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -29,6 +29,7 @@
* by Mike Melanson (melanson@pcisys.net)
* CD-ROM XA ADPCM codec by BERO
* EA ADPCM decoder by Robin Kay (komadori@myrealbox.com)
+ * THP ADPCM decoder by Marco Gerards (mgerards@xs4all.nl)
*
* Features and limitations:
*
@@ -1308,6 +1309,72 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
src++;
}
break;
+ case CODEC_ID_ADPCM_THP:
+ {
+ GetBitContext gb;
+ int table[16][2];
+ unsigned int samplecnt;
+ int prev1[2], prev2[2];
+ int ch;
+
+ if (buf_size < 80) {
+ av_log(avctx, AV_LOG_ERROR, "frame too small\n");
+ return -1;
+ }
+
+ init_get_bits(&gb, src, buf_size * 8);
+ src += buf_size;
+
+ get_bits_long(&gb, 32); /* Channel size */
+ samplecnt = get_bits_long(&gb, 32);
+
+ for (ch = 0; ch < 2; ch++)
+ for (i = 0; i < 16; i++)
+ table[i][ch] = get_sbits(&gb, 16);
+
+ /* Initialize the previous sample. */
+ for (ch = 0; ch < 2; ch++) {
+ prev1[ch] = get_sbits(&gb, 16);
+ prev2[ch] = get_sbits(&gb, 16);
+ }
+
+ if (samplecnt >= (samples_end - samples) / (st + 1)) {
+ av_log(avctx, AV_LOG_ERROR, "allocated output buffer is too small\n");
+ return -1;
+ }
+
+ for (ch = 0; ch <= st; ch++) {
+ samples = (unsigned short *) data + ch;
+
+ /* Read in every sample for this channel. */
+ for (i = 0; i < samplecnt / 14; i++) {
+ uint8_t index = get_bits (&gb, 4) & 7;
+ unsigned int exp = get_bits (&gb, 4);
+ int factor1 = table[index * 2][ch];
+ int factor2 = table[index * 2 + 1][ch];
+
+ /* Decode 14 samples. */
+ for (n = 0; n < 14; n++) {
+ int sampledat = get_sbits (&gb, 4);
+
+ *samples = ((prev1[ch]*factor1
+ + prev2[ch]*factor2) >> 11) + (sampledat << exp);
+ prev2[ch] = prev1[ch];
+ prev1[ch] = *samples++;
+
+ /* In case of stereo, skip one sample, this sample
+ is for the other channel. */
+ samples += st;
+ }
+ }
+ }
+
+ /* In the previous loop, in case stereo is used, samples is
+ increased exactly one time too often. */
+ samples -= st;
+ break;
+ }
+
default:
return -1;
}
@@ -1368,5 +1435,6 @@ ADPCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);
ADPCM_CODEC(CODEC_ID_ADPCM_SBPRO_4, adpcm_sbpro_4);
ADPCM_CODEC(CODEC_ID_ADPCM_SBPRO_3, adpcm_sbpro_3);
ADPCM_CODEC(CODEC_ID_ADPCM_SBPRO_2, adpcm_sbpro_2);
+ADPCM_CODEC(CODEC_ID_ADPCM_THP, adpcm_thp);
#undef ADPCM_CODEC
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 09612b40d2..be41c147f5 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -244,6 +244,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (ADPCM_SBPRO_3, adpcm_sbpro_3);
REGISTER_ENCDEC (ADPCM_SBPRO_4, adpcm_sbpro_4);
REGISTER_ENCDEC (ADPCM_SWF, adpcm_swf);
+ REGISTER_DECODER(ADPCM_THP, adpcm_thp);
REGISTER_ENCDEC (ADPCM_XA, adpcm_xa);
REGISTER_ENCDEC (ADPCM_YAMAHA, adpcm_yamaha);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index b7ed16248d..421171a183 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -200,6 +200,7 @@ enum CodecID {
CODEC_ID_ADPCM_SBPRO_4,
CODEC_ID_ADPCM_SBPRO_3,
CODEC_ID_ADPCM_SBPRO_2,
+ CODEC_ID_ADPCM_THP,
/* AMR */
CODEC_ID_AMR_NB= 0x12000,
@@ -2417,6 +2418,7 @@ PCM_CODEC(CODEC_ID_ADPCM_SBPRO_3, adpcm_sbpro_3);
PCM_CODEC(CODEC_ID_ADPCM_SBPRO_4, adpcm_sbpro_4);
PCM_CODEC(CODEC_ID_ADPCM_SMJPEG, adpcm_ima_smjpeg);
PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
+PCM_CODEC(CODEC_ID_ADPCM_THP, adpcm_thp);
PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);