[FFmpeg-cvslog] Add Kamil Nowosads j2k code.

Kamil Nowosad git at videolan.org
Tue May 24 02:02:37 CEST 2011


ffmpeg | branch: master | Kamil Nowosad <k.nowosad at students.mimuw.edu.pl> | Mon May 23 23:13:34 2011 +0200| [83654c7b1b598add9041c7add6b77478eb91177f] | committer: Michael Niedermayer

Add Kamil Nowosads j2k code.

This needs work but it should not rot in soc svn.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=83654c7b1b598add9041c7add6b77478eb91177f
---

 doc/general.texi       |    3 +-
 libavcodec/Makefile    |    2 +
 libavcodec/allcodecs.c |    1 +
 libavcodec/j2k.c       |  390 ++++++++++++++++++
 libavcodec/j2k.h       |  234 +++++++++++
 libavcodec/j2k_dwt.c   |  384 ++++++++++++++++++
 libavcodec/j2k_dwt.h   |   63 +++
 libavcodec/j2kdec.c    | 1053 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/j2kenc.c    | 1045 +++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/mqc.c       |  108 +++++
 libavcodec/mqc.h       |   75 ++++
 libavcodec/mqcdec.c    |   93 +++++
 libavcodec/mqcenc.c    |  119 ++++++
 libavformat/img2.c     |    1 +
 libavformat/riff.c     |    1 +
 15 files changed, 3570 insertions(+), 2 deletions(-)

diff --git a/doc/general.texi b/doc/general.texi
index f978713..8f0085d 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -284,8 +284,7 @@ following image formats are supported:
     @tab Digital Picture Exchange
 @item JPEG         @tab X @tab X
     @tab Progressive JPEG is not supported.
- at item JPEG 2000    @tab   @tab E
-    @tab decoding supported through external library libopenjpeg
+ at item JPEG 2000    @tab X @tab X
 @item JPEG-LS      @tab X @tab X
 @item LJPEG        @tab X @tab
     @tab Lossless JPEG
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index db184bc..53dd191 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -192,6 +192,8 @@ OBJS-$(CONFIG_INDEO3_DECODER)          += indeo3.o
 OBJS-$(CONFIG_INDEO5_DECODER)          += indeo5.o ivi_common.o ivi_dsp.o
 OBJS-$(CONFIG_INTERPLAY_DPCM_DECODER)  += dpcm.o
 OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o
+OBJS-$(CONFIG_JPEG2000_DECODER)        += j2kdec.o mqcdec.o mqc.o j2k.o j2k_dwt.o
+#OBJS-$(CONFIG_JPEG2000_ENCODER)        += j2kenc.o mqcenc.o mqc.o j2k.o dwt.o
 OBJS-$(CONFIG_JPEGLS_DECODER)          += jpeglsdec.o jpegls.o \
                                           mjpegdec.o mjpeg.o
 OBJS-$(CONFIG_JPEGLS_ENCODER)          += jpeglsenc.o jpegls.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index ff032dd..1ec2010 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -131,6 +131,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER (INDEO3, indeo3);
     REGISTER_DECODER (INDEO5, indeo5);
     REGISTER_DECODER (INTERPLAY_VIDEO, interplay_video);
+    REGISTER_DECODER (JPEG2000, jpeg2000);
     REGISTER_ENCDEC  (JPEGLS, jpegls);
     REGISTER_DECODER (JV, jv);
     REGISTER_DECODER (KGV1, kgv1);
diff --git a/libavcodec/j2k.c b/libavcodec/j2k.c
new file mode 100644
index 0000000..3cf87bc
--- /dev/null
+++ b/libavcodec/j2k.c
@@ -0,0 +1,390 @@
+/*
+ * JPEG2000 encoder and decoder common functions
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ */
+
+/**
+ * JPEG2000 image encoder and decoder common functions
+ * @file
+ * @author Kamil Nowosad
+ */
+
+
+#include "avcodec.h"
+#include "j2k.h"
+
+#define SHL(a, n) ((n)>=0 ? (a) << (n) : (a) >> -(n))
+
+#if 0
+void ff_j2k_printv(int *tab, int l)
+{
+    int i;
+    for (i = 0; i < l; i++)
+        printf("%.3d ", tab[i]);
+    printf("\n");
+}
+
+void ff_j2k_printu(uint8_t *tab, int l)
+{
+    int i;
+    for (i = 0; i < l; i++)
+        printf("%.3hd ", tab[i]);
+    printf("\n");
+}
+#endif
+
+/* tag tree routines */
+
+/** allocate the memory for tag tree */
+
+static int tag_tree_size(int w, int h)
+{
+    int res = 0;
+    while (w > 1 || h > 1){
+        res += w * h;
+        w = (w+1) >> 1;
+        h = (h+1) >> 1;
+    }
+    return res + 1;
+}
+
+J2kTgtNode *ff_j2k_tag_tree_init(int w, int h)
+{
+    int pw = w, ph = h;
+    J2kTgtNode *res, *t, *t2;
+
+    t = res = av_mallocz(tag_tree_size(w, h)*sizeof(J2kTgtNode));
+
+    if (res == NULL)
+        return NULL;
+
+    while (w > 1 || h > 1){
+        int i, j;
+        pw = w;
+        ph = h;
+
+        w = (w+1) >> 1;
+        h = (h+1) >> 1;
+        t2 = t + pw*ph;
+
+        for (i = 0; i < ph; i++)
+            for (j = 0; j < pw; j++){
+                t[i*pw + j].parent = &t2[(i>>1)*w + (j>>1)];
+            }
+        t = t2;
+    }
+    t[0].parent = NULL;
+    return res;
+}
+
+static void tag_tree_zero(J2kTgtNode *t, int w, int h)
+{
+    int i, siz = tag_tree_size(w, h);
+
+    for (i = 0; i < siz; i++){
+        t[i].val = 0;
+        t[i].vis = 0;
+    }
+}
+
+uint8_t ff_j2k_nbctxno_lut[256][4];
+
+static int getnbctxno(int flag, int bandno)
+{
+    int h, v, d;
+
+    h = ((flag & J2K_T1_SIG_E) ? 1:0)+
+        ((flag & J2K_T1_SIG_W) ? 1:0);
+    v = ((flag & J2K_T1_SIG_N) ? 1:0)+
+        ((flag & J2K_T1_SIG_S) ? 1:0);
+    d = ((flag & J2K_T1_SIG_NE) ? 1:0)+
+        ((flag & J2K_T1_SIG_NW) ? 1:0)+
+        ((flag & J2K_T1_SIG_SE) ? 1:0)+
+        ((flag & J2K_T1_SIG_SW) ? 1:0);
+    if (bandno < 3){
+            if (bandno == 1)
+                FFSWAP(int, h, v);
+            if (h == 2) return 8;
+            if (h == 1){
+                if (v >= 1) return 7;
+                if (d >= 1) return 6;
+                return 5;
+            }
+            if (v == 2) return 4;
+            if (v == 1) return 3;
+            if (d >= 2) return 2;
+            if (d == 1) return 1;
+            return 0;
+    } else{
+            if (d >= 3) return 8;
+            if (d == 2){
+                if (h+v >= 1) return 7;
+                return 6;
+            }
+            if (d == 1){
+                if (h+v >= 2) return 5;
+                if (h+v == 1) return 4;
+                return 3;
+            }
+            if (h+v >= 2) return 2;
+            if (h+v == 1) return 1;
+            return 0;
+    }
+    assert(0);
+}
+
+uint8_t ff_j2k_sgnctxno_lut[16][16], ff_j2k_xorbit_lut[16][16];
+
+static int getsgnctxno(int flag, uint8_t *xorbit)
+{
+    int vcontrib, hcontrib;
+    static const int contribtab[3][3] = {{0, -1, 1}, {-1, -1, 0}, {1, 0, 1}};
+    static const int ctxlbltab[3][3] = {{13, 12, 11}, {10, 9, 10}, {11, 12, 13}};
+    static const int xorbittab[3][3] = {{1, 1, 1,}, {1, 0, 0}, {0, 0, 0}};
+
+    hcontrib = contribtab[flag & J2K_T1_SIG_E ? flag & J2K_T1_SGN_E ? 1:2:0]
+                         [flag & J2K_T1_SIG_W ? flag & J2K_T1_SGN_W ? 1:2:0]+1;
+    vcontrib = contribtab[flag & J2K_T1_SIG_S ? flag & J2K_T1_SGN_S ? 1:2:0]
+                         [flag & J2K_T1_SIG_N ? flag & J2K_T1_SGN_N ? 1:2:0]+1;
+    *xorbit = xorbittab[hcontrib][vcontrib];
+    return ctxlbltab[hcontrib][vcontrib];
+}
+
+void ff_j2k_init_tier1_luts()
+{
+    int i, j;
+    for (i = 0; i < 256; i++)
+        for (j = 0; j < 4; j++)
+            ff_j2k_nbctxno_lut[i][j] = getnbctxno(i, j);
+    for (i = 0; i < 16; i++)
+        for (j = 0; j < 16; j++)
+            ff_j2k_sgnctxno_lut[i][j] = getsgnctxno(i + (j << 8), &ff_j2k_xorbit_lut[i][j]);
+}
+
+void ff_j2k_set_significant(J2kT1Context *t1, int x, int y, int negative)
+{
+    x++; y++;
+    t1->flags[y][x] |= J2K_T1_SIG;
+    if (negative){
+        t1->flags[y][x+1] |= J2K_T1_SIG_W | J2K_T1_SGN_W;
+        t1->flags[y][x-1] |= J2K_T1_SIG_E | J2K_T1_SGN_E;
+        t1->flags[y+1][x] |= J2K_T1_SIG_N | J2K_T1_SGN_N;
+        t1->flags[y-1][x] |= J2K_T1_SIG_S | J2K_T1_SGN_S;
+    } else{
+        t1->flags[y][x+1] |= J2K_T1_SIG_W;
+        t1->flags[y][x-1] |= J2K_T1_SIG_E;
+        t1->flags[y+1][x] |= J2K_T1_SIG_N;
+        t1->flags[y-1][x] |= J2K_T1_SIG_S;
+    }
+    t1->flags[y+1][x+1] |= J2K_T1_SIG_NW;
+    t1->flags[y+1][x-1] |= J2K_T1_SIG_NE;
+    t1->flags[y-1][x+1] |= J2K_T1_SIG_SW;
+    t1->flags[y-1][x-1] |= J2K_T1_SIG_SE;
+}
+
+int ff_j2k_init_component(J2kComponent *comp, J2kCodingStyle *codsty, J2kQuantStyle *qntsty, int cbps, int dx, int dy)
+{
+    int reslevelno, bandno, gbandno = 0, ret, i, j, csize = 1;
+
+    if (ret=ff_j2k_dwt_init(&comp->dwt, comp->coord, codsty->nreslevels-1, codsty->transform))
+        return ret;
+    for (i = 0; i < 2; i++)
+        csize *= comp->coord[i][1] - comp->coord[i][0];
+
+    comp->data = av_malloc(csize * sizeof(int));
+    if (!comp->data)
+        return AVERROR(ENOMEM);
+    comp->reslevel = av_malloc(codsty->nreslevels * sizeof(J2kResLevel));
+
+    if (!comp->reslevel)
+        return AVERROR(ENOMEM);
+    for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+        int declvl = codsty->nreslevels - reslevelno;
+        J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+        for (i = 0; i < 2; i++)
+            for (j = 0; j < 2; j++)
+                reslevel->coord[i][j] =
+                    ff_j2k_ceildivpow2(comp->coord[i][j], declvl - 1);
+
+        if (reslevelno == 0)
+            reslevel->nbands = 1;
+        else
+            reslevel->nbands = 3;
+
+        if (reslevel->coord[0][1] == reslevel->coord[0][0])
+            reslevel->num_precincts_x = 0;
+        else
+            reslevel->num_precincts_x = ff_j2k_ceildivpow2(reslevel->coord[0][1], codsty->log2_prec_width)
+                                        - (reslevel->coord[0][0] >> codsty->log2_prec_width);
+
+        if (reslevel->coord[1][1] == reslevel->coord[1][0])
+            reslevel->num_precincts_y = 0;
+        else
+            reslevel->num_precincts_y = ff_j2k_ceildivpow2(reslevel->coord[1][1], codsty->log2_prec_height)
+                                        - (reslevel->coord[1][0] >> codsty->log2_prec_height);
+
+        reslevel->band = av_malloc(reslevel->nbands * sizeof(J2kBand));
+        if (!reslevel->band)
+            return AVERROR(ENOMEM);
+        for (bandno = 0; bandno < reslevel->nbands; bandno++, gbandno++){
+            J2kBand *band = reslevel->band + bandno;
+            int cblkno, precx, precy, precno;
+            int x0, y0, x1, y1;
+            int xi0, yi0, xi1, yi1;
+            int cblkperprecw, cblkperprech;
+
+            if (qntsty->quantsty != J2K_QSTY_NONE){
+                const static uint8_t lut_gain[2][4] = {{0, 0, 0, 0}, {0, 1, 1, 2}};
+                int numbps;
+
+                numbps = cbps + lut_gain[codsty->transform][bandno + reslevelno>0];
+                band->stepsize = SHL(2048 + qntsty->mant[gbandno], 2 + numbps - qntsty->expn[gbandno]);
+            } else
+                band->stepsize = 1 << 13;
+
+            if (reslevelno == 0){  // the same everywhere
+                band->codeblock_width = 1 << FFMIN(codsty->log2_cblk_width, codsty->log2_prec_width-1);
+                band->codeblock_height = 1 << FFMIN(codsty->log2_cblk_height, codsty->log2_prec_height-1);
+                for (i = 0; i < 2; i++)
+                    for (j = 0; j < 2; j++)
+                        band->coord[i][j] = ff_j2k_ceildivpow2(comp->coord[i][j], declvl-1);
+            } else{
+                band->codeblock_width = 1 << FFMIN(codsty->log2_cblk_width, codsty->log2_prec_width);
+                band->codeblock_height = 1 << FFMIN(codsty->log2_cblk_height, codsty->log2_prec_height);
+
+                for (i = 0; i < 2; i++)
+                    for (j = 0; j < 2; j++)
+                        band->coord[i][j] = ff_j2k_ceildivpow2(comp->coord[i][j] - (((bandno+1>>i)&1) << declvl-1), declvl);
+            }
+            band->cblknx = ff_j2k_ceildiv(band->coord[0][1], band->codeblock_width)  - band->coord[0][0] / band->codeblock_width;
+            band->cblkny = ff_j2k_ceildiv(band->coord[1][1], band->codeblock_height) - band->coord[1][0] / band->codeblock_height;
+
+            for (j = 0; j < 2; j++)
+                band->coord[0][j] = ff_j2k_ceildiv(band->coord[0][j], dx);
+            for (j = 0; j < 2; j++)
+                band->coord[1][j] = ff_j2k_ceildiv(band->coord[1][j], dy);
+
+            band->cblknx = ff_j2k_ceildiv(band->cblknx, dx);
+            band->cblkny = ff_j2k_ceildiv(band->cblkny, dy);
+
+            band->cblk = av_malloc(band->cblknx * band->cblkny * sizeof(J2kCblk));
+            if (!band->cblk)
+                return AVERROR(ENOMEM);
+            band->prec = av_malloc(reslevel->num_precincts_x * reslevel->num_precincts_y * sizeof(J2kPrec));
+            if (!band->prec)
+                return AVERROR(ENOMEM);
+
+            for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+                J2kCblk *cblk = band->cblk + cblkno;
+                cblk->zero = 0;
+                cblk->lblock = 3;
+                cblk->length = 0;
+                cblk->lengthinc = 0;
+                cblk->npasses = 0;
+            }
+
+            y0 = band->coord[1][0];
+            y1 = ((band->coord[1][0] + (1<<codsty->log2_prec_height)) & ~((1<<codsty->log2_prec_height)-1)) - y0;
+            yi0 = 0;
+            yi1 = ff_j2k_ceildivpow2(y1 - y0, codsty->log2_cblk_height) << codsty->log2_cblk_height;
+            yi1 = FFMIN(yi1, band->cblkny);
+            cblkperprech = 1<<(codsty->log2_prec_height - codsty->log2_cblk_height);
+            for (precy = 0, precno = 0; precy < reslevel->num_precincts_y; precy++){
+                for (precx = 0; precx < reslevel->num_precincts_x; precx++, precno++){
+                    band->prec[precno].yi0 = yi0;
+                    band->prec[precno].yi1 = yi1;
+                }
+                yi1 += cblkperprech;
+                yi0 = yi1 - cblkperprech;
+                yi1 = FFMIN(yi1, band->cblkny);
+            }
+            x0 = band->coord[0][0];
+            x1 = ((band->coord[0][0] + (1<<codsty->log2_prec_width)) & ~((1<<codsty->log2_prec_width)-1)) - x0;
+            xi0 = 0;
+            xi1 = ff_j2k_ceildivpow2(x1 - x0, codsty->log2_cblk_width) << codsty->log2_cblk_width;
+            xi1 = FFMIN(xi1, band->cblknx);
+
+            cblkperprecw = 1<<(codsty->log2_prec_width - codsty->log2_cblk_width);
+            for (precx = 0, precno = 0; precx < reslevel->num_precincts_x; precx++){
+                for (precy = 0; precy < reslevel->num_precincts_y; precy++, precno = 0){
+                    J2kPrec *prec = band->prec + precno;
+                    prec->xi0 = xi0;
+                    prec->xi1 = xi1;
+                    prec->cblkincl = ff_j2k_tag_tree_init(prec->xi1 - prec->xi0,
+                                                          prec->yi1 - prec->yi0);
+                    prec->zerobits = ff_j2k_tag_tree_init(prec->xi1 - prec->xi0,
+                                                          prec->yi1 - prec->yi0);
+                    if (!prec->cblkincl || !prec->zerobits)
+                        return AVERROR(ENOMEM);
+
+                }
+                xi1 += cblkperprecw;
+                xi0 = xi1 - cblkperprecw;
+                xi1 = FFMIN(xi1, band->cblknx);
+            }
+        }
+    }
+    return 0;
+}
+
+void ff_j2k_reinit(J2kComponent *comp, J2kCodingStyle *codsty)
+{
+    int reslevelno, bandno, cblkno, precno;
+    for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+        J2kResLevel *rlevel = comp->reslevel + reslevelno;
+        for (bandno = 0; bandno < rlevel->nbands; bandno++){
+            J2kBand *band = rlevel->band + bandno;
+            for(precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++){
+                J2kPrec *prec = band->prec + precno;
+                tag_tree_zero(prec->zerobits, prec->xi1 - prec->xi0, prec->yi1 - prec->yi0);
+                tag_tree_zero(prec->cblkincl, prec->xi1 - prec->xi0, prec->yi1 - prec->yi0);
+            }
+            for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+                J2kCblk *cblk = band->cblk + cblkno;
+                cblk->length = 0;
+                cblk->lblock = 3;
+            }
+        }
+    }
+}
+
+void ff_j2k_cleanup(J2kComponent *comp, J2kCodingStyle *codsty)
+{
+    int reslevelno, bandno, precno;
+    for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+        J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+        for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+            J2kBand *band = reslevel->band + bandno;
+                for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+                    J2kPrec *prec = band->prec + precno;
+                    av_freep(&prec->zerobits);
+                    av_freep(&prec->cblkincl);
+                }
+                av_freep(&band->cblk);
+                av_freep(&band->prec);
+            }
+        av_freep(&reslevel->band);
+    }
+
+    ff_j2k_dwt_destroy(&comp->dwt);
+    av_freep(&comp->reslevel);
+    av_freep(&comp->data);
+}
diff --git a/libavcodec/j2k.h b/libavcodec/j2k.h
new file mode 100644
index 0000000..3a41b53
--- /dev/null
+++ b/libavcodec/j2k.h
@@ -0,0 +1,234 @@
+/*
+ * JPEG2000 tables
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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_J2K_H
+#define AVCODEC_J2K_H
+
+/**
+ * JPEG2000 tables
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "mqc.h"
+#include "j2k_dwt.h"
+
+enum J2kMarkers{
+    J2K_SOC = 0xff4f, ///< start of codestream
+    J2K_SIZ = 0xff51, ///< image and tile size
+    J2K_COD,          ///< coding style default
+    J2K_COC,          ///< coding style component
+    J2K_TLM = 0xff55, ///< packed packet headers, tile-part header
+    J2K_PLM = 0xff57, ///< tile-part lengths
+    J2K_PLT,          ///< packet length, main header
+    J2K_QCD = 0xff5c, ///< quantization default
+    J2K_QCC,          ///< quantization component
+    J2K_RGN,          ///< region of interest
+    J2K_POC,          ///< progression order change
+    J2K_PPM,          ///< packet length, tile-part header
+    J2K_PPT,          ///< packed packet headers, main header
+    J2K_CRG = 0xff63, ///< component registration
+    J2K_COM,          ///< comment
+    J2K_SOT = 0xff90, ///< start of tile-part
+    J2K_SOP,          ///< start of packet
+    J2K_EPH,          ///< end of packet header
+    J2K_SOD,          ///< start of data
+    J2K_EOC = 0xffd9, ///< end of codestream
+};
+
+enum J2kQuantsty{ ///< quantization style
+    J2K_QSTY_NONE, ///< no quantization
+    J2K_QSTY_SI,   ///< scalar derived
+    J2K_QSTY_SE    ///< scalar expoounded
+};
+
+#define J2K_MAX_CBLKW 64
+#define J2K_MAX_CBLKH 64
+
+// T1 flags
+// flags determining significance of neighbour coefficients
+#define J2K_T1_SIG_N  0x0001
+#define J2K_T1_SIG_E  0x0002
+#define J2K_T1_SIG_W  0x0004
+#define J2K_T1_SIG_S  0x0008
+#define J2K_T1_SIG_NE 0x0010
+#define J2K_T1_SIG_NW 0x0020
+#define J2K_T1_SIG_SE 0x0040
+#define J2K_T1_SIG_SW 0x0080
+#define J2K_T1_SIG_NB (J2K_T1_SIG_N | J2K_T1_SIG_E | J2K_T1_SIG_S | J2K_T1_SIG_W \
+                      |J2K_T1_SIG_NE | J2K_T1_SIG_NW | J2K_T1_SIG_SE | J2K_T1_SIG_SW)
+// flags determining sign bit of neighbour coefficients
+#define J2K_T1_SGN_N  0x0100
+#define J2K_T1_SGN_S  0x0200
+#define J2K_T1_SGN_W  0x0400
+#define J2K_T1_SGN_E  0x0800
+
+#define J2K_T1_VIS    0x1000
+#define J2K_T1_SIG    0x2000
+#define J2K_T1_REF    0x4000
+
+#define J2K_T1_SGN    0x8000
+
+// Codeblock coding styles
+#define J2K_CBLK_BYPASS    0x01 // Selective arithmetic coding bypass
+#define J2K_CBLK_RESET     0x02 // Reset context probabilities
+#define J2K_CBLK_TERMALL   0x04 // Terminate after each coding pass
+#define J2K_CBLK_VSC       0x08 // Vertical stripe causal context formation
+#define J2K_CBLK_PREDTERM  0x10 // Predictable termination
+#define J2K_CBLK_SEGSYM    0x20 // Segmentation symbols present
+
+// Coding styles
+#define J2K_CSTY_PREC      0x01 // Precincts defined in coding style
+#define J2K_CSTY_SOP       0x02 // SOP marker present
+#define J2K_CSTY_EPH       0x04 // EPH marker present
+
+typedef struct {
+    int data[J2K_MAX_CBLKW][J2K_MAX_CBLKH];
+    int flags[J2K_MAX_CBLKW+2][J2K_MAX_CBLKH+2];
+    MqcState mqc;
+} J2kT1Context;
+
+typedef struct J2kTgtNode {
+    uint8_t val;
+    uint8_t vis;
+    struct J2kTgtNode *parent;
+} J2kTgtNode;
+
+typedef struct {
+    uint8_t nreslevels;       ///< number of resolution levels
+    uint8_t log2_cblk_width,
+            log2_cblk_height; ///< exponent of codeblock size
+    uint8_t transform;        ///< DWT type
+    uint8_t csty;             ///< coding style
+    uint8_t log2_prec_width,
+            log2_prec_height; ///< precinct size
+    uint8_t nlayers;          ///< number of layers
+    uint8_t mct;              ///< multiple component transformation
+    uint8_t cblk_style;       ///< codeblock coding style
+} J2kCodingStyle;
+
+typedef struct {
+    uint8_t  expn[32 * 3]; ///< quantization exponent
+    uint16_t mant[32 * 3]; ///< quantization mantissa
+    uint8_t  quantsty;     ///< quantization style
+    uint8_t  nguardbits;   ///< number of guard bits
+} J2kQuantStyle;
+
+typedef struct {
+    uint16_t rate;
+    int64_t disto;
+} J2kPass;
+
+typedef struct {
+    uint8_t npasses;
+    uint8_t ninclpasses; ///< number coding of passes included in codestream
+    uint8_t nonzerobits;
+    uint16_t length;
+    uint16_t lengthinc;
+    uint8_t lblock;
+    uint8_t zero;
+    uint8_t data[8192];
+    J2kPass passes[100];
+} J2kCblk; ///< code block
+
+typedef struct {
+    uint16_t xi0, xi1, yi0, yi1; ///< codeblock indexes ([xi0, xi1))
+    J2kTgtNode *zerobits;
+    J2kTgtNode *cblkincl;
+} J2kPrec; ///< precinct
+
+typedef struct {
+    uint16_t coord[2][2]; ///< border coordinates {{x0, x1}, {y0, y1}}
+    uint16_t codeblock_width, codeblock_height;
+    uint16_t cblknx, cblkny;
+    uint32_t stepsize; ///< quantization stepsize (* 2^13)
+    J2kPrec *prec;
+    J2kCblk *cblk;
+} J2kBand; ///< subband
+
+typedef struct {
+    uint8_t nbands;
+    uint16_t coord[2][2]; ///< border coordinates {{x0, x1}, {y0, y1}}
+    uint16_t num_precincts_x, num_precincts_y; ///< number of precincts in x/y direction
+    uint8_t log2_prec_width, log2_prec_height; ///< exponent of precinct size
+    J2kBand *band;
+} J2kResLevel; ///< resolution level
+
+typedef struct {
+   J2kResLevel *reslevel;
+   DWTContext dwt;
+   int *data;
+   uint16_t coord[2][2]; ///< border coordinates {{x0, x1}, {y0, y1}}
+} J2kComponent;
+
+/* debug routines */
+#if 0
+#undef fprintf
+#undef printf
+void ff_j2k_printv(int *tab, int l);
+void ff_j2k_printu(uint8_t *tab, int l);
+#endif
+
+/* misc tools */
+static inline int ff_j2k_ceildivpow2(int a, int b)
+{
+    return (a + (1 << b) - 1)>> b;
+}
+
+static inline int ff_j2k_ceildiv(int a, int b)
+{
+    return (a + b - 1) / b;
+}
+
+/* tag tree routines */
+J2kTgtNode *ff_j2k_tag_tree_init(int w, int h);
+
+/* TIER-1 routines */
+void ff_j2k_init_tier1_luts(void);
+
+void ff_j2k_set_significant(J2kT1Context *t1, int x, int y, int negative);
+
+extern uint8_t ff_j2k_nbctxno_lut[256][4];
+
+static inline int ff_j2k_getnbctxno(int flag, int bandno)
+{
+    return ff_j2k_nbctxno_lut[flag&255][bandno];
+}
+
+static inline int ff_j2k_getrefctxno(int flag)
+{
+    static const uint8_t refctxno_lut[2][2] = {{14, 15}, {16, 16}};
+    return refctxno_lut[(flag>>14)&1][(flag & 255) != 0];
+}
+
+extern uint8_t ff_j2k_sgnctxno_lut[16][16], ff_j2k_xorbit_lut[16][16];
+
+static inline int ff_j2k_getsgnctxno(int flag, int *xorbit)
+{
+    *xorbit = ff_j2k_xorbit_lut[flag&15][(flag>>8)&15];
+    return  ff_j2k_sgnctxno_lut[flag&15][(flag>>8)&15];
+}
+
+int ff_j2k_init_component(J2kComponent *comp, J2kCodingStyle *codsty, J2kQuantStyle *qntsty, int cbps, int dx, int dy);
+void ff_j2k_reinit(J2kComponent *comp, J2kCodingStyle *codsty);
+void ff_j2k_cleanup(J2kComponent *comp, J2kCodingStyle *codsty);
+
+#endif /* AVCODEC_J2K_H */
diff --git a/libavcodec/j2k_dwt.c b/libavcodec/j2k_dwt.c
new file mode 100644
index 0000000..9ba770a
--- /dev/null
+++ b/libavcodec/j2k_dwt.c
@@ -0,0 +1,384 @@
+/*
+ * Discrete wavelet transform
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ */
+
+/**
+ * Discrete wavelet transform
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "j2k_dwt.h"
+
+const static float scale97[] = {1.625786, 1.230174};
+
+static inline void extend53(int *p, int i0, int i1)
+{
+    p[i0 - 1] = p[i0 + 1];
+    p[i1    ] = p[i1 - 2];
+    p[i0 - 2] = p[i0 + 2];
+    p[i1 + 1] = p[i1 - 3];
+}
+
+static inline void extend97(float *p, int i0, int i1)
+{
+    int i;
+
+    for (i = 1; i <= 4; i++){
+        p[i0 - i] = p[i0 + i];
+        p[i1 + i - 1] = p[i1 - i - 1];
+    }
+}
+
+static void sd_1d53(int *p, int i0, int i1)
+{
+    int i;
+
+    if (i1 == i0 + 1)
+        return;
+
+    extend53(p, i0, i1);
+
+    for (i = (i0+1)/2 - 1; i < (i1+1)/2; i++)
+        p[2*i+1] -= (p[2*i] + p[2*i+2]) >> 1;
+    for (i = (i0+1)/2; i < (i1+1)/2; i++)
+        p[2*i] += (p[2*i-1] + p[2*i+1] + 2) >> 2;
+}
+
+static void dwt_encode53(DWTContext *s, int *t)
+{
+    int lev,
+        w = s->linelen[s->ndeclevels-1][0];
+    int *line = s->linebuf;
+    line += 3;
+
+    for (lev = s->ndeclevels-1; lev >= 0; lev--){
+        int lh = s->linelen[lev][0],
+            lv = s->linelen[lev][1],
+            mh = s->mod[lev][0],
+            mv = s->mod[lev][1],
+            lp;
+        int *l;
+
+        // HOR_SD
+        l = line + mh;
+        for (lp = 0; lp < lv; lp++){
+            int i, j = 0;
+
+            for (i = 0; i < lh; i++)
+                l[i] = t[w*lp + i];
+
+            sd_1d53(line, mh, mh + lh);
+
+            // copy back and deinterleave
+            for (i =   mh; i < lh; i+=2, j++)
+                t[w*lp + j] = l[i];
+            for (i = 1-mh; i < lh; i+=2, j++)
+                t[w*lp + j] = l[i];
+        }
+
+        // VER_SD
+        l = line + mv;
+        for (lp = 0; lp < lh; lp++) {
+            int i, j = 0;
+
+            for (i = 0; i < lv; i++)
+                l[i] = t[w*i + lp];
+
+            sd_1d53(line, mv, mv + lv);
+
+            // copy back and deinterleave
+            for (i =   mv; i < lv; i+=2, j++)
+                t[w*j + lp] = l[i];
+            for (i = 1-mv; i < lv; i+=2, j++)
+                t[w*j + lp] = l[i];
+        }
+    }
+}
+
+static void sd_1d97(float *p, int i0, int i1)
+{
+    int i;
+
+    if (i1 == i0 + 1)
+        return;
+
+    extend97(p, i0, i1);
+    i0++; i1++;
+
+    for (i = i0/2 - 2; i < i1/2 + 1; i++)
+        p[2*i+1] -= 1.586134 * (p[2*i] + p[2*i+2]);
+    for (i = i0/2 - 1; i < i1/2 + 1; i++)
+        p[2*i] -= 0.052980 * (p[2*i-1] + p[2*i+1]);
+    for (i = i0/2 - 1; i < i1/2; i++)
+        p[2*i+1] += 0.882911 * (p[2*i] + p[2*i+2]);
+    for (i = i0/2; i < i1/2; i++)
+        p[2*i] += 0.443506 * (p[2*i-1] + p[2*i+1]);
+}
+
+static void dwt_encode97(DWTContext *s, int *t)
+{
+    int lev,
+        w = s->linelen[s->ndeclevels-1][0];
+    float *line = s->linebuf;
+    line += 5;
+
+    for (lev = s->ndeclevels-1; lev >= 0; lev--){
+        int lh = s->linelen[lev][0],
+            lv = s->linelen[lev][1],
+            mh = s->mod[lev][0],
+            mv = s->mod[lev][1],
+            lp;
+        float *l;
+
+        // HOR_SD
+        l = line + mh;
+        for (lp = 0; lp < lv; lp++){
+            int i, j = 0;
+
+            for (i = 0; i < lh; i++)
+                l[i] = t[w*lp + i];
+
+            sd_1d97(line, mh, mh + lh);
+
+            // copy back and deinterleave
+            for (i =   mh; i < lh; i+=2, j++)
+                t[w*lp + j] = scale97[mh] * l[i] / 2;
+            for (i = 1-mh; i < lh; i+=2, j++)
+                t[w*lp + j] = scale97[mh] * l[i] / 2;
+        }
+
+        // VER_SD
+        l = line + mv;
+        for (lp = 0; lp < lh; lp++) {
+            int i, j = 0;
+
+            for (i = 0; i < lv; i++)
+                l[i] = t[w*i + lp];
+
+            sd_1d97(line, mv, mv + lv);
+
+            // copy back and deinterleave
+            for (i =   mv; i < lv; i+=2, j++)
+                t[w*j + lp] = scale97[mv] * l[i] / 2;
+            for (i = 1-mv; i < lv; i+=2, j++)
+                t[w*j + lp] = scale97[mv] * l[i] / 2;
+        }
+    }
+}
+
+static void sr_1d53(int *p, int i0, int i1)
+{
+    int i;
+
+    if (i1 == i0 + 1)
+        return;
+
+    extend53(p, i0, i1);
+
+    for (i = i0/2; i < i1/2 + 1; i++)
+        p[2*i] -= (p[2*i-1] + p[2*i+1] + 2) >> 2;
+    for (i = i0/2; i < i1/2; i++)
+        p[2*i+1] += (p[2*i] + p[2*i+2]) >> 1;
+}
+
+static void dwt_decode53(DWTContext *s, int *t)
+{
+    int lev,
+        w = s->linelen[s->ndeclevels-1][0];
+    int *line = s->linebuf;
+    line += 3;
+
+    for (lev = 0; lev < s->ndeclevels; lev++){
+        int lh = s->linelen[lev][0],
+            lv = s->linelen[lev][1],
+            mh = s->mod[lev][0],
+            mv = s->mod[lev][1],
+            lp;
+        int *l;
+
+        // HOR_SD
+        l = line + mh;
+        for (lp = 0; lp < lv; lp++){
+            int i, j = 0;
+            // copy with interleaving
+            for (i =   mh; i < lh; i+=2, j++)
+                l[i] = t[w*lp + j];
+            for (i = 1-mh; i < lh; i+=2, j++)
+                l[i] = t[w*lp + j];
+
+            sr_1d53(line, mh, mh + lh);
+
+            for (i = 0; i < lh; i++)
+                t[w*lp + i] = l[i];
+        }
+
+        // VER_SD
+        l = line + mv;
+        for (lp = 0; lp < lh; lp++){
+            int i, j = 0;
+            // copy with interleaving
+            for (i =   mv; i < lv; i+=2, j++)
+                l[i] = t[w*j + lp];
+            for (i = 1-mv; i < lv; i+=2, j++)
+                l[i] = t[w*j + lp];
+
+            sr_1d53(line, mv, mv + lv);
+
+            for (i = 0; i < lv; i++)
+                t[w*i + lp] = l[i];
+        }
+    }
+}
+
+static void sr_1d97(float *p, int i0, int i1)
+{
+    int i;
+
+    if (i1 == i0 + 1)
+        return;
+
+    extend97(p, i0, i1);
+
+    for (i = i0/2 - 1; i < i1/2 + 2; i++)
+        p[2*i] -= 0.443506 * (p[2*i-1] + p[2*i+1]);
+    for (i = i0/2 - 1; i < i1/2 + 1; i++)
+        p[2*i+1] -= 0.882911 * (p[2*i] + p[2*i+2]);
+    for (i = i0/2; i < i1/2 + 1; i++)
+        p[2*i] += 0.052980 * (p[2*i-1] + p[2*i+1]);
+    for (i = i0/2; i < i1/2; i++)
+        p[2*i+1] += 1.586134 * (p[2*i] + p[2*i+2]);
+}
+
+static void dwt_decode97(DWTContext *s, int *t)
+{
+    int lev,
+        w = s->linelen[s->ndeclevels-1][0];
+    float *line = s->linebuf;
+    line += 5;
+
+    for (lev = 0; lev < s->ndeclevels; lev++){
+        int lh = s->linelen[lev][0],
+            lv = s->linelen[lev][1],
+            mh = s->mod[lev][0],
+            mv = s->mod[lev][1],
+            lp;
+        float *l;
+
+        // HOR_SD
+        l = line + mh;
+        for (lp = 0; lp < lv; lp++){
+            int i, j = 0;
+            // copy with interleaving
+            for (i =   mh; i < lh; i+=2, j++)
+                l[i] = scale97[1-mh] * t[w*lp + j];
+            for (i = 1-mh; i < lh; i+=2, j++)
+                l[i] = scale97[1-mh] * t[w*lp + j];
+
+            sr_1d97(line, mh, mh + lh);
+
+            for (i = 0; i < lh; i++)
+                t[w*lp + i] = l[i];
+        }
+
+        // VER_SD
+        l = line + mv;
+        for (lp = 0; lp < lh; lp++){
+            int i, j = 0;
+            // copy with interleaving
+            for (i =   mv; i < lv; i+=2, j++)
+                l[i] = scale97[1-mv] * t[w*j + lp];
+            for (i = 1-mv; i < lv; i+=2, j++)
+                l[i] = scale97[1-mv] * t[w*j + lp];
+
+            sr_1d97(line, mv, mv + lv);
+
+            for (i = 0; i < lv; i++)
+                t[w*i + lp] = l[i];
+        }
+    }
+}
+
+int ff_j2k_dwt_init(DWTContext *s, uint16_t border[2][2], int decomp_levels, int type)
+{
+    int i, j, lev = decomp_levels, maxlen,
+        b[2][2];
+
+    s->ndeclevels = decomp_levels;
+    s->type = type;
+
+    for (i = 0; i < 2; i++)
+        for(j = 0; j < 2; j++)
+            b[i][j] = border[i][j];
+
+    maxlen = FFMAX(b[0][1] - b[0][0],
+                   b[1][1] - b[1][0]);
+
+    while(--lev >= 0){
+        for (i = 0; i < 2; i++){
+            s->linelen[lev][i] = b[i][1] - b[i][0];
+            s->mod[lev][i] = b[i][0] & 1;
+            for (j = 0; j < 2; j++)
+                b[i][j] = (b[i][j] + 1) >> 1;
+        }
+    }
+    if (type == FF_DWT97)
+        s->linebuf = av_malloc((maxlen + 12) * sizeof(float));
+    else if (type == FF_DWT53)
+        s->linebuf = av_malloc((maxlen + 6) * sizeof(int));
+    else
+        return -1;
+
+    if (!s->linebuf)
+        return AVERROR(ENOMEM);
+
+    return 0;
+}
+
+int ff_j2k_dwt_encode(DWTContext *s, int *t)
+{
+    switch(s->type){
+        case FF_DWT97:
+            dwt_encode97(s, t); break;
+        case FF_DWT53:
+            dwt_encode53(s, t); break;
+        default:
+            return -1;
+    }
+    return 0;
+}
+
+int ff_j2k_dwt_decode(DWTContext *s, int *t)
+{
+    switch(s->type){
+        case FF_DWT97:
+            dwt_decode97(s, t); break;
+        case FF_DWT53:
+            dwt_decode53(s, t); break;
+        default:
+            return -1;
+    }
+    return 0;
+}
+
+void ff_j2k_dwt_destroy(DWTContext *s)
+{
+    av_freep(&s->linebuf);
+}
diff --git a/libavcodec/j2k_dwt.h b/libavcodec/j2k_dwt.h
new file mode 100644
index 0000000..a2a25a6
--- /dev/null
+++ b/libavcodec/j2k_dwt.h
@@ -0,0 +1,63 @@
+/*
+ * Discrete wavelet transform
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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_DWT_H
+#define AVCODEC_DWT_H
+
+/**
+ * Discrete wavelet transform
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "avcodec.h"
+
+#define FF_DWT_MAX_DECLVLS 32 ///< max number of decomposition levels
+
+enum DWTType{
+    FF_DWT97,
+    FF_DWT53
+};
+
+typedef struct {
+    ///line lengths {horizontal, vertical} in consecutive decomposition levels
+    uint16_t linelen[FF_DWT_MAX_DECLVLS][2];
+    uint8_t  mod[FF_DWT_MAX_DECLVLS][2]; ///< coordinates (x0, y0) of decomp. levels mod 2
+    uint8_t  ndeclevels;                 ///< number of decomposition levels
+    uint8_t  type;                       ///< 0 for 9/7; 1 for 5/3
+    void     *linebuf;                   ///< buffer used by transform (int or float)
+} DWTContext;
+
+/**
+ * initialize DWT
+ * @param s DWT context
+ * @param border coordinates of transformed region {{x0, x1}, {y0, y1}}
+ * @param decomp_levels number of decomposition levels
+ * @param type 0 for DWT 9/7; 1 for DWT 5/3
+ */
+int ff_j2k_dwt_init(DWTContext *s, uint16_t border[2][2], int decomp_levels, int type);
+
+int ff_j2k_dwt_encode(DWTContext *s, int *t);
+int ff_j2k_dwt_decode(DWTContext *s, int *t);
+
+void ff_j2k_dwt_destroy(DWTContext *s);
+
+#endif /* AVCODEC_DWT_H */
diff --git a/libavcodec/j2kdec.c b/libavcodec/j2kdec.c
new file mode 100644
index 0000000..112c0ff
--- /dev/null
+++ b/libavcodec/j2kdec.c
@@ -0,0 +1,1053 @@
+/*
+ * JPEG2000 image decoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ */
+
+/**
+ * JPEG2000 image decoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "j2k.h"
+#include "libavutil/common.h"
+
+#define JP2_SIG_TYPE    0x6A502020
+#define JP2_SIG_VALUE   0x0D0A870A
+#define JP2_CODESTREAM  0x6A703263
+
+#define HAD_COC 0x01
+#define HAD_QCC 0x02
+
+typedef struct {
+   J2kComponent *comp;
+   uint8_t properties[4];
+   J2kCodingStyle codsty[4];
+   J2kQuantStyle  qntsty[4];
+} J2kTile;
+
+typedef struct {
+    AVCodecContext *avctx;
+    AVFrame picture;
+
+    int width, height; ///< image width and height
+    int image_offset_x, image_offset_y;
+    int tile_offset_x, tile_offset_y;
+    uint8_t cbps[4]; ///< bits per sample in particular components
+    uint8_t sgnd[4]; ///< if a component is signed
+    uint8_t properties[4];
+    int cdx[4], cdy[4];
+    int precision;
+    int ncomponents;
+    int tile_width, tile_height; ///< tile size
+    int numXtiles, numYtiles;
+    int maxtilelen;
+
+    J2kCodingStyle codsty[4];
+    J2kQuantStyle  qntsty[4];
+
+    uint8_t *buf_start;
+    uint8_t *buf;
+    uint8_t *buf_end;
+    int bit_index;
+
+    int16_t curtileno;
+
+    J2kTile *tile;
+} J2kDecoderContext;
+
+static int get_bits(J2kDecoderContext *s, int n)
+{
+    int res = 0;
+    if (s->buf_end - s->buf < ((n - s->bit_index) >> 8))
+        return AVERROR(EINVAL);
+    while (--n >= 0){
+        res <<= 1;
+        if (s->bit_index == 0){
+            s->bit_index = 7 + (*s->buf != 0xff);
+            s->buf++;
+        }
+        s->bit_index--;
+        res |= (*s->buf >> s->bit_index) & 1;
+    }
+    return res;
+}
+
+static void j2k_flush(J2kDecoderContext *s)
+{
+    if (*s->buf == 0xff)
+        s->buf++;
+    s->bit_index = 8;
+    s->buf++;
+}
+#if 0
+void printcomp(J2kComponent *comp)
+{
+    int i;
+    for (i = 0; i < comp->y1 - comp->y0; i++)
+        ff_j2k_printv(comp->data + i * (comp->x1 - comp->x0), comp->x1 - comp->x0);
+}
+
+static void nspaces(FILE *fd, int n)
+{
+    while(n--) putc(' ', fd);
+}
+
+static void dump(J2kDecoderContext *s, FILE *fd)
+{
+    int tileno, compno, reslevelno, bandno, precno;
+    fprintf(fd, "XSiz = %d, YSiz = %d, tile_width = %d, tile_height = %d\n"
+                "numXtiles = %d, numYtiles = %d, ncomponents = %d\n"
+                "tiles:\n",
+            s->width, s->height, s->tile_width, s->tile_height,
+            s->numXtiles, s->numYtiles, s->ncomponents);
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+        J2kTile *tile = s->tile + tileno;
+        nspaces(fd, 2);
+        fprintf(fd, "tile %d:\n", tileno);
+        for(compno = 0; compno < s->ncomponents; compno++){
+            J2kComponent *comp = tile->comp + compno;
+            nspaces(fd, 4);
+            fprintf(fd, "component %d:\n", compno);
+            nspaces(fd, 4);
+            fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d\n",
+                        comp->x0, comp->x1, comp->y0, comp->y1);
+            for(reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+                J2kResLevel *reslevel = comp->reslevel + reslevelno;
+                nspaces(fd, 6);
+                fprintf(fd, "reslevel %d:\n", reslevelno);
+                nspaces(fd, 6);
+                fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d, nbands = %d\n",
+                        reslevel->x0, reslevel->x1, reslevel->y0,
+                        reslevel->y1, reslevel->nbands);
+                for(bandno = 0; bandno < reslevel->nbands; bandno++){
+                    J2kBand *band = reslevel->band + bandno;
+                    nspaces(fd, 8);
+                    fprintf(fd, "band %d:\n", bandno);
+                    nspaces(fd, 8);
+                    fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d,"
+                                "codeblock_width = %d, codeblock_height = %d cblknx = %d cblkny = %d\n",
+                                band->x0, band->x1,
+                                band->y0, band->y1,
+                                band->codeblock_width, band->codeblock_height,
+                                band->cblknx, band->cblkny);
+                    for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+                        J2kPrec *prec = band->prec + precno;
+                        nspaces(fd, 10);
+                        fprintf(fd, "prec %d:\n", precno);
+                        nspaces(fd, 10);
+                        fprintf(fd, "xi0 = %d, xi1 = %d, yi0 = %d, yi1 = %d\n",
+                                     prec->xi0, prec->xi1, prec->yi0, prec->yi1);
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
+/** decode the value stored in node */
+static int tag_tree_decode(J2kDecoderContext *s, J2kTgtNode *node, int threshold)
+{
+    J2kTgtNode *stack[30];
+    int sp = -1, curval = 0;
+
+    while(node && !node->vis){
+        stack[++sp] = node;
+        node = node->parent;
+    }
+
+    if (node)
+        curval = node->val;
+    else
+        curval = stack[sp]->val;
+
+    while(curval < threshold && sp >= 0){
+        if (curval < stack[sp]->val)
+            curval = stack[sp]->val;
+        while (curval < threshold){
+            int ret;
+            if ((ret = get_bits(s, 1)) > 0){
+                stack[sp]->vis++;
+                break;
+            } else if (!ret)
+                curval++;
+            else
+                return ret;
+        }
+        stack[sp]->val = curval;
+        sp--;
+    }
+    return curval;
+}
+
+/* marker segments */
+/** get sizes and offsets of image, tiles; number of components */
+static int get_siz(J2kDecoderContext *s)
+{
+    int i, ret;
+
+    if (s->buf_end - s->buf < 36)
+        return AVERROR(EINVAL);
+
+                        bytestream_get_be16(&s->buf); // Rsiz (skipped)
+             s->width = bytestream_get_be32(&s->buf); // width
+            s->height = bytestream_get_be32(&s->buf); // height
+    s->image_offset_x = bytestream_get_be32(&s->buf); // X0Siz
+    s->image_offset_y = bytestream_get_be32(&s->buf); // Y0Siz
+
+        s->tile_width = bytestream_get_be32(&s->buf); // XTSiz
+       s->tile_height = bytestream_get_be32(&s->buf); // YTSiz
+     s->tile_offset_x = bytestream_get_be32(&s->buf); // XT0Siz
+     s->tile_offset_y = bytestream_get_be32(&s->buf); // YT0Siz
+       s->ncomponents = bytestream_get_be16(&s->buf); // CSiz
+
+    if (s->buf_end - s->buf < 2 * s->ncomponents)
+        return AVERROR(EINVAL);
+
+    for (i = 0; i < s->ncomponents; i++){ // Ssiz_i XRsiz_i, YRsiz_i
+        uint8_t x = bytestream_get_byte(&s->buf);
+        s->cbps[i] = (x & 0x7f) + 1;
+        s->precision = FFMAX(s->cbps[i], s->precision);
+        s->sgnd[i] = (x & 0x80) == 1;
+        s->cdx[i] = bytestream_get_byte(&s->buf);
+        s->cdy[i] = bytestream_get_byte(&s->buf);
+    }
+
+    s->numXtiles = ff_j2k_ceildiv(s->width - s->tile_offset_x, s->tile_width);
+    s->numYtiles = ff_j2k_ceildiv(s->height - s->tile_offset_y, s->tile_height);
+
+    s->tile = av_mallocz(s->numXtiles * s->numYtiles * sizeof(J2kTile));
+    if (!s->tile)
+        return AVERROR(ENOMEM);
+
+    for (i = 0; i < s->numXtiles * s->numYtiles; i++){
+        J2kTile *tile = s->tile + i;
+
+        tile->comp = av_mallocz(s->ncomponents * sizeof(J2kComponent));
+        if (!tile->comp)
+            return AVERROR(ENOMEM);
+    }
+
+    s->avctx->width = s->width - s->image_offset_x;
+    s->avctx->height = s->height - s->image_offset_y;
+
+    switch(s->ncomponents){
+        case 1: if (s->precision > 8) {
+                    s->avctx->pix_fmt    = PIX_FMT_GRAY16;
+                } else s->avctx->pix_fmt = PIX_FMT_GRAY8;
+                break;
+        case 3: if (s->precision > 8) {
+                    s->avctx->pix_fmt    = PIX_FMT_RGB48;
+                } else s->avctx->pix_fmt = PIX_FMT_RGB24;
+                break;
+        case 4: s->avctx->pix_fmt = PIX_FMT_BGRA; break;
+    }
+
+    if (s->picture.data[0])
+        s->avctx->release_buffer(s->avctx, &s->picture);
+
+    if ((ret = s->avctx->get_buffer(s->avctx, &s->picture)) < 0)
+        return ret;
+
+    s->picture.pict_type = FF_I_TYPE;
+    s->picture.key_frame = 1;
+
+    return 0;
+}
+
+/** get common part for COD and COC segments */
+static int get_cox(J2kDecoderContext *s, J2kCodingStyle *c)
+{
+    if (s->buf_end - s->buf < 5)
+        return AVERROR(EINVAL);
+          c->nreslevels = bytestream_get_byte(&s->buf) + 1; // num of resolution levels - 1
+     c->log2_cblk_width = bytestream_get_byte(&s->buf) + 2; // cblk width
+    c->log2_cblk_height = bytestream_get_byte(&s->buf) + 2; // cblk height
+
+    c->cblk_style = bytestream_get_byte(&s->buf);
+    if (c->cblk_style != 0){ // cblk style
+        av_log(s->avctx, AV_LOG_ERROR, "no extra cblk styles supported\n");
+        return -1;
+    }
+    c->transform = bytestream_get_byte(&s->buf); // transformation
+    if (c->csty & J2K_CSTY_PREC) {
+        int i;
+        for (i = 0; i < c->nreslevels; i++)
+            bytestream_get_byte(&s->buf);
+    }
+    return 0;
+}
+
+/** get coding parameters for a particular tile or whole image*/
+static int get_cod(J2kDecoderContext *s, J2kCodingStyle *c, uint8_t *properties)
+{
+    J2kCodingStyle tmp;
+    int compno;
+
+    if (s->buf_end - s->buf < 5)
+        return AVERROR(EINVAL);
+
+    tmp.log2_prec_width  =
+    tmp.log2_prec_height = 15;
+
+    tmp.csty = bytestream_get_byte(&s->buf);
+
+    if (bytestream_get_byte(&s->buf)){ // progression level
+        av_log(s->avctx, AV_LOG_ERROR, "only LRCP progression supported\n");
+        return -1;
+    }
+
+    tmp.nlayers = bytestream_get_be16(&s->buf);
+        tmp.mct = bytestream_get_byte(&s->buf); // multiple component transformation
+
+    get_cox(s, &tmp);
+    for (compno = 0; compno < s->ncomponents; compno++){
+        if (!(properties[compno] & HAD_COC))
+            memcpy(c + compno, &tmp, sizeof(J2kCodingStyle));
+    }
+    return 0;
+}
+
+/** get coding parameters for a component in the whole image on a particular tile */
+static int get_coc(J2kDecoderContext *s, J2kCodingStyle *c, uint8_t *properties)
+{
+    int compno;
+
+    if (s->buf_end - s->buf < 2)
+        return AVERROR(EINVAL);
+
+    compno = bytestream_get_byte(&s->buf);
+
+    c += compno;
+    c->csty = bytestream_get_byte(&s->buf);
+    get_cox(s, c);
+
+    properties[compno] |= HAD_COC;
+    return 0;
+}
+
+/** get common part for QCD and QCC segments */
+static int get_qcx(J2kDecoderContext *s, int n, J2kQuantStyle *q)
+{
+    int i, x;
+
+    if (s->buf_end - s->buf < 1)
+        return AVERROR(EINVAL);
+
+    x = bytestream_get_byte(&s->buf); // Sqcd
+
+    q->nguardbits = x >> 5;
+      q->quantsty = x & 0x1f;
+
+    if (q->quantsty == J2K_QSTY_NONE){
+        n -= 3;
+        if (s->buf_end - s->buf < n)
+            return AVERROR(EINVAL);
+        for (i = 0; i < n; i++)
+            q->expn[i] = bytestream_get_byte(&s->buf) >> 3;
+    } else if (q->quantsty == J2K_QSTY_SI){
+        if (s->buf_end - s->buf < 2)
+            return AVERROR(EINVAL);
+        x = bytestream_get_be16(&s->buf);
+        q->expn[0] = x >> 11;
+        q->mant[0] = x & 0x7ff;
+        for (i = 1; i < 32 * 3; i++){
+            int curexpn = FFMAX(0, q->expn[0] - (i-1)/3);
+            q->expn[i] = curexpn;
+            q->mant[i] = q->mant[0];
+        }
+    } else{
+        n = (n - 3) >> 1;
+        if (s->buf_end - s->buf < n)
+            return AVERROR(EINVAL);
+        for (i = 0; i < n; i++){
+            x = bytestream_get_be16(&s->buf);
+            q->expn[i] = x >> 11;
+            q->mant[i] = x & 0x7ff;
+        }
+    }
+    return 0;
+}
+
+/** get quantization parameters for a particular tile or a whole image */
+static int get_qcd(J2kDecoderContext *s, int n, J2kQuantStyle *q, uint8_t *properties)
+{
+    J2kQuantStyle tmp;
+    int compno;
+
+    if (get_qcx(s, n, &tmp))
+        return -1;
+    for (compno = 0; compno < s->ncomponents; compno++)
+        if (!(properties[compno] & HAD_QCC))
+            memcpy(q + compno, &tmp, sizeof(J2kQuantStyle));
+    return 0;
+}
+
+/** get quantization parameters for a component in the whole image on in a particular tile */
+static int get_qcc(J2kDecoderContext *s, int n, J2kQuantStyle *q, uint8_t *properties)
+{
+    int compno;
+
+    if (s->buf_end - s->buf < 1)
+        return AVERROR(EINVAL);
+
+    compno = bytestream_get_byte(&s->buf);
+    properties[compno] |= HAD_QCC;
+    return get_qcx(s, n-1, q+compno);
+}
+
+/** get start of tile segment */
+static uint8_t get_sot(J2kDecoderContext *s)
+{
+    if (s->buf_end - s->buf < 4)
+        return AVERROR(EINVAL);
+
+    s->curtileno = bytestream_get_be16(&s->buf); ///< Isot
+
+    s->buf += 4; ///< Psot (ignored)
+
+    if (!bytestream_get_byte(&s->buf)){ ///< TPsot
+        J2kTile *tile = s->tile + s->curtileno;
+
+        /* copy defaults */
+        memcpy(tile->codsty, s->codsty, s->ncomponents * sizeof(J2kCodingStyle));
+        memcpy(tile->qntsty, s->qntsty, s->ncomponents * sizeof(J2kQuantStyle));
+    }
+    bytestream_get_byte(&s->buf); ///< TNsot
+
+    return 0;
+}
+
+static int init_tile(J2kDecoderContext *s, int tileno)
+{
+    int compno,
+        tilex = tileno % s->numXtiles,
+        tiley = tileno / s->numXtiles;
+    J2kTile *tile = s->tile + tileno;
+
+    if (!tile->comp)
+        return AVERROR(ENOMEM);
+    for (compno = 0; compno < s->ncomponents; compno++){
+        J2kComponent *comp = tile->comp + compno;
+        J2kCodingStyle *codsty = tile->codsty + compno;
+        J2kQuantStyle  *qntsty = tile->qntsty + compno;
+        int ret; // global bandno
+
+        comp->coord[0][0] = FFMAX(tilex * s->tile_width + s->tile_offset_x, s->image_offset_x);
+        comp->coord[0][1] = FFMIN((tilex+1)*s->tile_width + s->tile_offset_x, s->width);
+        comp->coord[1][0] = FFMAX(tiley * s->tile_height + s->tile_offset_y, s->image_offset_y);
+        comp->coord[1][1] = FFMIN((tiley+1)*s->tile_height + s->tile_offset_y, s->height);
+
+        if (ret = ff_j2k_init_component(comp, codsty, qntsty, s->cbps[compno], s->cdx[compno], s->cdy[compno]))
+            return ret;
+    }
+    return 0;
+}
+
+/** read the number of coding passes */
+static int getnpasses(J2kDecoderContext *s)
+{
+    int num;
+    if (!get_bits(s, 1))
+        return 1;
+    if (!get_bits(s, 1))
+        return 2;
+    if ((num = get_bits(s, 2)) != 3)
+        return num < 0 ? num : 3 + num;
+    if ((num = get_bits(s, 5)) != 31)
+        return num < 0 ? num : 6 + num;
+    num = get_bits(s, 7);
+    return num < 0 ? num : 37 + num;
+}
+
+static int getlblockinc(J2kDecoderContext *s)
+{
+    int res = 0, ret;
+    while (ret = get_bits(s, 1)){
+        if (ret < 0)
+            return ret;
+        res++;
+    }
+    return res;
+}
+
+static int decode_packet(J2kDecoderContext *s, J2kCodingStyle *codsty, J2kResLevel *rlevel, int precno,
+                         int layno, uint8_t *expn, int numgbits)
+{
+    int bandno, cblkny, cblknx, cblkno, ret;
+
+    if (!(ret = get_bits(s, 1))){
+        j2k_flush(s);
+        return 0;
+    } else if (ret < 0)
+        return ret;
+
+    for (bandno = 0; bandno < rlevel->nbands; bandno++){
+        J2kBand *band = rlevel->band + bandno;
+        J2kPrec *prec = band->prec + precno;
+        int pos = 0;
+
+        if (band->coord[0][0] == band->coord[0][1]
+        ||  band->coord[1][0] == band->coord[1][1])
+            continue;
+
+        for (cblkny = prec->yi0; cblkny < prec->yi1; cblkny++)
+            for(cblknx = prec->xi0, cblkno = cblkny * band->cblknx + cblknx; cblknx < prec->xi1; cblknx++, cblkno++, pos++){
+                J2kCblk *cblk = band->cblk + cblkno;
+                int incl, newpasses, llen;
+
+                if (cblk->npasses)
+                    incl = get_bits(s, 1);
+                else
+                    incl = tag_tree_decode(s, prec->cblkincl + pos, layno+1) == layno;
+                if (!incl)
+                    continue;
+                else if (incl < 0)
+                    return incl;
+
+                if (!cblk->npasses)
+                    cblk->nonzerobits = expn[bandno] + numgbits - 1 - tag_tree_decode(s, prec->zerobits + pos, 100);
+                if ((newpasses = getnpasses(s)) < 0)
+                    return newpasses;
+                if ((llen = getlblockinc(s)) < 0)
+                    return llen;
+                cblk->lblock += llen;
+                if ((ret = get_bits(s, av_log2(newpasses) + cblk->lblock)) < 0)
+                    return ret;
+                cblk->lengthinc = ret;
+                cblk->npasses += newpasses;
+            }
+    }
+    j2k_flush(s);
+
+    if (codsty->csty & J2K_CSTY_EPH) {
+        if (AV_RB16(s->buf) == J2K_EPH) {
+            s->buf += 2;
+        } else {
+            av_log(s->avctx, AV_LOG_ERROR, "EPH marker not found.\n");
+        }
+    }
+
+    for (bandno = 0; bandno < rlevel->nbands; bandno++){
+        J2kBand *band = rlevel->band + bandno;
+        int yi, cblknw = band->prec[precno].xi1 - band->prec[precno].xi0;
+        for (yi = band->prec[precno].yi0; yi < band->prec[precno].yi1; yi++){
+            int xi;
+            for (xi = band->prec[precno].xi0; xi < band->prec[precno].xi1; xi++){
+                J2kCblk *cblk = band->cblk + yi * cblknw + xi;
+                if (s->buf_end - s->buf < cblk->lengthinc)
+                    return AVERROR(EINVAL);
+                bytestream_get_buffer(&s->buf, cblk->data, cblk->lengthinc);
+                cblk->length += cblk->lengthinc;
+                cblk->lengthinc = 0;
+            }
+        }
+    }
+    return 0;
+}
+
+static int decode_packets(J2kDecoderContext *s, J2kTile *tile)
+{
+    int layno, reslevelno, compno, precno, ok_reslevel;
+    s->bit_index = 8;
+    for (layno = 0; layno < tile->codsty[0].nlayers; layno++){
+        ok_reslevel = 1;
+        for (reslevelno = 0; ok_reslevel; reslevelno++){
+            ok_reslevel = 0;
+            for (compno = 0; compno < s->ncomponents; compno++){
+                J2kCodingStyle *codsty = tile->codsty + compno;
+                J2kQuantStyle  *qntsty = tile->qntsty + compno;
+                if (reslevelno < codsty->nreslevels){
+                    J2kResLevel *rlevel = tile->comp[compno].reslevel + reslevelno;
+                    ok_reslevel = 1;
+                    for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++){
+                        if (decode_packet(s, codsty, rlevel, precno, layno, qntsty->expn +
+                                          (reslevelno ? 3*(reslevelno-1)+1 : 0), qntsty->nguardbits))
+                            return -1;
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+/* TIER-1 routines */
+static void decode_sigpass(J2kT1Context *t1, int width, int height, int bpno, int bandno)
+{
+    int mask = 3 << (bpno - 1), y0, x, y;
+
+    for (y0 = 0; y0 < height; y0 += 4)
+        for (x = 0; x < width; x++)
+            for (y = y0; y < height && y < y0+4; y++){
+                if ((t1->flags[y+1][x+1] & J2K_T1_SIG_NB)
+                && !(t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+                    if (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno))){
+                        int xorbit, ctxno = ff_j2k_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+
+                        t1->data[y][x] = (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) ? -mask : mask;
+
+                        ff_j2k_set_significant(t1, x, y, t1->data[y][x] < 0);
+                    }
+                    t1->flags[y+1][x+1] |= J2K_T1_VIS;
+                }
+            }
+}
+
+static void decode_refpass(J2kT1Context *t1, int width, int height, int bpno)
+{
+    int phalf, nhalf;
+    int y0, x, y;
+
+    phalf = 1 << (bpno - 1);
+    nhalf = -phalf;
+
+    for (y0 = 0; y0 < height; y0 += 4)
+        for (x = 0; x < width; x++)
+            for (y = y0; y < height && y < y0+4; y++){
+                if ((t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS)) == J2K_T1_SIG){
+                    int ctxno = ff_j2k_getrefctxno(t1->flags[y+1][x+1]);
+                    int r = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ? phalf : nhalf;
+                    t1->data[y][x] += t1->data[y][x] < 0 ? -r : r;
+                    t1->flags[y+1][x+1] |= J2K_T1_REF;
+                }
+            }
+}
+
+static void decode_clnpass(J2kDecoderContext *s, J2kT1Context *t1, int width, int height,
+                           int bpno, int bandno, int seg_symbols)
+{
+    int mask = 3 << (bpno - 1), y0, x, y, runlen, dec;
+
+    for (y0 = 0; y0 < height; y0 += 4) {
+        for (x = 0; x < width; x++){
+            if (y0 + 3 < height && !(
+            (t1->flags[y0+1][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+            (t1->flags[y0+2][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+            (t1->flags[y0+3][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+            (t1->flags[y0+4][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)))){
+                if (!ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_RL))
+                    continue;
+                runlen = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+                runlen = (runlen << 1) | ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+                dec = 1;
+            } else{
+                runlen = 0;
+                dec = 0;
+            }
+
+            for (y = y0 + runlen; y < y0 + 4 && y < height; y++){
+                if (!dec){
+                    if (!(t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS)))
+                        dec = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno));
+                }
+                if (dec){
+                    int xorbit, ctxno = ff_j2k_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+                    t1->data[y][x] = (ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + ctxno) ^ xorbit) ? -mask : mask;
+                    ff_j2k_set_significant(t1, x, y, t1->data[y][x] < 0);
+                }
+                dec = 0;
+                t1->flags[y+1][x+1] &= ~J2K_T1_VIS;
+            }
+        }
+    }
+    if (seg_symbols) {
+        int val;
+        val = ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+        val = (val << 1) + ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+        val = (val << 1) + ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+        val = (val << 1) + ff_mqc_decode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI);
+        if (val != 0xa) {
+            av_log(s->avctx, AV_LOG_ERROR,"Segmentation symbol value incorrect\n");
+        }
+    }
+}
+
+static int decode_cblk(J2kDecoderContext *s, J2kCodingStyle *codsty, J2kT1Context *t1, J2kCblk *cblk,
+                       int width, int height, int bandpos)
+{
+    int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1, y;
+
+    for (y = 0; y < height+2; y++)
+        memset(t1->flags[y], 0, (width+2)*sizeof(int));
+
+    for (y = 0; y < height; y++)
+        memset(t1->data[y], 0, width*sizeof(int));
+
+    ff_mqc_initdec(&t1->mqc, cblk->data);
+    cblk->data[cblk->length] = 0xff;
+    cblk->data[cblk->length+1] = 0xff;
+
+    while(passno--){
+        switch(pass_t){
+            case 0: decode_sigpass(t1, width, height, bpno+1, bandpos);
+                    break;
+            case 1: decode_refpass(t1, width, height, bpno+1);
+                    break;
+            case 2: decode_clnpass(s, t1, width, height, bpno+1, bandpos,
+                                   codsty->cblk_style & J2K_CBLK_SEGSYM);
+                    break;
+        }
+
+        pass_t++;
+        if (pass_t == 3){
+            bpno--;
+            pass_t = 0;
+        }
+    }
+    return 0;
+}
+
+static void mct_decode(J2kDecoderContext *s, J2kTile *tile)
+{
+    int i, *src[3], i0, i1, i2, csize = 1;
+
+    for (i = 0; i < 3; i++)
+        src[i] = tile->comp[i].data;
+
+    for (i = 0; i < 2; i++)
+        csize *= tile->comp[0].coord[i][1] - tile->comp[0].coord[i][0];
+
+    if (tile->codsty[0].transform == FF_DWT97){
+        for (i = 0; i < csize; i++){
+            i0 = *src[0] + (*src[2] * 46802 >> 16);
+            i1 = *src[0] - (*src[1] * 22553 + *src[2] * 46802 >> 16);
+            i2 = *src[0] + (116130 * *src[1] >> 16);
+            *src[0]++ = i0;
+            *src[1]++ = i1;
+            *src[2]++ = i2;
+        }
+    } else{
+        for (i = 0; i < csize; i++){
+            i1 = *src[0] - (*src[2] + *src[1] >> 2);
+            i0 = i1 + *src[2];
+            i2 = i1 + *src[1];
+            *src[0]++ = i0;
+            *src[1]++ = i1;
+            *src[2]++ = i2;
+        }
+    }
+}
+
+static int decode_tile(J2kDecoderContext *s, J2kTile *tile)
+{
+    int compno, reslevelno, bandno;
+    int x, y, *src[4];
+    uint8_t *line;
+    J2kT1Context t1;
+
+    for (compno = 0; compno < s->ncomponents; compno++){
+        J2kComponent *comp = tile->comp + compno;
+        J2kCodingStyle *codsty = tile->codsty + compno;
+
+        for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+            J2kResLevel *rlevel = comp->reslevel + reslevelno;
+            for (bandno = 0; bandno < rlevel->nbands; bandno++){
+                J2kBand *band = rlevel->band + bandno;
+                int cblkx, cblky, cblkno=0, xx0, x0, xx1, y0, yy0, yy1, bandpos;
+
+                bandpos = bandno + (reslevelno > 0);
+
+                yy0 = bandno == 0 ? 0 : comp->reslevel[reslevelno-1].coord[1][1] - comp->reslevel[reslevelno-1].coord[1][0];
+                y0 = yy0;
+                yy1 = FFMIN(ff_j2k_ceildiv(band->coord[1][0] + 1, band->codeblock_height) * band->codeblock_height,
+                            band->coord[1][1]) - band->coord[1][0] + yy0;
+
+                if (band->coord[0][0] == band->coord[0][1] || band->coord[1][0] == band->coord[1][1])
+                    continue;
+
+                for (cblky = 0; cblky < band->cblkny; cblky++){
+                    if (reslevelno == 0 || bandno == 1)
+                        xx0 = 0;
+                    else
+                        xx0 = comp->reslevel[reslevelno-1].coord[0][1] - comp->reslevel[reslevelno-1].coord[0][0];
+                    x0 = xx0;
+                    xx1 = FFMIN(ff_j2k_ceildiv(band->coord[0][0] + 1, band->codeblock_width) * band->codeblock_width,
+                                band->coord[0][1]) - band->coord[0][0] + xx0;
+
+                    for (cblkx = 0; cblkx < band->cblknx; cblkx++, cblkno++){
+                        int y, x;
+                        decode_cblk(s, codsty, &t1, band->cblk + cblkno, xx1 - xx0, yy1 - yy0, bandpos);
+                        if (codsty->transform == FF_DWT53){
+                            for (y = yy0; y < yy1; y+=s->cdy[compno]){
+                                int *ptr = t1.data[y-yy0];
+                                for (x = xx0; x < xx1; x+=s->cdx[compno]){
+                                    comp->data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] = *ptr++ >> 1;
+                                }
+                            }
+                        } else{
+                            for (y = yy0; y < yy1; y+=s->cdy[compno]){
+                                int *ptr = t1.data[y-yy0];
+                                for (x = xx0; x < xx1; x+=s->cdx[compno]){
+                                    int tmp = ((int64_t)*ptr++) * ((int64_t)band->stepsize) >> 13, tmp2;
+                                    tmp2 = FFABS(tmp>>1) + FFABS(tmp&1);
+                                    comp->data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] = tmp < 0 ? -tmp2 : tmp2;
+                                }
+                            }
+                        }
+                        xx0 = xx1;
+                        xx1 = FFMIN(xx1 + band->codeblock_width, band->coord[0][1] - band->coord[0][0] + x0);
+                    }
+                    yy0 = yy1;
+                    yy1 = FFMIN(yy1 + band->codeblock_height, band->coord[1][1] - band->coord[1][0] + y0);
+                }
+            }
+        }
+        ff_j2k_dwt_decode(&comp->dwt, comp->data);
+        src[compno] = comp->data;
+    }
+    if (tile->codsty[0].mct)
+        mct_decode(s, tile);
+
+    if (s->avctx->pix_fmt == PIX_FMT_BGRA) // RGBA -> BGRA
+        FFSWAP(int *, src[0], src[2]);
+
+    if (s->precision <= 8) {
+        for (compno = 0; compno < s->ncomponents; compno++){
+            y = tile->comp[compno].coord[1][0] - s->image_offset_y;
+            line = s->picture.data[0] + y * s->picture.linesize[0];
+            for (; y < tile->comp[compno].coord[1][1] - s->image_offset_y; y += s->cdy[compno]){
+                uint8_t *dst;
+
+                x = tile->comp[compno].coord[0][0] - s->image_offset_x;
+                dst = line + x * s->ncomponents + compno;
+
+                for (; x < tile->comp[compno].coord[0][1] - s->image_offset_x; x += s->cdx[compno]) {
+                    *src[compno] += 1 << (s->cbps[compno]-1);
+                    if (*src[compno] < 0)
+                        *src[compno] = 0;
+                    else if (*src[compno] >= (1 << s->cbps[compno]))
+                        *src[compno] = (1 << s->cbps[compno]) - 1;
+                    *dst = *src[compno]++;
+                    dst += s->ncomponents;
+                }
+                line += s->picture.linesize[0];
+            }
+        }
+    } else {
+        for (compno = 0; compno < s->ncomponents; compno++) {
+            y = tile->comp[compno].coord[1][0] - s->image_offset_y;
+            line = s->picture.data[0] + y * s->picture.linesize[0];
+            for (; y < tile->comp[compno].coord[1][1] - s->image_offset_y; y += s->cdy[compno]) {
+                uint16_t *dst;
+                x = tile->comp[compno].coord[0][0] - s->image_offset_x;
+                dst = line + (x * s->ncomponents + compno) * 2;
+                for (; x < tile->comp[compno].coord[0][1] - s->image_offset_x; x += s-> cdx[compno]) {
+                    int32_t val;
+                    val = *src[compno]++ << (16 - s->cbps[compno]);
+                    val += 1 << 15;
+                    val = av_clip(val, 0, (1 << 16) - 1);
+                    *dst = val;
+                    dst += s->ncomponents;
+                }
+                line += s->picture.linesize[0];
+            }
+        }
+    }
+    return 0;
+}
+
+static void cleanup(J2kDecoderContext *s)
+{
+    int tileno, compno;
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+        for (compno = 0; compno < s->ncomponents; compno++){
+            J2kComponent *comp = s->tile[tileno].comp + compno;
+            J2kCodingStyle *codsty = s->tile[tileno].codsty + compno;
+
+            ff_j2k_cleanup(comp, codsty);
+        }
+        av_freep(&s->tile[tileno].comp);
+    }
+    av_freep(&s->tile);
+}
+
+static int decode_codestream(J2kDecoderContext *s)
+{
+    J2kCodingStyle *codsty = s->codsty;
+    J2kQuantStyle  *qntsty = s->qntsty;
+    uint8_t *properties = s->properties;
+
+    for (;;){
+        int marker, len, ret = 0;
+        uint8_t *oldbuf;
+        if (s->buf_end - s->buf < 2){
+            av_log(s->avctx, AV_LOG_ERROR, "Missing EOC\n");
+            break;
+        }
+
+        marker = bytestream_get_be16(&s->buf);
+        oldbuf = s->buf;
+
+        if (marker == J2K_SOD){
+            J2kTile *tile = s->tile + s->curtileno;
+            if (ret = init_tile(s, s->curtileno))
+                return ret;
+            if (ret = decode_packets(s, tile))
+                return ret;
+            continue;
+        }
+        if (marker == J2K_EOC)
+            break;
+
+        if (s->buf_end - s->buf < 2)
+            return AVERROR(EINVAL);
+        len = bytestream_get_be16(&s->buf);
+        switch(marker){
+            case J2K_SIZ:
+                ret = get_siz(s); break;
+            case J2K_COC:
+                ret = get_coc(s, codsty, properties); break;
+            case J2K_COD:
+                ret = get_cod(s, codsty, properties); break;
+            case J2K_QCC:
+                ret = get_qcc(s, len, qntsty, properties); break;
+            case J2K_QCD:
+                ret = get_qcd(s, len, qntsty, properties); break;
+            case J2K_SOT:
+                if (!(ret = get_sot(s))){
+                    codsty = s->tile[s->curtileno].codsty;
+                    qntsty = s->tile[s->curtileno].qntsty;
+                    properties = s->tile[s->curtileno].properties;
+                }
+                break;
+            case J2K_COM:
+                // the comment is ignored
+                s->buf += len - 2; break;
+            default:
+                av_log(s->avctx, AV_LOG_ERROR, "unsupported marker 0x%.4X at pos 0x%x\n", marker, s->buf - s->buf_start - 4);
+                s->buf += len - 2; break;
+        }
+        if (s->buf - oldbuf != len || ret){
+            av_log(s->avctx, AV_LOG_ERROR, "error during processing marker segment %.4x\n", marker);
+            return ret ? ret : -1;
+        }
+    }
+    return 0;
+}
+
+static int jp2_find_codestream(J2kDecoderContext *s)
+{
+    int32_t atom_size;
+    int found_codestream = 0, search_range = 10;
+
+    // skip jpeg2k signature atom
+    s->buf += 12;
+
+    while(!found_codestream && search_range) {
+        atom_size = AV_RB32(s->buf);
+        if(AV_RB32(s->buf + 4) == JP2_CODESTREAM) {
+            found_codestream = 1;
+            s->buf += 8;
+        } else {
+            s->buf += atom_size;
+            search_range--;
+        }
+    }
+
+    if(found_codestream)
+        return 1;
+    return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx,
+                        void *data, int *data_size,
+                        AVPacket *avpkt)
+{
+    J2kDecoderContext *s = avctx->priv_data;
+    AVFrame *picture = data;
+    int tileno, ret;
+
+    s->avctx = avctx;
+    av_log(s->avctx, AV_LOG_DEBUG, "start\n");
+
+    // init
+    s->buf = s->buf_start = avpkt->data;
+    s->buf_end = s->buf_start + avpkt->size;
+    s->curtileno = -1;
+
+    ff_j2k_init_tier1_luts();
+
+    if (s->buf_end - s->buf < 2)
+        return AVERROR(EINVAL);
+
+    // check if the image is in jp2 format
+    if((AV_RB32(s->buf) == 12) && (AV_RB32(s->buf + 4) == JP2_SIG_TYPE) &&
+       (AV_RB32(s->buf + 8) == JP2_SIG_VALUE)) {
+        if(!jp2_find_codestream(s)) {
+            av_log(avctx, AV_LOG_ERROR, "couldn't find jpeg2k codestream atom\n");
+            return -1;
+        }
+    }
+
+    if (bytestream_get_be16(&s->buf) != J2K_SOC){
+        av_log(avctx, AV_LOG_ERROR, "SOC marker not present\n");
+        return -1;
+    }
+    if (ret = decode_codestream(s))
+        return ret;
+
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++)
+        if (ret = decode_tile(s, s->tile + tileno))
+            return ret;
+
+    cleanup(s);
+    av_log(s->avctx, AV_LOG_DEBUG, "end\n");
+
+    *data_size = sizeof(AVPicture);
+    *picture = s->picture;
+
+    return s->buf - s->buf_start;
+}
+
+static av_cold int j2kdec_init(AVCodecContext *avctx)
+{
+    J2kDecoderContext *s = avctx->priv_data;
+
+    avcodec_get_frame_defaults((AVFrame*)&s->picture);
+    avctx->coded_frame = (AVFrame*)&s->picture;
+    return 0;
+}
+
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+    J2kDecoderContext *s = avctx->priv_data;
+
+    if (s->picture.data[0])
+        avctx->release_buffer(avctx, &s->picture);
+
+    return 0;
+}
+
+AVCodec ff_jpeg2000_decoder = {
+    "j2k",
+    AVMEDIA_TYPE_VIDEO,
+    CODEC_ID_JPEG2000,
+    sizeof(J2kDecoderContext),
+    j2kdec_init,
+    NULL,
+    decode_end,
+    decode_frame,
+    0,
+    .pix_fmts =
+        (enum PixelFormat[]) {PIX_FMT_GRAY8, PIX_FMT_RGB24, -1}
+};
diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c
new file mode 100644
index 0000000..123b796
--- /dev/null
+++ b/libavcodec/j2kenc.c
@@ -0,0 +1,1045 @@
+/*
+ * JPEG2000 image encoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ */
+
+/**
+ * JPEG2000 image encoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include <float.h>
+#include "avcodec.h"
+#include "bytestream.h"
+#include "j2k.h"
+#include "libavutil/common.h"
+
+#define NMSEDEC_BITS 7
+#define NMSEDEC_FRACBITS (NMSEDEC_BITS-1)
+#define WMSEDEC_SHIFT 13 ///< must be >= 13
+#define LAMBDA_SCALE (100000000LL << (WMSEDEC_SHIFT - 13))
+
+static int lut_nmsedec_ref [1<<NMSEDEC_BITS],
+           lut_nmsedec_ref0[1<<NMSEDEC_BITS],
+           lut_nmsedec_sig [1<<NMSEDEC_BITS],
+           lut_nmsedec_sig0[1<<NMSEDEC_BITS];
+
+static const int dwt_norms[2][4][10] = { // [dwt_type][band][rlevel] (multiplied by 10000)
+    {{10000, 19650, 41770,  84030, 169000, 338400,  676900, 1353000, 2706000, 5409000},
+     {20220, 39890, 83550, 170400, 342700, 686300, 1373000, 2746000, 5490000},
+     {20220, 39890, 83550, 170400, 342700, 686300, 1373000, 2746000, 5490000},
+     {20800, 38650, 83070, 171800, 347100, 695900, 1393000, 2786000, 5572000}},
+
+    {{10000, 15000, 27500, 53750, 106800, 213400, 426700, 853300, 1707000, 3413000},
+     {10380, 15920, 29190, 57030, 113300, 226400, 452500, 904800, 1809000},
+     {10380, 15920, 29190, 57030, 113300, 226400, 452500, 904800, 1809000},
+     { 7186,  9218, 15860, 30430,  60190, 120100, 240000, 479700,  959300}}
+};
+
+typedef struct {
+   J2kComponent *comp;
+} J2kTile;
+
+typedef struct {
+    AVCodecContext *avctx;
+    AVFrame *picture;
+
+    int width, height; ///< image width and height
+    uint8_t cbps[4]; ///< bits per sample in particular components
+    int chroma_shift[2];
+    uint8_t planar;
+    int ncomponents;
+    int tile_width, tile_height; ///< tile size
+    int numXtiles, numYtiles;
+
+    uint8_t *buf_start;
+    uint8_t *buf;
+    uint8_t *buf_end;
+    int bit_index;
+
+    int64_t lambda;
+
+    J2kCodingStyle codsty;
+    J2kQuantStyle  qntsty;
+
+    J2kTile *tile;
+} J2kEncoderContext;
+
+
+/* debug */
+#if 0
+#undef ifprintf
+#undef printf
+
+static void nspaces(FILE *fd, int n)
+{
+    while(n--) putc(' ', fd);
+}
+
+static void printv(int *tab, int l)
+{
+    int i;
+    for (i = 0; i < l; i++)
+        printf("%.3d ", tab[i]);
+    printf("\n");
+}
+
+static void printu(uint8_t *tab, int l)
+{
+    int i;
+    for (i = 0; i < l; i++)
+        printf("%.3hd ", tab[i]);
+    printf("\n");
+}
+
+static void printcomp(J2kComponent *comp)
+{
+    int i;
+    for (i = 0; i < comp->y1 - comp->y0; i++)
+        printv(comp->data + i * (comp->x1 - comp->x0), comp->x1 - comp->x0);
+}
+
+static void dump(J2kEncoderContext *s, FILE *fd)
+{
+    int tileno, compno, reslevelno, bandno, precno;
+    fprintf(fd, "XSiz = %d, YSiz = %d, tile_width = %d, tile_height = %d\n"
+                "numXtiles = %d, numYtiles = %d, ncomponents = %d\n"
+                "tiles:\n",
+            s->width, s->height, s->tile_width, s->tile_height,
+            s->numXtiles, s->numYtiles, s->ncomponents);
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+        J2kTile *tile = s->tile + tileno;
+        nspaces(fd, 2);
+        fprintf(fd, "tile %d:\n", tileno);
+        for(compno = 0; compno < s->ncomponents; compno++){
+            J2kComponent *comp = tile->comp + compno;
+            nspaces(fd, 4);
+            fprintf(fd, "component %d:\n", compno);
+            nspaces(fd, 4);
+            fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d\n",
+                        comp->x0, comp->x1, comp->y0, comp->y1);
+            for(reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+                J2kResLevel *reslevel = comp->reslevel + reslevelno;
+                nspaces(fd, 6);
+                fprintf(fd, "reslevel %d:\n", reslevelno);
+                nspaces(fd, 6);
+                fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d, nbands = %d\n",
+                        reslevel->x0, reslevel->x1, reslevel->y0,
+                        reslevel->y1, reslevel->nbands);
+                for(bandno = 0; bandno < reslevel->nbands; bandno++){
+                    J2kBand *band = reslevel->band + bandno;
+                    nspaces(fd, 8);
+                    fprintf(fd, "band %d:\n", bandno);
+                    nspaces(fd, 8);
+                    fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d,"
+                                "codeblock_width = %d, codeblock_height = %d cblknx = %d cblkny = %d\n",
+                                band->x0, band->x1,
+                                band->y0, band->y1,
+                                band->codeblock_width, band->codeblock_height,
+                                band->cblknx, band->cblkny);
+                    for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+                        J2kPrec *prec = band->prec + precno;
+                        nspaces(fd, 10);
+                        fprintf(fd, "prec %d:\n", precno);
+                        nspaces(fd, 10);
+                        fprintf(fd, "xi0 = %d, xi1 = %d, yi0 = %d, yi1 = %d\n",
+                                     prec->xi0, prec->xi1, prec->yi0, prec->yi1);
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
+/* bitstream routines */
+
+/** put n times val bit */
+static void put_bits(J2kEncoderContext *s, int val, int n) // TODO: optimize
+{
+    while (n-- > 0){
+        if (s->bit_index == 8)
+        {
+            s->bit_index = *s->buf == 0xff;
+            *(++s->buf) = 0;
+        }
+        *s->buf |= val << (7 - s->bit_index++);
+    }
+}
+
+/** put n least significant bits of a number num */
+static void put_num(J2kEncoderContext *s, int num, int n)
+{
+    while(--n >= 0)
+        put_bits(s, (num >> n) & 1, 1);
+}
+
+/** flush the bitstream */
+static void j2k_flush(J2kEncoderContext *s)
+{
+    if (s->bit_index){
+        s->bit_index = 0;
+        s->buf++;
+    }
+}
+
+/* tag tree routines */
+
+/** code the value stored in node */
+static void tag_tree_code(J2kEncoderContext *s, J2kTgtNode *node, int threshold)
+{
+    J2kTgtNode *stack[30];
+    int sp = 1, curval = 0;
+    stack[0] = node;
+
+    node = node->parent;
+    while(node){
+        if (node->vis){
+            curval = node->val;
+            break;
+        }
+        node->vis++;
+        stack[sp++] = node;
+        node = node->parent;
+    }
+    while(--sp >= 0){
+        if (stack[sp]->val >= threshold){
+            put_bits(s, 0, threshold - curval);
+            break;
+        }
+        put_bits(s, 0, stack[sp]->val - curval);
+        put_bits(s, 1, 1);
+        curval = stack[sp]->val;
+    }
+}
+
+/** update the value in node */
+static void tag_tree_update(J2kTgtNode *node)
+{
+    int lev = 0;
+    while (node->parent){
+        if (node->parent->val <= node->val)
+            break;
+        node->parent->val = node->val;
+        node = node->parent;
+        lev++;
+    }
+}
+
+static int put_siz(J2kEncoderContext *s)
+{
+    int i;
+
+    if (s->buf_end - s->buf < 40 + 3 * s->ncomponents)
+        return -1;
+
+    bytestream_put_be16(&s->buf, J2K_SIZ);
+    bytestream_put_be16(&s->buf, 38 + 3 * s->ncomponents); // Lsiz
+    bytestream_put_be16(&s->buf, 0); // Rsiz
+    bytestream_put_be32(&s->buf, s->width); // width
+    bytestream_put_be32(&s->buf, s->height); // height
+    bytestream_put_be32(&s->buf, 0); // X0Siz
+    bytestream_put_be32(&s->buf, 0); // Y0Siz
+
+    bytestream_put_be32(&s->buf, s->tile_width); // XTSiz
+    bytestream_put_be32(&s->buf, s->tile_height); // YTSiz
+    bytestream_put_be32(&s->buf, 0); // XT0Siz
+    bytestream_put_be32(&s->buf, 0); // YT0Siz
+    bytestream_put_be16(&s->buf, s->ncomponents); // CSiz
+
+    for (i = 0; i < s->ncomponents; i++){ // Ssiz_i XRsiz_i, YRsiz_i
+        bytestream_put_byte(&s->buf, 7);
+        bytestream_put_byte(&s->buf, i?1<<s->chroma_shift[0]:1);
+        bytestream_put_byte(&s->buf, i?1<<s->chroma_shift[1]:1);
+    }
+    return 0;
+}
+
+static int put_cod(J2kEncoderContext *s)
+{
+    J2kCodingStyle *codsty = &s->codsty;
+
+    if (s->buf_end - s->buf < 14)
+        return -1;
+
+    bytestream_put_be16(&s->buf, J2K_COD);
+    bytestream_put_be16(&s->buf, 12); // Lcod
+    bytestream_put_byte(&s->buf, 0);  // Scod
+    // SGcod
+    bytestream_put_byte(&s->buf, 0); // progression level
+    bytestream_put_be16(&s->buf, 1); // num of layers
+    bytestream_put_byte(&s->buf, 0); // multiple component transformation
+    // SPcod
+    bytestream_put_byte(&s->buf, codsty->nreslevels - 1); // num of decomp. levels
+    bytestream_put_byte(&s->buf, codsty->log2_cblk_width-2); // cblk width
+    bytestream_put_byte(&s->buf, codsty->log2_cblk_height-2); // cblk height
+    bytestream_put_byte(&s->buf, 0); // cblk style
+    bytestream_put_byte(&s->buf, codsty->transform); // transformation
+    return 0;
+}
+
+static int put_qcd(J2kEncoderContext *s, int compno)
+{
+    int i, size;
+    J2kCodingStyle *codsty = &s->codsty;
+    J2kQuantStyle  *qntsty = &s->qntsty;
+
+    if (qntsty->quantsty == J2K_QSTY_NONE)
+        size = 4 + 3 * (codsty->nreslevels-1);
+    else // QSTY_SE
+        size = 5 + 6 * (codsty->nreslevels-1);
+
+    if (s->buf_end - s->buf < size + 2)
+        return -1;
+
+    bytestream_put_be16(&s->buf, J2K_QCD);
+    bytestream_put_be16(&s->buf, size);  // LQcd
+    bytestream_put_byte(&s->buf, (qntsty->nguardbits << 5) | qntsty->quantsty);  // Sqcd
+    if (qntsty->quantsty == J2K_QSTY_NONE)
+        for (i = 0; i < codsty->nreslevels * 3 - 2; i++)
+            bytestream_put_byte(&s->buf, qntsty->expn[i] << 3);
+    else // QSTY_SE
+        for (i = 0; i < codsty->nreslevels * 3 - 2; i++)
+            bytestream_put_be16(&s->buf, (qntsty->expn[i] << 11) | qntsty->mant[i]);
+    return 0;
+}
+
+static uint8_t *put_sot(J2kEncoderContext *s, int tileno)
+{
+    uint8_t *psotptr;
+
+    if (s->buf_end - s->buf < 12)
+        return -1;
+
+    bytestream_put_be16(&s->buf, J2K_SOT);
+    bytestream_put_be16(&s->buf, 10); // Lsot
+    bytestream_put_be16(&s->buf, tileno); // Isot
+
+    psotptr = s->buf;
+    bytestream_put_be32(&s->buf, 0); // Psot (filled in later)
+
+    bytestream_put_byte(&s->buf, 0); // TPsot
+    bytestream_put_byte(&s->buf, 1); // TNsot
+    return psotptr;
+}
+
+/**
+ * compute the sizes of tiles, resolution levels, bands, etc.
+ * allocate memory for them
+ * divide the input image into tile-components
+ */
+static int init_tiles(J2kEncoderContext *s)
+{
+    int tileno, tilex, tiley, compno;
+    J2kCodingStyle *codsty = &s->codsty;
+    J2kQuantStyle  *qntsty = &s->qntsty;
+
+    s->numXtiles = ff_j2k_ceildiv(s->width, s->tile_width);
+    s->numYtiles = ff_j2k_ceildiv(s->height, s->tile_height);
+
+    s->tile = av_malloc(s->numXtiles * s->numYtiles * sizeof(J2kTile));
+    if (!s->tile)
+        return AVERROR(ENOMEM);
+    for (tileno = 0, tiley = 0; tiley < s->numYtiles; tiley++)
+        for (tilex = 0; tilex < s->numXtiles; tilex++, tileno++){
+            J2kTile *tile = s->tile + tileno;
+
+            tile->comp = av_malloc(s->ncomponents * sizeof(J2kComponent));
+            if (!tile->comp)
+                return AVERROR(ENOMEM);
+            for (compno = 0; compno < s->ncomponents; compno++){
+                J2kComponent *comp = tile->comp + compno;
+                int ret, i, j;
+
+                comp->coord[0][0] = tilex * s->tile_width;
+                comp->coord[0][1] = FFMIN((tilex+1)*s->tile_width, s->width);
+                comp->coord[1][0] = tiley * s->tile_height;
+                comp->coord[1][1] = FFMIN((tiley+1)*s->tile_height, s->height);
+                if (compno > 0)
+                    for (i = 0; i < 2; i++)
+                        for (j = 0; j < 2; j++)
+                            comp->coord[i][j] = ff_j2k_ceildivpow2(comp->coord[i][j], s->chroma_shift[i]);
+
+                if (ret = ff_j2k_init_component(comp, codsty, qntsty, s->cbps[compno]))
+                    return ret;
+            }
+        }
+    return 0;
+}
+
+static void copy_frame(J2kEncoderContext *s)
+{
+    int tileno, compno, i, y, x;
+    uint8_t *line;
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+        J2kTile *tile = s->tile + tileno;
+        if (s->planar){
+            for (compno = 0; compno < s->ncomponents; compno++){
+                J2kComponent *comp = tile->comp + compno;
+                int *dst = comp->data;
+                line = s->picture->data[compno]
+                       + comp->coord[1][0] * s->picture->linesize[compno]
+                       + comp->coord[0][0];
+                for (y = comp->coord[1][0]; y < comp->coord[1][1]; y++){
+                    uint8_t *ptr = line;
+                    for (x = comp->coord[0][0]; x < comp->coord[0][1]; x++)
+                        *dst++ = *ptr++ - (1 << 7);
+                    line += s->picture->linesize[compno];
+                }
+            }
+        } else{
+            line = s->picture->data[0] + tile->comp[0].coord[1][0] * s->picture->linesize[0]
+                   + tile->comp[0].coord[0][0] * s->ncomponents;
+
+            i = 0;
+            for (y = tile->comp[0].coord[1][0]; y < tile->comp[0].coord[1][1]; y++){
+                uint8_t *ptr = line;
+                for (x = tile->comp[0].coord[0][0]; x < tile->comp[0].coord[0][1]; x++, i++){
+                    for (compno = 0; compno < s->ncomponents; compno++){
+                        tile->comp[compno].data[i] = *ptr++  - (1 << 7);
+                    }
+                }
+                line += s->picture->linesize[0];
+            }
+        }
+    }
+}
+
+static void init_quantization(J2kEncoderContext *s)
+{
+    int compno, reslevelno, bandno;
+    J2kQuantStyle  *qntsty = &s->qntsty;
+    J2kCodingStyle *codsty = &s->codsty;
+
+    for (compno = 0; compno < s->ncomponents; compno++){
+        int gbandno = 0;
+        for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+            int nbands, lev = codsty->nreslevels - reslevelno - 1;
+            nbands = reslevelno ? 3 : 1;
+            for (bandno = 0; bandno < nbands; bandno++, gbandno++){
+                int expn, mant;
+
+                if (codsty->transform == FF_DWT97){
+                    int bandpos = bandno + (reslevelno>0),
+                        ss = 81920000 / dwt_norms[0][bandpos][lev],
+                        log = av_log2(ss);
+                    mant = (11 - log < 0 ? ss >> log - 11 : ss << 11 - log) & 0x7ff;
+                    expn = s->cbps[compno] - log + 13;
+                } else
+                    expn = ((bandno&2)>>1) + (reslevelno>0) + s->cbps[compno];
+
+                qntsty->expn[gbandno] = expn;
+                qntsty->mant[gbandno] = mant;
+            }
+        }
+    }
+}
+
+static void init_luts()
+{
+    int i, a,
+        mask = ~((1<<NMSEDEC_FRACBITS)-1);
+
+    for (i = 0; i < (1 << NMSEDEC_BITS); i++){
+        lut_nmsedec_sig[i]  = FFMAX(6*i - (9<<NMSEDEC_FRACBITS-1) << 12-NMSEDEC_FRACBITS, 0);
+        lut_nmsedec_sig0[i] = FFMAX((i*i + (1<<NMSEDEC_FRACBITS-1) & mask) << 1, 0);
+
+        a = (i >> (NMSEDEC_BITS-2)&2) + 1;
+        lut_nmsedec_ref[i]  = FFMAX((-2*i + (1<<NMSEDEC_FRACBITS) + a*i - (a*a<<NMSEDEC_FRACBITS-2))
+                                    << 13-NMSEDEC_FRACBITS, 0);
+        lut_nmsedec_ref0[i] = FFMAX(((i*i + (1-4*i << NMSEDEC_FRACBITS-1) + (1<<2*NMSEDEC_FRACBITS)) & mask)
+                                    << 1, 0);
+    }
+}
+
+/* tier-1 routines */
+static int getnmsedec_sig(int x, int bpno)
+{
+    if (bpno > NMSEDEC_FRACBITS)
+        return lut_nmsedec_sig[(x >> (bpno - NMSEDEC_FRACBITS)) & ((1 << NMSEDEC_BITS) - 1)];
+    return lut_nmsedec_sig0[x & ((1 << NMSEDEC_BITS) - 1)];
+}
+
+static int getnmsedec_ref(int x, int bpno)
+{
+    if (bpno > NMSEDEC_FRACBITS)
+        return lut_nmsedec_ref[(x >> (bpno - NMSEDEC_FRACBITS)) & ((1 << NMSEDEC_BITS) - 1)];
+    return lut_nmsedec_ref0[x & ((1 << NMSEDEC_BITS) - 1)];
+}
+
+static void encode_sigpass(J2kT1Context *t1, int width, int height, int bandno, int *nmsedec, int bpno)
+{
+    int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+    for (y0 = 0; y0 < height; y0 += 4)
+        for (x = 0; x < width; x++)
+            for (y = y0; y < height && y < y0+4; y++){
+                if (!(t1->flags[y+1][x+1] & J2K_T1_SIG) && (t1->flags[y+1][x+1] & J2K_T1_SIG_NB)){
+                    int ctxno = ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno),
+                        bit = t1->data[y][x] & mask ? 1 : 0;
+                    ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, bit);
+                    if (bit){
+                        int xorbit;
+                        int ctxno = ff_j2k_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+                        ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit);
+                        *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+                        ff_j2k_set_significant(t1, x, y, t1->flags[y+1][x+1] >> 15);
+                    }
+                    t1->flags[y+1][x+1] |= J2K_T1_VIS;
+                }
+            }
+}
+
+static void encode_refpass(J2kT1Context *t1, int width, int height, int *nmsedec, int bpno)
+{
+    int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+    for (y0 = 0; y0 < height; y0 += 4)
+        for (x = 0; x < width; x++)
+            for (y = y0; y < height && y < y0+4; y++)
+                if ((t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS)) == J2K_T1_SIG){
+                    int ctxno = ff_j2k_getrefctxno(t1->flags[y+1][x+1]);
+                    *nmsedec += getnmsedec_ref(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+                    ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0);
+                    t1->flags[y+1][x+1] |= J2K_T1_REF;
+                }
+}
+
+static void encode_clnpass(J2kT1Context *t1, int width, int height, int bandno, int *nmsedec, int bpno)
+{
+    int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+    for (y0 = 0; y0 < height; y0 += 4)
+        for (x = 0; x < width; x++){
+            if (y0 + 3 < height && !(
+            (t1->flags[y0+1][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+            (t1->flags[y0+2][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+            (t1->flags[y0+3][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+            (t1->flags[y0+4][x+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG))))
+            {
+                // aggregation mode
+                int rlen;
+                for (rlen = 0; rlen < 4; rlen++)
+                    if (t1->data[y0+rlen][x] & mask)
+                        break;
+                ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_RL, rlen != 4);
+                if (rlen == 4)
+                    continue;
+                ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI, rlen >> 1);
+                ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI, rlen & 1);
+                for (y = y0 + rlen; y < y0 + 4; y++){
+                    if (!(t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+                        int ctxno = ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno);
+                        if (y > y0 + rlen)
+                            ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0);
+                        if (t1->data[y][x] & mask){ // newly significant
+                            int xorbit;
+                            int ctxno = ff_j2k_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+                            *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+                            ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit);
+                            ff_j2k_set_significant(t1, x, y, t1->flags[y+1][x+1] >> 15);
+                        }
+                    }
+                    t1->flags[y+1][x+1] &= ~J2K_T1_VIS;
+                }
+            } else{
+                for (y = y0; y < y0 + 4 && y < height; y++){
+                    if (!(t1->flags[y+1][x+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+                        int ctxno = ff_j2k_getnbctxno(t1->flags[y+1][x+1], bandno);
+                        ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0);
+                        if (t1->data[y][x] & mask){ // newly significant
+                            int xorbit;
+                            int ctxno = ff_j2k_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+                            *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+                            ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit);
+                            ff_j2k_set_significant(t1, x, y, t1->flags[y+1][x+1] >> 15);
+                        }
+                    }
+                    t1->flags[y+1][x+1] &= ~J2K_T1_VIS;
+                }
+            }
+        }
+}
+
+static void encode_cblk(J2kEncoderContext *s, J2kT1Context *t1, J2kCblk *cblk, J2kTile *tile,
+                        int width, int height, int bandpos, int lev)
+{
+    int pass_t = 2, passno, x, y, max=0, nmsedec, bpno;
+    int64_t wmsedec = 0;
+
+    for (y = 0; y < height+2; y++)
+        memset(t1->flags[y], 0, (width+2)*sizeof(int));
+
+    for (y = 0; y < height; y++){
+        for (x = 0; x < width; x++){
+            if (t1->data[y][x] < 0){
+                t1->flags[y+1][x+1] |= J2K_T1_SGN;
+                t1->data[y][x] = -t1->data[y][x];
+            }
+            max = FFMAX(max, t1->data[y][x]);
+        }
+    }
+
+    if (max == 0){
+        cblk->nonzerobits = 0;
+        bpno = 0;
+    } else{
+        cblk->nonzerobits = av_log2(max) + 1 - NMSEDEC_FRACBITS;
+        bpno = cblk->nonzerobits - 1;
+    }
+
+    ff_mqc_initenc(&t1->mqc, cblk->data);
+
+    for (passno = 0; bpno >= 0; passno++){
+        nmsedec=0;
+
+        switch(pass_t){
+            case 0: encode_sigpass(t1, width, height, bandpos, &nmsedec, bpno);
+                    break;
+            case 1: encode_refpass(t1, width, height, &nmsedec, bpno);
+                    break;
+            case 2: encode_clnpass(t1, width, height, bandpos, &nmsedec, bpno);
+                    break;
+        }
+
+        cblk->passes[passno].rate = 3 + ff_mqc_length(&t1->mqc);
+        wmsedec += (int64_t)nmsedec << (2*bpno);
+        cblk->passes[passno].disto = wmsedec;
+
+        if (++pass_t == 3){
+            pass_t = 0;
+            bpno--;
+        }
+    }
+    cblk->npasses = passno;
+    cblk->ninclpasses = passno;
+
+    // TODO: optional flush on each pass
+    cblk->passes[passno-1].rate = ff_mqc_flush(&t1->mqc);
+}
+
+/* tier-2 routines: */
+
+static void putnumpasses(J2kEncoderContext *s, int n)
+{
+    if (n == 1)
+        put_num(s, 0, 1);
+    else if (n == 2)
+        put_num(s, 2, 2);
+    else if (n <= 5)
+        put_num(s, 0xc | (n-3), 4);
+    else if (n <= 36)
+        put_num(s, 0x1e0 | (n-6), 9);
+    else
+        put_num(s, 0xff80 | (n-37), 16);
+}
+
+
+static int encode_packet(J2kEncoderContext *s, J2kResLevel *rlevel, int precno,
+                          uint8_t *expn, int numgbits)
+{
+    int bandno, empty = 1;
+
+    // init bitstream
+    *s->buf = 0;
+    s->bit_index = 0;
+
+    // header
+
+    // is the packet empty?
+    for (bandno = 0; bandno < rlevel->nbands; bandno++){
+        if (rlevel->band[bandno].coord[0][0] < rlevel->band[bandno].coord[0][1]
+        &&  rlevel->band[bandno].coord[1][0] < rlevel->band[bandno].coord[1][1]){
+            empty = 0;
+            break;
+        }
+    }
+
+    put_bits(s, !empty, 1);
+    if (empty){
+        j2k_flush(s);
+        return 0;
+    }
+
+    for (bandno = 0; bandno < rlevel->nbands; bandno++){
+        J2kBand *band = rlevel->band + bandno;
+        J2kPrec *prec = band->prec + precno;
+        int yi, xi, pos;
+        int cblknw = prec->xi1 - prec->xi0;
+
+        if (band->coord[0][0] == band->coord[0][1]
+        ||  band->coord[1][0] == band->coord[1][1])
+            continue;
+
+        for (pos=0, yi = prec->yi0; yi < prec->yi1; yi++){
+            for (xi = prec->xi0; xi < prec->xi1; xi++, pos++){
+                prec->cblkincl[pos].val = band->cblk[yi * cblknw + xi].ninclpasses == 0;
+                tag_tree_update(prec->cblkincl + pos);
+                prec->zerobits[pos].val = expn[bandno] + numgbits - 1 - band->cblk[yi * cblknw + xi].nonzerobits;
+                tag_tree_update(prec->zerobits + pos);
+            }
+        }
+
+        for (pos=0, yi = prec->yi0; yi < prec->yi1; yi++){
+            for (xi = prec->xi0; xi < prec->xi1; xi++, pos++){
+                int pad = 0, llen, length;
+                J2kCblk *cblk = band->cblk + yi * cblknw + xi;
+
+                if (s->buf_end - s->buf < 20) // approximately
+                    return -1;
+
+                // inclusion information
+                tag_tree_code(s, prec->cblkincl + pos, 1);
+                if (!cblk->ninclpasses)
+                    continue;
+                // zerobits information
+                tag_tree_code(s, prec->zerobits + pos, 100);
+                // number of passes
+                putnumpasses(s, cblk->ninclpasses);
+
+                length = cblk->passes[cblk->ninclpasses-1].rate;
+                llen = av_log2(length) - av_log2(cblk->ninclpasses) - 2;
+                if (llen < 0){
+                    pad = -llen;
+                    llen = 0;
+                }
+                // length of code block
+                put_bits(s, 1, llen);
+                put_bits(s, 0, 1);
+                put_num(s, length, av_log2(length)+1+pad);
+            }
+        }
+    }
+    j2k_flush(s);
+    for (bandno = 0; bandno < rlevel->nbands; bandno++){
+        J2kBand *band = rlevel->band + bandno;
+        J2kPrec *prec = band->prec + precno;
+        int yi, cblknw = prec->xi1 - prec->xi0;
+        for (yi = prec->yi0; yi < prec->yi1; yi++){
+            int xi;
+            for (xi = prec->xi0; xi < prec->xi1; xi++){
+                J2kCblk *cblk = band->cblk + yi * cblknw + xi;
+                if (cblk->ninclpasses){
+                    if (s->buf_end - s->buf < cblk->passes[cblk->ninclpasses-1].rate)
+                        return -1;
+                    bytestream_put_buffer(&s->buf, cblk->data, cblk->passes[cblk->ninclpasses-1].rate);
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+static int encode_packets(J2kEncoderContext *s, J2kTile *tile, int tileno)
+{
+    int compno, reslevelno, ret;
+    J2kCodingStyle *codsty = &s->codsty;
+    J2kQuantStyle  *qntsty = &s->qntsty;
+
+    av_log(s->avctx, AV_LOG_DEBUG, "tier2\n");
+    // lay-rlevel-comp-pos progression
+    for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+        for (compno = 0; compno < s->ncomponents; compno++){
+            int precno;
+            J2kResLevel *reslevel = s->tile[tileno].comp[compno].reslevel + reslevelno;
+            for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+                if (ret = encode_packet(s, reslevel, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0),
+                              qntsty->nguardbits))
+                    return ret;
+            }
+        }
+    }
+    av_log(s->avctx, AV_LOG_DEBUG, "after tier2\n");
+    return 0;
+}
+
+static int getcut(J2kCblk *cblk, int64_t lambda, int dwt_norm)
+{
+    int passno, res = 0;
+    for (passno = 0; passno < cblk->npasses; passno++){
+        int dr;
+        int64_t dd;
+
+        dr = cblk->passes[passno].rate
+           - (res ? cblk->passes[res-1].rate:0);
+        dd = cblk->passes[passno].disto
+           - (res ? cblk->passes[res-1].disto:0);
+
+        if (((dd * dwt_norm) >> WMSEDEC_SHIFT) * dwt_norm >= dr * lambda)
+            res = passno+1;
+    }
+    return res;
+}
+
+static void truncpasses(J2kEncoderContext *s, J2kTile *tile)
+{
+    int compno, reslevelno, bandno, cblkno, lev;
+    J2kCodingStyle *codsty = &s->codsty;
+
+    for (compno = 0; compno < s->ncomponents; compno++){
+        J2kComponent *comp = tile->comp + compno;
+
+        for (reslevelno = 0, lev = codsty->nreslevels-1; reslevelno < codsty->nreslevels; reslevelno++, lev--){
+            J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+            for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+                int bandpos = bandno + (reslevelno > 0);
+                J2kBand *band = reslevel->band + bandno;
+
+                for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+                    J2kCblk *cblk = band->cblk + cblkno;
+
+                    cblk->ninclpasses = getcut(cblk, s->lambda,
+                            (int64_t)dwt_norms[codsty->transform][bandpos][lev] * (int64_t)band->stepsize >> 13);
+                }
+            }
+        }
+    }
+}
+
+static int encode_tile(J2kEncoderContext *s, J2kTile *tile, int tileno)
+{
+    int compno, reslevelno, bandno, ret;
+    J2kT1Context t1;
+    J2kCodingStyle *codsty = &s->codsty;
+    for (compno = 0; compno < s->ncomponents; compno++){
+        J2kComponent *comp = s->tile[tileno].comp + compno;
+
+        av_log(s->avctx, AV_LOG_DEBUG,"dwt\n");
+        if (ret = ff_dwt_encode(&comp->dwt, comp->data))
+            return ret;
+        av_log(s->avctx, AV_LOG_DEBUG,"after dwt -> tier1\n");
+
+        for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+            J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+            for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+                J2kBand *band = reslevel->band + bandno;
+                int cblkx, cblky, cblkno=0, xx0, x0, xx1, y0, yy0, yy1, bandpos;
+                yy0 = bandno == 0 ? 0 : comp->reslevel[reslevelno-1].coord[1][1] - comp->reslevel[reslevelno-1].coord[1][0];
+                y0 = yy0;
+                yy1 = FFMIN(ff_j2k_ceildiv(band->coord[1][0] + 1, band->codeblock_height) * band->codeblock_height,
+                            band->coord[1][1]) - band->coord[1][0] + yy0;
+
+                if (band->coord[0][0] == band->coord[0][1] || band->coord[1][0] == band->coord[1][1])
+                    continue;
+
+                bandpos = bandno + (reslevelno > 0);
+
+                for (cblky = 0; cblky < band->cblkny; cblky++){
+                    if (reslevelno == 0 || bandno == 1)
+                        xx0 = 0;
+                    else
+                        xx0 = comp->reslevel[reslevelno-1].coord[0][1] - comp->reslevel[reslevelno-1].coord[0][0];
+                    x0 = xx0;
+                    xx1 = FFMIN(ff_j2k_ceildiv(band->coord[0][0] + 1, band->codeblock_width) * band->codeblock_width,
+                                band->coord[0][1]) - band->coord[0][0] + xx0;
+
+                    for (cblkx = 0; cblkx < band->cblknx; cblkx++, cblkno++){
+                        int y, x;
+                        if (codsty->transform == FF_DWT53){
+                            for (y = yy0; y < yy1; y++){
+                                int *ptr = t1.data[y-yy0];
+                                for (x = xx0; x < xx1; x++){
+                                    *ptr++ = comp->data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] << NMSEDEC_FRACBITS;
+                                }
+                            }
+                        } else{
+                            for (y = yy0; y < yy1; y++){
+                                int *ptr = t1.data[y-yy0];
+                                for (x = xx0; x < xx1; x++){
+                                    *ptr = (comp->data[(comp->coord[0][1] - comp->coord[0][0]) * y + x]);
+                                    *ptr++ = (int64_t)*ptr * (int64_t)(8192 * 8192 / band->stepsize) >> 13 - NMSEDEC_FRACBITS;
+                                }
+                            }
+                        }
+                        encode_cblk(s, &t1, band->cblk + cblkno, tile, xx1 - xx0, yy1 - yy0,
+                                    bandpos, codsty->nreslevels - reslevelno - 1);
+                        xx0 = xx1;
+                        xx1 = FFMIN(xx1 + band->codeblock_width, band->coord[0][1] - band->coord[0][0] + x0);
+                    }
+                    yy0 = yy1;
+                    yy1 = FFMIN(yy1 + band->codeblock_height, band->coord[1][1] - band->coord[1][0] + y0);
+                }
+            }
+        }
+        av_log(s->avctx, AV_LOG_DEBUG, "after tier1\n");
+    }
+
+    av_log(s->avctx, AV_LOG_DEBUG, "rate control\n");
+    truncpasses(s, tile);
+    if (ret = encode_packets(s, tile, tileno))
+        return ret;
+    av_log(s->avctx, AV_LOG_DEBUG, "after rate control\n");
+    return 0;
+}
+
+void cleanup(J2kEncoderContext *s)
+{
+    int tileno, compno;
+    J2kCodingStyle *codsty = &s->codsty;
+
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+        for (compno = 0; compno < s->ncomponents; compno++){
+            J2kComponent *comp = s->tile[tileno].comp + compno;
+            ff_j2k_cleanup(comp, codsty);
+        }
+        av_freep(&s->tile[tileno].comp);
+    }
+    av_freep(&s->tile);
+}
+
+static void reinit(J2kEncoderContext *s)
+{
+    int tileno, compno;
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+        J2kTile *tile = s->tile + tileno;
+        for (compno = 0; compno < s->ncomponents; compno++)
+            ff_j2k_reinit(tile->comp + compno, &s->codsty);
+    }
+}
+
+static int encode_frame(AVCodecContext *avctx,
+                        uint8_t *buf, int buf_size,
+                        void *data)
+{
+    int tileno, ret;
+    J2kEncoderContext *s = avctx->priv_data;
+
+    // init:
+    s->buf = s->buf_start = buf;
+    s->buf_end = buf + buf_size;
+
+    s->picture = data;
+
+    s->lambda = s->picture->quality * LAMBDA_SCALE;
+
+    copy_frame(s);
+    reinit(s);
+
+    if (s->buf_end - s->buf < 2)
+        return -1;
+    bytestream_put_be16(&s->buf, J2K_SOC);
+    if (ret = put_siz(s))
+        return ret;
+    if (ret = put_cod(s))
+        return ret;
+    if (ret = put_qcd(s, 0))
+        return ret;
+
+    for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+        uint8_t *psotptr;
+        if ((psotptr = put_sot(s, tileno)) < 0)
+            return psotptr;
+        if (s->buf_end - s->buf < 2)
+            return -1;
+        bytestream_put_be16(&s->buf, J2K_SOD);
+        if (ret = encode_tile(s, s->tile + tileno, tileno))
+            return ret;
+        bytestream_put_be32(&psotptr, s->buf - psotptr + 6);
+    }
+    if (s->buf_end - s->buf < 2)
+        return -1;
+    bytestream_put_be16(&s->buf, J2K_EOC);
+
+    av_log(s->avctx, AV_LOG_DEBUG, "end\n");
+    return s->buf - s->buf_start;
+}
+
+static av_cold int j2kenc_init(AVCodecContext *avctx)
+{
+    int i, ret;
+    J2kEncoderContext *s = avctx->priv_data;
+    J2kCodingStyle *codsty = &s->codsty;
+    J2kQuantStyle  *qntsty = &s->qntsty;
+
+    s->avctx = avctx;
+    av_log(s->avctx, AV_LOG_DEBUG, "init\n");
+
+    // defaults:
+    // TODO: implement setting non-standard precinct size
+    codsty->log2_prec_width  = 15;
+    codsty->log2_prec_height = 15;
+    codsty->nreslevels       = 7;
+    codsty->log2_cblk_width  = 4;
+    codsty->log2_cblk_height = 4;
+    codsty->transform        = 1;
+
+    qntsty->nguardbits       = 1;
+
+    s->tile_width            = 256;
+    s->tile_height           = 256;
+
+    if (codsty->transform == FF_DWT53)
+        qntsty->quantsty = J2K_QSTY_NONE;
+    else
+        qntsty->quantsty = J2K_QSTY_SE;
+
+    s->width = avctx->width;
+    s->height = avctx->height;
+
+    for (i = 0; i < 3; i++)
+        s->cbps[i] = 8;
+
+    if (avctx->pix_fmt == PIX_FMT_RGB24){
+        s->ncomponents = 3;
+    } else if (avctx->pix_fmt == PIX_FMT_GRAY8){
+        s->ncomponents = 1;
+    } else{ // planar YUV
+        s->planar = 1;
+        s->ncomponents = 3;
+        avcodec_get_chroma_sub_sample(avctx->pix_fmt,
+                s->chroma_shift, s->chroma_shift + 1);
+    }
+
+    ff_j2k_init_tier1_luts();
+
+    init_luts();
+
+    init_quantization(s);
+    if (ret=init_tiles(s))
+        return ret;
+
+    av_log(s->avctx, AV_LOG_DEBUG, "after init\n");
+
+    return 0;
+}
+
+static int j2kenc_destroy(AVCodecContext *avctx)
+{
+    J2kEncoderContext *s = avctx->priv_data;
+
+    cleanup(s);
+    return 0;
+}
+
+AVCodec jpeg2000_encoder = {
+    "j2k",
+    CODEC_TYPE_VIDEO,
+    CODEC_ID_JPEG2000,
+    sizeof(J2kEncoderContext),
+    j2kenc_init,
+    encode_frame,
+    j2kenc_destroy,
+    NULL,
+    0,
+    .pix_fmts =
+        (enum PixelFormat[]) {PIX_FMT_GRAY8, PIX_FMT_RGB24,
+                              PIX_FMT_YUV422P, PIX_FMT_YUV444P,
+                              PIX_FMT_YUV410P, PIX_FMT_YUV411P,
+                              -1}
+};
diff --git a/libavcodec/mqc.c b/libavcodec/mqc.c
new file mode 100644
index 0000000..700b957
--- /dev/null
+++ b/libavcodec/mqc.c
@@ -0,0 +1,108 @@
+/*
+ * MQ-coder encoder and decoder common functions
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ */
+
+/**
+ * MQ-coder ecoder and decoder common functions
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "mqc.h"
+
+typedef struct {
+        uint16_t qe;
+        uint8_t  nmps;
+        uint8_t  nlps;
+        uint8_t  sw;
+} MqcCxState;
+
+const static MqcCxState cx_states[47] = {
+    {0x5601,  1,  1, 1},
+    {0x3401,  2,  6, 0},
+    {0x1801,  3,  9, 0},
+    {0x0AC1,  4, 12, 0},
+    {0x0521,  5, 29, 0},
+    {0x0221, 38, 33, 0},
+    {0x5601,  7,  6, 1},
+    {0x5401,  8, 14, 0},
+    {0x4801,  9, 14, 0},
+    {0x3801, 10, 14, 0},
+    {0x3001, 11, 17, 0},
+    {0x2401, 12, 18, 0},
+    {0x1C01, 13, 20, 0},
+    {0x1601, 29, 21, 0},
+    {0x5601, 15, 14, 1},
+    {0x5401, 16, 14, 0},
+    {0x5101, 17, 15, 0},
+    {0x4801, 18, 16, 0},
+    {0x3801, 19, 17, 0},
+    {0x3401, 20, 18, 0},
+    {0x3001, 21, 19, 0},
+    {0x2801, 22, 19, 0},
+    {0x2401, 23, 20, 0},
+    {0x2201, 24, 21, 0},
+    {0x1C01, 25, 22, 0},
+    {0x1801, 26, 23, 0},
+    {0x1601, 27, 24, 0},
+    {0x1401, 28, 25, 0},
+    {0x1201, 29, 26, 0},
+    {0x1101, 30, 27, 0},
+    {0x0AC1, 31, 28, 0},
+    {0x09C1, 32, 29, 0},
+    {0x08A1, 33, 30, 0},
+    {0x0521, 34, 31, 0},
+    {0x0441, 35, 32, 0},
+    {0x02A1, 36, 33, 0},
+    {0x0221, 37, 34, 0},
+    {0x0141, 38, 35, 0},
+    {0x0111, 39, 36, 0},
+    {0x0085, 40, 37, 0},
+    {0x0049, 41, 38, 0},
+    {0x0025, 42, 39, 0},
+    {0x0015, 43, 40, 0},
+    {0x0009, 44, 41, 0},
+    {0x0005, 45, 42, 0},
+    {0x0001, 45, 43, 0},
+    {0x5601, 46, 46, 0}
+};
+
+uint16_t ff_mqc_qe [2*47];
+uint8_t ff_mqc_nlps[2*47];
+uint8_t ff_mqc_nmps[2*47];
+
+void ff_mqc_init_contexts(MqcState *mqc)
+{
+    int i;
+    memset(mqc->cx_states, 0, sizeof(mqc->cx_states));
+    mqc->cx_states[MQC_CX_UNI] = 2 * 46;
+    mqc->cx_states[MQC_CX_RL] = 2 * 3;
+    mqc->cx_states[0] = 2 * 4;
+
+    for (i = 0; i < 47; i++){
+        ff_mqc_qe[2*i  ] =
+        ff_mqc_qe[2*i+1] = cx_states[i].qe;
+
+        ff_mqc_nlps[2*i  ] = 2*cx_states[i].nlps + cx_states[i].sw;
+        ff_mqc_nlps[2*i+1] = 2*cx_states[i].nlps + 1 - cx_states[i].sw;
+        ff_mqc_nmps[2*i  ] = 2*cx_states[i].nmps;
+        ff_mqc_nmps[2*i+1] = 2*cx_states[i].nmps + 1;
+    }
+}
diff --git a/libavcodec/mqc.h b/libavcodec/mqc.h
new file mode 100644
index 0000000..b28c13e
--- /dev/null
+++ b/libavcodec/mqc.h
@@ -0,0 +1,75 @@
+/*
+ * MQ-coder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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_MQC_H
+#define AVCODEC_MQC_H
+
+/**
+ * MQ-coder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "avcodec.h"
+
+#define MQC_CX_UNI 17
+#define MQC_CX_RL  18
+
+extern uint16_t  ff_mqc_qe[2*47];
+extern uint8_t ff_mqc_nlps[2*47];
+extern uint8_t ff_mqc_nmps[2*47];
+
+typedef struct {
+    uint8_t *bp, *bpstart;
+    unsigned int a;
+    unsigned int c;
+    unsigned int ct;
+    uint8_t cx_states[19];
+} MqcState;
+
+/* encoder */
+
+/** initialize the encoder */
+void ff_mqc_initenc(MqcState *mqc, uint8_t *bp);
+
+/** code bit d with context cx */
+void ff_mqc_encode(MqcState *mqc, uint8_t *cxstate, int d);
+
+/** number of encoded bytes */
+int ff_mqc_length(MqcState *mqc);
+
+/** flush the encoder [returns number of bytes encoded] */
+int ff_mqc_flush(MqcState *mqc);
+
+/* decoder */
+
+/** initialize the decoder */
+void ff_mqc_initdec(MqcState *mqc, uint8_t *bp);
+
+/** returns decoded bit with context cx */
+int ff_mqc_decode(MqcState *mqc, uint8_t *cxstate);
+
+/* common */
+
+/** initialize the contexts */
+void ff_mqc_init_contexts(MqcState *mqc);
+
+#endif /* AVCODEC_MQC_H */
diff --git a/libavcodec/mqcdec.c b/libavcodec/mqcdec.c
new file mode 100644
index 0000000..56e22f8
--- /dev/null
+++ b/libavcodec/mqcdec.c
@@ -0,0 +1,93 @@
+/*
+ * MQ-coder decoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ */
+
+/**
+ * MQ-coder decoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "mqc.h"
+
+static void bytein(MqcState *mqc)
+{
+    if (*mqc->bp == 0xff){
+        if (*(mqc->bp+1) > 0x8f)
+            mqc->c++;
+        else{
+            mqc->bp++;
+            mqc->c += 2 + 0xfe00 - (*mqc->bp << 9);
+        }
+    } else{
+        mqc->bp++;
+        mqc->c += 1 + 0xff00 - (*mqc->bp << 8);
+    }
+}
+
+static int exchange(MqcState *mqc, uint8_t *cxstate, int lps)
+{
+    int d;
+    if ((mqc->a < ff_mqc_qe[*cxstate]) ^ (!lps)){
+        if (lps)
+            mqc->a = ff_mqc_qe[*cxstate];
+        d = *cxstate & 1;
+        *cxstate = ff_mqc_nmps[*cxstate];
+    } else{
+        if (lps)
+            mqc->a = ff_mqc_qe[*cxstate];
+        d = 1 - (*cxstate & 1);
+        *cxstate = ff_mqc_nlps[*cxstate];
+    }
+    // renormd:
+    do{
+        if (!(mqc->c & 0xff)){
+            mqc->c -= 0x100;
+            bytein(mqc);
+        }
+        mqc->a += mqc->a;
+        mqc->c += mqc->c;
+    } while (!(mqc->a & 0x8000));
+    return d;
+}
+
+void ff_mqc_initdec(MqcState *mqc, uint8_t *bp)
+{
+    ff_mqc_init_contexts(mqc);
+    mqc->bp = bp;
+    mqc->c = (*mqc->bp ^ 0xff) << 16;
+    bytein(mqc);
+    mqc->c = mqc->c << 7;
+    mqc->a = 0x8000;
+}
+
+int ff_mqc_decode(MqcState *mqc, uint8_t *cxstate)
+{
+    mqc->a -= ff_mqc_qe[*cxstate];
+    if ((mqc->c >> 16) < mqc->a){
+        if (mqc->a & 0x8000)
+            return *cxstate & 1;
+        else
+            return exchange(mqc, cxstate, 0);
+    } else {
+        mqc->c -= mqc->a << 16;
+        return exchange(mqc, cxstate, 1);
+    }
+}
diff --git a/libavcodec/mqcenc.c b/libavcodec/mqcenc.c
new file mode 100644
index 0000000..97d352b
--- /dev/null
+++ b/libavcodec/mqcenc.c
@@ -0,0 +1,119 @@
+/*
+ * MQ-coder encoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * 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
+ */
+
+/**
+ * MQ-coder encoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "mqc.h"
+
+static void byteout(MqcState *mqc)
+{
+retry:
+    if (*mqc->bp == 0xff){
+        mqc->bp++;
+        *mqc->bp = mqc->c >> 20;
+        mqc->c &= 0xfffff;
+        mqc->ct = 7;
+    } else if ((mqc->c & 0x8000000)){
+        (*mqc->bp)++;
+        mqc->c &= 0x7ffffff;
+        goto retry;
+    } else{
+        mqc->bp++;
+        *mqc->bp = mqc->c >> 19;
+        mqc->c &= 0x7ffff;
+        mqc->ct = 8;
+    }
+}
+
+static void renorme(MqcState *mqc)
+{
+    do{
+        mqc->a += mqc->a;
+        mqc->c += mqc->c;
+        if (!--mqc->ct)
+            byteout(mqc);
+    } while (!(mqc->a & 0x8000));
+}
+
+static void setbits(MqcState *mqc)
+{
+    int tmp = mqc->c + mqc->a;
+    mqc->c |= 0xffff;
+    if (mqc->c >= tmp)
+        mqc->c -= 0x8000;
+}
+
+void ff_mqc_initenc(MqcState *mqc, uint8_t *bp)
+{
+    ff_mqc_init_contexts(mqc);
+    mqc->a = 0x8000;
+    mqc->c = 0;
+    mqc->bp = bp-1;
+    mqc->bpstart = bp;
+    mqc->ct = 12 + (*mqc->bp == 0xff);
+}
+
+void ff_mqc_encode(MqcState *mqc, uint8_t *cxstate, int d)
+{
+    int qe;
+
+    qe = ff_mqc_qe[*cxstate];
+    mqc->a -= qe;
+    if ((*cxstate & 1) == d){
+        if (!(mqc->a & 0x8000)){
+            if (mqc->a < qe)
+                mqc->a = qe;
+            else
+                mqc->c += qe;
+            *cxstate = ff_mqc_nmps[*cxstate];
+            renorme(mqc);
+        } else
+            mqc->c += qe;
+    } else{
+        if (mqc->a < qe)
+            mqc->c += qe;
+        else
+            mqc->a = qe;
+        *cxstate = ff_mqc_nlps[*cxstate];
+        renorme(mqc);
+    }
+}
+
+int ff_mqc_length(MqcState *mqc)
+{
+    return mqc->bp - mqc->bpstart;
+}
+
+int ff_mqc_flush(MqcState *mqc)
+{
+    setbits(mqc);
+    mqc->c = mqc->c << mqc->ct;
+    byteout(mqc);
+    mqc->c = mqc->c << mqc->ct;
+    byteout(mqc);
+    if (*mqc->bp != 0xff)
+        mqc->bp++;
+    return mqc->bp - mqc->bpstart;
+}
diff --git a/libavformat/img2.c b/libavformat/img2.c
index 58b0780..e0d9293 100644
--- a/libavformat/img2.c
+++ b/libavformat/img2.c
@@ -77,6 +77,7 @@ static const IdStrMap img_tags[] = {
     { CODEC_ID_SUNRAST   , "sunras"},
     { CODEC_ID_JPEG2000  , "j2k"},
     { CODEC_ID_JPEG2000  , "jp2"},
+    { CODEC_ID_JPEG2000  , "jpc"},
     { CODEC_ID_DPX       , "dpx"},
     { CODEC_ID_PICTOR    , "pic"},
     { CODEC_ID_NONE      , NULL}
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 833a6bf..4b3ab60 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -250,6 +250,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
     { CODEC_ID_ZMBV,         MKTAG('Z', 'M', 'B', 'V') },
     { CODEC_ID_KMVC,         MKTAG('K', 'M', 'V', 'C') },
     { CODEC_ID_CAVS,         MKTAG('C', 'A', 'V', 'S') },
+    { CODEC_ID_JPEG2000,     MKTAG('m', 'j', 'p', '2') },
     { CODEC_ID_JPEG2000,     MKTAG('M', 'J', '2', 'C') },
     { CODEC_ID_VMNC,         MKTAG('V', 'M', 'n', 'c') },
     { CODEC_ID_TARGA,        MKTAG('t', 'g', 'a', ' ') },



More information about the ffmpeg-cvslog mailing list