flacdec: split off channel decorrelation as flacdsp
authorMans Rullgard <mans@mansr.com>
Sun, 17 Jun 2012 14:10:40 +0000 (15:10 +0100)
committerMans Rullgard <mans@mansr.com>
Wed, 4 Jul 2012 11:24:30 +0000 (12:24 +0100)
Signed-off-by: Mans Rullgard <mans@mansr.com>
libavcodec/Makefile
libavcodec/flacdec.c
libavcodec/flacdsp.c [new file with mode: 0644]
libavcodec/flacdsp.h [new file with mode: 0644]
libavcodec/flacdsp_template.c [new file with mode: 0644]

index efedee9..b23bc29 100644 (file)
@@ -158,7 +158,7 @@ OBJS-$(CONFIG_FFV1_DECODER)            += ffv1.o rangecoder.o
 OBJS-$(CONFIG_FFV1_ENCODER)            += ffv1.o rangecoder.o
 OBJS-$(CONFIG_FFVHUFF_DECODER)         += huffyuv.o
 OBJS-$(CONFIG_FFVHUFF_ENCODER)         += huffyuv.o
-OBJS-$(CONFIG_FLAC_DECODER)            += flacdec.o flacdata.o flac.o
+OBJS-$(CONFIG_FLAC_DECODER)            += flacdec.o flacdata.o flac.o flacdsp.o
 OBJS-$(CONFIG_FLAC_ENCODER)            += flacenc.o flacdata.o flac.o
 OBJS-$(CONFIG_FLASHSV_DECODER)         += flashsv.o
 OBJS-$(CONFIG_FLASHSV_ENCODER)         += flashsvenc.o
index ca6b4f2..daa5bd8 100644 (file)
@@ -42,6 +42,7 @@
 #include "golomb.h"
 #include "flac.h"
 #include "flacdata.h"
+#include "flacdsp.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -55,11 +56,12 @@ typedef struct FLACContext {
 
     int blocksize;                          ///< number of samples in the current frame
     int sample_shift;                       ///< shift required to make output samples 16-bit or 32-bit
-    int is32;                               ///< flag to indicate if output should be 32-bit instead of 16-bit
     int ch_mode;                            ///< channel decorrelation type in the current frame
     int got_streaminfo;                     ///< indicates if the STREAMINFO has been read
 
     int32_t *decoded[FLAC_MAX_CHANNELS];    ///< decoded samples
+
+    FLACDSPContext dsp;
 } FLACContext;
 
 static const int64_t flac_channel_layouts[6] = {
@@ -105,11 +107,9 @@ static void flac_set_bps(FLACContext *s)
     if (s->bps > 16) {
         s->avctx->sample_fmt = AV_SAMPLE_FMT_S32;
         s->sample_shift = 32 - s->bps;
-        s->is32 = 1;
     } else {
         s->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
         s->sample_shift = 16 - s->bps;
-        s->is32 = 0;
     }
 }
 
@@ -132,6 +132,7 @@ static av_cold int flac_decode_init(AVCodecContext *avctx)
     avpriv_flac_parse_streaminfo(avctx, (FLACStreaminfo *)s, streaminfo);
     allocate_buffers(s);
     flac_set_bps(s);
+    ff_flacdsp_init(&s->dsp, avctx->sample_fmt);
     s->got_streaminfo = 1;
 
     avcodec_get_frame_defaults(&s->frame);
@@ -231,6 +232,8 @@ static int parse_streaminfo(FLACContext *s, const uint8_t *buf, int buf_size)
     }
     avpriv_flac_parse_streaminfo(s->avctx, (FLACStreaminfo *)s, &buf[8]);
     allocate_buffers(s);
+    flac_set_bps(s);
+    ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt);
     s->got_streaminfo = 1;
 
     return 0;
@@ -548,6 +551,7 @@ static int decode_frame(FLACContext *s)
 
     if (!s->got_streaminfo) {
         allocate_buffers(s);
+        ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt);
         s->got_streaminfo = 1;
         dump_headers(s->avctx, (FLACStreaminfo *)s);
     }
@@ -574,9 +578,7 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
     FLACContext *s = avctx->priv_data;
-    int i, j = 0, bytes_read = 0;
-    int16_t *samples_16;
-    int32_t *samples_32;
+    int bytes_read = 0;
     int ret;
 
     *got_frame_ptr = 0;
@@ -616,42 +618,9 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return ret;
     }
-    samples_16 = (int16_t *)s->frame.data[0];
-    samples_32 = (int32_t *)s->frame.data[0];
-
-#define DECORRELATE(left, right)\
-            assert(s->channels == 2);\
-            for (i = 0; i < s->blocksize; i++) {\
-                int a= s->decoded[0][i];\
-                int b= s->decoded[1][i];\
-                if (s->is32) {\
-                    *samples_32++ = (left)  << s->sample_shift;\
-                    *samples_32++ = (right) << s->sample_shift;\
-                } else {\
-                    *samples_16++ = (left)  << s->sample_shift;\
-                    *samples_16++ = (right) << s->sample_shift;\
-                }\
-            }\
-            break;
-
-    switch (s->ch_mode) {
-    case FLAC_CHMODE_INDEPENDENT:
-        for (j = 0; j < s->blocksize; j++) {
-            for (i = 0; i < s->channels; i++) {
-                if (s->is32)
-                    *samples_32++ = s->decoded[i][j] << s->sample_shift;
-                else
-                    *samples_16++ = s->decoded[i][j] << s->sample_shift;
-            }
-        }
-        break;
-    case FLAC_CHMODE_LEFT_SIDE:
-        DECORRELATE(a,a-b)
-    case FLAC_CHMODE_RIGHT_SIDE:
-        DECORRELATE(a+b,b)
-    case FLAC_CHMODE_MID_SIDE:
-        DECORRELATE( (a-=b>>1) + b, a)
-    }
+
+    s->dsp.decorrelate[s->ch_mode](s->frame.data, s->decoded, s->channels,
+                                   s->blocksize, s->sample_shift);
 
     if (bytes_read > buf_size) {
         av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", bytes_read - buf_size);
diff --git a/libavcodec/flacdsp.c b/libavcodec/flacdsp.c
new file mode 100644 (file)
index 0000000..b7e0746
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/samplefmt.h"
+#include "flacdsp.h"
+
+#define SAMPLE_SIZE 16
+#include "flacdsp_template.c"
+
+#undef  SAMPLE_SIZE
+#define SAMPLE_SIZE 32
+#include "flacdsp_template.c"
+
+av_cold void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt)
+{
+    switch (fmt) {
+    case AV_SAMPLE_FMT_S32:
+        c->decorrelate[0] = flac_decorrelate_indep_c_32;
+        c->decorrelate[1] = flac_decorrelate_ls_c_32;
+        c->decorrelate[2] = flac_decorrelate_rs_c_32;
+        c->decorrelate[3] = flac_decorrelate_ms_c_32;
+        break;
+
+    case AV_SAMPLE_FMT_S16:
+        c->decorrelate[0] = flac_decorrelate_indep_c_16;
+        c->decorrelate[1] = flac_decorrelate_ls_c_16;
+        c->decorrelate[2] = flac_decorrelate_rs_c_16;
+        c->decorrelate[3] = flac_decorrelate_ms_c_16;
+        break;
+    }
+}
diff --git a/libavcodec/flacdsp.h b/libavcodec/flacdsp.h
new file mode 100644 (file)
index 0000000..bb289ee
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_FLACDSP_H
+#define AVCODEC_FLACDSP_H
+
+#include <stdint.h>
+#include "libavutil/samplefmt.h"
+
+typedef struct FLACDSPContext {
+    void (*decorrelate[4])(uint8_t **out, int32_t **in, int channels,
+                           int len, int shift);
+} FLACDSPContext;
+
+void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt);
+
+#endif /* AVCODEC_FLACDSP_H */
diff --git a/libavcodec/flacdsp_template.c b/libavcodec/flacdsp_template.c
new file mode 100644 (file)
index 0000000..34da5a6
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#undef FUNC
+#undef sample
+
+#if SAMPLE_SIZE == 32
+#   define FUNC(n) n ## _32
+#   define sample  int32_t
+#else
+#   define FUNC(n) n ## _16
+#   define sample  int16_t
+#endif
+
+static void FUNC(flac_decorrelate_indep_c)(uint8_t **out, int32_t **in,
+                                           int channels, int len, int shift)
+{
+    sample *samples = (sample *) out[0];
+    int i, j;
+
+    for (j = 0; j < len; j++)
+        for (i = 0; i < channels; i++)
+            *samples++ = in[i][j] << shift;
+}
+
+static void FUNC(flac_decorrelate_ls_c)(uint8_t **out, int32_t **in,
+                                        int channels, int len, int shift)
+{
+    sample *samples = (sample *) out[0];
+    int i;
+
+    for (i = 0; i < len; i++) {
+        int a = in[0][i];
+        int b = in[1][i];
+        *samples++ =  a      << shift;
+        *samples++ = (a - b) << shift;
+    }
+}
+
+static void FUNC(flac_decorrelate_rs_c)(uint8_t **out, int32_t **in,
+                                        int channels, int len, int shift)
+{
+    sample *samples = (sample *) out[0];
+    int i;
+
+    for (i = 0; i < len; i++) {
+        int a = in[0][i];
+        int b = in[1][i];
+        *samples++ = (a + b) << shift;
+        *samples++ =  b      << shift;
+    }
+}
+
+static void FUNC(flac_decorrelate_ms_c)(uint8_t **out, int32_t **in,
+                                        int channels, int len, int shift)
+{
+    sample *samples = (sample *) out[0];
+    int i;
+
+    for (i = 0; i < len; i++) {
+        int a = in[0][i];
+        int b = in[1][i];
+        a -= b >> 1;
+        *samples++ = (a + b) << shift;
+        *samples++ =  a      << shift;
+    }
+}