[Ffmpeg-devel] [PATCH] THP PCM decoder (GSoC Qualification)
Marco Gerards
mgerards
Mon Apr 2 17:53:54 CEST 2007
Hi,
Last week I sent in a patch demuxer for THP files, which was applied
yesterday. Here is a patch to extend it with a PCM decoder, as
promised. I have tested it with the files Mike uploaded.
Mike, do you happen to have version THP version 1.1 files? The
current samples are all THP version 1.0. Both should work, but you
can't be sure until it is tested ;-).
For now I assumed it is only possible to have THP files with a single
audio stream. If there are THP files with more than one audio stream,
please tell me and I will have a look :-).
--
Marco
Index: libavcodec/allcodecs.c
===================================================================
--- libavcodec/allcodecs.c (revision 8597)
+++ libavcodec/allcodecs.c (working copy)
@@ -244,6 +244,7 @@
REGISTER_ENCDEC (ADPCM_SWF, adpcm_swf);
REGISTER_ENCDEC (ADPCM_XA, adpcm_xa);
REGISTER_ENCDEC (ADPCM_YAMAHA, adpcm_yamaha);
+ REGISTER_DECODER (ADPCM_THP, adpcm_thp);
/* subtitles */
REGISTER_ENCDEC (DVBSUB, dvbsub);
Index: libavcodec/Makefile
===================================================================
--- libavcodec/Makefile (revision 8597)
+++ libavcodec/Makefile (working copy)
@@ -250,6 +250,7 @@
OBJS-$(CONFIG_ADPCM_XA_ENCODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcm.o
+OBJS-$(CONFIG_ADPCM_THP_DECODER) += adpcm.o
# external codec libraries
OBJS-$(CONFIG_LIBA52) += a52dec.o
Index: libavcodec/avcodec.h
===================================================================
--- libavcodec/avcodec.h (revision 8597)
+++ libavcodec/avcodec.h (working copy)
@@ -198,6 +198,7 @@
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,
@@ -2407,6 +2408,7 @@
PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);
+PCM_CODEC(CODEC_ID_ADPCM_thp, adpcm_thp);
#undef PCM_CODEC
Index: libavcodec/adpcm.c
===================================================================
--- libavcodec/adpcm.c (revision 8597)
+++ libavcodec/adpcm.c (working copy)
@@ -144,6 +144,7 @@
int coeff1;
int coeff2;
int idelta;
+
} ADPCMChannelStatus;
typedef struct ADPCMContext {
@@ -1308,6 +1309,59 @@
src++;
}
break;
+ case CODEC_ID_ADPCM_THP:
+ {
+ GetBitContext gb;
+ float table[16][2];
+ int samplecnt;
+ int prev1[2], prev2[2];
+ int ch;
+
+ init_get_bits(&gb, src, buf_size);
+ src += buf_size;
+
+ get_bits(&gb, 32); /* Channel size */
+ samplecnt = get_bits(&gb, 32);
+
+ for (ch = 0; ch < 2; ch++)
+ for (i = 0; i < 16; i++) {
+ /* Read the fixed point entry and store as floating
+ point. */
+ int entry = get_sbits(&gb, 16);
+ table[i][ch] = (float) entry / pow(2, 11);
+ }
+
+ /* Initialize the previous sample. */
+ for (ch = 0; ch < 2; ch++) {
+ prev1[ch] = get_sbits(&gb, 16);
+ prev2[ch] = get_sbits(&gb, 16);
+ }
+
+ for (ch = 0; ch <= st; ch++) {
+ int sample = samplecnt;
+
+ /* Read in every sample for this channel. */
+ while (sample > 0) {
+ uint8_t index = get_bits (&gb, 4) & 7;
+ float exp = pow(2, get_bits (&gb, 4));
+ float factor1 = table[index * 2][ch];
+ float 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 + sampledat * exp;
+ prev2[ch] = prev1[ch];
+ prev1[ch] = *samples++;
+ sample--;
+ }
+ }
+ }
+
+ break;
+ }
+
default:
return -1;
}
@@ -1368,5 +1422,6 @@
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_DECODER(CODEC_ID_ADPCM_THP, adpcm_thp);
#undef ADPCM_CODEC
Index: doc/ffmpeg-doc.texi
===================================================================
--- doc/ffmpeg-doc.texi (revision 8597)
+++ doc/ffmpeg-doc.texi (working copy)
@@ -902,7 +902,7 @@
@tab This format is used in non-Windows version of Feeble Files game and
different game cutscenes repacked for use with ScummVM.
@item THP @tab @tab X
- at tab Used on the Nintendo GameCube (video only)
+ at tab Used on the Nintendo GameCube
@end multitable
@code{X} means that encoding (resp. decoding) is supported.
Index: libavformat/thp.c
===================================================================
--- libavformat/thp.c (revision 8597)
+++ libavformat/thp.c (working copy)
@@ -35,10 +35,12 @@
int next_frame;
int next_framesz;
int video_stream_index;
+ int audio_stream_index;
int compcount;
unsigned char components[16];
AVStream* vst;
int has_audio;
+ int audiosize;
} ThpDemuxContext;
@@ -116,7 +118,23 @@
get_be32(pb); /* Unknown. */
}
else if (thp->components[i] == 1) {
- /* XXX: Required for audio playback. */
+ if (thp->has_audio != 0)
+ break;
+
+ /* Audio component. */
+ st = av_new_stream(s, 0);
+ if (!st)
+ return AVERROR_NOMEM;
+
+ st->codec->codec_type = CODEC_TYPE_AUDIO;
+ st->codec->codec_id = CODEC_ID_ADPCM_THP;
+ st->codec->codec_tag = 0; /* no fourcc */
+ st->codec->channels = get_be32(pb); /* numChannels. */
+ st->codec->sample_rate = get_be32(pb); /* Frequency. */
+
+ av_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ thp->audio_stream_index = st->index;
thp->has_audio = 1;
}
}
@@ -132,6 +150,8 @@
int size;
int ret;
+ if (thp->audiosize == 0) {
+
/* Terminate when last frame is reached. */
if (thp->frame >= thp->framecnt)
return AVERROR_IO;
@@ -145,8 +165,12 @@
get_be32(pb); /* Previous total size. */
size = get_be32(pb); /* Total size of this frame. */
+ /* Store the audiosize so the next time this function is called,
+ the audio can be read. */
if (thp->has_audio)
- get_be32(pb); /* Audio size. */
+ thp->audiosize = get_be32(pb); /* Audio size. */
+ else
+ thp->frame++;
ret = av_get_packet(pb, pkt, size);
if (ret != size) {
@@ -155,8 +179,19 @@
}
pkt->stream_index = thp->video_stream_index;
- thp->frame++;
+ }
+ else {
+ ret = av_get_packet(pb, pkt, thp->audiosize);
+ if (ret != thp->audiosize) {
+ av_free_packet(pkt);
+ return AVERROR_IO;
+ }
+ pkt->stream_index = thp->audio_stream_index;
+ thp->audiosize = 0;
+ thp->frame++;
+ }
+
return 0;
}
More information about the ffmpeg-devel
mailing list