ADPCM IMA Radical decoder
authorJames Almer <jamrial@gmail.com>
Fri, 10 May 2013 19:53:50 +0000 (16:53 -0300)
committerJames Almer <jamrial@gmail.com>
Fri, 10 May 2013 19:53:50 +0000 (16:53 -0300)
Signed-off-by: James Almer <jamrial@gmail.com>
12 files changed:
Changelog
doc/general.texi
libavcodec/Makefile
libavcodec/adpcm.c
libavcodec/allcodecs.c
libavcodec/avcodec.h
libavcodec/codec_desc.c
libavcodec/utils.c
libavcodec/version.h
libavformat/rsd.c
tests/fate/adpcm.mak
tests/ref/fate/adpcm-ima-rad [new file with mode: 0644]

index 41d84a4..98c0622 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -44,6 +44,7 @@ version <next>:
 - ADP demuxer
 - RSD demuxer
 - RedSpark demuxer
+- ADPCM IMA Radical decoder
 
 
 version 1.2:
index ff9858c..4f45497 100644 (file)
@@ -772,6 +772,7 @@ following image formats are supported:
     @tab Used in some Sega Saturn console games.
 @item ADPCM IMA Duck DK4     @tab     @tab  X
     @tab Used in some Sega Saturn console games.
+@item ADPCM IMA Radical      @tab     @tab  X
 @item ADPCM Microsoft        @tab  X  @tab  X
 @item ADPCM MS IMA           @tab  X  @tab  X
 @item ADPCM Nintendo Gamecube AFC  @tab     @tab  X
index 34fb5c5..4945592 100644 (file)
@@ -590,6 +590,7 @@ OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER)       += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER)       += adpcmenc.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_IMA_RAD_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER)   += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER)      += adpcmenc.o adpcm_data.o
index aa2a40f..1259bd4 100644 (file)
@@ -551,6 +551,11 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
             buf_size = FFMIN(buf_size, avctx->block_align);
         nb_samples = 1 + (buf_size - 4 * ch) * 2 / ch;
         break;
+    case AV_CODEC_ID_ADPCM_IMA_RAD:
+        if (avctx->block_align > 0)
+            buf_size = FFMIN(buf_size, avctx->block_align);
+        nb_samples = (buf_size - 4 * ch) * 2 / ch;
+        break;
     case AV_CODEC_ID_ADPCM_IMA_WAV:
         if (avctx->block_align > 0)
             buf_size = FFMIN(buf_size, avctx->block_align);
@@ -912,6 +917,31 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
             *samples++ = adpcm_ima_oki_expand_nibble(&c->status[st], v & 0x0F);
         }
         break;
+    case AV_CODEC_ID_ADPCM_IMA_RAD:
+        for (channel = 0; channel < avctx->channels; channel++) {
+            cs = &c->status[channel];
+            cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16);
+            cs->predictor  = sign_extend(bytestream2_get_le16u(&gb), 16);
+            if (cs->step_index > 88u){
+                av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n",
+                       channel, cs->step_index);
+                return AVERROR_INVALIDDATA;
+            }
+        }
+        for (n = 0; n < nb_samples / 2; n++) {
+            int byte[2];
+
+            byte[0] = bytestream2_get_byteu(&gb);
+            if (st)
+                byte[1] = bytestream2_get_byteu(&gb);
+            for(channel = 0; channel < avctx->channels; channel++) {
+                *samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] & 0x0F, 3);
+            }
+            for(channel = 0; channel < avctx->channels; channel++) {
+                *samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] >> 4  , 3);
+            }
+        }
+        break;
     case AV_CODEC_ID_ADPCM_IMA_WS:
         if (c->vqa_version == 3) {
             for (channel = 0; channel < avctx->channels; channel++) {
@@ -1489,6 +1519,7 @@ ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_EA_SEAD, sample_fmts_s16,  adpcm_ima_ea_sead
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_ISS,     sample_fmts_s16,  adpcm_ima_iss,     "ADPCM IMA Funcom ISS");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_OKI,     sample_fmts_s16,  adpcm_ima_oki,     "ADPCM IMA Dialogic OKI");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_QT,      sample_fmts_s16p, adpcm_ima_qt,      "ADPCM IMA QuickTime");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_RAD,     sample_fmts_s16,  adpcm_ima_rad,     "ADPCM IMA Radical");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_SMJPEG,  sample_fmts_s16,  adpcm_ima_smjpeg,  "ADPCM IMA Loki SDL MJPEG");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WAV,     sample_fmts_s16p, adpcm_ima_wav,     "ADPCM IMA WAV");
 ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WS,      sample_fmts_both, adpcm_ima_ws,      "ADPCM IMA Westwood");
index 145f7e4..4d5af67 100644 (file)
@@ -437,6 +437,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(ADPCM_IMA_ISS,     adpcm_ima_iss);
     REGISTER_DECODER(ADPCM_IMA_OKI,     adpcm_ima_oki);
     REGISTER_ENCDEC (ADPCM_IMA_QT,      adpcm_ima_qt);
+    REGISTER_DECODER(ADPCM_IMA_RAD,     adpcm_ima_rad);
     REGISTER_DECODER(ADPCM_IMA_SMJPEG,  adpcm_ima_smjpeg);
     REGISTER_ENCDEC (ADPCM_IMA_WAV,     adpcm_ima_wav);
     REGISTER_DECODER(ADPCM_IMA_WS,      adpcm_ima_ws);
index 8db0af4..21e5856 100644 (file)
@@ -363,6 +363,7 @@ enum AVCodecID {
     AV_CODEC_ID_ADPCM_AFC  = MKBETAG('A','F','C',' '),
     AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '),
     AV_CODEC_ID_ADPCM_DTK  = MKBETAG('D','T','K',' '),
+    AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '),
 
     /* AMR */
     AV_CODEC_ID_AMR_NB = 0x12000,
index a36aaad..b4fdd94 100644 (file)
@@ -1823,6 +1823,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube DTK"),
         .props     = AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_ADPCM_IMA_RAD,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "adpcm_ima_rad",
+        .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Radical"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     /* AMR */
     {
index 2040e6f..d647a23 100644 (file)
@@ -2883,6 +2883,8 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
                     return blocks * (((ba - 16) * 2 / 3 * 4) / ch);
                 case AV_CODEC_ID_ADPCM_IMA_DK4:
                     return blocks * (1 + (ba - 4 * ch) * 2 / ch);
+                case AV_CODEC_ID_ADPCM_IMA_RAD:
+                    return blocks * ((ba - 4 * ch) * 2 / ch);
                 case AV_CODEC_ID_ADPCM_MS:
                     return blocks * (2 + (ba - 7 * ch) * 2 / ch);
                 }
index e34e506..f5aa53b 100644 (file)
@@ -29,7 +29,7 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 55
-#define LIBAVCODEC_VERSION_MINOR  8
+#define LIBAVCODEC_VERSION_MINOR  9
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
index b935255..5b53cef 100644 (file)
@@ -27,6 +27,7 @@
 
 static const AVCodecTag rsd_tags[] = {
     { AV_CODEC_ID_ADPCM_THP,       MKTAG('G','A','D','P') },
+    { AV_CODEC_ID_ADPCM_IMA_RAD,   MKTAG('R','A','D','P') },
     { AV_CODEC_ID_PCM_S16BE,       MKTAG('P','C','M','B') },
     { AV_CODEC_ID_PCM_S16LE,       MKTAG('P','C','M',' ') },
     { AV_CODEC_ID_NONE, 0 },
@@ -34,7 +35,6 @@ static const AVCodecTag rsd_tags[] = {
 
 static const uint32_t rsd_unsupported_tags[] = {
     MKTAG('O','G','G',' '),
-    MKTAG('R','A','D','P'),
     MKTAG('V','A','G',' '),
     MKTAG('W','A','D','P'),
     MKTAG('X','A','D','P'),
@@ -92,6 +92,11 @@ static int rsd_read_header(AVFormatContext *s)
     avio_skip(pb, 4); // Unknown
 
     switch (codec->codec_id) {
+    case AV_CODEC_ID_ADPCM_IMA_RAD:
+        codec->block_align = 20 * codec->channels;
+        if (pb->seekable)
+            st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start);
+        break;
     case AV_CODEC_ID_ADPCM_THP:
         /* RSD3GADP is mono, so only alloc enough memory
            to store the coeff table for a single channel. */
@@ -131,12 +136,16 @@ static int rsd_read_header(AVFormatContext *s)
 
 static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
+    AVCodecContext *codec = s->streams[0]->codec;
     int ret, size = 1024;
 
     if (url_feof(s->pb))
         return AVERROR_EOF;
 
-    ret = av_get_packet(s->pb, pkt, size);
+    if (codec->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD)
+        ret = av_get_packet(s->pb, pkt, codec->block_align);
+    else
+        ret = av_get_packet(s->pb, pkt, size);
 
     if (ret != size) {
         if (ret < 0) {
index 280eb83..c87d7c9 100644 (file)
@@ -61,6 +61,9 @@ fate-adpcm-ima-iss: CMD = md5 -i $(SAMPLES)/funcom-iss/0004010100.iss -f s16le
 FATE_ADPCM-$(call DEMDEC, WAV, ADPCM_IMA_OKI) += fate-adpcm-ima-oki
 fate-adpcm-ima-oki: CMD = md5 -i $(SAMPLES)/oki/test.wav -f s16le
 
+FATE_ADPCM-$(call DEMDEC, RSD, ADPCM_IMA_RAD) += fate-adpcm-ima-rad
+fate-adpcm-ima-rad: CMD = md5 -i $(SAMPLES)/rsd/hit_run_partial.rsd -f s16le
+
 FATE_ADPCM-$(call DEMDEC, SMJPEG, ADPCM_IMA_SMJPEG) += fate-adpcm-ima-smjpeg
 fate-adpcm-ima-smjpeg: CMD = framecrc -i $(SAMPLES)/smjpeg/scenwin.mjpg -vn
 
diff --git a/tests/ref/fate/adpcm-ima-rad b/tests/ref/fate/adpcm-ima-rad
new file mode 100644 (file)
index 0000000..c5de1a6
--- /dev/null
@@ -0,0 +1 @@
+495f0ae514c28c6bdcbd40811a17e2a5