RoQ audio encoder
authorVitor Sessak <vitor1001@gmail.com>
Mon, 7 May 2007 08:55:27 +0000 (08:55 +0000)
committerBenoit Fouet <benoit.fouet@free.fr>
Mon, 7 May 2007 08:55:27 +0000 (08:55 +0000)
patch by Vitor vitor1001 gmail com

Originally committed as revision 8922 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/avcodec.h
libavcodec/roqaudioenc.c [new file with mode: 0644]

index f7d85b81ec20a8e7d784047a6b7053cb250470a9..8cc3a01db85f5164973aae6575d37aaa61332d12 100644 (file)
@@ -125,6 +125,7 @@ OBJS-$(CONFIG_RA_144_DECODER)          += ra144.o
 OBJS-$(CONFIG_RA_288_DECODER)          += ra288.o
 OBJS-$(CONFIG_ROQ_DECODER)             += roqvideo.o
 OBJS-$(CONFIG_ROQ_DPCM_DECODER)        += dpcm.o
+OBJS-$(CONFIG_ROQ_DPCM_ENCODER)        += roqaudioenc.o
 OBJS-$(CONFIG_RPZA_DECODER)            += rpza.o
 OBJS-$(CONFIG_RV10_DECODER)            += rv10.o
 OBJS-$(CONFIG_RV10_ENCODER)            += rv10.o
index 28820654e1ee3b3082eb68c34177fa0a8c50ce10..e593a6e8f1c94beebcaccf68fed1581c55656bb5 100644 (file)
@@ -226,7 +226,7 @@ void avcodec_register_all(void)
 
     /* dpcm codecs */
     REGISTER_DECODER(INTERPLAY_DPCM, interplay_dpcm);
-    REGISTER_DECODER(ROQ_DPCM, roq_dpcm);
+    REGISTER_ENCDEC (ROQ_DPCM, roq_dpcm);
     REGISTER_DECODER(SOL_DPCM, sol_dpcm);
     REGISTER_DECODER(XAN_DPCM, xan_dpcm);
 
index dee12c245bbf23f917538b588de726763bd531be..29b15c7213e1962746759766ab7362e663eb6e74 100644 (file)
@@ -2225,6 +2225,7 @@ extern AVCodec pgm_encoder;
 extern AVCodec pgmyuv_encoder;
 extern AVCodec png_encoder;
 extern AVCodec ppm_encoder;
+extern AVCodec roq_dpcm_encoder;
 extern AVCodec rv10_encoder;
 extern AVCodec rv20_encoder;
 extern AVCodec sgi_encoder;
diff --git a/libavcodec/roqaudioenc.c b/libavcodec/roqaudioenc.c
new file mode 100644 (file)
index 0000000..f76079e
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * RoQ audio encoder
+ *
+ * Copyright (c) 2005 Eric Lasota
+ *    Based on RoQ specs (c)2001 Tim Ferguson
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "bytestream.h"
+
+#define ROQ_FIRST_FRAME_SIZE     (735*8)
+#define ROQ_FRAME_SIZE           735
+
+
+#define MAX_DPCM (127*127)
+static unsigned char dpcmValues[MAX_DPCM];
+
+
+typedef struct
+{
+    short lastSample[2];
+} ROQDPCMContext_t;
+
+static void roq_dpcm_table_init(void)
+{
+    int i;
+
+    /* Create a table of quick DPCM values */
+    for (i=0; i<MAX_DPCM; i++) {
+        int s= ff_sqrt(i);
+        int mid= s*s + s;
+        dpcmValues[i]= s + (i>mid);
+    }
+}
+
+static int roq_dpcm_encode_init(AVCodecContext *avctx)
+{
+    ROQDPCMContext_t *context = avctx->priv_data;
+
+    if (avctx->channels > 2) {
+        av_log(avctx, AV_LOG_ERROR, "Audio must be mono or stereo\n");
+        return -1;
+    }
+    if (avctx->sample_rate != 22050) {
+        av_log(avctx, AV_LOG_ERROR, "Audio must be 22050 Hz\n");
+        return -1;
+    }
+    if (avctx->sample_fmt != SAMPLE_FMT_S16) {
+        av_log(avctx, AV_LOG_ERROR, "Audio must be signed 16-bit\n");
+        return -1;
+    }
+
+    roq_dpcm_table_init();
+
+    avctx->frame_size = ROQ_FIRST_FRAME_SIZE;
+
+    context->lastSample[0] = context->lastSample[1] = 0;
+
+    avctx->coded_frame= avcodec_alloc_frame();
+    avctx->coded_frame->key_frame= 1;
+
+    return 0;
+}
+
+static unsigned char dpcm_predict(short *previous, short current)
+{
+    int diff;
+    int negative;
+    int result;
+    int predicted;
+
+    diff = current - *previous;
+
+    negative = diff<0;
+    diff = FFABS(diff);
+
+    if (diff >= MAX_DPCM)
+        result = 127;
+    else
+        result = dpcmValues[diff];
+
+    /* See if this overflows */
+ retry:
+    diff = result*result;
+    if (negative)
+        diff = -diff;
+    predicted = *previous + diff;
+
+    /* If it overflows, back off a step */
+    if (predicted > 32767 || predicted < -32768) {
+        result--;
+        goto retry;
+    }
+
+    /* Add the sign bit */
+    result |= negative << 7;   //if (negative) result |= 128;
+
+    *previous = predicted;
+
+    return result;
+}
+
+static int roq_dpcm_encode_frame(AVCodecContext *avctx,
+                unsigned char *frame, int buf_size, void *data)
+{
+    int i, samples, stereo, ch;
+    short *in;
+    unsigned char *out;
+
+    ROQDPCMContext_t *context = avctx->priv_data;
+
+    stereo = (avctx->channels == 2);
+
+    if (stereo) {
+        context->lastSample[0] &= 0xFF00;
+        context->lastSample[1] &= 0xFF00;
+    }
+
+    out = frame;
+    in = data;
+
+    bytestream_put_byte(&out, stereo ? 0x21 : 0x20);
+    bytestream_put_byte(&out, 0x10);
+    bytestream_put_le32(&out, avctx->frame_size*avctx->channels);
+
+    if (stereo) {
+        bytestream_put_byte(&out, (context->lastSample[1])>>8);
+        bytestream_put_byte(&out, (context->lastSample[0])>>8);
+    } else
+        bytestream_put_le16(&out, context->lastSample[0]);
+
+    /* Write the actual samples */
+    samples = avctx->frame_size;
+    for (i=0; i<samples; i++)
+        for (ch=0; ch<avctx->channels; ch++)
+            *out++ = dpcm_predict(&context->lastSample[ch], *in++);
+
+    /* Use smaller frames from now on */
+    avctx->frame_size = ROQ_FRAME_SIZE;
+
+    /* Return the result size */
+    return out - frame;
+}
+
+static int roq_dpcm_encode_close(AVCodecContext *avctx)
+{
+    av_freep(&avctx->coded_frame);
+
+    return 0;
+}
+
+AVCodec roq_dpcm_encoder = {
+    "roq_dpcm",
+    CODEC_TYPE_AUDIO,
+    CODEC_ID_ROQ_DPCM,
+    sizeof(ROQDPCMContext_t),
+    roq_dpcm_encode_init,
+    roq_dpcm_encode_frame,
+    roq_dpcm_encode_close,
+    NULL,
+};