summaryrefslogtreecommitdiff
path: root/libavcodec/vc2enc_dwt.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/vc2enc_dwt.c')
-rw-r--r--libavcodec/vc2enc_dwt.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/libavcodec/vc2enc_dwt.c b/libavcodec/vc2enc_dwt.c
new file mode 100644
index 0000000000..c60b003a31
--- /dev/null
+++ b/libavcodec/vc2enc_dwt.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2007 Marco Gerards <marco@gnu.org>
+ * Copyright (C) 2016 Open Broadcast Systems Ltd.
+ * Author 2016 Rostislav Pehlivanov <atomnuker@gmail.com>
+ *
+ * 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 "libavutil/attributes.h"
+#include "libavutil/mem.h"
+#include "vc2enc_dwt.h"
+
+/* Since the transforms spit out interleaved coefficients, this function
+ * rearranges the coefficients into the more traditional subdivision,
+ * making it easier to encode and perform another level. */
+static av_always_inline void deinterleave(dwtcoef *linell, ptrdiff_t stride,
+ int width, int height, dwtcoef *synthl)
+{
+ int x, y;
+ ptrdiff_t synthw = width << 1;
+ dwtcoef *linehl = linell + width;
+ dwtcoef *linelh = linell + height*stride;
+ dwtcoef *linehh = linelh + width;
+
+ /* Deinterleave the coefficients. */
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ linell[x] = synthl[(x << 1)];
+ linehl[x] = synthl[(x << 1) + 1];
+ linelh[x] = synthl[(x << 1) + synthw];
+ linehh[x] = synthl[(x << 1) + synthw + 1];
+ }
+ synthl += synthw << 1;
+ linell += stride;
+ linelh += stride;
+ linehl += stride;
+ linehh += stride;
+ }
+}
+
+static void vc2_subband_dwt_97(VC2TransformContext *t, dwtcoef *data,
+ ptrdiff_t stride, int width, int height)
+{
+ int x, y;
+ dwtcoef *datal = data, *synth = t->buffer, *synthl = synth;
+ const ptrdiff_t synth_width = width << 1;
+ const ptrdiff_t synth_height = height << 1;
+
+ /*
+ * Shift in one bit that is used for additional precision and copy
+ * the data to the buffer.
+ */
+ for (y = 0; y < synth_height; y++) {
+ for (x = 0; x < synth_width; x++)
+ synthl[x] = datal[x] << 1;
+ synthl += synth_width;
+ datal += stride;
+ }
+
+ /* Horizontal synthesis. */
+ synthl = synth;
+ for (y = 0; y < synth_height; y++) {
+ /* Lifting stage 2. */
+ synthl[1] -= (8*synthl[0] + 9*synthl[2] - synthl[4] + 8) >> 4;
+ for (x = 1; x < width - 2; x++)
+ synthl[2*x + 1] -= (9*synthl[2*x] + 9*synthl[2*x + 2] - synthl[2*x + 4] -
+ synthl[2 * x - 2] + 8) >> 4;
+ synthl[synth_width - 1] -= (17*synthl[synth_width - 2] -
+ synthl[synth_width - 4] + 8) >> 4;
+ synthl[synth_width - 3] -= (8*synthl[synth_width - 2] +
+ 9*synthl[synth_width - 4] -
+ synthl[synth_width - 6] + 8) >> 4;
+ /* Lifting stage 1. */
+ synthl[0] += (synthl[1] + synthl[1] + 2) >> 2;
+ for (x = 1; x < width - 1; x++)
+ synthl[2*x] += (synthl[2*x - 1] + synthl[2*x + 1] + 2) >> 2;
+
+ synthl[synth_width - 2] += (synthl[synth_width - 3] +
+ synthl[synth_width - 1] + 2) >> 2;
+ synthl += synth_width;
+ }
+
+ /* Vertical synthesis: Lifting stage 2. */
+ synthl = synth + synth_width;
+ for (x = 0; x < synth_width; x++)
+ synthl[x] -= (8*synthl[x - synth_width] + 9*synthl[x + synth_width] -
+ synthl[x + 3 * synth_width] + 8) >> 4;
+
+ synthl = synth + (synth_width << 1);
+ for (y = 1; y < height - 2; y++) {
+ for (x = 0; x < synth_width; x++)
+ synthl[x + synth_width] -= (9*synthl[x] +
+ 9*synthl[x + 2 * synth_width] -
+ synthl[x - 2 * synth_width] -
+ synthl[x + 4 * synth_width] + 8) >> 4;
+ synthl += synth_width << 1;
+ }
+
+ synthl = synth + (synth_height - 1) * synth_width;
+ for (x = 0; x < synth_width; x++) {
+ synthl[x] -= (17*synthl[x - synth_width] -
+ synthl[x - 3*synth_width] + 8) >> 4;
+ synthl[x - 2*synth_width] -= (9*synthl[x - 3*synth_width] +
+ 8*synthl[x - 1*synth_width] - synthl[x - 5*synth_width] + 8) >> 4;
+ }
+
+ /* Vertical synthesis: Lifting stage 1. */
+ synthl = synth;
+ for (x = 0; x < synth_width; x++)
+ synthl[x] += (synthl[x + synth_width] + synthl[x + synth_width] + 2) >> 2;
+
+ synthl = synth + (synth_width << 1);
+ for (y = 1; y < height - 1; y++) {
+ for (x = 0; x < synth_width; x++)
+ synthl[x] += (synthl[x - synth_width] + synthl[x + synth_width] + 2) >> 2;
+ synthl += synth_width << 1;
+ }
+
+ synthl = synth + (synth_height - 2) * synth_width;
+ for (x = 0; x < synth_width; x++)
+ synthl[x] += (synthl[x - synth_width] + synthl[x + synth_width] + 2) >> 2;
+
+ deinterleave(data, stride, width, height, synth);
+}
+
+static void vc2_subband_dwt_53(VC2TransformContext *t, dwtcoef *data,
+ ptrdiff_t stride, int width, int height)
+{
+ int x, y;
+ dwtcoef *synth = t->buffer, *synthl = synth, *datal = data;
+ const ptrdiff_t synth_width = width << 1;
+ const ptrdiff_t synth_height = height << 1;
+
+ /*
+ * Shift in one bit that is used for additional precision and copy
+ * the data to the buffer.
+ */
+ for (y = 0; y < synth_height; y++) {
+ for (x = 0; x < synth_width; x++)
+ synthl[x] = datal[x] << 1;
+ synthl += synth_width;
+ datal += stride;
+ }
+
+ /* Horizontal synthesis. */
+ synthl = synth;
+ for (y = 0; y < synth_height; y++) {
+ /* Lifting stage 2. */
+ for (x = 0; x < width - 1; x++)
+ synthl[2 * x + 1] -= (synthl[2 * x] + synthl[2 * x + 2] + 1) >> 1;
+
+ synthl[synth_width - 1] -= (2*synthl[synth_width - 2] + 1) >> 1;
+
+ /* Lifting stage 1. */
+ synthl[0] += (2*synthl[1] + 2) >> 2;
+ for (x = 1; x < width - 1; x++)
+ synthl[2 * x] += (synthl[2 * x - 1] + synthl[2 * x + 1] + 2) >> 2;
+
+ synthl[synth_width - 2] += (synthl[synth_width - 3] + synthl[synth_width - 1] + 2) >> 2;
+
+ synthl += synth_width;
+ }
+
+ /* Vertical synthesis: Lifting stage 2. */
+ synthl = synth + synth_width;
+ for (x = 0; x < synth_width; x++)
+ synthl[x] -= (synthl[x - synth_width] + synthl[x + synth_width] + 1) >> 1;
+
+ synthl = synth + (synth_width << 1);
+ for (y = 1; y < height - 1; y++) {
+ for (x = 0; x < synth_width; x++)
+ synthl[x + synth_width] -= (synthl[x] + synthl[x + synth_width * 2] + 1) >> 1;
+ synthl += (synth_width << 1);
+ }
+
+ synthl = synth + (synth_height - 1) * synth_width;
+ for (x = 0; x < synth_width; x++)
+ synthl[x] -= (2*synthl[x - synth_width] + 1) >> 1;
+
+ /* Vertical synthesis: Lifting stage 1. */
+ synthl = synth;
+ for (x = 0; x < synth_width; x++)
+ synthl[x] += (2*synthl[synth_width + x] + 2) >> 2;
+
+ synthl = synth + (synth_width << 1);
+ for (y = 1; y < height - 1; y++) {
+ for (x = 0; x < synth_width; x++)
+ synthl[x] += (synthl[x + synth_width] + synthl[x - synth_width] + 2) >> 2;
+ synthl += (synth_width << 1);
+ }
+
+ synthl = synth + (synth_height - 2)*synth_width;
+ for (x = 0; x < synth_width; x++)
+ synthl[x] += (synthl[x - synth_width] + synthl[x + synth_width] + 2) >> 2;
+
+
+ deinterleave(data, stride, width, height, synth);
+}
+
+static av_always_inline void dwt_haar(VC2TransformContext *t, dwtcoef *data,
+ ptrdiff_t stride, int width, int height,
+ const int s)
+{
+ int x, y;
+ dwtcoef *synth = t->buffer, *synthl = synth, *datal = data;
+ const ptrdiff_t synth_width = width << 1;
+ const ptrdiff_t synth_height = height << 1;
+
+ /* Horizontal synthesis. */
+ for (y = 0; y < synth_height; y++) {
+ for (x = 0; x < synth_width; x += 2) {
+ synthl[y*synth_width + x + 1] = (datal[y*stride + x + 1] << s) -
+ (datal[y*stride + x] << s);
+ synthl[y*synth_width + x] = (datal[y*stride + x + 0] << s) +
+ ((synthl[y*synth_width + x + 1] + 1) >> 1);
+ }
+ }
+
+ /* Vertical synthesis. */
+ for (x = 0; x < synth_width; x++) {
+ for (y = 0; y < synth_height; y += 2) {
+ synthl[(y + 1)*synth_width + x] = synthl[(y + 1)*synth_width + x] -
+ synthl[y*synth_width + x];
+ synthl[y*synth_width + x] = synthl[y*synth_width + x] +
+ ((synthl[(y + 1)*synth_width + x] + 1) >> 1);
+ }
+ }
+
+ deinterleave(data, stride, width, height, synth);
+}
+
+static void vc2_subband_dwt_haar(VC2TransformContext *t, dwtcoef *data,
+ ptrdiff_t stride, int width, int height)
+{
+ dwt_haar(t, data, stride, width, height, 0);
+}
+
+static void vc2_subband_dwt_haar_shift(VC2TransformContext *t, dwtcoef *data,
+ ptrdiff_t stride, int width, int height)
+{
+ dwt_haar(t, data, stride, width, height, 1);
+}
+
+av_cold int ff_vc2enc_init_transforms(VC2TransformContext *s, int p_width, int p_height)
+{
+ s->vc2_subband_dwt[VC2_TRANSFORM_9_7] = vc2_subband_dwt_97;
+ s->vc2_subband_dwt[VC2_TRANSFORM_5_3] = vc2_subband_dwt_53;
+ s->vc2_subband_dwt[VC2_TRANSFORM_HAAR] = vc2_subband_dwt_haar;
+ s->vc2_subband_dwt[VC2_TRANSFORM_HAAR_S] = vc2_subband_dwt_haar_shift;
+
+ s->buffer = av_malloc(2*p_width*p_height*sizeof(dwtcoef));
+ if (!s->buffer)
+ return 1;
+
+ return 0;
+}
+
+av_cold void ff_vc2enc_free_transforms(VC2TransformContext *s)
+{
+ av_freep(&s->buffer);
+}