[FFmpeg-devel] [PATCH] Lego Mindstorms ADPCM IMA codec

Rafaël Carré rafael.carre
Tue Aug 3 09:34:32 CEST 2010


Add a new codec since it differs a bit from ADPCM IMA WAV
Pretend to support S16 sample format and do the conversion from/to U8,
so we can use existing code
Still untested on real Lego

Pretend to use S16 format instead of U8 so existing functions can be used as-is
---
 Changelog              |    2 +-
 configure              |    1 +
 doc/general.texi       |    1 +
 libavcodec/Makefile    |    2 ++
 libavcodec/adpcm.c     |   48 +++++++++++++++++++++++++++++++++++++++++++++++-
 libavcodec/allcodecs.c |    1 +
 libavcodec/avcodec.h   |    5 +++--
 libavcodec/utils.c     |    1 +
 libavformat/rso.c      |    2 +-
 libavformat/rsodec.c   |    5 -----
 libavformat/rsoenc.c   |    5 -----
 11 files changed, 58 insertions(+), 15 deletions(-)

diff --git a/Changelog b/Changelog
index eded417..8943d15 100644
--- a/Changelog
+++ b/Changelog
@@ -22,7 +22,7 @@ version <next>:
 - native GSM / GSM MS decoder
 - RTP depacketization of QDM2
 - ANSI/ASCII art playback system
-- Lego Mindstorms RSO de/muxer
+- Lego Mindstorms RSO de/muxer and associated ADPCM IMA codec
 - libavcore added
 - SubRip subtitle file muxer and demuxer
 - Chinese AVS encoding via libxavs
diff --git a/configure b/configure
index f546954..6cfe230 100755
--- a/configure
+++ b/configure
@@ -1417,6 +1417,7 @@ test_deps _encoder _decoder                                             \
     ac3                                                                 \
     adpcm_g726=g726                                                     \
     adpcm_ima_qt                                                        \
+    adpcm_ima_rso                                                       \
     adpcm_ima_wav                                                       \
     adpcm_ms                                                            \
     adpcm_swf                                                           \
diff --git a/doc/general.texi b/doc/general.texi
index bee34e4..df64da8 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -539,6 +539,7 @@ following image formats are supported:
 @item ADPCM IMA Electronic Arts SEAD  @tab     @tab  X
 @item ADPCM IMA Funcom       @tab     @tab  X
 @item ADPCM IMA QuickTime    @tab  X  @tab  X
+ at item ADPCM IMA RSO          @tab  X  @tab  X
 @item ADPCM IMA Loki SDL MJPEG  @tab     @tab  X
 @item ADPCM IMA WAV          @tab  X  @tab  X
 @item ADPCM IMA Westwood     @tab     @tab  X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index fc5a086..cb46e02 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -481,6 +481,8 @@ OBJS-$(CONFIG_ADPCM_IMA_EA_SEAD_DECODER)  += adpcm.o
 OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER)      += adpcm.o
 OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER)       += adpcm.o
 OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER)       += adpcm.o
+OBJS-$(CONFIG_ADPCM_IMA_RSO_DECODER)      += adpcm.o
+OBJS-$(CONFIG_ADPCM_IMA_RSO_ENCODER)      += adpcm.o
 OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER)   += adpcm.o
 OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER)      += adpcm.o
 OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER)      += adpcm.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index dbb57e5..d25a1ac 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -192,6 +192,11 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx)
     }
 
     switch(avctx->codec->id) {
+    case CODEC_ID_ADPCM_IMA_RSO:
+        s->status[0].prev_sample = 0;
+        s->status[0].step_index  = 0;
+        avctx->frame_size = 1;
+        break;
     case CODEC_ID_ADPCM_IMA_WAV:
         avctx->frame_size = (BLKSIZE - 4 * avctx->channels) * 8 / (4 * avctx->channels) + 1; /* each 16 bits sample gives one nibble */
                                                              /* and we have 4 bytes per channel overhead */
@@ -405,7 +410,7 @@ static void adpcm_compress_trellis(AVCodecContext *avctx, const short *samples,
                     next_##NAME:;
                     STORE_NODE(ms, FFMAX(16, (AdaptationTable[nibble] * step) >> 8));
                 }
-            } else if((version == CODEC_ID_ADPCM_IMA_WAV)|| (version == CODEC_ID_ADPCM_IMA_QT)|| (version == CODEC_ID_ADPCM_SWF)) {
+            } else if((version == CODEC_ID_ADPCM_IMA_WAV)|| (version == CODEC_ID_ADPCM_IMA_QT)|| (version == CODEC_ID_ADPCM_SWF)|| (version == CODEC_ID_ADPCM_IMA_RSO)) {
 #define LOOP_NODES(NAME, STEP_TABLE, STEP_INDEX)\
                 const int predictor = nodes[j]->sample1;\
                 const int div = (sample - predictor) * 4 / STEP_TABLE;\
@@ -482,6 +487,28 @@ static int adpcm_encode_frame(AVCodecContext *avctx,
 /*    n = (BLKSIZE - 4 * avctx->channels) / (2 * 8 * avctx->channels); */
 
     switch(avctx->codec->id) {
+    case CODEC_ID_ADPCM_IMA_RSO:
+        n = buf_size * 2; /* number of samples (4bits per sample) */
+
+        for(i=0; i<n; i++) {
+            samples[i] += 1<<15;                            /* s16 -> u16 */
+            samples[i] = (unsigned short)samples[i] >> 8;   /* u16 -> u8  */
+        }
+
+        if(avctx->trellis > 0) {
+            FF_ALLOC_OR_GOTO(avctx, buf, n, error);
+            adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n);
+            for(i=0; i<buf_size; i++) {
+                *dst++ = (buf[2*i] << 4) | buf[2*i+1];
+            }
+            av_free(buf);
+        } else {
+            while(buf_size--) {
+                *dst    = adpcm_ima_compress_sample(&c->status[0], *samples++) << 4;
+                *dst++ |= adpcm_ima_compress_sample(&c->status[0], *samples++);
+            }
+        }
+        break;
     case CODEC_ID_ADPCM_IMA_WAV:
         n = avctx->frame_size / 8;
             c->status[0].prev_sample = (signed short)samples[0]; /* XXX */
@@ -733,6 +760,10 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
             c->status[1].predictor = AV_RL32(avctx->extradata + 4);
         }
         break;
+    case CODEC_ID_ADPCM_IMA_RSO:
+        c->status[0].predictor  = 0;
+        c->status[0].step_index = 0;
+        break;
     default:
         break;
     }
@@ -1034,6 +1065,20 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
             src += 4*st;
         }
         break;
+    case CODEC_ID_ADPCM_IMA_RSO:
+        while(src < buf + buf_size){
+            short s;
+            s = adpcm_ima_expand_nibble(&c->status[0], *src >> 4    , 3);
+            s <<= 8;    /* u8  -> u16 */
+            s -= 1<<15; /* u16 -> s16 */
+            *samples++ = s;
+
+            s = adpcm_ima_expand_nibble(&c->status[0], *src++ & 0x0F, 3);
+            s <<= 8;    /* u8  -> u16 */
+            s -= 1<<15; /* u16 -> s16 */
+            *samples++ = s;
+        }
+        break;
     case CODEC_ID_ADPCM_4XM:
         cs = &(c->status[0]);
         c->status[0].predictor= (int16_t)bytestream_get_le16(&src);
@@ -1720,6 +1765,7 @@ ADPCM_DECODER(CODEC_ID_ADPCM_IMA_EA_EACS, adpcm_ima_ea_eacs, "ADPCM IMA Electron
 ADPCM_DECODER(CODEC_ID_ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead, "ADPCM IMA Electronic Arts SEAD");
 ADPCM_DECODER(CODEC_ID_ADPCM_IMA_ISS, adpcm_ima_iss, "ADPCM IMA Funcom ISS");
 ADPCM_CODEC  (CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt, "ADPCM IMA QuickTime");
+ADPCM_CODEC  (CODEC_ID_ADPCM_IMA_RSO, adpcm_ima_rso, "ADPCM IMA RSO");
 ADPCM_DECODER(CODEC_ID_ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg, "ADPCM IMA Loki SDL MJPEG");
 ADPCM_CODEC  (CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav, "ADPCM IMA WAV");
 ADPCM_DECODER(CODEC_ID_ADPCM_IMA_WS, adpcm_ima_ws, "ADPCM IMA Westwood");
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 83f075a..4c1ec87 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -323,6 +323,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER (ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead);
     REGISTER_DECODER (ADPCM_IMA_ISS, adpcm_ima_iss);
     REGISTER_ENCDEC  (ADPCM_IMA_QT, adpcm_ima_qt);
+    REGISTER_ENCDEC  (ADPCM_IMA_RSO, adpcm_ima_rso);
     REGISTER_DECODER (ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg);
     REGISTER_ENCDEC  (ADPCM_IMA_WAV, adpcm_ima_wav);
     REGISTER_DECODER (ADPCM_IMA_WS, adpcm_ima_ws);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index a38b630..67446bf 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -30,8 +30,8 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 52
-#define LIBAVCODEC_VERSION_MINOR 84
-#define LIBAVCODEC_VERSION_MICRO  2
+#define LIBAVCODEC_VERSION_MINOR 85
+#define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \
@@ -270,6 +270,7 @@ enum CodecID {
     CODEC_ID_ADPCM_EA_XAS,
     CODEC_ID_ADPCM_EA_MAXIS_XA,
     CODEC_ID_ADPCM_IMA_ISS,
+    CODEC_ID_ADPCM_IMA_RSO,
 
     /* AMR */
     CODEC_ID_AMR_NB= 0x12000,
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 1d12f69..9cd9c3c 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -1020,6 +1020,7 @@ int av_get_bits_per_sample(enum CodecID codec_id){
     case CODEC_ID_ADPCM_SBPRO_4:
     case CODEC_ID_ADPCM_CT:
     case CODEC_ID_ADPCM_IMA_WAV:
+    case CODEC_ID_ADPCM_IMA_RSO:
     case CODEC_ID_ADPCM_MS:
     case CODEC_ID_ADPCM_YAMAHA:
         return 4;
diff --git a/libavformat/rso.c b/libavformat/rso.c
index 178fd3f..586932d 100644
--- a/libavformat/rso.c
+++ b/libavformat/rso.c
@@ -25,6 +25,6 @@
 
 const AVCodecTag ff_codec_rso_tags[] = {
     { CODEC_ID_PCM_U8,          0x0100 },
-    { CODEC_ID_ADPCM_IMA_WAV,   0x0101 },
+    { CODEC_ID_ADPCM_IMA_RSO,   0x0101 },
     { CODEC_ID_NONE, 0 },
 };
diff --git a/libavformat/rsodec.c b/libavformat/rsodec.c
index fbcf918..ddeab28 100644
--- a/libavformat/rsodec.c
+++ b/libavformat/rsodec.c
@@ -42,11 +42,6 @@ static int rso_read_header(AVFormatContext *s, AVFormatParameters *ap)
 
     codec = ff_codec_get_id(ff_codec_rso_tags, id);
 
-    if (codec == CODEC_ID_ADPCM_IMA_WAV) {
-        av_log(s, AV_LOG_ERROR, "ADPCM in RSO not implemented\n");
-        return AVERROR_PATCHWELCOME;
-    }
-
     bps = av_get_bits_per_sample(codec);
     if (!bps) {
         av_log_ask_for_sample(s, "could not determine bits per sample\n");
diff --git a/libavformat/rsoenc.c b/libavformat/rsoenc.c
index 5e670f4..04fa365 100644
--- a/libavformat/rsoenc.c
+++ b/libavformat/rsoenc.c
@@ -49,11 +49,6 @@ static int rso_write_header(AVFormatContext *s)
         return AVERROR_INVALIDDATA;
     }
 
-    if (enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
-        av_log(s, AV_LOG_ERROR, "ADPCM in RSO not implemented\n");
-        return AVERROR_PATCHWELCOME;
-    }
-
     /* format header */
     put_be16(pb, enc->codec_tag);   /* codec ID */
     put_be16(pb, 0);                /* data size, will be written at EOF */
-- 
1.7.1





More information about the ffmpeg-devel mailing list