changeset 4932:7c6a0470eb63 libavcodec

RoQ audio encoder patch by Vitor vitor1001 gmail com
author benoit
date Mon, 07 May 2007 08:55:27 +0000
parents 0d1cc37d9430
children ed67837533b0
files Makefile allcodecs.c avcodec.h roqaudioenc.c
diffstat 4 files changed, 180 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon May 07 00:47:03 2007 +0000
+++ b/Makefile	Mon May 07 08:55:27 2007 +0000
@@ -125,6 +125,7 @@
 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
--- a/allcodecs.c	Mon May 07 00:47:03 2007 +0000
+++ b/allcodecs.c	Mon May 07 08:55:27 2007 +0000
@@ -226,7 +226,7 @@
 
     /* 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);
 
--- a/avcodec.h	Mon May 07 00:47:03 2007 +0000
+++ b/avcodec.h	Mon May 07 08:55:27 2007 +0000
@@ -2225,6 +2225,7 @@
 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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/roqaudioenc.c	Mon May 07 08:55:27 2007 +0000
@@ -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,
+};