[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