DIRAC Decoder stable version, MMX support removed.
authormultiple authors <multiple@multiple.x>
Thu, 6 Oct 2011 15:57:17 +0000 (17:57 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 30 Oct 2011 20:50:08 +0000 (21:50 +0100)
Look for MMX_DISABLED to find the disabled functions.

Authors of this code are Marco Gerards <marco@gnu.org> and David Conrad <lessen42@gmail.com>
With changes from Jordi Ortiz <nenjordi@gmail.com>

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
19 files changed:
libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/dirac.c
libavcodec/dirac_arith.c [new file with mode: 0644]
libavcodec/dirac_arith.h [new file with mode: 0644]
libavcodec/diracdec.c [new file with mode: 0644]
libavcodec/diracdsp.c [new file with mode: 0644]
libavcodec/diracdsp.h [new file with mode: 0644]
libavcodec/dsputil.c
libavcodec/dwt.c
libavcodec/dwt.h
libavcodec/x86/Makefile
libavcodec/x86/diracdsp_mmx.c [new file with mode: 0644]
libavcodec/x86/diracdsp_mmx.h [new file with mode: 0644]
libavcodec/x86/diracdsp_yasm.asm [new file with mode: 0644]
libavcodec/x86/dsputil_mmx.c
libavcodec/x86/dwt.c [new file with mode: 0644]
libavcodec/x86/dwt.h [new file with mode: 0644]
libavcodec/x86/dwt_yasm.asm [new file with mode: 0644]

index 82d9cb2..b2c0c99 100644 (file)
@@ -111,6 +111,8 @@ OBJS-$(CONFIG_CSCD_DECODER)            += cscd.o
 OBJS-$(CONFIG_CYUV_DECODER)            += cyuv.o
 OBJS-$(CONFIG_DCA_DECODER)             += dca.o synth_filter.o dcadsp.o
 OBJS-$(CONFIG_DCA_ENCODER)             += dcaenc.o
+OBJS-$(CONFIG_DIRAC_DECODER)           += diracdec.o dirac.o diracdsp.o \
+                                          dirac_arith.o mpeg12data.o dwt.o
 OBJS-$(CONFIG_DFA_DECODER)             += dfa.o
 OBJS-$(CONFIG_DNXHD_DECODER)           += dnxhddec.o dnxhddata.o
 OBJS-$(CONFIG_DNXHD_ENCODER)           += dnxhdenc.o dnxhddata.o       \
index b0bba51..29ffe9f 100644 (file)
@@ -90,6 +90,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER (CLJR, cljr);
     REGISTER_DECODER (CSCD, cscd);
     REGISTER_DECODER (CYUV, cyuv);
+    REGISTER_DECODER (DIRAC, dirac);
     REGISTER_DECODER (DFA, dfa);
     REGISTER_ENCDEC  (DNXHD, dnxhd);
     REGISTER_ENCDEC  (DPX, dpx);
index e637c49..befb296 100644 (file)
@@ -58,6 +58,7 @@ static const dirac_source_params dirac_source_parameters_defaults[] = {
     { 7680, 4320, 1, 0, 1, 6,  1, 3840, 2160, 0, 0, 3, 3 },
 };
 
+//[DIRAC_STD] Table 10.4 Available preset pixel aspect ratio values
 static const AVRational dirac_preset_aspect_ratios[] = {
     {1, 1},
     {10, 11},
@@ -67,11 +68,13 @@ static const AVRational dirac_preset_aspect_ratios[] = {
     {4, 3},
 };
 
+//[DIRAC_STD] Values 9,10 of 10.3.5 Frame Rate. Table 10.3 Available preset frame rate values
 static const AVRational dirac_frame_rate[] = {
     {15000, 1001},
     {25, 2},
 };
 
+//[DIRAC_STD] This should be equivalent to Table 10.5 Available signal range presets
 static const struct {
     uint8_t             bitdepth;
     enum AVColorRange   color_range;
@@ -100,11 +103,13 @@ static const struct {
     { AVCOL_PRI_BT709,     AVCOL_SPC_BT709,   AVCOL_TRC_UNSPECIFIED /* DCinema */ },
 };
 
+//[DIRAC_STD] Table 10.2 Supported chroma sampling formats + Luma Offset
 static const enum PixelFormat dirac_pix_fmt[2][3] = {
     { PIX_FMT_YUV444P,  PIX_FMT_YUV422P,  PIX_FMT_YUV420P  },
     { PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P },
 };
 
+// [DIRAC_STD] 10.3 Parse Source Parameters. source_parameters(base_video_format)
 static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
                                    dirac_source_params *source)
 {
@@ -112,49 +117,51 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
     unsigned luma_depth = 8, luma_offset = 16;
     int idx;
 
-    if (get_bits1(gb)) {
-        source->width  = svq3_get_ue_golomb(gb);
-        source->height = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.2 Frame size. frame_size(video_params)
+    if (get_bits1(gb)) {   //[DIRAC_STD] custom_dimensions_flag
+      source->width  = svq3_get_ue_golomb(gb); //[DIRAC_STD] FRAME_WIDTH
+      source->height = svq3_get_ue_golomb(gb); //[DIRAC_STD] FRAME_HEIGHT
     }
 
-    // chroma subsampling
-    if (get_bits1(gb))
-        source->chroma_format = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.3 Chroma Sampling Format. chroma_sampling_format(video_params)
+    if (get_bits1(gb)) //[DIRAC_STD] custom_chroma_format_flag
+      source->chroma_format = svq3_get_ue_golomb(gb); //[DIRAC_STD] CHROMA_FORMAT_INDEX
     if (source->chroma_format > 2U) {
         av_log(avctx, AV_LOG_ERROR, "Unknown chroma format %d\n",
                source->chroma_format);
         return -1;
     }
 
-    if (get_bits1(gb))
-        source->interlaced = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.4 Scan Format. scan_format(video_params)
+    if (get_bits1(gb)) //[DIRAC_STD] custom_scan_format_flag
+      source->interlaced = svq3_get_ue_golomb(gb); //[DIRAC_STD] SOURCE_SAMPLING
     if (source->interlaced > 1U)
         return -1;
 
-    // frame rate
-    if (get_bits1(gb)) {
-        source->frame_rate_index = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.5 Frame Rate. frame_rate(video_params)
+    if (get_bits1(gb)) { //[DIRAC_STD] custom_frame_rate_flag
+      source->frame_rate_index = svq3_get_ue_golomb(gb);
 
         if (source->frame_rate_index > 10U)
             return -1;
 
         if (!source->frame_rate_index) {
-            frame_rate.num = svq3_get_ue_golomb(gb);
-            frame_rate.den = svq3_get_ue_golomb(gb);
+          frame_rate.num = svq3_get_ue_golomb(gb); //[DIRAC_STD] FRAME_RATE_NUMER
+          frame_rate.den = svq3_get_ue_golomb(gb); //[DIRAC_STD] FRAME_RATE_DENOM
         }
     }
-    if (source->frame_rate_index > 0) {
+    if (source->frame_rate_index > 0) { //[DIRAC_STD] preset_frame_rate(video_params,index)
         if (source->frame_rate_index <= 8)
-            frame_rate = avpriv_frame_rate_tab[source->frame_rate_index];
+            frame_rate = avpriv_frame_rate_tab[source->frame_rate_index]; //[DIRAC_STD] Table 10.3 values 1-8
         else
-            frame_rate = dirac_frame_rate[source->frame_rate_index-9];
+          frame_rate = dirac_frame_rate[source->frame_rate_index-9]; //[DIRAC_STD] Table 10.3 values 9-10
     }
     av_reduce(&avctx->time_base.num, &avctx->time_base.den,
               frame_rate.den, frame_rate.num, 1<<30);
 
-    // aspect ratio
-    if (get_bits1(gb)) {
-        source->aspect_ratio_index = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.6 Pixel Aspect Ratio. pixel_aspect_ratio(video_params)
+    if (get_bits1(gb)) { //[DIRAC_STD] custom_pixel_aspect_ratio_flag
+      source->aspect_ratio_index = svq3_get_ue_golomb(gb); //[DIRAC_STD] index
 
         if (source->aspect_ratio_index > 6U)
             return -1;
@@ -164,20 +171,22 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
             avctx->sample_aspect_ratio.den = svq3_get_ue_golomb(gb);
         }
     }
-    if (source->aspect_ratio_index > 0)
+    if (source->aspect_ratio_index > 0) //[DIRAC_STD] Take value from Table 10.4 Available preset pixel aspect ratio values
         avctx->sample_aspect_ratio =
                 dirac_preset_aspect_ratios[source->aspect_ratio_index-1];
 
-    if (get_bits1(gb)) {
-        source->clean_width        = svq3_get_ue_golomb(gb);
-        source->clean_height       = svq3_get_ue_golomb(gb);
-        source->clean_left_offset  = svq3_get_ue_golomb(gb);
-        source->clean_right_offset = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.7 Clean area. clean_area(video_params)
+    if (get_bits1(gb)) { //[DIRAC_STD] custom_clean_area_flag
+      source->clean_width        = svq3_get_ue_golomb(gb); //[DIRAC_STD] CLEAN_WIDTH
+      source->clean_height       = svq3_get_ue_golomb(gb); //[DIRAC_STD] CLEAN_HEIGHT
+      source->clean_left_offset  = svq3_get_ue_golomb(gb); //[DIRAC_STD] CLEAN_LEFT_OFFSET
+      source->clean_right_offset = svq3_get_ue_golomb(gb); //[DIRAC_STD] CLEAN_RIGHT_OFFSET
     }
 
-    // Override signal range.
-    if (get_bits1(gb)) {
-        source->pixel_range_index = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.8 Signal range. signal_range(video_params)
+    //[DIRAC_STD] WARNING: Some adaptation seemed to be done using the AVCOL_RANGE_MPEG/JPEG values
+    if (get_bits1(gb)) { //[DIRAC_STD] custom_signal_range_flag
+      source->pixel_range_index = svq3_get_ue_golomb(gb); //[DIRAC_STD] index
 
         if (source->pixel_range_index > 4U)
             return -1;
@@ -186,13 +195,13 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
         if (!source->pixel_range_index) {
             luma_offset = svq3_get_ue_golomb(gb);
             luma_depth  = av_log2(svq3_get_ue_golomb(gb))+1;
-            svq3_get_ue_golomb(gb); // chroma offset
+            svq3_get_ue_golomb(gb); // chroma offset //@Jordi: Why are these two ignored?
             svq3_get_ue_golomb(gb); // chroma excursion
 
             avctx->color_range = luma_offset ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
         }
     }
-    if (source->pixel_range_index > 0) {
+    if (source->pixel_range_index > 0) { //[DIRAC_STD] Take values from Table 10.5 Available signal range presets
         idx                = source->pixel_range_index-1;
         luma_depth         = pixel_range_presets[idx].bitdepth;
         avctx->color_range = pixel_range_presets[idx].color_range;
@@ -203,9 +212,9 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
 
     avctx->pix_fmt = dirac_pix_fmt[!luma_offset][source->chroma_format];
 
-    // color spec
-    if (get_bits1(gb)) {
-        idx = source->color_spec_index = svq3_get_ue_golomb(gb);
+    //[DIRAC_STD] 10.3.9 Colour specification. colour_spec(video_params)
+    if (get_bits1(gb)) { //[DIRAC_STD] custom_colour_spec_flag
+      idx = source->color_spec_index = svq3_get_ue_golomb(gb); //[DIRAC_STD] index
 
         if (source->color_spec_index > 4U)
             return -1;
@@ -215,12 +224,13 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
         avctx->color_trc       = dirac_color_presets[idx].color_trc;
 
         if (!source->color_spec_index) {
+          //[DIRAC_STD] 10.3.9.1 Color primaries
             if (get_bits1(gb)) {
                 idx = svq3_get_ue_golomb(gb);
                 if (idx < 3U)
                     avctx->color_primaries = dirac_primaries[idx];
             }
-
+            //[DIRAC_STD] 10.3.9.2 Color matrix
             if (get_bits1(gb)) {
                 idx = svq3_get_ue_golomb(gb);
                 if (!idx)
@@ -228,7 +238,7 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
                 else if (idx == 1)
                     avctx->colorspace = AVCOL_SPC_BT470BG;
             }
-
+            //[DIRAC_STD] 10.3.9.3 Transfer function
             if (get_bits1(gb) && !svq3_get_ue_golomb(gb))
                 avctx->color_trc = AVCOL_TRC_BT709;
         }
@@ -242,16 +252,20 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
     return 0;
 }
 
+//[DIRAC_SPEC] 10. Sequence Header. sequence_header()
 int avpriv_dirac_parse_sequence_header(AVCodecContext *avctx, GetBitContext *gb,
                                    dirac_source_params *source)
 {
     unsigned version_major;
     unsigned video_format, picture_coding_mode;
 
+    //[DIRAC_SPEC] 10.1 Parse Parameters. parse_parameters()
     version_major  = svq3_get_ue_golomb(gb);
     svq3_get_ue_golomb(gb); /* version_minor */
     avctx->profile = svq3_get_ue_golomb(gb);
     avctx->level   = svq3_get_ue_golomb(gb);
+    //[DIRAC_SPEC] sequence_header() -> base_video_format as defined in...
+    // ... 10.2 Base Video Format, table 10.1 Dirac predefined video formats
     video_format   = svq3_get_ue_golomb(gb);
 
     if (version_major < 2)
@@ -265,6 +279,7 @@ int avpriv_dirac_parse_sequence_header(AVCodecContext *avctx, GetBitContext *gb,
     // Fill in defaults for the source parameters.
     *source = dirac_source_parameters_defaults[video_format];
 
+    //[DIRAC_STD] 10.3 Source Parameters
     // Override the defaults.
     if (parse_source_parameters(avctx, gb, source))
         return -1;
@@ -274,6 +289,7 @@ int avpriv_dirac_parse_sequence_header(AVCodecContext *avctx, GetBitContext *gb,
 
     avcodec_set_dimensions(avctx, source->width, source->height);
 
+    //[DIRAC_STD] picture_coding_mode shall be 0 for fields and 1 for frames
     // currently only used to signal field coding
     picture_coding_mode = svq3_get_ue_golomb(gb);
     if (picture_coding_mode != 0) {
diff --git a/libavcodec/dirac_arith.c b/libavcodec/dirac_arith.c
new file mode 100644 (file)
index 0000000..ae40beb
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 Marco Gerards <marco@gnu.org>
+ * Copyright (C) 2009 David Conrad
+ *
+ * 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
+ */
+
+/**
+ * @file libavcodec/dirac_arith.c
+ * Arithmetic decoder for Dirac
+ * @author Marco Gerards <marco@gnu.org>
+ */
+
+#include "dirac_arith.h"
+
+const uint16_t ff_dirac_prob[256] = {
+    0,    2,    5,    8,    11,   15,   20,   24,
+    29,   35,   41,   47,   53,   60,   67,   74,
+    82,   89,   97,   106,  114,  123,  132,  141,
+    150,  160,  170,  180,  190,  201,  211,  222,
+    233,  244,  256,  267,  279,  291,  303,  315,
+    327,  340,  353,  366,  379,  392,  405,  419,
+    433,  447,  461,  475,  489,  504,  518,  533,
+    548,  563,  578,  593,  609,  624,  640,  656,
+    672,  688,  705,  721,  738,  754,  771,  788,
+    805,  822,  840,  857,  875,  892,  910,  928,
+    946,  964,  983,  1001, 1020, 1038, 1057, 1076,
+    1095, 1114, 1133, 1153, 1172, 1192, 1211, 1231,
+    1251, 1271, 1291, 1311, 1332, 1352, 1373, 1393,
+    1414, 1435, 1456, 1477, 1498, 1520, 1541, 1562,
+    1584, 1606, 1628, 1649, 1671, 1694, 1716, 1738,
+    1760, 1783, 1806, 1828, 1851, 1874, 1897, 1920,
+    1935, 1942, 1949, 1955, 1961, 1968, 1974, 1980,
+    1985, 1991, 1996, 2001, 2006, 2011, 2016, 2021,
+    2025, 2029, 2033, 2037, 2040, 2044, 2047, 2050,
+    2053, 2056, 2058, 2061, 2063, 2065, 2066, 2068,
+    2069, 2070, 2071, 2072, 2072, 2072, 2072, 2072,
+    2072, 2071, 2070, 2069, 2068, 2066, 2065, 2063,
+    2060, 2058, 2055, 2052, 2049, 2045, 2042, 2038,
+    2033, 2029, 2024, 2019, 2013, 2008, 2002, 1996,
+    1989, 1982, 1975, 1968, 1960, 1952, 1943, 1934,
+    1925, 1916, 1906, 1896, 1885, 1874, 1863, 1851,
+    1839, 1827, 1814, 1800, 1786, 1772, 1757, 1742,
+    1727, 1710, 1694, 1676, 1659, 1640, 1622, 1602,
+    1582, 1561, 1540, 1518, 1495, 1471, 1447, 1422,
+    1396, 1369, 1341, 1312, 1282, 1251, 1219, 1186,
+    1151, 1114, 1077, 1037, 995,  952,  906,  857,
+    805,  750,  690,  625,  553,  471,  376,  255
+};
+
+const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT] = {
+    [CTX_ZPZN_F1]   = CTX_ZP_F2,
+    [CTX_ZPNN_F1]   = CTX_ZP_F2,
+    [CTX_ZP_F2]     = CTX_ZP_F3,
+    [CTX_ZP_F3]     = CTX_ZP_F4,
+    [CTX_ZP_F4]     = CTX_ZP_F5,
+    [CTX_ZP_F5]     = CTX_ZP_F6,
+    [CTX_ZP_F6]     = CTX_ZP_F6,
+    [CTX_NPZN_F1]   = CTX_NP_F2,
+    [CTX_NPNN_F1]   = CTX_NP_F2,
+    [CTX_NP_F2]     = CTX_NP_F3,
+    [CTX_NP_F3]     = CTX_NP_F4,
+    [CTX_NP_F4]     = CTX_NP_F5,
+    [CTX_NP_F5]     = CTX_NP_F6,
+    [CTX_NP_F6]     = CTX_NP_F6,
+    [CTX_DELTA_Q_F] = CTX_DELTA_Q_F,
+};
+
+int16_t ff_dirac_prob_branchless[256][2];
+
+void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length)
+{
+    int i;
+    align_get_bits(gb);
+
+    length = FFMIN(length, get_bits_left(gb)/8);
+
+    c->bytestream     = gb->buffer + get_bits_count(gb)/8;
+    c->bytestream_end = c->bytestream + length;
+    skip_bits_long(gb, length*8);
+
+    c->low = 0;
+    for (i = 0; i < 4; i++) {
+        c->low <<= 8;
+        if (c->bytestream < c->bytestream_end)
+            c->low |= *c->bytestream++;
+        else
+            c->low |= 0xff;
+    }
+
+    c->counter = -16;
+    c->range   = 0xffff;
+
+    for (i = 0; i < 256; i++) {
+        ff_dirac_prob_branchless[i][0] =  ff_dirac_prob[255-i];
+        ff_dirac_prob_branchless[i][1] = -ff_dirac_prob[i];
+    }
+
+    for (i = 0; i < DIRAC_CTX_COUNT; i++)
+        c->contexts[i] = 0x8000;
+}
diff --git a/libavcodec/dirac_arith.h b/libavcodec/dirac_arith.h
new file mode 100644 (file)
index 0000000..d004724
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2007 Marco Gerards <marco@gnu.org>
+ * Copyright (C) 2009 David Conrad
+ *
+ * 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
+ */
+
+/**
+ * @file libavcodec/dirac_arith.h
+ * Arithmetic decoder for Dirac
+ * @author Marco Gerards <marco@gnu.org>
+ */
+
+#ifndef AVCODEC_DIRAC_ARITH_H
+#define AVCODEC_DIRAC_ARITH_H
+
+#include "bytestream.h"
+#include "get_bits.h"
+
+enum dirac_arith_contexts {
+    CTX_ZPZN_F1,
+    CTX_ZPNN_F1,
+    CTX_NPZN_F1,
+    CTX_NPNN_F1,
+    CTX_ZP_F2,
+    CTX_ZP_F3,
+    CTX_ZP_F4,
+    CTX_ZP_F5,
+    CTX_ZP_F6,
+    CTX_NP_F2,
+    CTX_NP_F3,
+    CTX_NP_F4,
+    CTX_NP_F5,
+    CTX_NP_F6,
+    CTX_COEFF_DATA,
+    CTX_SIGN_NEG,
+    CTX_SIGN_ZERO,
+    CTX_SIGN_POS,
+    CTX_ZERO_BLOCK,
+    CTX_DELTA_Q_F,
+    CTX_DELTA_Q_DATA,
+    CTX_DELTA_Q_SIGN,
+
+    DIRAC_CTX_COUNT
+};
+
+// Dirac resets the arith decoder between decoding various types of data,
+// so many contexts are never used simultaneously. Thus, we can reduce
+// the number of contexts needed by reusing them.
+#define CTX_SB_F1        CTX_ZP_F5
+#define CTX_SB_DATA      0
+#define CTX_PMODE_REF1   0
+#define CTX_PMODE_REF2   1
+#define CTX_GLOBAL_BLOCK 2
+#define CTX_MV_F1        CTX_ZP_F2
+#define CTX_MV_DATA      0
+#define CTX_DC_F1        CTX_ZP_F5
+#define CTX_DC_DATA      0
+
+typedef struct {
+    unsigned low;
+    uint16_t range;
+    int16_t  counter;
+
+    const uint8_t *bytestream;
+    const uint8_t *bytestream_end;
+
+    uint16_t contexts[DIRAC_CTX_COUNT];
+} DiracArith;
+
+extern const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT];
+extern const uint16_t ff_dirac_prob[256];
+extern int16_t ff_dirac_prob_branchless[256][2];
+
+static inline void renorm(DiracArith *c)
+{
+#if HAVE_FAST_CLZ
+    int shift = 14 - av_log2_16bit(c->range-1) + ((c->range-1)>>15);
+
+    c->low    <<= shift;
+    c->range  <<= shift;
+    c->counter += shift;
+#else
+    while (c->range <= 0x4000) {
+        c->low   <<= 1;
+        c->range <<= 1;
+        c->counter++;
+    }
+#endif
+}
+
+static inline void refill(DiracArith *c)
+{
+    int counter = c->counter;
+
+    if (counter >= 0) {
+        int new = bytestream_get_be16(&c->bytestream);
+
+        // the spec defines overread bits to be 1, and streams rely on this
+        if (c->bytestream > c->bytestream_end) {
+            new |= 0xff;
+            if (c->bytestream > c->bytestream_end+1)
+                new |= 0xff00;
+
+            c->bytestream = c->bytestream_end;
+        }
+
+        c->low += new << counter;
+        counter -= 16;
+    }
+    c->counter = counter;
+}
+
+static inline int dirac_get_arith_bit(DiracArith *c, int ctx)
+{
+    int prob_zero = c->contexts[ctx];
+    int range_times_prob, bit;
+    unsigned low = c->low;
+    int    range = c->range;
+
+    range_times_prob = (c->range * prob_zero) >> 16;
+
+#if HAVE_FAST_CMOV
+    low   -= range_times_prob << 16;
+    range -= range_times_prob;
+    bit = 0;
+    __asm__(
+        "cmpl   %5, %4 \n\t"
+        "setae  %b0    \n\t"
+        "cmovb  %3, %2 \n\t"
+        "cmovb  %5, %1 \n\t"
+        : "+q"(bit), "+r"(range), "+r"(low)
+        : "r"(c->low), "r"(c->low>>16),
+          "r"(range_times_prob)
+    );
+#else
+    bit = (low >> 16) >= range_times_prob;
+    if (bit) {
+        low   -= range_times_prob << 16;
+        range -= range_times_prob;
+    } else {
+        range  = range_times_prob;
+    }
+#endif
+
+    c->contexts[ctx] += ff_dirac_prob_branchless[prob_zero>>8][bit];
+    c->low   = low;
+    c->range = range;
+
+    renorm(c);
+    refill(c);
+    return bit;
+}
+
+static inline int dirac_get_arith_uint(DiracArith *c, int follow_ctx, int data_ctx)
+{
+    int ret = 1;
+    while (!dirac_get_arith_bit(c, follow_ctx)) {
+        ret <<= 1;
+        ret += dirac_get_arith_bit(c, data_ctx);
+        follow_ctx = ff_dirac_next_ctx[follow_ctx];
+    }
+    return ret-1;
+}
+
+static inline int dirac_get_arith_int(DiracArith *c, int follow_ctx, int data_ctx)
+{
+    int ret = dirac_get_arith_uint(c, follow_ctx, data_ctx);
+    if (ret && dirac_get_arith_bit(c, data_ctx+1))
+        ret = -ret;
+    return ret;
+}
+
+void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length);
+
+#endif /* AVCODEC_DIRAC_ARITH_H */
diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c
new file mode 100644 (file)
index 0000000..86c3619
--- /dev/null
@@ -0,0 +1,1876 @@
+/*
+ * Copyright (C) 2007 Marco Gerards <marco@gnu.org>
+ * Copyright (C) 2009 David Conrad
+ *
+ * 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
+ */
+
+/**
+ * @file libavcodec/diracdec.c
+ * Dirac Decoder
+ * @author Marco Gerards <marco@gnu.org>
+ */
+
+#include "avcodec.h"
+#include "dsputil.h"
+#include "get_bits.h"
+#include "bytestream.h"
+#include "golomb.h"
+#include "dirac_arith.h"
+#include "mpeg12data.h"
+#include "dwt.h"
+#include "dirac.h"
+#include "diracdsp.h"
+
+#undef printf
+
+/**
+ * The spec limits the number of wavelet decompositions to 4 for both
+ * level 1 (VC-2) and 128 (long-gop default).
+ * 5 decompositions is the maximum before >16-bit buffers are needed.
+ * Schroedinger allows this for DD 9,7 and 13,7 wavelets only, limiting
+ * the others to 4 decompositions (or 3 for the fidelity filter).
+ *
+ * We use this instead of MAX_DECOMPOSITIONS to save some memory.
+ */
+#define MAX_DWT_LEVELS 5
+
+/**
+ * The spec limits this to 3 for frame coding, but in practice can be as high as 6
+ */
+#define MAX_REFERENCE_FRAMES 8
+#define MAX_DELAY 5         ///< limit for main profile for frame coding (TODO: field coding)
+#define MAX_FRAMES (MAX_REFERENCE_FRAMES + MAX_DELAY + 1)
+#define MAX_QUANT 68        ///< max quant for VC-2
+#define MAX_BLOCKSIZE 32    ///< maximum xblen/yblen we support
+
+/**
+ * DiracBlock->ref flags, if set then the block does MC from the given ref
+ */
+#define DIRAC_REF_MASK_REF1   1
+#define DIRAC_REF_MASK_REF2   2
+#define DIRAC_REF_MASK_GLOBAL 4
+
+/**
+ * Value of Picture.reference when Picture is not a reference picture, but
+ * is held for delayed output.
+ */
+#define DELAYED_PIC_REF 4
+
+#define ff_emulated_edge_mc ff_emulated_edge_mc_8 //Fix: change the calls to this function regarding bit depth
+
+#define CALC_PADDING(size, depth) \
+         (((size + (1 << depth) - 1) >> depth) << depth)
+
+#define DIVRNDUP(a, b) (((a) + (b) - 1) / (b))
+
+typedef struct {
+  //FF_COMMON_FRAME
+  AVFrame avframe;
+
+  int interpolated[3];    ///< 1 if hpel[] is valid
+  uint8_t *hpel[3][4];
+  uint8_t *hpel_base[3][4];
+} DiracFrame;
+
+typedef struct {
+    union {
+        int16_t mv[2][2];
+        int16_t dc[3];
+    } u; // anonymous unions aren't in C99 :(
+    uint8_t ref;
+} DiracBlock;
+
+typedef struct SubBand {
+    int level;
+    int orientation;
+    int stride;
+    int width;
+    int height;
+    int quant;
+    IDWTELEM *ibuf;
+    struct SubBand *parent;
+
+    // for low delay
+    unsigned length;
+    const uint8_t *coeff_data;
+} SubBand;
+
+typedef struct Plane {
+    int width;
+    int height;
+    int stride;
+
+    int idwt_width;
+    int idwt_height;
+    int idwt_stride;
+    IDWTELEM *idwt_buf;
+    IDWTELEM *idwt_buf_base;
+    IDWTELEM *idwt_tmp;
+
+    // block length
+    uint8_t xblen;
+    uint8_t yblen;
+    // block separation (block n+1 starts after this many pixels in block n)
+    uint8_t xbsep;
+    uint8_t ybsep;
+    // amount of overspill on each edge (half of the overlap between blocks)
+    uint8_t xoffset;
+    uint8_t yoffset;
+
+    SubBand band[MAX_DWT_LEVELS][4];
+} Plane;
+
+typedef struct DiracContext {
+    AVCodecContext *avctx;
+    DSPContext dsp;
+    DiracDSPContext diracdsp;
+    GetBitContext gb;
+    dirac_source_params source;
+    int seen_sequence_header;
+    int frame_number;           ///< number of the next frame to display
+    Plane plane[3];
+    int chroma_x_shift;
+    int chroma_y_shift;
+
+    int zero_res;               ///< zero residue flag
+    int is_arith;               ///< whether coeffs use arith or golomb coding
+    int low_delay;              ///< use the low delay syntax
+    int globalmc_flag;          ///< use global motion compensation
+    int num_refs;               ///< number of reference pictures
+
+    // wavelet decoding
+    unsigned wavelet_depth;     ///< depth of the IDWT
+    unsigned wavelet_idx;
+
+    /**
+     * schroedinger older than 1.0.8 doesn't store
+     * quant delta if only one codebook exists in a band
+     */
+    unsigned old_delta_quant;
+    unsigned codeblock_mode;
+
+    struct {
+        unsigned width;
+        unsigned height;
+    } codeblock[MAX_DWT_LEVELS+1];
+
+    struct {
+        unsigned num_x;         ///< number of horizontal slices
+        unsigned num_y;         ///< number of vertical slices
+        AVRational bytes;       ///< average bytes per slice
+      uint8_t quant[MAX_DWT_LEVELS][4]; //[DIRAC_STD] E.1
+    } lowdelay;
+
+    struct {
+        int pan_tilt[2];        ///< pan/tilt vector
+        int zrs[2][2];          ///< zoom/rotate/shear matrix
+        int perspective[2];     ///< perspective vector
+        unsigned zrs_exp;
+        unsigned perspective_exp;
+    } globalmc[2];
+
+    // motion compensation
+  uint8_t mv_precision; //[DIRAC_STD] REFS_WT_PRECISION
+  int16_t weight[2]; ////[DIRAC_STD] REF1_WT and REF2_WT
+  unsigned weight_log2denom; ////[DIRAC_STD] REFS_WT_PRECISION
+
+    int blwidth;            ///< number of blocks (horizontally)
+    int blheight;           ///< number of blocks (vertically)
+    int sbwidth;            ///< number of superblocks (horizontally)
+    int sbheight;           ///< number of superblocks (vertically)
+
+    uint8_t *sbsplit;
+    DiracBlock *blmotion;
+
+    uint8_t *edge_emu_buffer[4];
+    uint8_t *edge_emu_buffer_base;
+
+    uint16_t *mctmp;        ///< buffer holding the MC data multipled by OBMC weights
+    uint8_t *mcscratch;
+
+    DECLARE_ALIGNED(16, uint8_t, obmc_weight)[3][MAX_BLOCKSIZE*MAX_BLOCKSIZE];
+
+    void (*put_pixels_tab[4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+    void (*avg_pixels_tab[4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+    void (*add_obmc)(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+    dirac_weight_func weight_func;
+    dirac_biweight_func biweight_func;
+
+    DiracFrame *current_picture;
+    DiracFrame *ref_pics[2];
+
+    DiracFrame *ref_frames[MAX_REFERENCE_FRAMES+1];
+    DiracFrame *delay_frames[MAX_DELAY+1];
+    DiracFrame all_frames[MAX_FRAMES];
+} DiracContext;
+
+// [DIRAC_STD] Parse code values. 9.6.1 Table 9.1
+enum dirac_parse_code {
+    pc_seq_header         = 0x00,
+    pc_eos                = 0x10,
+    pc_aux_data           = 0x20,
+    pc_padding            = 0x30,
+};
+
+enum dirac_subband {
+    subband_ll = 0,
+    subband_hl = 1,
+    subband_lh = 2,
+    subband_hh = 3
+};
+
+static const uint8_t default_qmat[][4][4] = {
+    { { 5,  3,  3,  0}, { 0,  4,  4,  1}, { 0,  5,  5,  2}, { 0,  6,  6,  3} },
+    { { 4,  2,  2,  0}, { 0,  4,  4,  2}, { 0,  5,  5,  3}, { 0,  7,  7,  5} },
+    { { 5,  3,  3,  0}, { 0,  4,  4,  1}, { 0,  5,  5,  2}, { 0,  6,  6,  3} },
+    { { 8,  4,  4,  0}, { 0,  4,  4,  0}, { 0,  4,  4,  0}, { 0,  4,  4,  0} },
+    { { 8,  4,  4,  0}, { 0,  4,  4,  0}, { 0,  4,  4,  0}, { 0,  4,  4,  0} },
+    { { 0,  4,  4,  8}, { 0,  8,  8, 12}, { 0, 13, 13, 17}, { 0, 17, 17, 21} },
+    { { 3,  1,  1,  0}, { 0,  4,  4,  2}, { 0,  6,  6,  5}, { 0,  9,  9,  7} },
+};
+
+static const int qscale_tab[MAX_QUANT+1] = {
+        4,     5,     6,     7,     8,    10,    11,    13,
+       16,    19,    23,    27,    32,    38,    45,    54,
+       64,    76,    91,   108,   128,   152,   181,   215,
+      256,   304,   362,   431,   512,   609,   724,   861,
+     1024,  1218,  1448,  1722,  2048,  2435,  2896,  3444,
+     4096,  4871,  5793,  6889,  8192,  9742, 11585, 13777,
+    16384, 19484, 23170, 27554, 32768, 38968, 46341, 55109,
+    65536, 77936
+};
+
+static const int qoffset_intra_tab[MAX_QUANT+1] = {
+        1,     2,     3,     4,     4,     5,     6,     7,
+        8,    10,    12,    14,    16,    19,    23,    27,
+       32,    38,    46,    54,    64,    76,    91,   108,
+      128,   152,   181,   216,   256,   305,   362,   431,
+      512,   609,   724,   861,  1024,  1218,  1448,  1722,
+     2048,  2436,  2897,  3445,  4096,  4871,  5793,  6889,
+     8192,  9742, 11585, 13777, 16384, 19484, 23171, 27555,
+    32768, 38968
+};
+
+static const int qoffset_inter_tab[MAX_QUANT+1] = {
+        1,     2,     2,     3,     3,     4,     4,     5,
+        6,     7,     9,    10,    12,    14,    17,    20,
+       24,    29,    34,    41,    48,    57,    68,    81,
+       96,   114,   136,   162,   192,   228,   272,   323,
+      384,   457,   543,   646,   768,   913,  1086,  1292,
+     1536,  1827,  2172,  2583,  3072,  3653,  4344,  5166,
+     6144,  7307,  8689, 10333, 12288, 14613, 17378, 20666,
+    24576, 29226
+};
+
+// magic number division by 3 from schroedinger
+static inline int divide3(int x)
+{
+    return ((x+1)*21845 + 10922) >> 16;
+}
+
+static DiracFrame *remove_frame(DiracFrame *framelist[], int picnum)
+{
+    DiracFrame *remove_pic = NULL;
+    int i, remove_idx = -1;
+
+    for (i = 0; framelist[i]; i++)
+        if (framelist[i]->avframe.display_picture_number == picnum) {
+            remove_pic = framelist[i];
+            remove_idx = i;
+        }
+
+    if (remove_pic)
+        for (i = remove_idx; framelist[i]; i++)
+            framelist[i] = framelist[i+1];
+
+    return remove_pic;
+}
+
+static int add_frame(DiracFrame *framelist[], int maxframes, DiracFrame *frame)
+{
+    int i;
+    for (i = 0; i < maxframes; i++)
+        if (!framelist[i]) {
+            framelist[i] = frame;
+            return 0;
+        }
+    return -1;
+}
+
+static int alloc_sequence_buffers(DiracContext *s)
+{
+    int sbwidth  = DIVRNDUP(s->source.width,  4);
+    int sbheight = DIVRNDUP(s->source.height, 4);
+    int i, w, h, top_padding;
+
+    // todo: think more about this / use or set Plane here
+    for (i = 0; i < 3; i++) {
+        int max_xblen = MAX_BLOCKSIZE >> (i ? s->chroma_x_shift : 0);
+        int max_yblen = MAX_BLOCKSIZE >> (i ? s->chroma_y_shift : 0);
+        w = s->source.width  >> (i ? s->chroma_x_shift : 0);
+        h = s->source.height >> (i ? s->chroma_y_shift : 0);
+
+        // we allocate the max we support here since num decompositions can
+        // change from frame to frame. Stride is aligned to 16 for SIMD, and
+        // 1<<MAX_DWT_LEVELS top padding to avoid if(y>0) in arith decoding
+        // MAX_BLOCKSIZE padding for MC: blocks can spill up to half of that
+        // on each side
+        top_padding = FFMAX(1<<MAX_DWT_LEVELS, max_yblen/2);
+        w = FFALIGN(CALC_PADDING(w, MAX_DWT_LEVELS), 8); //FIXME: Should this be 16 for SSE???
+        h = top_padding + CALC_PADDING(h, MAX_DWT_LEVELS) + max_yblen/2;
+
+        s->plane[i].idwt_buf_base = av_mallocz((w+max_xblen)*h * sizeof(IDWTELEM));
+        s->plane[i].idwt_tmp      = av_malloc((w+16) * sizeof(IDWTELEM));
+        s->plane[i].idwt_buf      = s->plane[i].idwt_buf_base + top_padding*w;
+        if (!s->plane[i].idwt_buf_base || !s->plane[i].idwt_tmp)
+            return AVERROR(ENOMEM);
+    }
+
+    w = s->source.width;
+    h = s->source.height;
+
+    // fixme: allocate using real stride here
+    s->sbsplit  = av_malloc(sbwidth * sbheight);
+    s->blmotion = av_malloc(sbwidth * sbheight * 4 * sizeof(*s->blmotion));
+    s->edge_emu_buffer_base = av_malloc((w+64)*MAX_BLOCKSIZE);
+
+    s->mctmp    = av_malloc((w+64+MAX_BLOCKSIZE) * (h*MAX_BLOCKSIZE) * sizeof(*s->mctmp));
+    s->mcscratch= av_malloc((w+64)*MAX_BLOCKSIZE);
+
+    if (!s->sbsplit || !s->blmotion)
+        return AVERROR(ENOMEM);
+    return 0;
+}
+
+static void free_sequence_buffers(DiracContext *s)
+{
+    int i, j, k;
+
+    for (i = 0; i < MAX_FRAMES; i++) {
+        if (s->all_frames[i].avframe.data[0]) {
+            s->avctx->release_buffer(s->avctx, &s->all_frames[i].avframe);
+            memset(s->all_frames[i].interpolated, 0, sizeof(s->all_frames[i].interpolated));
+        }
+
+        for (j = 0; j < 3; j++)
+            for (k = 1; k < 4; k++)
+                av_freep(&s->all_frames[i].hpel_base[j][k]);
+    }
+
+    memset(s->ref_frames, 0, sizeof(s->ref_frames));
+    memset(s->delay_frames, 0, sizeof(s->delay_frames));
+
+    for (i = 0; i < 3; i++) {
+        av_freep(&s->plane[i].idwt_buf_base);
+        av_freep(&s->plane[i].idwt_tmp);
+    }
+
+    av_freep(&s->sbsplit);
+    av_freep(&s->blmotion);
+    av_freep(&s->edge_emu_buffer_base);
+
+    av_freep(&s->mctmp);
+    av_freep(&s->mcscratch);
+}
+
+static av_cold int dirac_decode_init(AVCodecContext *avctx)
+{
+    DiracContext *s = avctx->priv_data;
+    s->avctx = avctx;
+    s->frame_number = -1;
+
+    if (avctx->flags&CODEC_FLAG_EMU_EDGE) {
+        av_log(avctx, AV_LOG_ERROR, "Edge emulation not supported!\n");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    dsputil_init(&s->dsp, avctx);
+    ff_diracdsp_init(&s->diracdsp);
+
+    return 0;
+}
+
+static void dirac_decode_flush(AVCodecContext *avctx)
+{
+    DiracContext *s = avctx->priv_data;
+    free_sequence_buffers(s);
+    s->seen_sequence_header = 0;
+    s->frame_number = -1;
+}
+
+static av_cold int dirac_decode_end(AVCodecContext *avctx)
+{
+    dirac_decode_flush(avctx);
+    return 0;
+}
+
+#define SIGN_CTX(x) (CTX_SIGN_ZERO + ((x) > 0) - ((x) < 0))
+
+static inline void coeff_unpack_arith(DiracArith *c, int qfactor, int qoffset,
+                                      SubBand *b, IDWTELEM *buf, int x, int y)
+{
+    int coeff, sign;
+    int sign_pred = 0;
+    int pred_ctx = CTX_ZPZN_F1;
+
+    // Check if the parent subband has a 0 in the corresponding position
+    if (b->parent)
+        pred_ctx += !!b->parent->ibuf[b->parent->stride * (y>>1) + (x>>1)] << 1;
+
+    if (b->orientation == subband_hl)
+        sign_pred = buf[-b->stride];
+
+    // Determine if the pixel has only zeros in its neighbourhood
+    if (x) {
+        pred_ctx += !(buf[-1] | buf[-b->stride] | buf[-1-b->stride]);
+        if (b->orientation == subband_lh)
+            sign_pred = buf[-1];
+    } else {
+        pred_ctx += !buf[-b->stride];
+    }
+
+    coeff = dirac_get_arith_uint(c, pred_ctx, CTX_COEFF_DATA);
+    if (coeff) {
+        coeff = (coeff*qfactor + qoffset + 2)>>2;
+        sign = dirac_get_arith_bit(c, SIGN_CTX(sign_pred));
+        coeff = (coeff ^ -sign) + sign;
+    }
+    *buf = coeff;
+}
+
+static inline int coeff_unpack_golomb(GetBitContext *gb, int qfactor, int qoffset)
+{
+    int sign, coeff;
+
+    coeff = svq3_get_ue_golomb(gb);
+    if (coeff) {
+        coeff = (coeff*qfactor + qoffset + 2)>>2;
+        sign = get_bits1(gb);
+        coeff = (coeff ^ -sign) + sign;
+    }
+    return coeff;
+}
+
+/**
+ * Decode the coeffs in the rectangle defined by left, right, top, bottom
+ * [DIRAC_STD] 13.4.3.2 Codeblock unpacking loop. codeblock()
+ */
+static inline void codeblock(DiracContext *s, SubBand *b,
+                             GetBitContext *gb, DiracArith *c,
+                             int left, int right, int top, int bottom,
+                             int blockcnt_one, int is_arith)
+{
+    int x, y, zero_block;
+    int qoffset, qfactor;
+    IDWTELEM *buf;
+
+    // check for any coded coefficients in this codeblock
+    if (!blockcnt_one) {
+        if (is_arith)
+            zero_block = dirac_get_arith_bit(c, CTX_ZERO_BLOCK);
+        else
+            zero_block = get_bits1(gb);
+
+        if (zero_block)
+            return;
+    }
+
+    if (s->codeblock_mode && !(s->old_delta_quant && blockcnt_one)) {
+        if (is_arith)
+            b->quant += dirac_get_arith_int(c, CTX_DELTA_Q_F, CTX_DELTA_Q_DATA);
+        else
+            b->quant += dirac_get_se_golomb(gb);
+    }
+
+    b->quant = FFMIN(b->quant, MAX_QUANT);
+
+    qfactor = qscale_tab[b->quant];
+    // TODO: context pointer?
+    if (!s->num_refs)
+        qoffset = qoffset_intra_tab[b->quant];
+    else
+        qoffset = qoffset_inter_tab[b->quant];
+
+    buf = b->ibuf + top*b->stride;
+    for (y = top; y < bottom; y++) {
+        for (x = left; x < right; x++) {
+          //[DIRAC_STD] 13.4.4 Subband coefficients. coeff_unpack()
+            if (is_arith)
+                coeff_unpack_arith(c, qfactor, qoffset, b, buf+x, x, y);
+            else
+                buf[x] = coeff_unpack_golomb(gb, qfactor, qoffset);
+        }
+        buf += b->stride;
+    }
+}
+
+//[DIRAC_STD] 13.3 intra_dc_prediction(band)
+static inline void intra_dc_prediction(SubBand *b)
+{
+    IDWTELEM *buf = b->ibuf;
+    int x, y;
+
+    for (x = 1; x < b->width; x++)
+        buf[x] += buf[x-1];
+    buf += b->stride;
+
+    for (y = 1; y < b->height; y++) {
+        buf[0] += buf[-b->stride];
+
+        for (x = 1; x < b->width; x++) {
+            int pred = buf[x - 1] + buf[x - b->stride] + buf[x - b->stride-1];
+            buf[x] += divide3(pred);
+        }
+        buf += b->stride;
+    }
+}
+
+//[DIRAC_STD] 13.4.2 Non-skipped subbands.  subband_coeffs()
+static av_always_inline
+void decode_subband_internal(DiracContext *s, SubBand *b, int is_arith)
+{
+    int cb_x, cb_y, left, right, top, bottom;
+    DiracArith c;
+    GetBitContext gb;
+    int cb_width  = s->codeblock[b->level + (b->orientation != subband_ll)].width;
+    int cb_height = s->codeblock[b->level + (b->orientation != subband_ll)].height;
+    int blockcnt_one = (cb_width + cb_height) == 2;
+
+    if (!b->length)
+        return;
+
+    init_get_bits(&gb, b->coeff_data, b->length*8);
+
+    if (is_arith)
+        ff_dirac_init_arith_decoder(&c, &gb, b->length);
+
+    top = 0;
+    for (cb_y = 0; cb_y < cb_height; cb_y++) {
+        bottom = (b->height * (cb_y+1)) / cb_height;
+        left = 0;
+        for (cb_x = 0; cb_x < cb_width; cb_x++) {
+            right = (b->width * (cb_x+1)) / cb_width;
+            codeblock(s, b, &gb, &c, left, right, top, bottom, blockcnt_one, is_arith);
+            left = right;
+        }
+        top = bottom;
+    }
+
+    if (b->orientation == subband_ll && s->num_refs == 0)
+        intra_dc_prediction(b);
+}
+
+static int decode_subband_arith(AVCodecContext *avctx, void *b)
+{
+    DiracContext *s = avctx->priv_data;
+    decode_subband_internal(s, b, 1);
+    return 0;
+}
+
+static int decode_subband_golomb(AVCodecContext *avctx, void *arg)
+{
+    DiracContext *s = avctx->priv_data;
+    SubBand **b = arg;
+    decode_subband_internal(s, *b, 0);
+    return 0;
+}
+
+//[DIRAC_STD] 13.4.1 core_transform_data()
+static void decode_component(DiracContext *s, int comp)
+{
+    AVCodecContext *avctx = s->avctx;
+    SubBand *bands[3*MAX_DWT_LEVELS+1];
+    enum dirac_subband orientation;
+    int level, num_bands = 0;
+
+    // Unpack all subbands at all levels.
+    for (level = 0; level < s->wavelet_depth; level++) {
+        for (orientation = !!level; orientation < 4; orientation++) {
+            SubBand *b = &s->plane[comp].band[level][orientation];
+            bands[num_bands++] = b;
+
+            align_get_bits(&s->gb);
+            //[DIRAC_STD] 13.4.2 subband()
+            b->length = svq3_get_ue_golomb(&s->gb);
+            if (b->length) {
+                b->quant = svq3_get_ue_golomb(&s->gb);
+                align_get_bits(&s->gb);
+                b->coeff_data = s->gb.buffer + get_bits_count(&s->gb)/8;
+                b->length = FFMIN(b->length, get_bits_left(&s->gb)/8);
+                skip_bits_long(&s->gb, b->length*8);
+            }
+        }
+        // arithmetic coding has inter-level dependencies, so we can only execute one level at a time
+        if (s->is_arith)
+            avctx->execute(avctx, decode_subband_arith, &s->plane[comp].band[level][!!level],
+                           NULL, 4-!!level, sizeof(SubBand));
+    }
+    // golomb coding has no inter-level dependencies, so we can execute all subbands in parallel
+    if (!s->is_arith)
+        avctx->execute(avctx, decode_subband_golomb, bands, NULL, num_bands, sizeof(SubBand*));
+}
+
+//[DIRAC_STD] 13.5.5.2 Luma slice subband data. luma_slice_band(level,orient,sx,sy) --> if b2 == NULL
+//[DIRAC_STD] 13.5.5.3 Chroma slice subband data. chroma_slice_band(level,orient,sx,sy) --> if b2 != NULL
+static void lowdelay_subband(DiracContext *s, GetBitContext *gb, int quant,
+                             int slice_x, int slice_y, int bits_end,
+                             SubBand *b1, SubBand *b2)
+{
+    int left   = b1->width * slice_x    / s->lowdelay.num_x;
+    int right  = b1->width *(slice_x+1) / s->lowdelay.num_x;
+    int top    = b1->height* slice_y    / s->lowdelay.num_y;
+    int bottom = b1->height*(slice_y+1) / s->lowdelay.num_y;
+
+    int qfactor = qscale_tab[FFMIN(quant, MAX_QUANT)];
+    int qoffset = qoffset_intra_tab[FFMIN(quant, MAX_QUANT)];
+
+    IDWTELEM *buf1 =      b1->ibuf + top*b1->stride;
+    IDWTELEM *buf2 = b2 ? b2->ibuf + top*b2->stride : NULL;
+    int x, y;
+    // we have to constantly check for overread since the spec explictly
+    // requires this, with the meaning that all remaining coeffs are set to 0
+    if (get_bits_count(gb) >= bits_end)
+        return;
+
+    for (y = top; y < bottom; y++) {
+        for (x = left; x < right; x++) {
+            buf1[x] = coeff_unpack_golomb(gb, qfactor, qoffset);
+            if (get_bits_count(gb) >= bits_end)
+                return;
+            if (buf2) {
+                buf2[x] = coeff_unpack_golomb(gb, qfactor, qoffset);
+                if (get_bits_count(gb) >= bits_end)
+                    return;
+            }
+        }
+        buf1 += b1->stride;
+        if (buf2)
+            buf2 += b2->stride;
+    }
+}
+
+struct lowdelay_slice {
+    GetBitContext gb;
+    int slice_x;
+    int slice_y;
+    int bytes;
+};
+
+
+//[DIRAC_STD] 13.5.2 Slices. slice(sx,sy)
+static int decode_lowdelay_slice(AVCodecContext *avctx, void *arg)
+{
+    DiracContext *s = avctx->priv_data;
+    struct lowdelay_slice *slice = arg;
+    GetBitContext *gb = &slice->gb;
+    enum dirac_subband orientation;
+    int level, quant, chroma_bits, chroma_end;
+
+    int quant_base  = get_bits(gb, 7); //[DIRAC_STD] qindex
+    int length_bits = av_log2(8*slice->bytes)+1;
+    int luma_bits   = get_bits_long(gb, length_bits);
+    int luma_end    = get_bits_count(gb) + FFMIN(luma_bits, get_bits_left(gb));
+
+    //[DIRAC_STD] 13.5.5.2 luma_slice_band
+    for (level = 0; level < s->wavelet_depth; level++)
+        for (orientation = !!level; orientation < 4; orientation++) {
+            quant = FFMAX(quant_base - s->lowdelay.quant[level][orientation], 0);
+            lowdelay_subband(s, gb, quant, slice->slice_x, slice->slice_y, luma_end,
+                             &s->plane[0].band[level][orientation], NULL);
+        }
+
+    // consume any unused bits from luma
+    skip_bits_long(gb, get_bits_count(gb) - luma_end);
+
+    chroma_bits = 8*slice->bytes - 7 - length_bits - luma_bits;
+    chroma_end = get_bits_count(gb) + FFMIN(chroma_bits, get_bits_left(gb));
+    //[DIRAC_STD] 13.5.5.3 chroma_slice_band
+    for (level = 0; level < s->wavelet_depth; level++)
+        for (orientation = !!level; orientation < 4; orientation++) {
+            quant = FFMAX(quant_base - s->lowdelay.quant[level][orientation], 0);
+            lowdelay_subband(s, gb, quant, slice->slice_x, slice->slice_y, chroma_end,
+                             &s->plane[1].band[level][orientation],
+                             &s->plane[2].band[level][orientation]);
+        }
+
+    return 0;
+}
+
+//[DIRAC_STD] 13.5.1 low_delay_transform_data()
+static void decode_lowdelay(DiracContext *s)
+{
+    AVCodecContext *avctx = s->avctx;
+    int slice_x, slice_y, bytes, bufsize;
+    const uint8_t *buf;
+    struct lowdelay_slice *slices;
+    int slice_num = 0;
+
+    slices = av_mallocz(s->lowdelay.num_x * s->lowdelay.num_y * sizeof(struct lowdelay_slice));
+
+    align_get_bits(&s->gb);
+    //[DIRAC_STD] 13.5.2 Slices. slice(sx,sy)
+    buf = s->gb.buffer + get_bits_count(&s->gb)/8;
+    bufsize = get_bits_left(&s->gb);
+
+    for (slice_y = 0; slice_y < s->lowdelay.num_y; slice_y++)
+        for (slice_x = 0; slice_x < s->lowdelay.num_x; slice_x++) {
+            bytes = (slice_num+1) * s->lowdelay.bytes.num / s->lowdelay.bytes.den
+                   - slice_num    * s->lowdelay.bytes.num / s->lowdelay.bytes.den;
+
+            slices[slice_num].bytes   = bytes;
+            slices[slice_num].slice_x = slice_x;
+            slices[slice_num].slice_y = slice_y;
+            init_get_bits(&slices[slice_num].gb, buf, bufsize);
+            slice_num++;
+
+            buf     += bytes;
+            bufsize -= bytes*8;
+            if (bufsize <= 0)
+                goto end;
+        }
+end:
+
+    avctx->execute(avctx, decode_lowdelay_slice, slices, NULL, slice_num,
+                   sizeof(struct lowdelay_slice)); //[DIRAC_STD] 13.5.2 Slices
+    intra_dc_prediction(&s->plane[0].band[0][0]); //[DIRAC_STD] 13.3 intra_dc_prediction()
+    intra_dc_prediction(&s->plane[1].band[0][0]); //[DIRAC_STD] 13.3 intra_dc_prediction()
+    intra_dc_prediction(&s->plane[2].band[0][0]); //[DIRAC_STD] 13.3 intra_dc_prediction()
+
+    av_free(slices);
+}
+
+static void init_planes(DiracContext *s)
+{
+    int i, w, h, level, orientation;
+
+    for (i = 0; i < 3; i++) {
+        Plane *p = &s->plane[i];
+
+        p->width  = s->source.width  >> (i ? s->chroma_x_shift : 0);
+        p->height = s->source.height >> (i ? s->chroma_y_shift : 0);
+        p->idwt_width  = w = CALC_PADDING(p->width , s->wavelet_depth);
+        p->idwt_height = h = CALC_PADDING(p->height, s->wavelet_depth);
+        p->idwt_stride = FFALIGN(p->idwt_width, 8);
+
+        for (level = s->wavelet_depth-1; level >= 0; level--) {
+            w = w>>1;
+            h = h>>1;
+            for (orientation = !!level; orientation < 4; orientation++) {
+                SubBand *b = &p->band[level][orientation];
+
+                b->ibuf   = p->idwt_buf;
+                b->level  = level;
+                b->stride = p->idwt_stride << (s->wavelet_depth - level);
+                b->width  = w;
+                b->height = h;
+                b->orientation = orientation;
+
+                if (orientation & 1)
+                    b->ibuf += w;
+                if (orientation > 1)
+                    b->ibuf += b->stride>>1;
+
+                if (level)
+                    b->parent = &p->band[level-1][orientation];
+            }
+        }
+
+        if (i > 0) {
+            p->xblen = s->plane[0].xblen >> s->chroma_x_shift;
+            p->yblen = s->plane[0].yblen >> s->chroma_y_shift;
+            p->xbsep = s->plane[0].xbsep >> s->chroma_x_shift;
+            p->ybsep = s->plane[0].ybsep >> s->chroma_y_shift;
+        }
+
+        p->xoffset = (p->xblen - p->xbsep)/2;
+        p->yoffset = (p->yblen - p->ybsep)/2;
+    }
+}
+
+/**
+ * Unpack the motion compensation parameters
+ * [DIRAC_STD] 11.2 Picture prediction data. picture_prediction()
+ */
+static int dirac_unpack_prediction_parameters(DiracContext *s)
+{
+    static const uint8_t default_blen[] = { 4, 12, 16, 24 };
+    static const uint8_t default_bsep[] = { 4,  8, 12, 16 };
+
+    GetBitContext *gb = &s->gb;
+    unsigned idx, ref;
+
+    align_get_bits(gb);
+    //[DIRAC_STD] 11.2.2 Block parameters. block_parameters()
+    //Luma and Chroma are equal. 11.2.3
+    idx = svq3_get_ue_golomb(gb); ////[DIRAC_STD] index
+
+    if (idx > 4)
+      {
+         av_log(s->avctx, AV_LOG_ERROR, "Block prediction index too high\n");
+        return -1;
+      }
+
+    if (idx == 0) {
+        s->plane[0].xblen = svq3_get_ue_golomb(gb);
+        s->plane[0].yblen = svq3_get_ue_golomb(gb);
+        s->plane[0].xbsep = svq3_get_ue_golomb(gb);
+        s->plane[0].ybsep = svq3_get_ue_golomb(gb);
+    } else {
+      //[DIRAC_STD] preset_block_params(index). Table 11.1
+        s->plane[0].xblen = default_blen[idx-1];
+        s->plane[0].yblen = default_blen[idx-1];
+        s->plane[0].xbsep = default_bsep[idx-1];
+        s->plane[0].ybsep = default_bsep[idx-1];
+    }
+    //[DIRAC_STD] 11.2.4 motion_data_dimensions() --> Calculated in function dirac_unpack_block_motion_data
+
+    if (s->plane[0].xbsep < s->plane[0].xblen/2 || s->plane[0].ybsep < s->plane[0].yblen/2) {
+        av_log(s->avctx, AV_LOG_ERROR, "Block separation too small\n");
+        return -1;
+    }
+    if (s->plane[0].xbsep > s->plane[0].xblen || s->plane[0].ybsep > s->plane[0].yblen) {
+        av_log(s->avctx, AV_LOG_ERROR, "Block seperation greater than size\n");
+        return -1;
+    }
+    if (FFMAX(s->plane[0].xblen, s->plane[0].yblen) > MAX_BLOCKSIZE) {
+        av_log(s->avctx, AV_LOG_ERROR, "Unsupported large block size\n");
+        return -1;
+    }
+
+    //[DIRAC_STD] 11.2.5 Motion vector precision. motion_vector_precision()
+    // Read motion vector precision
+    s->mv_precision = svq3_get_ue_golomb(gb);
+    if (s->mv_precision > 3) {
+        av_log(s->avctx, AV_LOG_ERROR, "MV precision finer than eighth-pel\n");
+        return -1;
+    }
+
+    //[DIRAC_STD] 11.2.6 Global motion. global_motion()
+    // Read the global motion compensation parameters
+    s->globalmc_flag = get_bits1(gb);
+    if (s->globalmc_flag) {
+        memset(s->globalmc, 0, sizeof(s->globalmc));
+        //[DIRAC_STD] pan_tilt(gparams)
+        for (ref = 0; ref < s->num_refs; ref++) {
+            if (get_bits1(gb)) {
+                s->globalmc[ref].pan_tilt[0] = dirac_get_se_golomb(gb);
+                s->globalmc[ref].pan_tilt[1] = dirac_get_se_golomb(gb);
+            }
+            //[DIRAC_STD] zoom_rotate_shear(gparams)
+            // zoom/rotation/shear parameters
+            if (get_bits1(gb)) {
+                s->globalmc[ref].zrs_exp = svq3_get_ue_golomb(gb);
+                s->globalmc[ref].zrs[0][0] = dirac_get_se_golomb(gb);
+                s->globalmc[ref].zrs[0][1] = dirac_get_se_golomb(gb);
+                s->globalmc[ref].zrs[1][0] = dirac_get_se_golomb(gb);
+                s->globalmc[ref].zrs[1][1] = dirac_get_se_golomb(gb);
+            } else {
+                s->globalmc[ref].zrs[0][0] = 1;
+                s->globalmc[ref].zrs[1][1] = 1;
+            }
+            //[DIRAC_STD] perspective(gparams)
+            if (get_bits1(gb)) {
+                s->globalmc[ref].perspective_exp = svq3_get_ue_golomb(gb);
+                s->globalmc[ref].perspective[0] = dirac_get_se_golomb(gb);
+                s->globalmc[ref].perspective[1] = dirac_get_se_golomb(gb);
+            }
+        }
+    }
+
+    //[DIRAC_STD] 11.2.7 Picture prediction mode. prediction_mode()
+    // Picture prediction mode, not currently used.
+    if (svq3_get_ue_golomb(gb)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Unknown picture prediction mode\n");
+        return -1;
+    }
+
+    //[DIRAC_STD] 11.2.8 Reference picture weight. reference_picture_weights()
+    //just data read, weight calculation will be done later on.
+    s->weight_log2denom = 1;
+    s->weight[0]        = 1;
+    s->weight[1]        = 1;
+
+    if (get_bits1(gb)) {
+        s->weight_log2denom = svq3_get_ue_golomb(gb);
+        s->weight[0] = dirac_get_se_golomb(gb);
+        if (s->num_refs == 2)
+            s->weight[1] = dirac_get_se_golomb(gb);
+    }
+    return 0;
+}
+
+//[DIRAC_STD] 11.3 Wavelet transform data. wavelet_transform()
+static int dirac_unpack_idwt_params(DiracContext *s)
+{
+    GetBitContext *gb = &s->gb;
+    int i, level;
+
+    align_get_bits(gb);
+
+    s->zero_res = s->num_refs ? get_bits1(gb) : 0;
+    if (s->zero_res)
+        return 0;
+
+    //[DIRAC_STD] 11.3.1 Transform parameters. transform_parameters()
+    s->wavelet_idx = svq3_get_ue_golomb(gb);
+    if (s->wavelet_idx > 6)
+        return -1;
+
+    s->wavelet_depth = svq3_get_ue_golomb(gb);
+    if (s->wavelet_depth > MAX_DWT_LEVELS) {
+        av_log(s->avctx, AV_LOG_ERROR, "too many dwt decompositions\n");
+        return -1;
+    }
+
+    if (!s->low_delay) {
+        /* Codeblock paramaters (core syntax only) */
+        if (get_bits1(gb)) {
+            for (i = 0; i <= s->wavelet_depth; i++) {
+                s->codeblock[i].width  = svq3_get_ue_golomb(gb);
+                s->codeblock[i].height = svq3_get_ue_golomb(gb);
+            }
+
+            s->codeblock_mode = svq3_get_ue_golomb(gb);
+            if (s->codeblock_mode > 1) {
+                av_log(s->avctx, AV_LOG_ERROR, "unknown codeblock mode\n");
+                return -1;
+            }
+        } else
+            for (i = 0; i <= s->wavelet_depth; i++)
+                s->codeblock[i].width = s->codeblock[i].height = 1;
+    } else {
+      /* Slice parameters + quantization matrix*/
+      //[DIRAC_STD] 11.3.4 Slice coding Parameters (low delay syntax only). slice_parameters()
+        s->lowdelay.num_x     = svq3_get_ue_golomb(gb);
+        s->lowdelay.num_y     = svq3_get_ue_golomb(gb);
+        s->lowdelay.bytes.num = svq3_get_ue_golomb(gb);
+        s->lowdelay.bytes.den = svq3_get_ue_golomb(gb);
+
+        //[DIRAC_STD] 11.3.5 Quantisation matrices (low-delay syntax). quant_matrix()
+        if (get_bits1(gb)) {
+          av_log(s->avctx,AV_LOG_DEBUG,"Low Delay: Has Custom Quantization Matrix!\n");
+            // custom quantization matrix
+            s->lowdelay.quant[0][0] = svq3_get_ue_golomb(gb);
+            for (level = 0; level < s->wavelet_depth; level++) {
+                s->lowdelay.quant[level][1] = svq3_get_ue_golomb(gb);
+                s->lowdelay.quant[level][2] = svq3_get_ue_golomb(gb);
+                s->lowdelay.quant[level][3] = svq3_get_ue_golomb(gb);
+            }
+        } else {
+            // default quantization matrix
+            for (level = 0; level < s->wavelet_depth; level++)
+                for (i = 0; i < 4; i++) {
+                    s->lowdelay.quant[level][i] = default_qmat[s->wavelet_idx][level][i];
+                    // haar with no shift differs for different depths
+                    if (s->wavelet_idx == 3)
+                        s->lowdelay.quant[level][i] += 4*(s->wavelet_depth-1 - level);
+                }
+        }
+    }
+    return 0;
+}
+
+static inline int pred_sbsplit(uint8_t *sbsplit, int stride, int x, int y)
+{
+    static const uint8_t avgsplit[7] = { 0, 0, 1, 1, 1, 2, 2 };
+
+    if (!(x|y))
+        return 0;
+    else if (!y)
+        return sbsplit[-1];
+    else if (!x)
+        return sbsplit[-stride];
+
+    return avgsplit[sbsplit[-1] + sbsplit[-stride] + sbsplit[-stride-1]];
+}
+
+static inline int pred_block_mode(DiracBlock *block, int stride, int x, int y, int refmask)
+{
+    int pred;
+
+    if (!(x|y))
+        return 0;
+    else if (!y)
+        return block[-1].ref & refmask;
+    else if (!x)
+        return block[-stride].ref & refmask;
+
+    // return the majority
+    pred = (block[-1].ref & refmask) + (block[-stride].ref & refmask) + (block[-stride-1].ref & refmask);
+    return (pred >> 1) & refmask;
+}
+
+static inline void pred_block_dc(DiracBlock *block, int stride, int x, int y)
+{
+    int i, n = 0;
+
+    memset(block->u.dc, 0, sizeof(block->u.dc));
+
+    if (x && !(block[-1].ref & 3)) {
+        for (i = 0; i < 3; i++)
+            block->u.dc[i] += block[-1].u.dc[i];
+        n++;
+    }
+
+    if (y && !(block[-stride].ref & 3)) {
+        for (i = 0; i < 3; i++)
+            block->u.dc[i] += block[-stride].u.dc[i];
+        n++;
+    }
+
+    if (x && y && !(block[-1-stride].ref & 3)) {
+        for (i = 0; i < 3; i++)
+            block->u.dc[i] += block[-1-stride].u.dc[i];
+        n++;
+    }
+
+    if (n == 2) {
+        for (i = 0; i < 3; i++)
+            block->u.dc[i] = (block->u.dc[i]+1)>>1;
+    } else if (n == 3) {
+        for (i = 0; i < 3; i++)
+            block->u.dc[i] = divide3(block->u.dc[i]);
+    }
+}
+
+static inline void pred_mv(DiracBlock *block, int stride, int x, int y, int ref)
+{
+    int16_t *pred[3];
+    int refmask = ref+1;
+    int mask = refmask | DIRAC_REF_MASK_GLOBAL; // exclude gmc blocks
+    int n = 0;
+
+    if (x && (block[-1].ref & mask) == refmask)
+        pred[n++] = block[-1].u.mv[ref];
+
+    if (y && (block[-stride].ref & mask) == refmask)
+        pred[n++] = block[-stride].u.mv[ref];
+
+    if (x && y && (block[-stride-1].ref & mask) == refmask)
+        pred[n++] = block[-stride-1].u.mv[ref];
+
+    switch (n) {
+    case 0:
+        block->u.mv[ref][0] = 0;
+        block->u.mv[ref][1] = 0;
+        break;
+    case 1:
+        block->u.mv[ref][0] = pred[0][0];
+        block->u.mv[ref][1] = pred[0][1];
+        break;
+    case 2:
+        block->u.mv[ref][0] = (pred[0][0] + pred[1][0] + 1) >> 1;
+        block->u.mv[ref][1] = (pred[0][1] + pred[1][1] + 1) >> 1;
+        break;
+    case 3:
+        block->u.mv[ref][0] = mid_pred(pred[0][0], pred[1][0], pred[2][0]);
+        block->u.mv[ref][1] = mid_pred(pred[0][1], pred[1][1], pred[2][1]);
+        break;
+    }
+}
+
+static void global_mv(DiracContext *s, DiracBlock *block, int x, int y, int ref)
+{
+    int ez = s->globalmc[ref].zrs_exp;
+    int ep = s->globalmc[ref].perspective_exp;
+    int (*A)[2] = s->globalmc[ref].zrs;
+    int *b = s->globalmc[ref].pan_tilt;
+    int *c = s->globalmc[ref].perspective;
+
+    int m = (1<<ep) - (c[0]*x + c[1]*y);
+    int mx = m*((A[0][0]*x + A[0][1]*y) + (1<<ez)*b[0]);
+    int my = m*((A[1][0]*x + A[1][1]*y) + (1<<ez)*b[1]);
+
+    block->u.mv[ref][0] = (mx + (1<<(ez+ep))) >> (ez+ep);
+    block->u.mv[ref][1] = (my + (1<<(ez+ep))) >> (ez+ep);
+}
+
+static void decode_block_params(DiracContext *s, DiracArith arith[8], DiracBlock *block,
+                                int stride, int x, int y)
+{
+    int i;
+
+    block->ref = pred_block_mode(block, stride, x, y, DIRAC_REF_MASK_REF1);
+    block->ref ^= dirac_get_arith_bit(arith, CTX_PMODE_REF1);
+
+    if (s->num_refs == 2) {
+        block->ref |= pred_block_mode(block, stride, x, y, DIRAC_REF_MASK_REF2);
+        block->ref ^= dirac_get_arith_bit(arith, CTX_PMODE_REF2) << 1;
+    }
+
+    if (!block->ref) {
+        pred_block_dc(block, stride, x, y);
+        for (i = 0; i < 3; i++)
+            block->u.dc[i] += dirac_get_arith_int(arith+1+i, CTX_DC_F1, CTX_DC_DATA);
+        return;
+    }
+
+    if (s->globalmc_flag) {
+        block->ref |= pred_block_mode(block, stride, x, y, DIRAC_REF_MASK_GLOBAL);
+        block->ref ^= dirac_get_arith_bit(arith, CTX_GLOBAL_BLOCK) << 2;
+    }
+
+    for (i = 0; i < s->num_refs; i++)
+        if (block->ref & (i+1)) {
+            if (block->ref & DIRAC_REF_MASK_GLOBAL) {
+                global_mv(s, block, x, y, i);
+            } else {
+                pred_mv(block, stride, x, y, i);
+                block->u.mv[i][0] += dirac_get_arith_int(arith+4+2*i, CTX_MV_F1, CTX_MV_DATA);
+                block->u.mv[i][1] += dirac_get_arith_int(arith+5+2*i, CTX_MV_F1, CTX_MV_DATA);
+            }
+        }
+}
+
+/**
+ * Copies the current block to the other blocks covered by the current superblock split mode
+ */
+static void propagate_block_data(DiracBlock *block, int stride, int size)
+{
+    int x, y;
+    DiracBlock *dst = block;
+
+    for (x = 1; x < size; x++)
+        dst[x] = *block;
+
+    for (y = 1; y < size; y++) {
+        dst += stride;
+        for (x = 0; x < size; x++)
+            dst[x] = *block;
+    }
+}
+
+//[DIRAC_STD] 12. Block motion data syntax
+static void dirac_unpack_block_motion_data(DiracContext *s)
+{
+    GetBitContext *gb = &s->gb;
+    uint8_t *sbsplit = s->sbsplit;
+    int i, x, y, q, p;
+    DiracArith arith[8];
+
+    align_get_bits(gb);
+
+    //[DIRAC_STD] 11.2.4 and 12.2.1 Number of blocks and superblocks
+    s->sbwidth  = DIVRNDUP(s->source.width,  4*s->plane[0].xbsep);
+    s->sbheight = DIVRNDUP(s->source.height, 4*s->plane[0].ybsep);
+    s->blwidth  = 4*s->sbwidth;
+    s->blheight = 4*s->sbheight;
+
+    //[DIRAC_STD] 12.3.1 Superblock splitting modes. superblock_split_modes()
+    // decode superblock split modes
+    ff_dirac_init_arith_decoder(arith, gb, svq3_get_ue_golomb(gb));     //svq3_get_ue_golomb(gb) is the length
+    for (y = 0; y < s->sbheight; y++) {
+        for (x = 0; x < s->sbwidth; x++) {
+            int split = dirac_get_arith_uint(arith, CTX_SB_F1, CTX_SB_DATA);
+            sbsplit[x] = (split + pred_sbsplit(sbsplit+x, s->sbwidth, x, y)) % 3;
+        }
+        sbsplit += s->sbwidth;
+    }
+
+    // setup arith decoding
+    ff_dirac_init_arith_decoder(arith, gb, svq3_get_ue_golomb(gb));
+    for (i = 0; i < s->num_refs; i++) {
+        ff_dirac_init_arith_decoder(arith+4+2*i, gb, svq3_get_ue_golomb(gb));
+        ff_dirac_init_arith_decoder(arith+5+2*i, gb, svq3_get_ue_golomb(gb));
+    }
+    for (i = 0; i < 3; i++)
+        ff_dirac_init_arith_decoder(arith+1+i, gb, svq3_get_ue_golomb(gb));
+
+    for (y = 0; y < s->sbheight; y++)
+        for (x = 0; x < s->sbwidth; x++) {
+            int blkcnt = 1 << s->sbsplit[y*s->sbwidth + x];
+            int step   = 4 >> s->sbsplit[y*s->sbwidth + x];
+
+            for (q = 0; q < blkcnt; q++)
+                for (p = 0; p < blkcnt; p++) {
+                    int bx = 4*x + p*step;
+                    int by = 4*y + q*step;
+                    DiracBlock *block = &s->blmotion[by*s->blwidth + bx];
+                    decode_block_params(s, arith, block, s->blwidth, bx, by);
+                    propagate_block_data(block, s->blwidth, step);
+                }
+        }
+}
+
+static int weight(int i, int blen, int offset)
+{
+#define ROLLOFF(i) offset == 1 ? ((i) ? 5 : 3) : \
+    (1 + (6*(i) + offset - 1) / (2*offset - 1))
+
+    if (i < 2*offset)
+        return ROLLOFF(i);
+    else if (i > blen-1 - 2*offset)
+        return ROLLOFF(blen-1 - i);
+    return 8;
+}
+
+static void init_obmc_weight_row(Plane *p, uint8_t *obmc_weight, int stride,
+                                 int left, int right, int wy)
+{
+    int x;
+    for (x = 0; left && x < p->xblen >> 1; x++)
+        obmc_weight[x] = wy*8;
+    for (; x < p->xblen >> right; x++)
+        obmc_weight[x] = wy*weight(x, p->xblen, p->xoffset);
+    for (; x < p->xblen; x++)
+        obmc_weight[x] = wy*8;
+    for (; x < stride; x++)
+        obmc_weight[x] = 0;
+}
+
+static void init_obmc_weight(Plane *p, uint8_t *obmc_weight, int stride,
+                             int left, int right, int top, int bottom)
+{
+    int y;
+    for (y = 0; top && y < p->yblen >> 1; y++) {
+        init_obmc_weight_row(p, obmc_weight, stride, left, right, 8);
+        obmc_weight += stride;
+    }
+    for (; y < p->yblen >> bottom; y++) {
+        int wy = weight(y, p->yblen, p->yoffset);
+        init_obmc_weight_row(p, obmc_weight, stride, left, right, wy);
+        obmc_weight += stride;
+    }
+    for (; y < p->yblen; y++) {
+        init_obmc_weight_row(p, obmc_weight, stride, left, right, 8);
+        obmc_weight += stride;
+    }
+}
+
+static void init_obmc_weights(DiracContext *s, Plane *p, int by)
+{
+    int top = !by;
+    int bottom = by == s->blheight-1;
+
+    // don't bother re-initing for rows 2 to blheight-2, the weights don't change
+    if (top || bottom || by == 1) {
+        init_obmc_weight(p, s->obmc_weight[0], MAX_BLOCKSIZE, 1, 0, top, bottom);
+        init_obmc_weight(p, s->obmc_weight[1], MAX_BLOCKSIZE, 0, 0, top, bottom);
+        init_obmc_weight(p, s->obmc_weight[2], MAX_BLOCKSIZE, 0, 1, top, bottom);
+    }
+}
+
+static const uint8_t epel_weights[4][4][4] = {
+    {{ 16,  0,  0,  0 },
+     { 12,  4,  0,  0 },
+     {  8,  8,  0,  0 },
+     {  4, 12,  0,  0 }},
+    {{ 12,  0,  4,  0 },
+     {  9,  3,  3,  1 },
+     {  6,  6,  2,  2 },
+     {  3,  9,  1,  3 }},
+    {{  8,  0,  8,  0 },
+     {  6,  2,  6,  2 },
+     {  4,  4,  4,  4 },
+     {  2,  6,  2,  6 }},
+    {{  4,  0, 12,  0 },
+     {  3,  1,  9,  3 },
+     {  2,  2,  6,  6 },
+     {  1,  3,  3,  9 }}
+};
+
+/**
+ * For block x,y, determine which of the hpel planes to do bilinear
+ * interpolation from and set src[] to the location in each hpel plane
+ * to MC from.
+ *
+ * @return the index of the put_dirac_pixels_tab function to use
+ *  0 for 1 plane (fpel,hpel), 1 for 2 planes (qpel), 2 for 4 planes (qpel), and 3 for epel
+ */
+static int mc_subpel(DiracContext *s, DiracBlock *block, const uint8_t *src[5],
+                     int x, int y, int ref, int plane)
+{
+    Plane *p = &s->plane[plane];
+    uint8_t **ref_hpel = s->ref_pics[ref]->hpel[plane];
+    int motion_x = block->u.mv[ref][0];
+    int motion_y = block->u.mv[ref][1];
+    int mx, my, i, epel, nplanes = 0;
+
+    if (plane) {
+        motion_x >>= s->chroma_x_shift;
+        motion_y >>= s->chroma_y_shift;
+    }
+
+    mx = motion_x & ~(-1 << s->mv_precision);
+    my = motion_y & ~(-1 << s->mv_precision);
+    motion_x >>= s->mv_precision;
+    motion_y >>= s->mv_precision;
+    // normalize subpel coordinates to epel
+    // TODO: template this function?
+    mx <<= 3-s->mv_precision;
+    my <<= 3-s->mv_precision;
+
+    x += motion_x;
+    y += motion_y;
+    epel = (mx|my)&1;
+
+    // hpel position
+    if (!((mx|my)&3)) {
+        nplanes = 1;
+        src[0] = ref_hpel[(my>>1)+(mx>>2)] + y*p->stride + x;
+    } else {
+        // qpel or epel
+        nplanes = 4;
+        for (i = 0; i < 4; i++)
+            src[i] = ref_hpel[i] + y*p->stride + x;
+
+        // if we're interpolating in the right/bottom halves, adjust the planes as needed
+        // we increment x/y because the edge changes for half of the pixels
+        if (mx > 4) {
+            src[0] += 1;
+            src[2] += 1;
+            x++;
+        }
+        if (my > 4) {
+            src[0] += p->stride;
+            src[1] += p->stride;
+            y++;
+        }
+
+        // hpel planes are:
+        // [0]: F  [1]: H
+        // [2]: V  [3]: C
+        if (!epel) {
+            // check if we really only need 2 planes since either mx or my is
+            // a hpel position. (epel weights of 0 handle this there)
+            if (!(mx&3)) {
+                // mx == 0: average [0] and [2]
+                // mx == 4: average [1] and [3]
+                src[!mx] = src[2 + !!mx];
+                nplanes = 2;
+            } else if (!(my&3)) {
+                src[0] = src[(my>>1)  ];
+                src[1] = src[(my>>1)+1];
+                nplanes = 2;
+            }
+        } else {
+            // adjust the ordering if needed so the weights work
+            if (mx > 4) {
+                FFSWAP(const uint8_t *, src[0], src[1]);
+                FFSWAP(const uint8_t *, src[2], src[3]);
+            }
+            if (my > 4) {
+                FFSWAP(const uint8_t *, src[0], src[2]);
+                FFSWAP(const uint8_t *, src[1], src[3]);
+            }
+            src[4] = epel_weights[my&3][mx&3];
+        }
+    }
+
+    // fixme: v/h _edge_pos
+    if ((unsigned)x > p->width +EDGE_WIDTH/2 - p->xblen ||
+        (unsigned)y > p->height+EDGE_WIDTH/2 - p->yblen) {
+        for (i = 0; i < nplanes; i++) {
+            ff_emulated_edge_mc(s->edge_emu_buffer[i], src[i], p->stride,
+                                p->xblen, p->yblen, x, y,
+                                p->width+EDGE_WIDTH/2, p->height+EDGE_WIDTH/2);
+            src[i] = s->edge_emu_buffer[i];
+        }
+    }
+    return (nplanes>>1) + epel;
+}
+
+static void add_dc(uint16_t *dst, int dc, int stride,
+                   uint8_t *obmc_weight, int xblen, int yblen)
+{
+    int x, y;
+    dc += 128;
+
+    for (y = 0; y < yblen; y++) {
+        for (x = 0; x < xblen; x += 2) {
+            dst[x  ] += dc * obmc_weight[x  ];
+            dst[x+1] += dc * obmc_weight[x+1];
+        }
+        dst         += stride;
+        obmc_weight += MAX_BLOCKSIZE;
+    }
+}
+
+static void block_mc(DiracContext *s, DiracBlock *block,
+                     uint16_t *mctmp, uint8_t *obmc_weight,
+                     int plane, int dstx, int dsty)
+{
+    Plane *p = &s->plane[plane];
+    const uint8_t *src[5];
+    int idx;
+
+    switch (block->ref&3) {
+    case 0: // DC
+        add_dc(mctmp, block->u.dc[plane], p->stride, obmc_weight, p->xblen, p->yblen);
+        return;
+    case 1:
+    case 2:
+        idx = mc_subpel(s, block, src, dstx, dsty, (block->ref&3)-1, plane);
+        s->put_pixels_tab[idx](s->mcscratch, src, p->stride, p->yblen);
+        if (s->weight_func)
+            s->weight_func(s->mcscratch, p->stride, s->weight_log2denom,
+                           s->weight[0] + s->weight[1], p->yblen);
+        break;
+    case 3:
+        idx = mc_subpel(s, block, src, dstx, dsty, 0, plane);
+        s->put_pixels_tab[idx](s->mcscratch, src, p->stride, p->yblen);
+        idx = mc_subpel(s, block, src, dstx, dsty, 1, plane);
+        if (s->biweight_func) {
+            // fixme: +32 is a quick hack
+            s->put_pixels_tab[idx](s->mcscratch + 32, src, p->stride, p->yblen);
+            s->biweight_func(s->mcscratch, s->mcscratch+32, p->stride, s->weight_log2denom,
+                             s->weight[0], s->weight[1], p->yblen);
+        } else
+            s->avg_pixels_tab[idx](s->mcscratch, src, p->stride, p->yblen);
+        break;
+    }
+    s->add_obmc(mctmp, s->mcscratch, p->stride, obmc_weight, p->yblen);
+}
+
+static void mc_row(DiracContext *s, DiracBlock *block, uint16_t *mctmp, int plane, int dsty)
+{
+    Plane *p = &s->plane[plane];
+    int x, dstx = p->xbsep - p->xoffset;
+
+    block_mc(s, block, mctmp, s->obmc_weight[0], plane, -p->xoffset, dsty);
+    mctmp += p->xbsep;
+
+    for (x = 1; x < s->blwidth-1; x++) {
+        block_mc(s, block+x, mctmp, s->obmc_weight[1], plane, dstx, dsty);
+        dstx  += p->xbsep;
+        mctmp += p->xbsep;
+    }
+    block_mc(s, block+x, mctmp, s->obmc_weight[2], plane, dstx, dsty);
+}
+
+static void select_dsp_funcs(DiracContext *s, int width, int height, int xblen, int yblen)
+{
+    int idx = 0;
+    if (xblen > 8)
+        idx = 1;
+    if (xblen > 16)
+        idx = 2;
+
+    memcpy(s->put_pixels_tab, s->diracdsp.put_dirac_pixels_tab[idx], sizeof(s->put_pixels_tab));
+    memcpy(s->avg_pixels_tab, s->diracdsp.avg_dirac_pixels_tab[idx], sizeof(s->avg_pixels_tab));
+    s->add_obmc = s->diracdsp.add_dirac_obmc[idx];
+    if (s->weight_log2denom > 1 || s->weight[0] != 1 || s->weight[1] != 1) {
+        s->weight_func   = s->diracdsp.weight_dirac_pixels_tab[idx];
+        s->biweight_func = s->diracdsp.biweight_dirac_pixels_tab[idx];
+    } else {
+        s->weight_func   = NULL;
+        s->biweight_func = NULL;
+    }
+}
+
+static void interpolate_refplane(DiracContext *s, DiracFrame *ref, int plane, int width, int height)
+{
+    // chroma allocates an edge of 8 when subsampled
+    // which for 4:2:2 means an h edge of 16 and v edge of 8
+    // just use 8 for everything for the moment
+    int i, edge = EDGE_WIDTH/2;
+
+    ref->hpel[plane][0] = ref->avframe.data[plane];
+    s->dsp.draw_edges(ref->hpel[plane][0], ref->avframe.linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM); //EDGE_TOP | EDGE_BOTTOM values just copied to make it build, this needs to be ensured
+
+    // no need for hpel if we only have fpel vectors
+    if (!s->mv_precision)
+        return;
+
+    for (i = 1; i < 4; i++) {
+        if (!ref->hpel_base[plane][i])
+            ref->hpel_base[plane][i] = av_malloc((height+2*edge) * ref->avframe.linesize[plane] + 32);
+        // we need to be 16-byte aligned even for chroma
+        ref->hpel[plane][i] = ref->hpel_base[plane][i] + edge*ref->avframe.linesize[plane] + 16;
+    }
+
+    if (!ref->interpolated[plane]) {
+        s->diracdsp.dirac_hpel_filter(ref->hpel[plane][1], ref->hpel[plane][2],
+                                      ref->hpel[plane][3], ref->hpel[plane][0],
+                                      ref->avframe.linesize[plane], width, height);
+        s->dsp.draw_edges(ref->hpel[plane][1], ref->avframe.linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM);
+        s->dsp.draw_edges(ref->hpel[plane][2], ref->avframe.linesize[plane], width, height, edge, edge,  EDGE_TOP | EDGE_BOTTOM);
+        s->dsp.draw_edges(ref->hpel[plane][3], ref->avframe.linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM);
+    }
+    ref->interpolated[plane] = 1;
+}
+
+//[DIRAC_STD] 13.0 Transform data syntax. transform_data()
+static int dirac_decode_frame_internal(DiracContext *s)
+{
+  DWTContext d;
+  int y, i, comp, dsty;
+
+  if (s->low_delay) {
+    //[DIRAC_STD] 13.5.1 low_delay_transform_data()
+    for (comp = 0; comp < 3; comp++) {
+      Plane *p = &s->plane[comp];
+      memset(p->idwt_buf, 0, p->idwt_stride * p->idwt_height * sizeof(IDWTELEM));
+    }
+    if (!s->zero_res)
+      decode_lowdelay(s);
+  }
+
+  for (comp = 0; comp < 3; comp++) {
+    Plane *p = &s->plane[comp];
+    uint8_t *frame = s->current_picture->avframe.data[comp];
+
+    // FIXME: small resolutions
+    for (i = 0; i < 4; i++)
+      s->edge_emu_buffer[i] = s->edge_emu_buffer_base + i*FFALIGN(p->width, 16);
+
+    if (!s->zero_res && !s->low_delay)
+      {
+        memset(p->idwt_buf, 0, p->idwt_stride * p->idwt_height * sizeof(IDWTELEM));
+          decode_component(s, comp); //[DIRAC_STD] 13.4.1 core_transform_data()
+      }
+    if (ff_spatial_idwt_init2(&d, p->idwt_buf, p->idwt_width, p->idwt_height, p->idwt_stride,
+                              s->wavelet_idx+2, s->wavelet_depth, p->idwt_tmp))
+        return -1;
+
+    if (!s->num_refs) { //intra
+      for (y = 0; y < p->height; y += 16) {
+        ff_spatial_idwt_slice2(&d, y+16); //decode
+        s->diracdsp.put_signed_rect_clamped(frame + y*p->stride, p->stride,
+                                            p->idwt_buf + y*p->idwt_stride, p->idwt_stride, p->width, 16);
+      }
+    } else { //inter
+      int rowheight = p->ybsep*p->stride;
+
+      select_dsp_funcs(s, p->width, p->height, p->xblen, p->yblen);
+
+      for (i = 0; i < s->num_refs; i++)
+        interpolate_refplane(s, s->ref_pics[i], comp, p->width, p->height);
+
+      memset(s->mctmp, 0, 4*p->yoffset*p->stride);
+
+      dsty = -p->yoffset;
+      for (y = 0; y < s->blheight; y++) {
+        int h = 0, start = FFMAX(dsty, 0);
+        uint16_t *mctmp = s->mctmp + y*rowheight;
+        DiracBlock *blocks = s->blmotion + y*s->blwidth;
+
+        init_obmc_weights(s, p, y);
+
+        if (y == s->blheight-1 || start+p->ybsep > p->height)
+          h = p->height - start;
+        else
+          h = p->ybsep - (start - dsty);
+        if (h < 0)
+          break;
+
+        memset(mctmp+2*p->yoffset*p->stride, 0, 2*rowheight);
+        mc_row(s, blocks, mctmp, comp, dsty);
+
+        mctmp += (start - dsty)*p->stride + p->xoffset;
+        ff_spatial_idwt_slice2(&d, start + h); //decode
+        s->diracdsp.add_rect_clamped(frame + start*p->stride, mctmp, p->stride,
+                                     p->idwt_buf + start*p->idwt_stride, p->idwt_stride, p->width, h);
+
+        dsty += p->ybsep;
+      }
+    }
+  }
+
+
+  return 0;
+}
+
+//[DIRAC_STD] 11.1.1 Picture Header. picture_header()
+static int dirac_decode_picture_header(DiracContext *s)
+{
+    int retire, picnum;
+    int i, j, refnum, refdist;
+    GetBitContext *gb = &s->gb;
+
+    //[DIRAC_STD] 11.1.1 Picture Header. picture_header() PICTURE_NUM
+    picnum = s->current_picture->avframe.display_picture_number = get_bits_long(gb, 32);
+
+
+    av_log(s->avctx,AV_LOG_DEBUG,"PICTURE_NUM: %d\n",picnum);
+
+    // if this is the first keyframe after a sequence header, start our
+    // reordering from here
+    if (s->frame_number < 0)
+        s->frame_number = picnum;
+
+    s->ref_pics[0] = s->ref_pics[1] = NULL;
+    for (i = 0; i < s->num_refs; i++) {
+        refnum = picnum + dirac_get_se_golomb(gb);
+        refdist = INT_MAX;
+
+        // find the closest reference to the one we want
+        // Jordi: this is needed if the referenced picture hasn't yet arrived
+        for (j = 0; j < MAX_REFERENCE_FRAMES && refdist; j++)
+            if (s->ref_frames[j]
+                && FFABS(s->ref_frames[j]->avframe.display_picture_number - refnum) < refdist) {
+                s->ref_pics[i] = s->ref_frames[j];
+                refdist = FFABS(s->ref_frames[j]->avframe.display_picture_number - refnum);
+            }
+
+        if (!s->ref_pics[i] || refdist)
+            av_log(s->avctx, AV_LOG_DEBUG, "Reference not found\n");
+
+        // if there were no references at all, allocate one
+        if (!s->ref_pics[i])
+            for (j = 0; j < MAX_FRAMES; j++)
+                if (!s->all_frames[j].avframe.data[0]) {
+                    s->ref_pics[i] = &s->all_frames[j];
+                    s->avctx->get_buffer(s->avctx, &s->ref_pics[i]->avframe);
+                }
+    }
+
+    // retire the reference frames that are not used anymore
+    if (s->current_picture->avframe.reference) {
+        retire = picnum + dirac_get_se_golomb(gb);
+        if (retire != picnum) {
+            DiracFrame *retire_pic = remove_frame(s->ref_frames, retire);
+
+            if (retire_pic)
+                retire_pic->avframe.reference &= DELAYED_PIC_REF;
+            else
+                av_log(s->avctx, AV_LOG_DEBUG, "Frame to retire not found\n");
+        }
+
+        // if reference array is full, remove the oldest as per the spec
+        while (add_frame(s->ref_frames, MAX_REFERENCE_FRAMES, s->current_picture)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Reference frame overflow\n");
+            remove_frame(s->ref_frames, s->ref_frames[0]->avframe.display_picture_number)->avframe.reference &= DELAYED_PIC_REF;
+        }
+    }
+
+    if (s->num_refs) {
+      if (dirac_unpack_prediction_parameters(s))  //[DIRAC_STD] 11.2 Picture Prediction Data. picture_prediction()
+            return -1;
+      dirac_unpack_block_motion_data(s); //[DIRAC_STD] 12. Block motion data syntax
+    }
+    if (dirac_unpack_idwt_params(s)) //[DIRAC_STD] 11.3 Wavelet transform data
+        return -1;
+
+    init_planes(s); //Jordi... ????
+    return 0;
+}
+
+static int get_delayed_pic(DiracContext *s, DiracFrame *picture, int *data_size)
+{
+    DiracFrame *out = s->delay_frames[0];
+    int i, out_idx = 0;
+
+    // find frame with lowest picture number
+    for (i = 1; s->delay_frames[i]; i++)
+        if (s->delay_frames[i]->avframe.display_picture_number < out->avframe.display_picture_number) {
+            out = s->delay_frames[i];
+            out_idx = i;
+        }
+
+    for (i = out_idx; s->delay_frames[i]; i++)
+        s->delay_frames[i] = s->delay_frames[i+1];
+
+    if (out) {
+        out->avframe.reference ^= DELAYED_PIC_REF;
+        *data_size = sizeof(DiracFrame);
+        *picture = *out;
+    }
+
+    return 0;
+}
+
+// [DIRAC_STD] 9.6 Parse Info Header Syntax. parse_info()
+// 4 byte start code + byte parse code + 4 byte size + 4 byte previous size
+#define DATA_UNIT_HEADER_SIZE 13
+
+//[DIRAC_STD] dirac_decode_data_unit makes reference to the while defined in 9.3 inside the function parse_sequence()
+static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int size)
+{
+    DiracContext *s = avctx->priv_data;
+    DiracFrame *pic = NULL;
+    int i, parse_code = buf[4];
+
+    if (size < DATA_UNIT_HEADER_SIZE)
+        return -1;
+
+    init_get_bits(&s->gb, &buf[13], 8*(size - DATA_UNIT_HEADER_SIZE));
+
+    if (parse_code == pc_seq_header) {
+        if (s->seen_sequence_header)
+            return 0;
+
+        //[DIRAC_STD] 10. Sequence header
+        if (avpriv_dirac_parse_sequence_header(avctx, &s->gb, &s->source))
+            return -1;
+
+        avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift);
+
+        if (alloc_sequence_buffers(s))
+            return -1;
+
+        s->seen_sequence_header = 1;
+    } else if (parse_code == pc_eos) { //[DIRAC_STD] End of Sequence
+        free_sequence_buffers(s);
+        s->seen_sequence_header = 0;
+    } else if (parse_code == pc_aux_data) {
+        if (buf[13] == 1) {     // encoder implementation/version
+            int ver[3];
+            // versions older than 1.0.8 don't store quant delta for
+            // subbands with only one codeblock
+            if (sscanf(buf+14, "Schroedinger %d.%d.%d", ver, ver+1, ver+2) == 3)
+                if (ver[0] == 1 && ver[1] == 0 && ver[2] <= 7)
+                    s->old_delta_quant = 1;
+        }
+    } else if (parse_code & 0x8) {  // picture data unit
+        if (!s->seen_sequence_header) {
+            av_log(avctx, AV_LOG_DEBUG, "Dropping frame without sequence header\n");
+            return -1;
+        }
+
+        // find an unused frame
+        for (i = 0; i < MAX_FRAMES; i++)
+            if (s->all_frames[i].avframe.data[0] == NULL)
+                pic = &s->all_frames[i];
+        if (!pic) {
+            av_log(avctx, AV_LOG_ERROR, "framelist full\n");
+            return -1;
+        }
+
+        avcodec_get_frame_defaults(&pic->avframe);
+
+        //[DIRAC_STD] Defined in 9.6.1 ...
+        s->num_refs    =  parse_code & 0x03; //[DIRAC_STD] num_refs()
+        s->is_arith    = (parse_code & 0x48) == 0x08; //[DIRAC_STD] using_ac()
+        s->low_delay   = (parse_code & 0x88) == 0x88; //[DIRAC_STD] is_low_delay()
+        pic->avframe.reference = (parse_code & 0x0C) == 0x0C; //[DIRAC_STD]  is_reference()
+        pic->avframe.key_frame = s->num_refs == 0; //[DIRAC_STD] is_intra()
+        pic->avframe.pict_type = s->num_refs + 1; //Definition of AVPictureType in avutil.h
+
+        if (avctx->get_buffer(avctx, &pic->avframe) < 0) {
+            av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+            return -1;
+        }
+        s->current_picture = pic;
+        s->plane[0].stride = pic->avframe.linesize[0];
+        s->plane[1].stride = pic->avframe.linesize[1];
+        s->plane[2].stride = pic->avframe.linesize[2];
+
+        //[DIRAC_STD] 11.1 Picture parse. picture_parse()
+        if (dirac_decode_picture_header(s))
+            return -1;
+
+        //[DIRAC_STD] 13.0 Transform data syntax. transform_data()
+        if (dirac_decode_frame_internal(s))
+            return -1;
+    }
+    return 0;
+}
+
+static int dirac_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *pkt)
+{
+    DiracContext *s = avctx->priv_data;
+    DiracFrame *picture = data;
+    uint8_t *buf = pkt->data;
+    int buf_size = pkt->size;
+    int i, data_unit_size, buf_idx = 0;
+
+    // release unused frames
+    for (i = 0; i < MAX_FRAMES; i++)
+        if (s->all_frames[i].avframe.data[0] && !s->all_frames[i].avframe.reference) {
+            avctx->release_buffer(avctx, &s->all_frames[i].avframe);
+            memset(s->all_frames[i].interpolated, 0, sizeof(s->all_frames[i].interpolated));
+        }
+
+    s->current_picture = NULL;
+    *data_size = 0;
+
+    // end of stream, so flush delayed pics
+    if (buf_size == 0)
+        return get_delayed_pic(s, picture, data_size);
+
+    for (;;) {
+      //[DIRAC_STD] Here starts the code from parse_info() defined in 9.6
+      //[DIRAC_STD] PARSE_INFO_PREFIX = "BBCD" as defined in ISO/IEC 646
+        // BBCD start code search
+        for (; buf_idx + DATA_UNIT_HEADER_SIZE < buf_size; buf_idx++) {
+            if (buf[buf_idx  ] == 'B' && buf[buf_idx+1] == 'B' &&
+                buf[buf_idx+2] == 'C' && buf[buf_idx+3] == 'D')
+                break;
+        }
+        //BBCD found or end of data
+        if (buf_idx + DATA_UNIT_HEADER_SIZE >= buf_size)
+            break;
+
+        data_unit_size = AV_RB32(buf+buf_idx+5);
+        if (buf_idx + data_unit_size > buf_size) {
+            av_log(s->avctx, AV_LOG_ERROR,
+                "Data unit with size %d is larger than input buffer, discarding\n",
+                data_unit_size);
+            buf_idx += 4;
+            continue;
+        }
+
+        // [DIRAC_STD] dirac_decode_data_unit makes reference to the while defined in 9.3 inside the function parse_sequence()
+        if (dirac_decode_data_unit(avctx, buf+buf_idx, data_unit_size))
+            return -1;
+        buf_idx += data_unit_size;
+    }
+
+    if (!s->current_picture)
+        return 0;
+
+    if (s->current_picture->avframe.display_picture_number > s->frame_number) {
+        DiracFrame *delayed_frame = remove_frame(s->delay_frames, s->frame_number);
+
+        s->current_picture->avframe.reference |= DELAYED_PIC_REF;
+
+        if (add_frame(s->delay_frames, MAX_DELAY, s->current_picture)) {
+            int min_num = s->delay_frames[0]->avframe.display_picture_number;
+            // Too many delayed frames, so we display the frame with the lowest pts
+            av_log(avctx, AV_LOG_ERROR, "Delay frame overflow\n");
+            delayed_frame = s->delay_frames[0];
+
+            for (i = 1; s->delay_frames[i]; i++)
+                if (s->delay_frames[i]->avframe.display_picture_number < min_num)
+                    min_num = s->delay_frames[i]->avframe.display_picture_number;
+
+            delayed_frame = remove_frame(s->delay_frames, min_num);
+            add_frame(s->delay_frames, MAX_DELAY, s->current_picture);
+        }
+
+        if (delayed_frame) {
+            delayed_frame->avframe.reference ^= DELAYED_PIC_REF;
+            *data_size = sizeof(DiracFrame);
+            *picture = *delayed_frame;
+        }
+    } else if (s->current_picture->avframe.display_picture_number == s->frame_number) {
+        // The right frame at the right time :-)
+        *data_size = sizeof(DiracFrame);
+        *picture = *s->current_picture;
+    }
+
+    if (*data_size)
+        s->frame_number = picture->avframe.display_picture_number + 1;
+
+    return buf_idx;
+}
+
+AVCodec ff_dirac_decoder = {
+    "dirac",
+    AVMEDIA_TYPE_VIDEO,  //CODEC_TYPE_VIDEO --> AVMEDIA_TYPE_VIDEO
+    CODEC_ID_DIRAC,
+    sizeof(DiracContext),
+    dirac_decode_init,
+    NULL,
+    dirac_decode_end,
+    dirac_decode_frame,
+    CODEC_CAP_DELAY,
+    .flush = dirac_decode_flush,
+    .long_name = NULL_IF_CONFIG_SMALL("BBC Dirac VC-2"),
+};
diff --git a/libavcodec/diracdsp.c b/libavcodec/diracdsp.c
new file mode 100644 (file)
index 0000000..4c3cddb
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2009 David Conrad
+ *
+ * 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 "dsputil.h"
+#include "diracdsp.h"
+//MMX_DISABLE #include "libavcodec/x86/diracdsp_mmx.h"
+
+#define FILTER(src, stride) \
+  ((21*((src)[ 0*stride] + (src)[1*stride]) \
+    -7*((src)[-1*stride] + (src)[2*stride]) \
+    +3*((src)[-2*stride] + (src)[3*stride]) \
+    -1*((src)[-3*stride] + (src)[4*stride]) + 16) >> 5)
+
+static void dirac_hpel_filter(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src,
+                              int stride, int width, int height)
+{
+    int x, y;
+
+    for (y = 0; y < height; y++) {
+        for (x = -3; x < width+5; x++)
+            dstv[x] = av_clip_uint8(FILTER(src+x, stride));
+
+        for (x = 0; x < width; x++)
+            dstc[x] = av_clip_uint8(FILTER(dstv+x, 1));
+
+        for (x = 0; x < width; x++)
+            dsth[x] = av_clip_uint8(FILTER(src+x, 1));
+
+        src  += stride;
+        dsth += stride;
+        dstv += stride;
+        dstc += stride;
+    }
+}
+
+#define PIXOP_BILINEAR(PFX, OP, WIDTH) \
+static void ff_ ## PFX ## _dirac_pixels ## WIDTH ## _bilinear_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    int x;\
+    const uint8_t *s0 = src[0];\
+    const uint8_t *s1 = src[1];\
+    const uint8_t *s2 = src[2];\
+    const uint8_t *s3 = src[3];\
+    const uint8_t *w  = src[4];\
+\
+    while (h--) {\
+        for (x = 0; x < WIDTH; x++) {\
+            OP(dst[x], (s0[x]*w[0] + s1[x]*w[1] + s2[x]*w[2] + s3[x]*w[3] + 8) >> 4);\
+        }\
+\
+        dst += stride;\
+        s0 += stride;\
+        s1 += stride;\
+        s2 += stride;\
+        s3 += stride;\
+    }\
+}
+
+#define OP_PUT(dst, val) (dst) = (val)
+#define OP_AVG(dst, val) (dst) = (((dst) + (val) + 1)>>1)
+
+PIXOP_BILINEAR(put, OP_PUT, 8)
+PIXOP_BILINEAR(put, OP_PUT, 16)
+PIXOP_BILINEAR(put, OP_PUT, 32)
+PIXOP_BILINEAR(avg, OP_AVG, 8)
+PIXOP_BILINEAR(avg, OP_AVG, 16)
+PIXOP_BILINEAR(avg, OP_AVG, 32)
+
+#define op_scale1(x)  block[x] = av_clip_uint8( (block[x]*weight + (1<<(log2_denom-1))) >> log2_denom)
+#define op_scale2(x)  dst[x] = av_clip_uint8( (src[x]*weights + dst[x]*weightd + (1<<(log2_denom-1))) >> log2_denom)
+
+#define DIRAC_WEIGHT(W) \
+static void weight_dirac_pixels ## W ## _c(uint8_t *block, int stride, int log2_denom, \
+                                           int weight, int h) { \
+    int x; \
+    while (h--) { \
+        for (x = 0; x < W; x++) { \
+            op_scale1(x); \
+            op_scale1(x+1); \
+        } \
+        block += stride; \
+    } \
+} \
+static void biweight_dirac_pixels ## W ## _c(uint8_t *dst, uint8_t *src, int stride, int log2_denom, \
+                                             int weightd, int weights, int h) { \
+    int x; \
+    while (h--) { \
+        for (x = 0; x < W; x++) { \
+            op_scale2(x); \
+            op_scale2(x+1); \
+        } \
+        dst += stride; \
+        src += stride; \
+    } \
+}
+
+DIRAC_WEIGHT(8)
+DIRAC_WEIGHT(16)
+DIRAC_WEIGHT(32)
+
+#define ADD_OBMC(xblen) \
+static void add_obmc ## xblen ## _c(uint16_t *dst, const uint8_t *src, int stride, \
+                                    const uint8_t *obmc_weight, int yblen) \
+{ \
+    int x; \
+    while (yblen--) { \
+        for (x = 0; x < xblen; x += 2) { \
+            dst[x  ] += src[x  ] * obmc_weight[x  ]; \
+            dst[x+1] += src[x+1] * obmc_weight[x+1]; \
+        } \
+        dst += stride; \
+        src += stride; \
+        obmc_weight += 32; \
+    } \
+}
+
+ADD_OBMC(8)
+ADD_OBMC(16)
+ADD_OBMC(32)
+
+static void put_signed_rect_clamped_c(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height)
+{
+    int x, y;
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x+=4) {
+            dst[x  ] = av_clip_uint8(src[x  ] + 128);
+            dst[x+1] = av_clip_uint8(src[x+1] + 128);
+            dst[x+2] = av_clip_uint8(src[x+2] + 128);
+            dst[x+3] = av_clip_uint8(src[x+3] + 128);
+        }
+        dst += dst_stride;
+        src += src_stride;
+    }
+}
+
+static void add_rect_clamped_c(uint8_t *dst, const uint16_t *src, int stride,
+                               const int16_t *idwt, int idwt_stride,
+                               int width, int height)
+{
+    int x, y;
+
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x+=2) {
+            dst[x  ] = av_clip_uint8(((src[x  ]+32)>>6) + idwt[x  ]);
+            dst[x+1] = av_clip_uint8(((src[x+1]+32)>>6) + idwt[x+1]);
+        }
+        dst += stride;
+        src += stride;
+        idwt += idwt_stride;
+    }
+}
+
+#define PIXFUNC(PFX, WIDTH) \
+    c->PFX ## _dirac_pixels_tab[WIDTH>>4][0] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _c; \
+    c->PFX ## _dirac_pixels_tab[WIDTH>>4][1] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _l2_c; \
+    c->PFX ## _dirac_pixels_tab[WIDTH>>4][2] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _l4_c; \
+    c->PFX ## _dirac_pixels_tab[WIDTH>>4][3] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _bilinear_c
+
+void ff_diracdsp_init(DiracDSPContext *c)
+{
+    c->dirac_hpel_filter = dirac_hpel_filter;
+    c->add_rect_clamped = add_rect_clamped_c;
+    c->put_signed_rect_clamped = put_signed_rect_clamped_c;
+
+    c->add_dirac_obmc[0] = add_obmc8_c;
+    c->add_dirac_obmc[1] = add_obmc16_c;
+    c->add_dirac_obmc[2] = add_obmc32_c;
+
+    c->weight_dirac_pixels_tab[0] = weight_dirac_pixels8_c;
+    c->weight_dirac_pixels_tab[1] = weight_dirac_pixels16_c;
+    c->weight_dirac_pixels_tab[2] = weight_dirac_pixels32_c;
+    c->biweight_dirac_pixels_tab[0] = biweight_dirac_pixels8_c;
+    c->biweight_dirac_pixels_tab[1] = biweight_dirac_pixels16_c;
+    c->biweight_dirac_pixels_tab[2] = biweight_dirac_pixels32_c;
+
+    PIXFUNC(put, 8);
+    PIXFUNC(put, 16);
+    PIXFUNC(put, 32);
+    PIXFUNC(avg, 8);
+    PIXFUNC(avg, 16);
+    PIXFUNC(avg, 32);
+
+    //MMX_DISABLE    if (HAVE_MMX) ff_diracdsp_init_mmx(c);
+}
diff --git a/libavcodec/diracdsp.h b/libavcodec/diracdsp.h
new file mode 100644 (file)
index 0000000..2135ee9
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 David Conrad
+ *
+ * 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
+ */
+
+#ifndef AVCODEC_DIRACDSP_H
+#define AVCODEC_DIRACDSP_H
+
+typedef void (*dirac_weight_func)(uint8_t *block, int stride, int log2_denom, int weight, int h);
+typedef void (*dirac_biweight_func)(uint8_t *dst, uint8_t *src, int stride, int log2_denom, int weightd, int weights, int h);
+
+typedef struct {
+    void (*dirac_hpel_filter)(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, int stride, int width, int height);
+    /**
+     * dirac_pixels_tab[width][subpel]
+     * width is 2 for 32, 1 for 16, 0 for 8
+     * subpel is 0 for fpel and hpel (only need to copy from the first plane in src)
+     *           1 if an average of the first 2 planes is needed (TODO: worth it?)
+     *           2 for general qpel (avg of 4)
+     *           3 for general epel (biweight of 4 using the weights in src[4])
+     * src[0-3] is each of the hpel planes
+     * src[4] is the 1/8 pel weights if needed
+     */
+    void (*put_dirac_pixels_tab[3][4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+    void (*avg_dirac_pixels_tab[3][4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+
+    void (*put_signed_rect_clamped)(uint8_t *dst/*align 16*/, int dst_stride, const int16_t *src/*align 16*/, int src_stride, int width, int height/*mod 2*/);
+    void (*put_rect_clamped)(uint8_t *dst/*align 16*/, int dst_stride, const int16_t *src/*align 16*/, int src_stride, int width, int height/*mod 2*/);
+    void (*add_rect_clamped)(uint8_t *dst/*align 16*/, const uint16_t *src/*align 16*/, int stride, const int16_t *idwt/*align 16*/, int idwt_stride, int width, int height/*mod 2*/);
+    void (*add_dirac_obmc[3])(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+
+    dirac_weight_func weight_dirac_pixels_tab[3];
+    dirac_biweight_func biweight_dirac_pixels_tab[3];
+} DiracDSPContext;
+
+#define DECL_DIRAC_PIXOP(PFX, EXT) \
+    void ff_ ## PFX ## _dirac_pixels8_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h); \
+    void ff_ ## PFX ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h); \
+    void ff_ ## PFX ## _dirac_pixels32_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+
+DECL_DIRAC_PIXOP(put, c);
+DECL_DIRAC_PIXOP(avg, c);
+DECL_DIRAC_PIXOP(put, l2_c);
+DECL_DIRAC_PIXOP(avg, l2_c);
+DECL_DIRAC_PIXOP(put, l4_c);
+DECL_DIRAC_PIXOP(avg, l4_c);
+
+void ff_diracdsp_init(DiracDSPContext *c);
+
+#endif
index c451c97..6a33ef4 100644 (file)
@@ -38,6 +38,7 @@
 #include "config.h"
 #include "ac3dec.h"
 #include "vorbis.h"
+#include "diracdsp.h"
 
 uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP] = {0, };
 uint32_t ff_squareTbl[512] = {0, };
@@ -1328,6 +1329,51 @@ void ff_avg_rv40_qpel8_mc33_c(uint8_t *dst, uint8_t *src, int stride){
 }
 #endif /* CONFIG_RV40_DECODER */
 
+#if CONFIG_DIRAC_DECODER
+#define DIRAC_MC(OPNAME)\
+void ff_ ## OPNAME ## _dirac_pixels8_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+     OPNAME ## _pixels8_8_c(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels16_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_8_c(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels32_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_8_c(dst   , src[0]   , stride, h);\
+    OPNAME ## _pixels16_8_c(dst+16, src[0]+16, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels8_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels8_l2_8(dst, src[0], src[1], stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels16_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_l2_8(dst, src[0], src[1], stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels32_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_l2_8(dst   , src[0]   , src[1]   , stride, stride, stride, h);\
+    OPNAME ## _pixels16_l2_8(dst+16, src[0]+16, src[1]+16, stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels8_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels8_l4_8(dst, src[0], src[1], src[2], src[3], stride, stride, stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels16_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_l4_8(dst, src[0], src[1], src[2], src[3], stride, stride, stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels32_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_l4_8(dst   , src[0]   , src[1]   , src[2]   , src[3]   , stride, stride, stride, stride, stride, h);\
+    OPNAME ## _pixels16_l4_8(dst+16, src[0]+16, src[1]+16, src[2]+16, src[3]+16, stride, stride, stride, stride, stride, h);\
+}
+DIRAC_MC(put)
+DIRAC_MC(avg)
+#endif
+
 static void wmv2_mspel8_v_lowpass(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int w){
     uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
     int i;
index d9d58de..fa56906 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2004-2010 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2008 David Conrad
  *
  * This file is part of FFmpeg.
  *
@@ -21,6 +22,7 @@
 #include "libavutil/attributes.h"
 #include "dsputil.h"
 #include "dwt.h"
+#include "libavcodec/x86/dwt.h"
 
 void ff_slice_buffer_init(slice_buffer * buf, int line_count, int max_allocated_lines, int line_width, IDWTELEM * base_buffer)
 {
@@ -841,3 +843,541 @@ void ff_dwt_init(DWTContext *c)
 
     if (HAVE_MMX) ff_dwt_init_x86(c);
 }
+
+
+static av_always_inline
+void interleave(IDWTELEM *dst, IDWTELEM *src0, IDWTELEM *src1, int w2, int add, int shift)
+{
+    int i;
+    for (i = 0; i < w2; i++) {
+        dst[2*i  ] = (src0[i] + add) >> shift;
+        dst[2*i+1] = (src1[i] + add) >> shift;
+    }
+}
+
+static void horizontal_compose_dirac53i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+    const int w2 = w >> 1;
+    int x;
+
+    temp[0] = COMPOSE_53iL0(b[w2], b[0], b[w2]);
+    for (x = 1; x < w2; x++) {
+        temp[x     ] = COMPOSE_53iL0     (b[x+w2-1], b[x     ], b[x+w2]);
+        temp[x+w2-1] = COMPOSE_DIRAC53iH0(temp[x-1], b[x+w2-1], temp[x]);
+    }
+    temp[w-1] = COMPOSE_DIRAC53iH0(temp[w2-1], b[w-1], temp[w2-1]);
+
+    interleave(b, temp, temp+w2, w2, 1, 1);
+}
+
+static void horizontal_compose_dd97i(IDWTELEM *b, IDWTELEM *tmp, int w)
+{
+    const int w2 = w >> 1;
+    int x;
+
+    tmp[0] = COMPOSE_53iL0(b[w2], b[0], b[w2]);
+    for (x = 1; x < w2; x++)
+        tmp[x] = COMPOSE_53iL0(b[x+w2-1], b[x], b[x+w2]);
+
+    // extend the edges
+    tmp[-1]   = tmp[0];
+    tmp[w2+1] = tmp[w2] = tmp[w2-1];
+
+    for (x = 0; x < w2; x++) {
+        b[2*x  ] = (tmp[x] + 1)>>1;
+        b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1;
+    }
+}
+
+static void horizontal_compose_dd137i(IDWTELEM *b, IDWTELEM *tmp, int w)
+{
+    const int w2 = w >> 1;
+    int x;
+
+    tmp[0] = COMPOSE_DD137iL0(b[w2], b[w2], b[0], b[w2  ], b[w2+1]);
+    tmp[1] = COMPOSE_DD137iL0(b[w2], b[w2], b[1], b[w2+1], b[w2+2]);
+    for (x = 2; x < w2-1; x++)
+        tmp[x] = COMPOSE_DD137iL0(b[x+w2-2], b[x+w2-1], b[x], b[x+w2], b[x+w2+1]);
+    tmp[w2-1] = COMPOSE_DD137iL0(b[w-3], b[w-2], b[w2-1], b[w-1], b[w-1]);
+
+    // extend the edges
+    tmp[-1]   = tmp[0];
+    tmp[w2+1] = tmp[w2] = tmp[w2-1];
+
+    for (x = 0; x < w2; x++) {
+        b[2*x  ] = (tmp[x] + 1)>>1;
+        b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1;
+    }
+}
+
+static av_always_inline
+void horizontal_compose_haari(IDWTELEM *b, IDWTELEM *temp, int w, int shift)
+{
+    const int w2 = w >> 1;
+    int x;
+
+    for (x = 0; x < w2; x++) {
+        temp[x   ] = COMPOSE_HAARiL0(b[x   ], b[x+w2]);
+        temp[x+w2] = COMPOSE_HAARiH0(b[x+w2], temp[x]);
+    }
+
+    interleave(b, temp, temp+w2, w2, shift, shift);
+}
+
+static void horizontal_compose_haar0i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+    horizontal_compose_haari(b, temp, w, 0);
+}
+
+static void horizontal_compose_haar1i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+    horizontal_compose_haari(b, temp, w, 1);
+}
+
+static void horizontal_compose_fidelityi(IDWTELEM *b, IDWTELEM *tmp, int w)
+{
+    const int w2 = w >> 1;
+    int i, x;
+    IDWTELEM v[8];
+
+    for (x = 0; x < w2; x++) {
+        for (i = 0; i < 8; i++)
+            v[i] = b[av_clip(x-3+i, 0, w2-1)];
+        tmp[x] = COMPOSE_FIDELITYiH0(v[0], v[1], v[2], v[3], b[x+w2], v[4], v[5], v[6], v[7]);
+    }
+
+    for (x = 0; x < w2; x++) {
+        for (i = 0; i < 8; i++)
+            v[i] = tmp[av_clip(x-4+i, 0, w2-1)];
+        tmp[x+w2] = COMPOSE_FIDELITYiL0(v[0], v[1], v[2], v[3], b[x], v[4], v[5], v[6], v[7]);
+    }
+
+    interleave(b, tmp+w2, tmp, w2, 0, 0);
+}
+
+static void horizontal_compose_daub97i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+    const int w2 = w >> 1;
+    int x, b0, b1, b2;
+
+    temp[0] = COMPOSE_DAUB97iL1(b[w2], b[0], b[w2]);
+    for (x = 1; x < w2; x++) {
+        temp[x     ] = COMPOSE_DAUB97iL1(b[x+w2-1], b[x     ], b[x+w2]);
+        temp[x+w2-1] = COMPOSE_DAUB97iH1(temp[x-1], b[x+w2-1], temp[x]);
+    }
+    temp[w-1] = COMPOSE_DAUB97iH1(temp[w2-1], b[w-1], temp[w2-1]);
+
+    // second stage combined with interleave and shift
+    b0 = b2 = COMPOSE_DAUB97iL0(temp[w2], temp[0], temp[w2]);
+    b[0] = (b0 + 1) >> 1;
+    for (x = 1; x < w2; x++) {
+        b2 = COMPOSE_DAUB97iL0(temp[x+w2-1], temp[x     ], temp[x+w2]);
+        b1 = COMPOSE_DAUB97iH0(          b0, temp[x+w2-1], b2        );
+        b[2*x-1] = (b1 + 1) >> 1;
+        b[2*x  ] = (b2 + 1) >> 1;
+        b0 = b2;
+    }
+    b[w-1] = (COMPOSE_DAUB97iH0(b2, temp[w-1], b2) + 1) >> 1;
+}
+
+static void vertical_compose_dirac53iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        b1[i] = COMPOSE_DIRAC53iH0(b0[i], b1[i], b2[i]);
+    }
+}
+
+static void vertical_compose_dd97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+                                  IDWTELEM *b3, IDWTELEM *b4, int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        b2[i] = COMPOSE_DD97iH0(b0[i], b1[i], b2[i], b3[i], b4[i]);
+    }
+}
+
+static void vertical_compose_dd137iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+                                      IDWTELEM *b3, IDWTELEM *b4, int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        b2[i] = COMPOSE_DD137iL0(b0[i], b1[i], b2[i], b3[i], b4[i]);
+    }
+}
+
+static void vertical_compose_haar(IDWTELEM *b0, IDWTELEM *b1, int width)
+{
+    int i;
+
+    for (i = 0; i < width; i++) {
+        b0[i] = COMPOSE_HAARiL0(b0[i], b1[i]);
+        b1[i] = COMPOSE_HAARiH0(b1[i], b0[i]);
+    }
+}
+
+static void vertical_compose_fidelityiH0(IDWTELEM *dst, IDWTELEM *b[8], int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        dst[i] = COMPOSE_FIDELITYiH0(b[0][i], b[1][i], b[2][i], b[3][i], dst[i], b[4][i], b[5][i], b[6][i], b[7][i]);
+    }
+}
+
+static void vertical_compose_fidelityiL0(IDWTELEM *dst, IDWTELEM *b[8], int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        dst[i] = COMPOSE_FIDELITYiL0(b[0][i], b[1][i], b[2][i], b[3][i], dst[i], b[4][i], b[5][i], b[6][i], b[7][i]);
+    }
+}
+
+static void vertical_compose_daub97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        b1[i] = COMPOSE_DAUB97iH0(b0[i], b1[i], b2[i]);
+    }
+}
+
+static void vertical_compose_daub97iH1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        b1[i] = COMPOSE_DAUB97iH1(b0[i], b1[i], b2[i]);
+    }
+}
+
+static void vertical_compose_daub97iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        b1[i] = COMPOSE_DAUB97iL0(b0[i], b1[i], b2[i]);
+    }
+}
+
+static void vertical_compose_daub97iL1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+    int i;
+
+    for(i=0; i<width; i++){
+        b1[i] = COMPOSE_DAUB97iL1(b0[i], b1[i], b2[i]);
+    }
+}
+
+
+static void spatial_compose_dd97i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+    vertical_compose_3tap vertical_compose_l0 = d->vertical_compose_l0;
+    vertical_compose_5tap vertical_compose_h0 = d->vertical_compose_h0;
+    DWTCompose *cs = d->cs + level;
+
+    int i, y = cs->y;
+    IDWTELEM *b[8];
+    for (i = 0; i < 6; i++)
+        b[i] = cs->b[i];
+    b[6] = d->buffer + av_clip(y+5, 0, height-2)*stride;
+    b[7] = d->buffer + av_clip(y+6, 1, height-1)*stride;
+
+        if(y+5<(unsigned)height) vertical_compose_l0(      b[5], b[6], b[7],       width);
+        if(y+1<(unsigned)height) vertical_compose_h0(b[0], b[2], b[3], b[4], b[6], width);
+
+        if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+        if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+    for (i = 0; i < 6; i++)
+        cs->b[i] = b[i+2];
+    cs->y += 2;
+}
+
+static void spatial_compose_dirac53i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+    vertical_compose_3tap vertical_compose_l0 = d->vertical_compose_l0;
+    vertical_compose_3tap vertical_compose_h0 = d->vertical_compose_h0;
+    DWTCompose *cs = d->cs + level;
+
+    int y= cs->y;
+    IDWTELEM *b[4] = { cs->b[0], cs->b[1] };
+    b[2] = d->buffer + mirror(y+1, height-1)*stride;
+    b[3] = d->buffer + mirror(y+2, height-1)*stride;
+
+        if(y+1<(unsigned)height) vertical_compose_l0(b[1], b[2], b[3], width);
+        if(y+0<(unsigned)height) vertical_compose_h0(b[0], b[1], b[2], width);
+
+        if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+        if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+    cs->b[0] = b[2];
+    cs->b[1] = b[3];
+    cs->y += 2;
+}
+
+
+static void spatial_compose_dd137i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+    vertical_compose_5tap vertical_compose_l0 = d->vertical_compose_l0;
+    vertical_compose_5tap vertical_compose_h0 = d->vertical_compose_h0;
+    DWTCompose *cs = d->cs + level;
+
+    int i, y = cs->y;
+    IDWTELEM *b[10];
+    for (i = 0; i < 8; i++)
+        b[i] = cs->b[i];
+    b[8] = d->buffer + av_clip(y+7, 0, height-2)*stride;
+    b[9] = d->buffer + av_clip(y+8, 1, height-1)*stride;
+
+        if(y+5<(unsigned)height) vertical_compose_l0(b[3], b[5], b[6], b[7], b[9], width);
+        if(y+1<(unsigned)height) vertical_compose_h0(b[0], b[2], b[3], b[4], b[6], width);
+
+        if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+        if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+    for (i = 0; i < 8; i++)
+        cs->b[i] = b[i+2];
+    cs->y += 2;
+}
+
+// haar makes the assumption that height is even (always true for dirac)
+static void spatial_compose_haari_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+    vertical_compose_2tap vertical_compose = d->vertical_compose;
+    int y = d->cs[level].y;
+    IDWTELEM *b0 = d->buffer + (y-1)*stride;
+    IDWTELEM *b1 = d->buffer + (y  )*stride;
+
+    vertical_compose(b0, b1, width);
+    d->horizontal_compose(b0, d->temp, width);
+    d->horizontal_compose(b1, d->temp, width);
+
+    d->cs[level].y += 2;
+}
+
+// Don't do sliced idwt for fidelity; the 9 tap filter makes it a bit annoying
+// Fortunately, this filter isn't used in practice.
+static void spatial_compose_fidelity(DWTContext *d, int level, int width, int height, int stride)
+{
+    vertical_compose_9tap vertical_compose_l0 = d->vertical_compose_l0;
+    vertical_compose_9tap vertical_compose_h0 = d->vertical_compose_h0;
+    int i, y;
+    IDWTELEM *b[8];
+
+    for (y = 1; y < height; y += 2) {
+        for (i = 0; i < 8; i++)
+            b[i] = d->buffer + av_clip((y-7 + 2*i), 0, height-2)*stride;
+        vertical_compose_h0(d->buffer + y*stride, b, width);
+    }
+
+    for (y = 0; y < height; y += 2) {
+        for (i = 0; i < 8; i++)
+            b[i] = d->buffer + av_clip((y-7 + 2*i), 1, height-1)*stride;
+        vertical_compose_l0(d->buffer + y*stride, b, width);
+    }
+
+    for (y = 0; y < height; y++)
+        d->horizontal_compose(d->buffer + y*stride, d->temp, width);
+
+    d->cs[level].y = height+1;
+}
+
+static void spatial_compose_daub97i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+    vertical_compose_3tap vertical_compose_l0 = d->vertical_compose_l0;
+    vertical_compose_3tap vertical_compose_h0 = d->vertical_compose_h0;
+    vertical_compose_3tap vertical_compose_l1 = d->vertical_compose_l1;
+    vertical_compose_3tap vertical_compose_h1 = d->vertical_compose_h1;
+    DWTCompose *cs = d->cs + level;
+
+    int i, y = cs->y;
+    IDWTELEM *b[6];
+    for (i = 0; i < 4; i++)
+        b[i] = cs->b[i];
+    b[4] = d->buffer + mirror(y+3, height-1)*stride;
+    b[5] = d->buffer + mirror(y+4, height-1)*stride;
+
+        if(y+3<(unsigned)height) vertical_compose_l1(b[3], b[4], b[5], width);
+        if(y+2<(unsigned)height) vertical_compose_h1(b[2], b[3], b[4], width);
+        if(y+1<(unsigned)height) vertical_compose_l0(b[1], b[2], b[3], width);
+        if(y+0<(unsigned)height) vertical_compose_h0(b[0], b[1], b[2], width);
+
+        if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+        if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+    for (i = 0; i < 4; i++)
+        cs->b[i] = b[i+2];
+    cs->y += 2;
+}
+
+
+static void spatial_compose97i_init2(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+    cs->b[0] = buffer + mirror(-3-1, height-1)*stride;
+    cs->b[1] = buffer + mirror(-3  , height-1)*stride;
+    cs->b[2] = buffer + mirror(-3+1, height-1)*stride;
+    cs->b[3] = buffer + mirror(-3+2, height-1)*stride;
+    cs->y = -3;
+}
+
+static void spatial_compose53i_init2(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+    cs->b[0] = buffer + mirror(-1-1, height-1)*stride;
+    cs->b[1] = buffer + mirror(-1  , height-1)*stride;
+    cs->y = -1;
+}
+
+static void spatial_compose_dd97i_init(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+    cs->b[0] = buffer + av_clip(-5-1, 0, height-2)*stride;
+    cs->b[1] = buffer + av_clip(-5  , 1, height-1)*stride;
+    cs->b[2] = buffer + av_clip(-5+1, 0, height-2)*stride;
+    cs->b[3] = buffer + av_clip(-5+2, 1, height-1)*stride;
+    cs->b[4] = buffer + av_clip(-5+3, 0, height-2)*stride;
+    cs->b[5] = buffer + av_clip(-5+4, 1, height-1)*stride;
+    cs->y = -5;
+}
+
+static void spatial_compose_dd137i_init(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+    cs->b[0] = buffer + av_clip(-5-1, 0, height-2)*stride;
+    cs->b[1] = buffer + av_clip(-5  , 1, height-1)*stride;
+    cs->b[2] = buffer + av_clip(-5+1, 0, height-2)*stride;
+    cs->b[3] = buffer + av_clip(-5+2, 1, height-1)*stride;
+    cs->b[4] = buffer + av_clip(-5+3, 0, height-2)*stride;
+    cs->b[5] = buffer + av_clip(-5+4, 1, height-1)*stride;
+    cs->b[6] = buffer + av_clip(-5+5, 0, height-2)*stride;
+    cs->b[7] = buffer + av_clip(-5+6, 1, height-1)*stride;
+    cs->y = -5;
+}
+
+int ff_spatial_idwt_init2(DWTContext *d, IDWTELEM *buffer, int width, int height,
+                          int stride, enum dwt_type type, int decomposition_count,
+                          IDWTELEM *temp)
+{
+    int level;
+
+    d->buffer = buffer;
+    d->width = width;
+    d->height = height;
+    d->stride = stride;
+    d->decomposition_count = decomposition_count;
+    d->temp = temp + 8;
+
+    for(level=decomposition_count-1; level>=0; level--){
+        int hl = height >> level;
+        int stride_l = stride << level;
+
+        switch(type){
+        case DWT_DIRAC_DD9_7:
+            spatial_compose_dd97i_init(d->cs+level, buffer, hl, stride_l);
+            break;
+        case DWT_DIRAC_LEGALL5_3:
+            spatial_compose53i_init2(d->cs+level, buffer, hl, stride_l);
+            break;
+        case DWT_DIRAC_DD13_7:
+            spatial_compose_dd137i_init(d->cs+level, buffer, hl, stride_l);
+            break;
+        case DWT_DIRAC_HAAR0:
+        case DWT_DIRAC_HAAR1:
+            d->cs[level].y = 1;
+            break;
+        case DWT_DIRAC_DAUB9_7:
+            spatial_compose97i_init2(d->cs+level, buffer, hl, stride_l);
+            break;
+        default:
+            d->cs[level].y = 0;
+            break;
+        }
+    }
+
+    switch (type) {
+    case DWT_DIRAC_DD9_7:
+        d->spatial_compose = spatial_compose_dd97i_dy;
+        d->vertical_compose_l0 = vertical_compose53iL0;
+        d->vertical_compose_h0 = vertical_compose_dd97iH0;
+        d->horizontal_compose = horizontal_compose_dd97i;
+        d->support = 7;
+        break;
+    case DWT_DIRAC_LEGALL5_3:
+        d->spatial_compose = spatial_compose_dirac53i_dy;
+        d->vertical_compose_l0 = vertical_compose53iL0;
+        d->vertical_compose_h0 = vertical_compose_dirac53iH0;
+        d->horizontal_compose = horizontal_compose_dirac53i;
+        d->support = 3;
+        break;
+    case DWT_DIRAC_DD13_7:
+        d->spatial_compose = spatial_compose_dd137i_dy;
+        d->vertical_compose_l0 = vertical_compose_dd137iL0;
+        d->vertical_compose_h0 = vertical_compose_dd97iH0;
+        d->horizontal_compose = horizontal_compose_dd137i;
+        d->support = 7;
+        break;
+    case DWT_DIRAC_HAAR0:
+    case DWT_DIRAC_HAAR1:
+        d->spatial_compose = spatial_compose_haari_dy;
+        d->vertical_compose = vertical_compose_haar;
+        if (type == DWT_DIRAC_HAAR0)
+            d->horizontal_compose = horizontal_compose_haar0i;
+        else
+            d->horizontal_compose = horizontal_compose_haar1i;
+        d->support = 1;
+        break;
+    case DWT_DIRAC_FIDELITY:
+        d->spatial_compose = spatial_compose_fidelity;
+        d->vertical_compose_l0 = vertical_compose_fidelityiL0;
+        d->vertical_compose_h0 = vertical_compose_fidelityiH0;
+        d->horizontal_compose = horizontal_compose_fidelityi;
+        break;
+    case DWT_DIRAC_DAUB9_7:
+        d->spatial_compose = spatial_compose_daub97i_dy;
+        d->vertical_compose_l0 = vertical_compose_daub97iL0;
+        d->vertical_compose_h0 = vertical_compose_daub97iH0;
+        d->vertical_compose_l1 = vertical_compose_daub97iL1;
+        d->vertical_compose_h1 = vertical_compose_daub97iH1;
+        d->horizontal_compose = horizontal_compose_daub97i;
+        d->support = 5;
+        break;
+    default:
+        av_log(NULL, AV_LOG_ERROR, "Unknown wavelet type %d\n", type);
+        return -1;
+    }
+
+    /////MMX_DISABLE    if (HAVE_MMX) ff_spatial_idwt_init_mmx(d, type);
+
+    return 0;
+}
+
+void ff_spatial_idwt_slice2(DWTContext *d, int y)
+{
+    int level, support = d->support;
+
+    for (level = d->decomposition_count-1; level >= 0; level--) {
+        int wl = d->width  >> level;
+        int hl = d->height >> level;
+        int stride_l = d->stride << level;
+
+        while (d->cs[level].y <= FFMIN((y>>level)+support, hl))
+            d->spatial_compose(d, level, wl, hl, stride_l);
+    }
+}
+
+int ff_spatial_idwt2(IDWTELEM *buffer, int width, int height, int stride,
+                     enum dwt_type type, int decomposition_count, IDWTELEM *temp)
+{
+    DWTContext d;
+    int y;
+
+    if (ff_spatial_idwt_init2(&d, buffer, width, height, stride, type, decomposition_count, temp))
+        return -1;
+
+    for (y = 0; y < d.height; y += 4)
+        ff_spatial_idwt_slice2(&d, y);
+
+    return 0;
+}
index b10e4f5..441d5e6 100644 (file)
 typedef int DWTELEM;
 typedef short IDWTELEM;
 
+#define MAX_DWT_SUPPORT 8
+#define MAX_DECOMPOSITIONS 8
+
 typedef struct {
+    IDWTELEM *b[MAX_DWT_SUPPORT];
+
     IDWTELEM *b0;
     IDWTELEM *b1;
     IDWTELEM *b2;
@@ -45,13 +50,99 @@ typedef struct slice_buffer_s {
     IDWTELEM * base_buffer; ///< Buffer that this structure is caching.
 } slice_buffer;
 
+struct DWTContext;
+
+// Possible prototypes for vertical_compose functions
+typedef void (*vertical_compose_2tap)(IDWTELEM *b0, IDWTELEM *b1, int width);
+typedef void (*vertical_compose_3tap)(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width);
+typedef void (*vertical_compose_5tap)(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, int width);
+typedef void (*vertical_compose_9tap)(IDWTELEM *dst, IDWTELEM *b[8], int width);
+
 typedef struct DWTContext {
+    IDWTELEM *buffer;
+    IDWTELEM *temp;
+    int width;
+    int height;
+    int stride;
+    int decomposition_count;
+    int support;
+
+    void (*spatial_compose)(struct DWTContext *cs, int level, int width, int height, int stride);
+    void (*vertical_compose_l0)();
+    void (*vertical_compose_h0)();
+    void (*vertical_compose_l1)();
+    void (*vertical_compose_h1)();
+    void (*vertical_compose)();     ///< one set of lowpass and highpass combined
+    void (*horizontal_compose)(IDWTELEM *b, IDWTELEM *tmp, int width);
+
     void (*vertical_compose97i)(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width);
     void (*horizontal_compose97i)(IDWTELEM *b, int width);
     void (*inner_add_yblock)(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h, int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8);
+
+    DWTCompose cs[MAX_DECOMPOSITIONS];
 } DWTContext;
 
-#define MAX_DECOMPOSITIONS 8
+enum dwt_type {
+    DWT_SNOW_DAUB9_7,
+    DWT_SNOW_LEGALL5_3,
+    DWT_DIRAC_DD9_7,
+    DWT_DIRAC_LEGALL5_3,
+    DWT_DIRAC_DD13_7,
+    DWT_DIRAC_HAAR0,
+    DWT_DIRAC_HAAR1,
+    DWT_DIRAC_FIDELITY,
+    DWT_DIRAC_DAUB9_7,
+    DWT_NUM_TYPES
+};
+
+// -1 if an error occurred, e.g. the dwt_type isn't recognized
+int ff_spatial_idwt_init2(DWTContext *d, IDWTELEM *buffer, int width, int height,
+                          int stride, enum dwt_type type, int decomposition_count,
+                          IDWTELEM *temp);
+
+int ff_spatial_idwt2(IDWTELEM *buffer, int width, int height, int stride,
+                     enum dwt_type type, int decomposition_count, IDWTELEM *temp);
+
+void ff_spatial_idwt_slice2(DWTContext *d, int y);
+
+// shared stuff for simd optimiztions
+#define COMPOSE_53iL0(b0, b1, b2)\
+    (b1 - ((b0 + b2 + 2) >> 2))
+
+#define COMPOSE_DIRAC53iH0(b0, b1, b2)\
+    (b1 + ((b0 + b2 + 1) >> 1))
+
+#define COMPOSE_DD97iH0(b0, b1, b2, b3, b4)\
+    (b2 + ((-b0 + 9*b1 + 9*b3 - b4 + 8) >> 4))
+
+#define COMPOSE_DD137iL0(b0, b1, b2, b3, b4)\
+    (b2 - ((-b0 + 9*b1 + 9*b3 - b4 + 16) >> 5))
+
+#define COMPOSE_HAARiL0(b0, b1)\
+    (b0 - ((b1 + 1) >> 1))
+
+#define COMPOSE_HAARiH0(b0, b1)\
+    (b0 + b1)
+
+#define COMPOSE_FIDELITYiL0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\
+    (b4 - ((-8*(b0+b8) + 21*(b1+b7) - 46*(b2+b6) + 161*(b3+b5) + 128) >> 8))
+
+#define COMPOSE_FIDELITYiH0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\
+    (b4 + ((-2*(b0+b8) + 10*(b1+b7) - 25*(b2+b6) + 81*(b3+b5) + 128) >> 8))
+
+#define COMPOSE_DAUB97iL1(b0, b1, b2)\
+    (b1 - ((1817*(b0 + b2) + 2048) >> 12))
+
+#define COMPOSE_DAUB97iH1(b0, b1, b2)\
+    (b1 - (( 113*(b0 + b2) + 64) >> 7))
+
+#define COMPOSE_DAUB97iL0(b0, b1, b2)\
+    (b1 + (( 217*(b0 + b2) + 2048) >> 12))
+
+#define COMPOSE_DAUB97iH0(b0, b1, b2)\
+    (b1 + ((6497*(b0 + b2) + 2048) >> 12))
+
+
 
 #define DWT_97 0
 #define DWT_53 1
index f4783bc..082d5e0 100644 (file)
@@ -9,6 +9,8 @@ YASM-OBJS-FFT-$(HAVE_SSE)              += x86/fft_sse.o
 YASM-OBJS-$(CONFIG_FFT)                += x86/fft_mmx.o                 \
                                           $(YASM-OBJS-FFT-yes)
 
+YASM-OBJS-$(CONFIG_DWT)                += x86/dwt_yasm.o
+
 MMX-OBJS-$(CONFIG_H264DSP)             += x86/h264dsp_mmx.o
 YASM-OBJS-$(CONFIG_H264DSP)            += x86/h264_deblock.o            \
                                           x86/h264_deblock_10bit.o      \
@@ -25,6 +27,8 @@ MMX-OBJS-$(CONFIG_RV40_DECODER)        += x86/rv40dsp.o                 \
 
 YASM-OBJS-$(CONFIG_VC1_DECODER)        += x86/vc1dsp_yasm.o
 
+#DISABLE_MMX YASM-OBJS-$(CONFIG_DIRAC_DECODER)      += x86/diracdsp_mmx.o x86/diracdsp_yasm.o
+
 MMX-OBJS-$(CONFIG_AC3DSP)              += x86/ac3dsp_mmx.o
 YASM-OBJS-$(CONFIG_AC3DSP)             += x86/ac3dsp.o
 MMX-OBJS-$(CONFIG_CAVS_DECODER)        += x86/cavsdsp_mmx.o
@@ -38,7 +42,8 @@ YASM-OBJS-$(CONFIG_PRORES_LGPL_DECODER)     += x86/proresdsp.o
 MMX-OBJS-$(CONFIG_PRORES_LGPL_DECODER)      += x86/proresdsp-init.o
 YASM-OBJS-$(CONFIG_PRORES_DECODER)     += x86/proresdsp.o
 MMX-OBJS-$(CONFIG_PRORES_DECODER)      += x86/proresdsp-init.o
-MMX-OBJS-$(CONFIG_DWT)                 += x86/snowdsp_mmx.o
+MMX-OBJS-$(CONFIG_DWT)                 += x86/snowdsp_mmx.o \
+                                          x86/dwt.o
 YASM-OBJS-$(CONFIG_V210_DECODER)       += x86/v210.o
 MMX-OBJS-$(CONFIG_V210_DECODER)        += x86/v210-init.o
 MMX-OBJS-$(CONFIG_VC1_DECODER)         += x86/vc1dsp_mmx.o
diff --git a/libavcodec/x86/diracdsp_mmx.c b/libavcodec/x86/diracdsp_mmx.c
new file mode 100644 (file)
index 0000000..9a2e858
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 David Conrad
+ *
+ * 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 "dsputil_mmx.h"
+#include "diracdsp_mmx.h"
+
+void ff_put_rect_clamped_mmx(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+void ff_put_rect_clamped_sse2(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+void ff_put_signed_rect_clamped_mmx(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+void ff_put_signed_rect_clamped_sse2(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+
+#define HPEL_FILTER(MMSIZE, EXT) \
+void ff_dirac_hpel_filter_v_ ## EXT(uint8_t *, uint8_t *, int, int);\
+void ff_dirac_hpel_filter_h_ ## EXT(uint8_t *, uint8_t *, int);\
+\
+static void dirac_hpel_filter_ ## EXT(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc,\
+                                      uint8_t *src, int stride, int width, int height)\
+{\
+    while( height-- )\
+    {\
+        ff_dirac_hpel_filter_v_ ## EXT(dstv-MMSIZE, src-MMSIZE, stride, width+MMSIZE+5);\
+        ff_dirac_hpel_filter_h_ ## EXT(dsth, src, width);\
+        ff_dirac_hpel_filter_h_ ## EXT(dstc, dstv, width);\
+\
+        dsth += stride;\
+        dstv += stride;\
+        dstc += stride;\
+        src  += stride;\
+    }\
+}
+
+#if !ARCH_X86_64
+HPEL_FILTER(8, mmx)
+#endif
+HPEL_FILTER(16, sse2)
+
+#define PIXFUNC(PFX, IDX, EXT) \
+    c->PFX ## _dirac_pixels_tab[0][IDX] = ff_ ## PFX ## _dirac_pixels8_ ## EXT; \
+    c->PFX ## _dirac_pixels_tab[1][IDX] = ff_ ## PFX ## _dirac_pixels16_ ## EXT; \
+    c->PFX ## _dirac_pixels_tab[2][IDX] = ff_ ## PFX ## _dirac_pixels32_ ## EXT
+
+void ff_diracdsp_init_mmx(DiracDSPContext* c)
+{
+  int mm_flags = av_get_cpu_flags();;
+
+#if HAVE_YASM
+    c->add_dirac_obmc[0] = ff_add_dirac_obmc8_mmx;
+#if !ARCH_X86_64
+    c->add_dirac_obmc[1] = ff_add_dirac_obmc16_mmx;
+    c->add_dirac_obmc[2] = ff_add_dirac_obmc32_mmx;
+    c->dirac_hpel_filter = dirac_hpel_filter_mmx;
+    c->add_rect_clamped = ff_add_rect_clamped_mmx;
+    c->put_signed_rect_clamped = ff_put_signed_rect_clamped_mmx;
+#endif
+#endif
+
+    PIXFUNC(put, 0, mmx);
+    PIXFUNC(avg, 0, mmx);
+
+    if (mm_flags & AV_CPU_FLAG_MMX2) {
+        PIXFUNC(avg, 0, mmx2);
+    }
+
+    if (mm_flags & AV_CPU_FLAG_SSE2) {
+#if HAVE_YASM
+        c->dirac_hpel_filter = dirac_hpel_filter_sse2;
+        c->add_rect_clamped = ff_add_rect_clamped_sse2;
+        c->put_signed_rect_clamped = ff_put_signed_rect_clamped_sse2;
+
+        c->add_dirac_obmc[1] = ff_add_dirac_obmc16_sse2;
+        c->add_dirac_obmc[2] = ff_add_dirac_obmc32_sse2;
+#endif
+        c->put_dirac_pixels_tab[1][0] = ff_put_dirac_pixels16_sse2;
+        c->avg_dirac_pixels_tab[1][0] = ff_avg_dirac_pixels16_sse2;
+        c->put_dirac_pixels_tab[2][0] = ff_put_dirac_pixels32_sse2;
+        c->avg_dirac_pixels_tab[2][0] = ff_avg_dirac_pixels32_sse2;
+    }
+}
diff --git a/libavcodec/x86/diracdsp_mmx.h b/libavcodec/x86/diracdsp_mmx.h
new file mode 100644 (file)
index 0000000..3d8e117
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010 David Conrad
+ *
+ * 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
+ */
+
+#ifndef AVCODEC_X86_DIRACDSP_H
+#define AVCODEC_X86_DIRACDSP_H
+
+#include "libavcodec/diracdsp.h"
+
+void ff_diracdsp_init_mmx(DiracDSPContext* c);
+
+DECL_DIRAC_PIXOP(put, mmx);
+DECL_DIRAC_PIXOP(avg, mmx);
+DECL_DIRAC_PIXOP(avg, mmx2);
+
+void ff_put_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+void ff_avg_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+void ff_put_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+void ff_avg_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+
+void ff_add_rect_clamped_mmx(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int);
+void ff_add_rect_clamped_sse2(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int);
+
+void ff_add_dirac_obmc8_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+void ff_add_dirac_obmc16_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+void ff_add_dirac_obmc32_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+
+void ff_add_dirac_obmc16_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+void ff_add_dirac_obmc32_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+
+#endif
diff --git a/libavcodec/x86/diracdsp_yasm.asm b/libavcodec/x86/diracdsp_yasm.asm
new file mode 100644 (file)
index 0000000..666e657
--- /dev/null
@@ -0,0 +1,260 @@
+;******************************************************************************
+;* Copyright (c) 2010 David Conrad
+;*
+;* 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
+;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "x86inc.asm"
+
+SECTION_RODATA
+pw_3: times 8 dw 3
+pw_7: times 8 dw 7
+pw_16: times 8 dw 16
+pw_32: times 8 dw 32
+pb_128: times 16 db 128
+
+section .text
+
+%macro UNPACK_ADD 6
+    mov%5   %1, %3
+    mov%6   m5, %4
+    mova    m4, %1
+    mova    %2, m5
+    punpcklbw %1, m7
+    punpcklbw m5, m7
+    punpckhbw m4, m7
+    punpckhbw %2, m7
+    paddw   %1, m5
+    paddw   %2, m4
+%endmacro
+
+%macro HPEL_FILTER 1
+; dirac_hpel_filter_v_sse2(uint8_t *dst, uint8_t *src, int stride, int width);
+cglobal dirac_hpel_filter_v_%1, 4,6,8, dst, src, stride, width, src0, stridex3
+    mov     src0q, srcq
+    lea     stridex3q, [3*strideq]
+    sub     src0q, stridex3q
+    pxor    m7, m7
+.loop:
+    ; 7*(src[0] + src[1])
+    UNPACK_ADD m0, m1, [srcq], [srcq + strideq], a,a
+    pmullw  m0, [pw_7]
+    pmullw  m1, [pw_7]
+
+    ; 3*( ... + src[-2] + src[3])
+    UNPACK_ADD m2, m3, [src0q + strideq], [srcq + stridex3q], a,a
+    paddw   m0, m2
+    paddw   m1, m3
+    pmullw  m0, [pw_3]
+    pmullw  m1, [pw_3]
+
+    ; ... - 7*(src[-1] + src[2])
+    UNPACK_ADD m2, m3, [src0q + strideq*2], [srcq + strideq*2], a,a
+    pmullw  m2, [pw_7]
+    pmullw  m3, [pw_7]
+    psubw   m0, m2
+    psubw   m1, m3
+
+    ; ... - (src[-3] + src[4])
+    UNPACK_ADD m2, m3, [src0q], [srcq + strideq*4], a,a
+    psubw   m0, m2
+    psubw   m1, m3
+
+    paddw   m0, [pw_16]
+    paddw   m1, [pw_16]
+    psraw   m0, 5
+    psraw   m1, 5
+    packuswb m0, m1
+    mova    [dstq], m0
+    add     dstq, mmsize
+    add     srcq, mmsize
+    add     src0q, mmsize
+    sub     widthd, mmsize
+    jg      .loop
+    RET
+
+; dirac_hpel_filter_h_sse2(uint8_t *dst, uint8_t *src, int width);
+cglobal dirac_hpel_filter_h_%1, 3,3,8, dst, src, width
+    dec     widthd
+    pxor    m7, m7
+    and     widthd, ~(mmsize-1)
+.loop:
+    ; 7*(src[0] + src[1])
+    UNPACK_ADD m0, m1, [srcq + widthq], [srcq + widthq + 1], a,u
+    pmullw  m0, [pw_7]
+    pmullw  m1, [pw_7]
+
+    ; 3*( ... + src[-2] + src[3])
+    UNPACK_ADD m2, m3, [srcq + widthq - 2], [srcq + widthq + 3], u,u
+    paddw   m0, m2
+    paddw   m1, m3
+    pmullw  m0, [pw_3]
+    pmullw  m1, [pw_3]
+
+    ; ... - 7*(src[-1] + src[2])
+    UNPACK_ADD m2, m3, [srcq + widthq - 1], [srcq + widthq + 2], u,u
+    pmullw  m2, [pw_7]
+    pmullw  m3, [pw_7]
+    psubw   m0, m2
+    psubw   m1, m3
+
+    ; ... - (src[-3] + src[4])
+    UNPACK_ADD m2, m3, [srcq + widthq - 3], [srcq + widthq + 4], u,u
+    psubw   m0, m2
+    psubw   m1, m3
+
+    paddw   m0, [pw_16]
+    paddw   m1, [pw_16]
+    psraw   m0, 5
+    psraw   m1, 5
+    packuswb m0, m1
+    mova    [dstq + widthq], m0
+    sub     widthd, mmsize
+    jge     .loop
+    RET
+%endmacro
+
+%macro PUT_RECT 1
+; void put_rect_clamped(uint8_t *dst, int dst_stride, int16_t *src, int src_stride, int width, int height)
+cglobal put_signed_rect_clamped_%1, 5,7,3, dst, dst_stride, src, src_stride, w, dst2, src2
+    mova    m0, [pb_128]
+    add     wd, (mmsize-1)
+    and     wd, ~(mmsize-1)
+
+%ifdef ARCH_X86_64
+    mov   r10d, r5m
+    mov   r11d, wd
+    %define wspill r11d
+    %define hd r10d
+%else
+    mov    r4m, wd
+    %define wspill r4m
+    %define hd r5mp
+%endif
+
+.loopy
+    lea     src2q, [srcq+src_strideq*2]
+    lea     dst2q, [dstq+dst_strideq]
+.loopx:
+    sub      wd, mmsize
+    mova     m1, [srcq +2*wq]
+    mova     m2, [src2q+2*wq]
+    packsswb m1, [srcq +2*wq+mmsize]
+    packsswb m2, [src2q+2*wq+mmsize]
+    paddb    m1, m0
+    paddb    m2, m0
+    mova    [dstq +wq], m1
+    mova    [dst2q+wq], m2
+    jg      .loopx
+
+    lea   srcq, [srcq+src_strideq*4]
+    lea   dstq, [dstq+dst_strideq*2]
+    sub     hd, 2
+    mov     wd, wspill
+    jg      .loopy
+    RET
+%endm
+
+%macro ADD_RECT 1
+; void add_rect_clamped(uint8_t *dst, uint16_t *src, int stride, int16_t *idwt, int idwt_stride, int width, int height)
+cglobal add_rect_clamped_%1, 7,7,3, dst, src, stride, idwt, idwt_stride, w, h
+    mova    m0, [pw_32]
+    add     wd, (mmsize-1)
+    and     wd, ~(mmsize-1)
+
+%ifdef ARCH_X86_64
+    mov   r11d, wd
+    %define wspill r11d
+%else
+    mov    r5m, wd
+    %define wspill r5m
+%endif
+
+.loop:
+    sub     wd, mmsize
+    movu    m1, [srcq +2*wq] ; FIXME: ensure alignment
+    paddw   m1, m0
+    psraw   m1, 6
+    movu    m2, [srcq +2*wq+mmsize] ; FIXME: ensure alignment
+    paddw   m2, m0
+    psraw   m2, 6
+    paddw   m1, [idwtq+2*wq]
+    paddw   m2, [idwtq+2*wq+mmsize]
+    packuswb m1, m2
+    mova    [dstq +wq], m1
+    jg      .loop
+
+    lea   srcq, [srcq + 2*strideq]
+    add   dstq, strideq
+    lea  idwtq, [idwtq+ 2*idwt_strideq]
+    sub     hd, 1
+    mov     wd, wspill
+    jg      .loop
+    RET
+%endm
+
+%macro ADD_OBMC 2
+; void add_obmc(uint16_t *dst, uint8_t *src, int stride, uint8_t *obmc_weight, int yblen)
+cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen
+    pxor        m4, m4
+.loop:
+%assign i 0
+%rep %1 / mmsize
+    mova        m0, [srcq+i]
+    mova        m1, m0
+    punpcklbw   m0, m4
+    punpckhbw   m1, m4
+    mova        m2, [obmcq+i]
+    mova        m3, m2
+   punpcklbw   m2, m4
+    punpckhbw   m3, m4
+    pmullw      m0, m2
+    pmullw      m1, m3
+    movu        m2, [dstq+2*i]
+    movu        m3, [dstq+2*i+mmsize]
+    paddw       m0, m2
+    paddw       m1, m3
+    movu        [dstq+2*i], m0
+    movu        [dstq+2*i+mmsize], m1
+%assign i i+mmsize
+%endrep
+    lea         srcq, [srcq+strideq]
+    lea         dstq, [dstq+2*strideq]
+    add         obmcq, 32
+    sub         yblend, 1
+    jg          .loop
+    RET
+%endm
+
+INIT_MMX
+%ifndef ARCH_X86_64
+PUT_RECT mmx
+ADD_RECT mmx
+
+HPEL_FILTER mmx
+ADD_OBMC 32, mmx
+ADD_OBMC 16, mmx
+%endif
+ADD_OBMC 8, mmx
+
+INIT_XMM
+PUT_RECT sse2
+ADD_RECT sse2
+
+HPEL_FILTER sse2
+ADD_OBMC 32, sse2
+ADD_OBMC 16, sse2
index da93e94..8ec3a08 100644 (file)
@@ -31,6 +31,7 @@
 #include "libavcodec/ac3dec.h"
 #include "dsputil_mmx.h"
 #include "idct_xvid.h"
+#include "diracdsp_mmx.h"
 
 //#undef NDEBUG
 //#include <assert.h>
@@ -1902,6 +1903,46 @@ static void put_vp_no_rnd_pixels16_l2_mmx(uint8_t *dst, const uint8_t *a, const
     put_vp_no_rnd_pixels8_l2_mmx(dst+8, a+8, b+8, stride, h);
 }
 
+#if CONFIG_DIRAC_DECODER
+#define DIRAC_PIXOP(OPNAME, EXT)\
+void ff_ ## OPNAME ## _dirac_pixels8_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels8_ ## EXT(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_ ## EXT(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels32_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+    OPNAME ## _pixels16_ ## EXT(dst   , src[0]   , stride, h);\
+    OPNAME ## _pixels16_ ## EXT(dst+16, src[0]+16, stride, h);\
+}
+
+DIRAC_PIXOP(put, mmx)
+DIRAC_PIXOP(avg, mmx)
+DIRAC_PIXOP(avg, mmx2)
+
+void ff_put_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+    put_pixels16_sse2(dst, src[0], stride, h);
+}
+void ff_avg_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+    avg_pixels16_sse2(dst, src[0], stride, h);
+}
+void ff_put_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+    put_pixels16_sse2(dst   , src[0]   , stride, h);
+    put_pixels16_sse2(dst+16, src[0]+16, stride, h);
+}
+void ff_avg_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+    avg_pixels16_sse2(dst   , src[0]   , stride, h);
+    avg_pixels16_sse2(dst+16, src[0]+16, stride, h);
+}
+#endif
+
 /* XXX: those functions should be suppressed ASAP when all IDCTs are
    converted */
 #if CONFIG_GPL
diff --git a/libavcodec/x86/dwt.c b/libavcodec/x86/dwt.c
new file mode 100644 (file)
index 0000000..5cfc2be
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * MMX optimized discrete wavelet transform
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2010 David Conrad
+ *
+ * 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/x86_cpu.h"
+#include "dsputil_mmx.h"
+#include "dwt.h"
+
+#define COMPOSE_VERTICAL(ext, align) \
+void ff_vertical_compose53iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width); \
+void ff_vertical_compose_dirac53iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width); \
+void ff_vertical_compose_dd137iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, int width); \
+void ff_vertical_compose_dd97iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, int width); \
+void ff_vertical_compose_haar##ext(IDWTELEM *b0, IDWTELEM *b1, int width); \
+\
+static void vertical_compose53iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width) \
+{ \
+    int i, width_align = width&~(align-1); \
+\
+    for(i=width_align; i<width; i++) \
+        b1[i] = COMPOSE_53iL0(b0[i], b1[i], b2[i]); \
+\
+    ff_vertical_compose53iL0##ext(b0, b1, b2, width_align); \
+} \
+\
+static void vertical_compose_dirac53iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width) \
+{ \
+    int i, width_align = width&~(align-1); \
+\
+    for(i=width_align; i<width; i++) \
+        b1[i] = COMPOSE_DIRAC53iH0(b0[i], b1[i], b2[i]); \
+\
+    ff_vertical_compose_dirac53iH0##ext(b0, b1, b2, width_align); \
+} \
+\
+static void vertical_compose_dd137iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, \
+                                           IDWTELEM *b3, IDWTELEM *b4, int width) \
+{ \
+    int i, width_align = width&~(align-1); \
+\
+    for(i=width_align; i<width; i++) \
+        b2[i] = COMPOSE_DD137iL0(b0[i], b1[i], b2[i], b3[i], b4[i]); \
+\
+    ff_vertical_compose_dd137iL0##ext(b0, b1, b2, b3, b4, width_align); \
+} \
+\
+static void vertical_compose_dd97iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, \
+                                          IDWTELEM *b3, IDWTELEM *b4, int width) \
+{ \
+    int i, width_align = width&~(align-1); \
+\
+    for(i=width_align; i<width; i++) \
+        b2[i] = COMPOSE_DD97iH0(b0[i], b1[i], b2[i], b3[i], b4[i]); \
+\
+    ff_vertical_compose_dd97iH0##ext(b0, b1, b2, b3, b4, width_align); \
+} \
+static void vertical_compose_haar##ext(IDWTELEM *b0, IDWTELEM *b1, int width) \
+{ \
+    int i, width_align = width&~(align-1); \
+\
+    for(i=width_align; i<width; i++) { \
+        b0[i] = COMPOSE_HAARiL0(b0[i], b1[i]); \
+        b1[i] = COMPOSE_HAARiH0(b1[i], b0[i]); \
+    } \
+\
+    ff_vertical_compose_haar##ext(b0, b1, width_align); \
+} \
+\
+
+#if HAVE_YASM
+#if !ARCH_X86_64
+COMPOSE_VERTICAL(_mmx, 4)
+#endif
+COMPOSE_VERTICAL(_sse2, 8)
+#endif
+
+
+void ff_horizontal_compose_dd97i_ssse3(IDWTELEM *b, IDWTELEM *tmp, int w);
+
+void ff_horizontal_compose_haar0i_mmx(IDWTELEM *b, IDWTELEM *tmp, int w);
+void ff_horizontal_compose_haar1i_mmx(IDWTELEM *b, IDWTELEM *tmp, int w);
+void ff_horizontal_compose_haar0i_sse2(IDWTELEM *b, IDWTELEM *tmp, int w);
+void ff_horizontal_compose_haar1i_sse2(IDWTELEM *b, IDWTELEM *tmp, int w);
+
+void ff_horizontal_compose_dd97i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x)
+{
+    for (; x < w2; x++) {
+        b[2*x  ] = (tmp[x] + 1)>>1;
+        b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1;
+    }
+}
+
+void ff_horizontal_compose_haar0i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x)
+{
+    for (; x < w2; x++) {
+        b[2*x  ] = tmp[x];
+        b[2*x+1] = COMPOSE_HAARiH0(b[x+w2], tmp[x]);
+    }
+}
+
+void ff_horizontal_compose_haar1i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x)
+{
+    for (; x < w2; x++) {
+        b[2*x  ] = (tmp[x] + 1)>>1;
+        b[2*x+1] = (COMPOSE_HAARiH0(b[x+w2], tmp[x]) + 1)>>1;
+    }
+}
+
+void ff_spatial_idwt_init_mmx(DWTContext *d, enum dwt_type type)
+{
+#if HAVE_YASM
+  int mm_flags = av_get_cpu_flags();;
+
+#if !ARCH_X86_64
+    if (!(mm_flags & AV_CPU_FLAG_MMX))
+        return;
+
+    switch (type) {
+    case DWT_DIRAC_DD9_7:
+        d->vertical_compose_l0 = vertical_compose53iL0_mmx;
+        d->vertical_compose_h0 = vertical_compose_dd97iH0_mmx;
+        break;
+    case DWT_DIRAC_LEGALL5_3:
+        d->vertical_compose_l0 = vertical_compose53iL0_mmx;
+        d->vertical_compose_h0 = vertical_compose_dirac53iH0_mmx;
+        break;
+    case DWT_DIRAC_DD13_7:
+        d->vertical_compose_l0 = vertical_compose_dd137iL0_mmx;
+        d->vertical_compose_h0 = vertical_compose_dd97iH0_mmx;
+        break;
+    case DWT_DIRAC_HAAR0:
+        d->vertical_compose   = vertical_compose_haar_mmx;
+        d->horizontal_compose = ff_horizontal_compose_haar0i_mmx;
+        break;
+    case DWT_DIRAC_HAAR1:
+        d->vertical_compose   = vertical_compose_haar_mmx;
+        d->horizontal_compose = ff_horizontal_compose_haar1i_mmx;
+        break;
+    }
+#endif
+
+    if (!(mm_flags & AV_CPU_FLAG_SSE2))
+        return;
+
+    switch (type) {
+    case DWT_DIRAC_DD9_7:
+        d->vertical_compose_l0 = vertical_compose53iL0_sse2;
+        d->vertical_compose_h0 = vertical_compose_dd97iH0_sse2;
+        break;
+    case DWT_DIRAC_LEGALL5_3:
+        d->vertical_compose_l0 = vertical_compose53iL0_sse2;
+        d->vertical_compose_h0 = vertical_compose_dirac53iH0_sse2;
+        break;
+    case DWT_DIRAC_DD13_7:
+        d->vertical_compose_l0 = vertical_compose_dd137iL0_sse2;
+        d->vertical_compose_h0 = vertical_compose_dd97iH0_sse2;
+        break;
+    case DWT_DIRAC_HAAR0:
+        d->vertical_compose   = vertical_compose_haar_sse2;
+        d->horizontal_compose = ff_horizontal_compose_haar0i_sse2;
+        break;
+    case DWT_DIRAC_HAAR1:
+        d->vertical_compose   = vertical_compose_haar_sse2;
+        d->horizontal_compose = ff_horizontal_compose_haar1i_sse2;
+        break;
+    }
+
+    if (!(mm_flags & AV_CPU_FLAG_SSSE3))
+        return;
+
+    switch (type) {
+    case DWT_DIRAC_DD9_7:
+        d->horizontal_compose = ff_horizontal_compose_dd97i_ssse3;
+        break;
+    }
+#endif // HAVE_YASM
+}
diff --git a/libavcodec/x86/dwt.h b/libavcodec/x86/dwt.h
new file mode 100644 (file)
index 0000000..199f611
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_X86_DWT_H
+#define AVCODEC_X86_DWT_H
+
+#include "libavcodec/dwt.h"
+
+void ff_horizontal_compose_dd97i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x);
+void ff_horizontal_compose_haar1i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x);
+void ff_horizontal_compose_haar0i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x);
+
+void ff_spatial_idwt_init_mmx(DWTContext *d, enum dwt_type type);
+
+#endif
diff --git a/libavcodec/x86/dwt_yasm.asm b/libavcodec/x86/dwt_yasm.asm
new file mode 100644 (file)
index 0000000..bdff9dd
--- /dev/null
@@ -0,0 +1,312 @@
+;******************************************************************************
+;* MMX optimized discrete wavelet trasnform
+;* Copyright (c) 2010 David Conrad
+;*
+;* 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
+;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "x86inc.asm"
+
+cextern horizontal_compose_dd97i_end_c
+cextern horizontal_compose_haar0i_end_c
+cextern horizontal_compose_haar1i_end_c
+
+SECTION_RODATA
+pw_1: times 8 dw 1
+pw_2: times 8 dw 2
+pw_8: times 8 dw 8
+pw_16: times 8 dw 16
+pw_1991: times 4 dw 9,-1
+
+section .text
+
+; %1 -= (%2 + %3 + 2)>>2     %4 is pw_2
+%macro COMPOSE_53iL0 4
+    paddw   %2, %3
+    paddw   %2, %4
+    psraw   %2, 2
+    psubw   %1, %2
+%endm
+
+; m1 = %1 + (-m0 + 9*m1 + 9*%2 -%3 + 8)>>4
+; if %4 is supplied, %1 is loaded unaligned from there
+; m2: clobbered  m3: pw_8  m4: pw_1991
+%macro COMPOSE_DD97iH0 3-4
+    paddw   m0, %3
+    paddw   m1, %2
+    psubw   m0, m3
+    mova    m2, m1
+    punpcklwd m1, m0
+    punpckhwd m2, m0
+    pmaddwd m1, m4
+    pmaddwd m2, m4
+%if %0 > 3
+    movu    %1, %4
+%endif
+    psrad   m1, 4
+    psrad   m2, 4
+    packssdw m1, m2
+    paddw   m1, %1
+%endm
+
+%macro COMPOSE_VERTICAL 1
+; void vertical_compose53iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+;                                  int width)
+cglobal vertical_compose53iL0_%1, 4,4,1, b0, b1, b2, width
+    mova    m2, [pw_2]
+.loop:
+    sub     widthd, mmsize/2
+    mova    m1, [b0q+2*widthq]
+    mova    m0, [b1q+2*widthq]
+    COMPOSE_53iL0 m0, m1, [b2q+2*widthq], m2
+    mova    [b1q+2*widthq], m0
+    jg      .loop
+    REP_RET
+
+; void vertical_compose_dirac53iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+;                                  int width)
+cglobal vertical_compose_dirac53iH0_%1, 4,4,1, b0, b1, b2, width
+    mova    m1, [pw_1]
+.loop:
+    sub     widthd, mmsize/2
+    mova    m0, [b0q+2*widthq]
+    paddw   m0, [b2q+2*widthq]
+    paddw   m0, m1
+    psraw   m0, 1
+    paddw   m0, [b1q+2*widthq]
+    mova    [b1q+2*widthq], m0
+    jg      .loop
+    REP_RET
+
+; void vertical_compose_dd97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+;                               IDWTELEM *b3, IDWTELEM *b4, int width)
+cglobal vertical_compose_dd97iH0_%1, 6,6,5, b0, b1, b2, b3, b4, width
+    mova    m3, [pw_8]
+    mova    m4, [pw_1991]
+.loop:
+    sub     widthd, mmsize/2
+    mova    m0, [b0q+2*widthq]
+    mova    m1, [b1q+2*widthq]
+    COMPOSE_DD97iH0 [b2q+2*widthq], [b3q+2*widthq], [b4q+2*widthq]
+    mova    [b2q+2*widthq], m1
+    jg      .loop
+    REP_RET
+
+; void vertical_compose_dd137iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+;                                IDWTELEM *b3, IDWTELEM *b4, int width)
+cglobal vertical_compose_dd137iL0_%1, 6,6,6, b0, b1, b2, b3, b4, width
+    mova    m3, [pw_16]
+    mova    m4, [pw_1991]
+.loop:
+    sub     widthd, mmsize/2
+    mova    m0, [b0q+2*widthq]
+    mova    m1, [b1q+2*widthq]
+    mova    m5, [b2q+2*widthq]
+    paddw   m0, [b4q+2*widthq]
+    paddw   m1, [b3q+2*widthq]
+    psubw   m0, m3
+    mova    m2, m1
+    punpcklwd m1, m0
+    punpckhwd m2, m0
+    pmaddwd m1, m4
+    pmaddwd m2, m4
+    psrad   m1, 5
+    psrad   m2, 5
+    packssdw m1, m2
+    psubw   m5, m1
+    mova    [b2q+2*widthq], m5
+    jg      .loop
+    REP_RET
+
+; void vertical_compose_haar(IDWTELEM *b0, IDWTELEM *b1, int width)
+cglobal vertical_compose_haar_%1, 3,4,3, b0, b1, width
+    mova    m3, [pw_1]
+.loop:
+    sub     widthd, mmsize/2
+    mova    m1, [b1q+2*widthq]
+    mova    m0, [b0q+2*widthq]
+    mova    m2, m1
+    paddw   m1, m3
+    psraw   m1, 1
+    psubw   m0, m1
+    mova    [b0q+2*widthq], m0
+    paddw   m2, m0
+    mova    [b1q+2*widthq], m2
+    jg      .loop
+    REP_RET
+%endmacro
+
+; extend the left and right edges of the tmp array by %1 and %2 respectively
+%macro EDGE_EXTENSION 3
+    mov     %3, [tmpq]
+%assign %%i 1
+%rep %1
+    mov     [tmpq-2*%%i], %3
+    %assign %%i %%i+1
+%endrep
+    mov     %3, [tmpq+2*w2q-2]
+%assign %%i 0
+%rep %2
+    mov     [tmpq+2*w2q+2*%%i], %3
+    %assign %%i %%i+1
+%endrep
+%endmacro
+
+; On x86-64 this does a tail call to the C function to do the final bit
+; x86-32 doesn't because isn't enough stack space for the additional argument x
+%macro END_HORIZONTAL 1
+    shr     wd, 1
+%ifdef ARCH_X86_64
+    RET                                ;This RET was a CLEANUP call
+    jmp     %1
+%else
+    push    xd
+    push    wd
+    push    tmpd
+    push    bd
+    call    %1
+    add     esp, 16
+    RET
+%endif
+%endmacro
+
+%macro HAAR_HORIZONTAL 2
+; void horizontal_compose_haari(IDWTELEM *b, IDWTELEM *tmp, int width)
+cglobal horizontal_compose_haar%2i_%1, 3,6,4, b, tmp, w, x, w2, b_w2
+    mov    w2d, wd
+    xor     xd, xd
+    shr    w2d, 1
+    lea  b_w2q, [bq+wq]
+    mova    m3, [pw_1]
+.lowpass_loop:
+    movu    m1, [b_w2q + 2*xq]
+    mova    m0, [bq    + 2*xq]
+    paddw   m1, m3
+    psraw   m1, 1
+    psubw   m0, m1
+    mova    [tmpq + 2*xq], m0
+    add     xd, mmsize/2
+    cmp     xd, w2d
+    jl      .lowpass_loop
+
+    xor     xd, xd
+    and    w2d, ~(mmsize/2 - 1)
+    cmp    w2d, mmsize/2
+    jl      .end
+
+.highpass_loop:
+    mova    m1, [b_w2q + 2*xq]
+    mova    m0, [tmpq  + 2*xq]
+    paddw   m1, m0
+
+    ; shift and interleave
+%if %2 == 1
+    paddw   m0, m3
+    paddw   m1, m3
+    psraw   m0, 1
+    psraw   m1, 1
+%endif
+    mova    m2, m0
+    punpcklwd m0, m1
+    punpckhwd m2, m1
+    mova    [bq+4*xq], m0
+    mova    [bq+4*xq+mmsize], m2
+
+    add     xd, mmsize/2
+    cmp     xd, w2d
+    jl      .highpass_loop
+.end:
+    END_HORIZONTAL horizontal_compose_haar%2i_end_c
+%endmacro
+
+
+INIT_XMM
+; void horizontal_compose_dd97i(IDWTELEM *b, IDWTELEM *tmp, int width)
+cglobal horizontal_compose_dd97i_ssse3, 3,6,8, b, tmp, w, x, w2, b_w2
+    mov    w2d, wd
+    xor     xd, xd
+    shr    w2d, 1
+    lea  b_w2q, [bq+wq]
+    movu    m4, [bq+wq]
+    mova    m7, [pw_2]
+    pslldq  m4, 14
+.lowpass_loop:
+    movu    m1, [b_w2q + 2*xq]
+    mova    m0, [bq    + 2*xq]
+    mova    m2, m1
+    palignr m1, m4, 14
+    mova    m4, m2
+    COMPOSE_53iL0 m0, m1, m2, m7
+    mova    [tmpq + 2*xq], m0
+    add     xd, mmsize/2
+    cmp     xd, w2d
+    jl      .lowpass_loop
+
+    EDGE_EXTENSION 1, 2, xw
+    ; leave the last up to 7 (sse) or 3 (mmx) values for C
+    xor     xd, xd
+    and    w2d, ~(mmsize/2 - 1)
+    cmp    w2d, mmsize/2
+    jl      .end
+
+    mova    m7, [tmpq-mmsize]
+    mova    m0, [tmpq]
+    mova    m5, [pw_1]
+    mova    m3, [pw_8]
+    mova    m4, [pw_1991]
+.highpass_loop:
+    mova    m6, m0
+    palignr m0, m7, 14
+    mova    m7, [tmpq + 2*xq + 16]
+    mova    m1, m7
+    mova    m2, m7
+    palignr m1, m6, 2
+    palignr m2, m6, 4
+    COMPOSE_DD97iH0 m0, m6, m2, [b_w2q + 2*xq]
+    mova    m0, m7
+    mova    m7, m6
+
+    ; shift and interleave
+    paddw   m6, m5
+    paddw   m1, m5
+    psraw   m6, 1
+    psraw   m1, 1
+    mova    m2, m6
+    punpcklwd m6, m1
+    punpckhwd m2, m1
+    mova    [bq+4*xq], m6
+    mova    [bq+4*xq+mmsize], m2
+
+    add     xd, mmsize/2
+    cmp     xd, w2d
+    jl      .highpass_loop
+.end:
+    END_HORIZONTAL horizontal_compose_dd97i_end_c
+
+
+%ifndef ARCH_X86_64
+INIT_MMX
+COMPOSE_VERTICAL mmx
+HAAR_HORIZONTAL mmx, 0
+HAAR_HORIZONTAL mmx, 1
+%endif
+
+;;INIT_XMM
+INIT_XMM
+COMPOSE_VERTICAL sse2
+HAAR_HORIZONTAL sse2, 0
+HAAR_HORIZONTAL sse2, 1