summaryrefslogtreecommitdiff
path: root/libavcodec/roqaudioenc.c
diff options
context:
space:
mode:
authorVitor Sessak <vitor1001@gmail.com>2007-05-07 08:55:27 +0000
committerBenoit Fouet <benoit.fouet@free.fr>2007-05-07 08:55:27 +0000
commitf025588bb6008600195184b733800f768ed8e025 (patch)
treebd79de60f4b89f0e5a25ed3cda8ae9fce5b60a21 /libavcodec/roqaudioenc.c
parentc53d2d90425e0abcca6ff96251bff84fc3993f80 (diff)
RoQ audio encoder
patch by Vitor vitor1001 gmail com Originally committed as revision 8922 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/roqaudioenc.c')
-rw-r--r--libavcodec/roqaudioenc.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/libavcodec/roqaudioenc.c b/libavcodec/roqaudioenc.c
new file mode 100644
index 0000000000..f76079e1d1
--- /dev/null
+++ b/libavcodec/roqaudioenc.c
@@ -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,
+};