[FFmpeg-soc] [soc]: r282 - in jpeg2000: checkout.sh ffmpeg.patch j2k.h j2kenc.c
k.nowosad
subversion at mplayerhq.hu
Mon Jun 25 12:28:41 CEST 2007
Author: k.nowosad
Date: Mon Jun 25 12:28:41 2007
New Revision: 282
Log:
The basics of encoder. Quantization, dwt 9-7 and some smaller features will be added.
Added:
jpeg2000/checkout.sh (contents, props changed)
jpeg2000/ffmpeg.patch
jpeg2000/j2k.h
jpeg2000/j2kenc.c
Added: jpeg2000/checkout.sh
==============================================================================
--- (empty file)
+++ jpeg2000/checkout.sh Mon Jun 25 12:28:41 2007
@@ -0,0 +1,9 @@
+echo "checking out ffmpeg svn"
+svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk/ ffmpeg
+echo "patching ffmpeg"
+cd ffmpeg/libavcodec ;
+patch -p0 <../../ffmpeg.patch
+echo "copying the jpeg2000 files to ffmpeg/libavcodec"
+ln -s ../../j2kenc.c j2kenc.c
+ln -s ../../j2k.h j2k.h
+echo "Done, now just do a regular configure and make to build."
Added: jpeg2000/ffmpeg.patch
==============================================================================
--- (empty file)
+++ jpeg2000/ffmpeg.patch Mon Jun 25 12:28:41 2007
@@ -0,0 +1,36 @@
+Index: Makefile
+===================================================================
+--- Makefile (wersja 9417)
++++ Makefile (kopia robocza)
+@@ -93,6 +93,7 @@
+ OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o
+ OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o
+ OBJS-$(CONFIG_INTERPLAY_DPCM_DECODER) += dpcm.o
++OBJS-$(CONFIG_JPEG2000_ENCODER) += j2kenc.o
+ OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o mjpegdec.o mjpeg.o golomb.o
+ OBJS-$(CONFIG_JPEGLS_ENCODER) += jpeglsenc.o jpegls.o golomb.o
+ OBJS-$(CONFIG_KMVC_DECODER) += kmvc.o
+Index: allcodecs.c
+===================================================================
+--- allcodecs.c (wersja 9417)
++++ allcodecs.c (kopia robocza)
+@@ -92,6 +92,7 @@
+ REGISTER_DECODER(INDEO3, indeo3);
+ REGISTER_DECODER(INTERPLAY_VIDEO, interplay_video);
+ REGISTER_ENCDEC (JPEGLS, jpegls);
++ REGISTER_ENCODER(JPEG2000, jpeg2000);
+ REGISTER_DECODER(KMVC, kmvc);
+ REGISTER_ENCODER(LIBX264, libx264);
+ REGISTER_ENCODER(LIBXVID, libxvid);
+Index: allcodecs.h
+===================================================================
+--- allcodecs.h (wersja 9417)
++++ allcodecs.h (kopia robocza)
+@@ -40,6 +40,7 @@
+ extern AVCodec h264_encoder;
+ extern AVCodec huffyuv_encoder;
+ extern AVCodec jpegls_encoder;
++extern AVCodec jpeg2000_encoder;
+ extern AVCodec ljpeg_encoder;
+ extern AVCodec mdec_encoder;
+ extern AVCodec mjpeg_encoder;
Added: jpeg2000/j2k.h
==============================================================================
--- (empty file)
+++ jpeg2000/j2k.h Mon Jun 25 12:28:41 2007
@@ -0,0 +1,163 @@
+/*
+ * 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
+ *
+ */
+
+/**
+ * JPEG2000 tables
+ * @file j2k.h
+ * @author Kamil Nowosad
+ */
+
+#ifndef _J2K_H_
+#define _J2K_H_
+
+enum J2kMarkers{
+ J2K_SOC = 0xff4f,
+ J2K_SIZ = 0xff51,
+ J2K_COD,
+ J2K_COC,
+ J2K_TLM = 0xff55,
+ J2K_PLM = 0xff57,
+ J2K_PLT,
+ J2K_QCD = 0xff5c,
+ J2K_QCC,
+ J2K_RGN,
+ J2K_POC,
+ J2K_PPM,
+ J2K_PPT,
+ J2K_CRG,
+ J2K_COM,
+ J2K_SOT = 0xff90,
+ J2K_SOP,
+ J2K_EPH,
+ J2K_SOD,
+ J2K_EOC = 0xffd9,
+};
+
+
+/* arithmetic entropy coder context */
+//TODO: optimize [nice solution in openjpeg]
+typedef struct {
+ unsigned int qe;
+ unsigned int nmps;
+ unsigned int nlps;
+ unsigned int sw;
+} J2kAecState;
+
+const static J2kAecState aec_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}
+};
+
+typedef struct {
+ unsigned int state;
+ unsigned int mps;
+} J2kAecContext;
+
+typedef struct {
+ uint8_t *bp, *bpstart;
+ unsigned int a;
+ unsigned int c;
+ unsigned int ct;
+ J2kAecContext contexts[19];
+ J2kAecContext *curctx;
+} J2kAec;
+
+#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_CTX_RL 17
+#define J2K_T1_CTX_UNI 18
+
+typedef struct {
+ int data[J2K_MAX_CBLKW][J2K_MAX_CBLKH];
+ int flags[J2K_MAX_CBLKW+2][J2K_MAX_CBLKH+2];
+ J2kAec aec;
+} J2kT1Context;
+
+#endif
Added: jpeg2000/j2kenc.c
==============================================================================
--- (empty file)
+++ jpeg2000/j2kenc.c Mon Jun 25 12:28:41 2007
@@ -0,0 +1,1266 @@
+/*
+ * 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 j2kenc.c
+ * @author Kamil Nowosad
+ */
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "j2k.h"
+#include "common.h"
+
+// TODO: doxygen-compatible comments
+
+typedef struct {
+ int length;
+ int npassess;
+ int zerobits;
+ int zero;
+ uint8_t data[8192];
+} J2kCblk; // code block
+
+typedef struct J2kTgtNode {
+ uint8_t val;
+ uint8_t vis;
+ struct J2kTgtNode *parent;
+} J2kTgtNode;
+
+typedef struct {
+ int xi0, xi1, yi0, yi1; /// indices of codeblocks ([xi0, xi1))
+} J2kPrec; // precinct
+
+typedef struct {
+ int x0, x1, y0, y1;
+ int cblkw, cblkh;
+ int cblknx, cblkny;
+ J2kPrec *prec;
+ J2kCblk *cblk;
+} J2kBand; // subband
+
+typedef struct {
+ int x0, x1, y0, y1;
+ int nbands;
+ int nprecw, nprech;
+ J2kBand *band;
+} J2kResLevel; // resolution level
+
+typedef struct {
+ J2kResLevel *reslevel;
+ int *data;
+ int x0, x1, y0, y1;
+} J2kComponent;
+
+typedef struct { // flatten with context
+ J2kComponent *comp;
+} J2kTile;
+
+typedef struct {
+ AVCodecContext *avctx;
+ AVFrame *picture;
+
+ int Xsiz, Ysiz; // image width and height
+ unsigned int bpp;
+ int ncomponents;
+ int ppx, ppy; // exponent of the precinct size [global]
+ int xcb, ycb; // exponent of the code block size
+ int XTsiz, YTsiz; // tile size
+ int numXtiles, numYtiles;
+
+ int expn;
+ int nguardbits;
+
+// int *samples[3];
+ int nreslevels; // number of resolution levels
+ uint8_t *buf_start;
+ uint8_t *buf;
+ uint8_t *buf_end;
+ int bit_index;
+
+ 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, XTsiz = %d, YTsiz = %d\n"
+ "numXtiles = %d, numYtiles = %d, ncomponents = %d\n"
+ "tiles:\n",
+ s->Xsiz, s->Ysiz, s->XTsiz, s->YTsiz,
+ 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,"
+ "cblkw = %d, cblkh = %d cblknx = %d cblkny = %d\n",
+ band->x0, band->x1,
+ band->y0, band->y1,
+ band->cblkw, band->cblkh,
+ band->cblknx, band->cblkny);
+ for (precno = 0; precno < reslevel->nprecw * reslevel->nprech; 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
+
+/* misc tools */
+static int ceildivpow2(int a, int b)
+{
+ return (a + (1 << b) - 1)>> b;
+}
+
+static int ceildiv(int a, int b)
+{
+ return (a + b - 1) / b;
+}
+
+/* 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 ? 1:0;
+ *(++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 & (1<<n)) ? 1:0, 1);
+}
+
+/* flush the bitstream */
+static void j2k_flush(J2kEncoderContext *s)
+{
+ if (s->bit_index){
+ s->bit_index = 0;
+ s->buf++;
+ }
+}
+
+/* tag tree routines */
+
+/* allocate the memory for tag tree */
+//TODO: optimize (too many mallocs)
+static J2kTgtNode *tag_tree_alloc(int w, int h)
+{
+ int i;
+ J2kTgtNode *t = av_malloc(w*h*sizeof(J2kTgtNode));
+ if (t == NULL)
+ return NULL;
+ for (i = 0; i < w*h; i++){
+ t[i].val = 0xff;
+ t[i].vis = 0;
+ }
+ return t;
+}
+
+static J2kTgtNode *tag_tree_init(int w, int h)
+{
+ J2kTgtNode *res = tag_tree_alloc(w, h),
+ *t = res;
+
+ if (res == NULL)
+ return NULL;
+
+ while (w > 1 || h > 1){
+ int pw = w, ph = h;
+ int i, j;
+ J2kTgtNode *t2;
+
+ w = (w+1) >> 1;
+ h = (h+1) >> 1;
+ t2 = tag_tree_alloc(w, h);
+ if (t2 == NULL)
+ return NULL;
+
+ 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;
+}
+
+/* code the value stored in node */
+static void tag_tree_code(J2kEncoderContext *s, J2kTgtNode *node)
+{
+ J2kTgtNode *stack[30];
+ int sp = 1, curval = 0;
+ stack[0] = node;
+
+ node = node->parent;
+ while(node != NULL){
+ if (node->vis){
+ curval = node->val;
+ break;
+ }
+ node->vis++;
+ stack[sp++] = node;
+ node = node->parent;
+ }
+ while(--sp >= 0){
+ 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 != NULL){
+ if (node->parent->val <= node->val)
+ break;
+ node->parent->val = node->val;
+ node = node->parent;
+ lev++;
+ }
+}
+
+static void tag_tree_destroy(J2kTgtNode *tree)
+{
+ while (tree != NULL){
+ J2kTgtNode *parent = tree[0].parent;
+ av_free(tree);
+ tree = parent;
+ }
+}
+
+/* marker segments */
+static void put_marker(J2kEncoderContext *s, uint16_t marker)
+{
+ bytestream_put_be16(&s->buf, marker);
+}
+
+static void put_soc(J2kEncoderContext *s)
+{
+ put_marker(s, J2K_SOC);
+}
+
+static void put_siz(J2kEncoderContext *s)
+{
+ int i;
+
+ put_marker(s, 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->Xsiz); // Xsiz
+ bytestream_put_be32(&s->buf, s->Ysiz); // Ysiz
+ bytestream_put_be32(&s->buf, 0); // X0Siz
+ bytestream_put_be32(&s->buf, 0); // Y0Siz
+
+ bytestream_put_be32(&s->buf, s->XTsiz); // XTSiz
+ bytestream_put_be32(&s->buf, s->YTsiz); // 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 < 3; i++){ // Ssiz_i XRsiz_i, YRsiz_i
+ bytestream_put_byte(&s->buf, 7);
+ bytestream_put_byte(&s->buf, 1);
+ bytestream_put_byte(&s->buf, 1);
+ }
+}
+
+static void put_cod(J2kEncoderContext *s)
+{
+ put_marker(s, 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, s->nreslevels - 1); // num of decomp. levels
+ bytestream_put_byte(&s->buf, s->xcb-2); // cblk width
+ bytestream_put_byte(&s->buf, s->ycb-2); // cblk height
+ bytestream_put_byte(&s->buf, 0); // cblk style
+ bytestream_put_byte(&s->buf, 1); // transformation
+}
+
+static void put_qcd(J2kEncoderContext *s)
+{
+ int reslevelno;
+ put_marker(s, J2K_QCD);
+ bytestream_put_be16(&s->buf, 4+3*(s->nreslevels-1)); // LQcd
+ bytestream_put_byte(&s->buf, s->nguardbits << 5); // Sqcd
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ int bandno, nbands = reslevelno == 0 ? 1:3;
+ for (bandno = 0; bandno < nbands; bandno++)
+ bytestream_put_byte(&s->buf, s->expn << 3);
+ }
+}
+
+static uint8_t *put_sot(J2kEncoderContext *s, int tileno)
+{
+ uint8_t *psotptr;
+ put_marker(s, 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)
+{
+ // only one tile
+ // only rgb24 supported now
+ int y, x, tno, i;
+
+ s->numXtiles = ceildiv(s->Xsiz, s->XTsiz);
+ s->numYtiles = ceildiv(s->Ysiz, s->YTsiz);
+
+ s->tile = av_malloc(s->numXtiles * s->numYtiles * sizeof(J2kTile));
+ if (s->tile == NULL)
+ return -1;
+ for (tno = 0; tno < s->numXtiles * s->numYtiles; tno++){
+ J2kTile *tile = s->tile + tno;
+ int p = tno % s->numXtiles;
+ int q = tno / s->numXtiles;
+ int compno;
+
+ tile->comp = av_malloc(s->ncomponents * sizeof(J2kComponent));
+ if (tile->comp == NULL)
+ return -1;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ int reslevelno;
+
+ comp->x0 = p * s->XTsiz;
+ comp->x1 = FFMIN((p+1)*s->XTsiz, s->Xsiz);
+ comp->y0 = q * s->YTsiz;
+ comp->y1 = FFMIN((q+1)*s->YTsiz, s->Ysiz);
+
+ comp->data = av_malloc((comp->y1 - comp->y0) * (comp->x1 -comp->x0) * sizeof(int));
+ if (comp->data == NULL)
+ return -1;
+ comp->reslevel = av_malloc(s->nreslevels * sizeof(J2kResLevel));
+ if (comp->reslevel == NULL)
+ return -1;
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ int bandno;
+ int n = s->nreslevels - reslevelno;
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ reslevel->x0 = ceildivpow2(comp->x0, s->nreslevels - reslevelno - 1);
+ reslevel->x1 = ceildivpow2(comp->x1, s->nreslevels - reslevelno - 1);
+ reslevel->y0 = ceildivpow2(comp->y0, s->nreslevels - reslevelno - 1);
+ reslevel->y1 = ceildivpow2(comp->y1, s->nreslevels - reslevelno - 1);
+
+ if (reslevelno == 0)
+ reslevel->nbands = 1;
+ else
+ reslevel->nbands = 3;
+
+ if (reslevel->x1 == reslevel->x0)
+ reslevel->nprecw = 0;
+ else
+ reslevel->nprecw = ceildivpow2(reslevel->x1, s->ppx) - reslevel->x0 / (1<<s->ppx);
+
+ if (reslevel->y1 == reslevel->y0)
+ reslevel->nprech = 0;
+ else
+ reslevel->nprech = ceildivpow2(reslevel->y1, s->ppy) - reslevel->y0 / (1<<s->ppy);
+
+ reslevel->band = av_malloc(reslevel->nbands * sizeof(J2kBand));
+ if (reslevel->band == NULL)
+ return -1;
+ for (bandno = 0; bandno < reslevel->nbands; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ int cblkno, precx, precy, precno;
+ int x0, y0, x1, y1;
+ int xi0, yi0, xi1, yi1;
+ int cblkperprecw, cblkperprech;
+
+ if (reslevelno == 0){ // the same everywhere
+ band->cblkw = 1 << FFMIN(s->xcb, s->ppx-1);
+ band->cblkh = 1 << FFMIN(s->ycb, s->ppy-1);
+
+ band->x0 = ceildivpow2(comp->x0, n-1);
+ band->x1 = ceildivpow2(comp->x1, n-1);
+ band->y0 = ceildivpow2(comp->y0, n-1);
+ band->y1 = ceildivpow2(comp->y1, n-1);
+ }
+ else{
+ band->cblkw = 1 << FFMIN(s->xcb, s->ppx);
+ band->cblkh = 1 << FFMIN(s->ycb, s->ppy);
+
+ band->x0 = ceildivpow2(comp->x0 - (1 << (n-1)) * ((bandno+1)&1), n);
+ band->x1 = ceildivpow2(comp->x1 - (1 << (n-1)) * ((bandno+1)&1), n);
+ band->y0 = ceildivpow2(comp->y0 - (1 << (n-1)) * (((bandno+1)&2)>>1), n);
+ band->y1 = ceildivpow2(comp->y1 - (1 << (n-1)) * (((bandno+1)&2)>>1), n);
+ }
+
+ band->cblknx = ceildiv(band->x1 - band->x0, band->cblkw);
+ band->cblkny = ceildiv(band->y1 - band->y0, band->cblkh);
+
+ band->cblk = av_malloc(band->cblknx * band->cblkny * sizeof(J2kCblk));
+ if (band->cblk == NULL)
+ return -1;
+ band->prec = av_malloc(reslevel->nprecw * reslevel->nprech * sizeof(J2kPrec));
+ if (band->prec == NULL)
+ return -1;
+
+ for (cblkno = 0; cblkno < band->cblknx * band->cblkny; cblkno++){
+ band->cblk[cblkno].zero = 0;
+ }
+
+ y0 = band->y0;
+ y1 = (band->y0 + (1<<s->ppy))/(1<<s->ppy)*(1<<s->ppy) - band->y0;
+ yi0 = 0;
+ yi1 = ceildiv(y1 - y0, 1<<s->ycb) * (1<<s->ycb);
+ yi1 = FFMIN(yi1, band->cblkny);
+ cblkperprech = 1<<(s->ppy - s->ycb);
+ for (precy = 0, precno = 0; precy < reslevel->nprech; precy++){
+ for (precx = 0; precx < reslevel->nprecw; precx++, precno++){
+ band->prec[precno].yi0 = yi0;
+ band->prec[precno].yi1 = yi1;
+ }
+ yi1 += cblkperprech;
+ yi0 = yi1 - cblkperprech;
+ yi1 = FFMIN(yi1, band->cblkny);
+ }
+ x0 = band->x0;
+ x1 = (band->x0 + (1<<s->ppx))/(1<<s->ppx)*(1<<s->ppx) - band->x0;
+ xi0 = 0;
+ xi1 = ceildiv(x1 - x0, 1<<s->xcb) * (1<<s->xcb);
+ xi1 = FFMIN(xi1, band->cblknx);
+ cblkperprecw = 1<<(s->ppx - s->xcb);
+ for (precx = 0, precno = 0; precx < reslevel->nprecw; precx++){
+ for (precy = 0; precy < reslevel->nprech; precy++, precno = 0){
+ band->prec[precno].xi0 = xi0;
+ band->prec[precno].xi1 = xi1;
+ }
+ xi1 += cblkperprecw;
+ xi0 = xi1 - cblkperprecw;
+ xi1 = FFMIN(xi1, band->cblknx);
+ }
+ }
+ }
+ }
+ }
+ for (tno = 0; tno < s->numXtiles * s->numYtiles; tno++){
+ J2kTile *tile = s->tile + tno;
+ uint8_t *line = s->picture->data[0] + tile->comp[0].y0 * s->picture->linesize[0] + tile->comp[0].x0 * s->ncomponents;
+
+ i = 0;
+ for (y = tile->comp[0].y0; y < tile->comp[0].y1; y++){
+ uint8_t *ptr = line;
+ for (x = tile->comp[0].x0; x < tile->comp[0].x1; x++, i++){
+ int compno;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ tile->comp[compno].data[i] = *ptr++ - (1 << 7);
+ }
+ }
+ line += s->picture->linesize[0];
+ }
+ }
+ return 0;
+}
+
+/* discrete wavelet transform routines */
+static void sd_1d(int *p, int i0, int i1, int ileft, int iright)
+{
+#define PSE (i0 + FFMIN((i-i0+2*(i1-i0-1))%(2*(i1-i0-1)), 2*(i1-i0-1)-(i-i0+2*(i1-i0-1))%(2*(i1-i0-1))))
+ int i;
+
+ for (i = i0 - ileft; i < i0; i++){
+ p[i] = p[PSE];
+ }
+ for (i = i1; i < i1+iright; i++){
+ p[i] = p[PSE];
+ }
+
+ 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;
+ }
+#undef PSE
+}
+
+static void dwt_encode53(J2kEncoderContext *s, J2kComponent *comp)
+{
+ int lev = s->nreslevels,
+ *t = comp->data, w = comp->x1 - comp->x0;
+ int *ppv = av_malloc((comp->reslevel[lev-1].y1 + 4)*sizeof(int)), *pv = ppv+2;
+ int *ppu = av_malloc((comp->reslevel[lev-1].x1 + 4)*sizeof(int)), *pu = ppu+2;
+
+ while (--lev){
+ int u0 = comp->reslevel[lev].x0,
+ u1 = comp->reslevel[lev].x1,
+ v0 = comp->reslevel[lev].y0,
+ v1 = comp->reslevel[lev].y1,
+ u = u0, v = v0;
+ const static int tileft[2] = {2, 1}, tiright[2] = {1, 2};
+
+ //VER_SD
+ while (u < u1){
+ int i, j;
+ for (i = v0; i < v1; i++)
+ pv[i] = t[w*(i-v0) + u-u0];
+ sd_1d(pv, v0, v1, tileft[v0&1], tiright[v1&1]);
+
+ // copy back and deinterleave
+ for (i = (v0+1)/2, j = 0; i < (v1+1)/2; i++, j++){
+ t[w*j + u-u0] = pv[2*i];
+ }
+ for (i = v0/2; i < v1/2; i++, j++){
+ t[w*j + u-u0] = pv[2*i+1];
+ }
+ u++;
+ }
+
+ //HOR_SD
+ while (v < v1){
+ int i, j;
+ for (i = u0; i < u1; i++)
+ pu[i] = t[w*(v-v0) + i-u0];
+ sd_1d(pu, u0, u1, tileft[u0&1], tiright[u1&1]);
+
+ // copy back and deinterleave
+ for (i = (u0+1)/2, j = 0; i < (u1+1)/2; i++, j++){
+ t[w*(v-v0) + j] = pu[2*i];
+ }
+ for (i = u0/2; i < u1/2; i++, j++){
+ t[w*(v-v0) + j] = pu[2*i + 1];
+ }
+ v++;
+ }
+ }
+ av_free(ppv);
+ av_free(ppu);
+}
+
+/* arithmetic entropy coder routines: */
+static void aec_initenc(J2kAec *aec, uint8_t *bp)
+{
+ bzero(aec->contexts, 19*sizeof(J2kAecContext));
+ aec->contexts[J2K_T1_CTX_UNI].state = 46;
+ aec->contexts[J2K_T1_CTX_RL].state = 3;
+ aec->contexts[0].state = 4;
+ aec->curctx = aec->contexts;
+
+ aec->a = 0x8000;
+ aec->c = 0;
+ aec->bp = bp-1;
+ aec->bpstart = bp;
+ if (*aec->bp == 0xff)
+ aec->ct = 13;
+ else
+ aec->ct = 12;
+}
+
+static void aec_byteout_l(J2kAec *aec)
+{
+ aec->bp++;
+ *aec->bp = aec->c >> 19;
+ aec->c &= 0x7ffff;
+ aec->ct = 8;
+}
+
+static void aec_byteout_r(J2kAec *aec)
+{
+ aec->bp++;
+ *aec->bp = aec->c >> 20;
+ aec->c &= 0xfffff;
+ aec->ct = 7;
+}
+
+static void aec_byteout(J2kAec *aec)
+{
+ if (*aec->bp == 0xff){
+ aec_byteout_r(aec);
+ }
+ else
+ {
+ if ((aec->c & 0x8000000) == 0){
+ aec_byteout_l(aec);
+ }
+ else{
+ (*aec->bp)++;
+ if (*aec->bp == 0xff){
+ aec->c &= 0x7ffffff;
+ aec_byteout_r(aec);
+ }
+ else{
+ aec_byteout_l(aec);
+ }
+ }
+ }
+}
+
+static void aec_renorme(J2kAec *aec)
+{
+ do{
+ aec->a = aec->a << 1;
+ aec->c = aec->c << 1;
+ aec->ct--;
+ if (!aec->ct)
+ aec_byteout(aec);
+ }
+ while ((aec->a & 0x8000) == 0);
+}
+
+static void aec_codelps(J2kAec *aec)
+{
+ int qe = aec_cx_states[aec->curctx->state].qe;
+ aec->a -= qe;
+ if (aec->a < qe)
+ aec->c += qe;
+ else
+ aec->a = qe;
+ if (aec_cx_states[aec->curctx->state].sw)
+ aec->curctx->mps = 1 - aec->curctx->mps;
+ aec->curctx->state = aec_cx_states[aec->curctx->state].nlps;
+ aec_renorme(aec);
+}
+
+static void aec_codemps(J2kAec *aec)
+{
+ int qe = aec_cx_states[aec->curctx->state].qe;
+ aec->a -= qe;
+ if ((aec->a & 0x8000) == 0){
+ if (aec->a < qe)
+ aec->a = qe;
+ else
+ aec->c += qe;
+ aec->curctx->state = aec_cx_states[aec->curctx->state].nmps;
+ aec_renorme(aec);
+ }
+ else
+ aec->c += qe;
+}
+
+/* code bit d with context cx */
+static void aec_encode(J2kAec *aec, int cx, int d)
+{
+ aec->curctx = aec->contexts + cx;
+ if (aec->curctx->mps == d){
+ aec_codemps(aec);
+ }
+ else{
+ aec_codelps(aec);
+ }
+}
+
+static void aec_setbits(J2kAec *aec)
+{
+ int tmp = aec->c + aec->a;
+ aec->c |= 0xffff;
+ if (aec->c >= tmp)
+ aec->c -= 0x8000;
+}
+
+/* flush the encoder [returns number of bytes encoded] */
+static int aec_flush(J2kAec *aec)
+{
+ aec_setbits(aec);
+ aec->c = aec->c << aec->ct;
+ aec_byteout(aec);
+ aec->c = aec->c << aec->ct;
+ aec_byteout(aec);
+ if (*aec->bp != 0xff)
+ aec->bp++;
+ return aec->bp - aec->bpstart;
+}
+
+/* tier-1 routines */
+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);
+ switch(bandno){
+ case 0: // LL || LH
+ case 2:
+ 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;
+ case 1: // HL
+ if (v == 2) return 8;
+ if (v == 1){
+ if (h >= 1) return 7;
+ if (d >= 1) return 6;
+ return 5;
+ }
+ if (h == 2) return 4;
+ if (h == 1) return 3;
+ if (d >= 2) return 2;
+ if (d >= 1) return 1;
+ return 0;
+ case 3:
+ 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);
+}
+
+static int getrefctxno(int flag)
+{
+ if (!(flag & J2K_T1_REF)){
+ if (flag & J2K_T1_SIG_NB)
+ return 15;
+ return 14;
+ }
+ return 16;
+}
+
+static int getsgnctxno(int flag, int *xorbit)
+{
+ int vcontrib, hcontrib;
+ const int contribtab[3][3] = {{0, -1, 1}, {-1, -1, 0}, {1, 0, 1}};
+ const int ctxlbltab[3][3] = {{13, 12, 11}, {10, 9, 10}, {11, 12, 13}};
+ 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];
+}
+
+static void set_significant(J2kT1Context *t1, int x, int y)
+{
+ x++; y++;
+ t1->flags[y][x] |= J2K_T1_SIG;
+ if (t1->data[y-1][x-1] < 0){
+ 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;
+}
+
+
+static void encode_sigpass(J2kT1Context *t1, int width, int height, int mask, int bandno)
+{
+ int i, j, k;
+ for (i = 0; i < height; i += 4)
+ for (j = 0; j < width; j++)
+ for (k = i; k < height && k < i+4; k++){
+ if (!(t1->flags[k+1][j+1] & J2K_T1_SIG) && (t1->flags[k+1][j+1] & J2K_T1_SIG_NB)){
+ int ctxno = getnbctxno(t1->flags[k+1][j+1], bandno),
+ bit = abs(t1->data[k][j]) & mask ? 1 : 0;
+ aec_encode(&t1->aec, ctxno, bit);
+ if (bit){
+ int xorbit;
+ int ctxno = getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+ aec_encode(&t1->aec, ctxno, (t1->data[k][j] < 0 ? 1:0) ^ xorbit);
+ set_significant(t1, j, k);
+ }
+ t1->flags[k+1][j+1] |= J2K_T1_VIS;
+ }
+ }
+}
+
+static void encode_refpass(J2kT1Context *t1, int width, int height, int mask)
+{
+ int i, j, k;
+ for (i = 0; i < height; i += 4)
+ for (j = 0; j < width; j++)
+ for (k = i; k < height && k < i+4; k++)
+ if ((t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS)) == J2K_T1_SIG){
+ int ctxno = getrefctxno(t1->flags[k+1][j+1]);
+ aec_encode(&t1->aec, ctxno, abs(t1->data[k][j]) & mask ? 1:0);
+ t1->flags[k+1][j+1] |= J2K_T1_REF;
+ }
+}
+
+static void encode_clnpass(J2kT1Context *t1, int width, int height, int mask, int bandno)
+{
+ int i, j, k;
+ for (i = 0; i < height; i += 4)
+ for (j = 0; j < width; j++){
+ if (i + 3 < height && !(
+ (t1->flags[i+1][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[i+2][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[i+3][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG)) ||
+ (t1->flags[i+4][j+1] & (J2K_T1_SIG_NB | J2K_T1_VIS | J2K_T1_SIG))))
+ {
+ // aggregation mode
+ int rlen;
+ for (rlen = 0; rlen < 4; rlen++)
+ if (abs(t1->data[i+rlen][j]) & mask)
+ break;
+ aec_encode(&t1->aec, J2K_T1_CTX_RL, rlen != 4);
+ if (rlen == 4)
+ continue;
+ aec_encode(&t1->aec, J2K_T1_CTX_UNI, rlen >> 1);
+ aec_encode(&t1->aec, J2K_T1_CTX_UNI, rlen & 1);
+ for (k = i + rlen; k < i + 4; k++){
+ if (!(t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+ int ctxno = getnbctxno(t1->flags[k+1][j+1], bandno);
+ if (k > i + rlen)
+ aec_encode(&t1->aec, ctxno, abs(t1->data[k][j]) & mask ? 1:0);
+ if (abs(t1->data[k][j]) & mask){ // newly significant
+ int xorbit;
+ int ctxno = getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+ aec_encode(&t1->aec, ctxno, (t1->data[k][j] < 0 ? 1:0) ^ xorbit);
+ set_significant(t1, j, k);
+ }
+ }
+ t1->flags[k+1][j+1] &= ~J2K_T1_VIS;
+ }
+ }
+ else{
+ for (k = i; k < i + 4 && k < height; k++){
+ if (!(t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+ int ctxno = getnbctxno(t1->flags[k+1][j+1], bandno);
+ aec_encode(&t1->aec, ctxno, abs(t1->data[k][j]) & mask ? 1:0);
+ if (abs(t1->data[k][j]) & mask){ // newly significant
+ int xorbit;
+ int ctxno = getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+ aec_encode(&t1->aec, ctxno, (t1->data[k][j] < 0 ? 1:0) ^ xorbit);
+ set_significant(t1, j, k);
+ }
+ }
+ t1->flags[k+1][j+1] &= ~J2K_T1_VIS;
+ }
+ }
+ }
+}
+
+static void encode_cblk(J2kEncoderContext *s, J2kT1Context *t1, J2kCblk *cblk, int width, int height, int bandno)
+{
+ int pass_t = 2, passno, i, j, mask, max=0, nonzerobits;
+
+ for (i = 0; i < height+2; i++)
+ bzero(t1->flags[i], (width+2)*sizeof(int));
+
+ for (i = 0; i < height; i++){
+ for (j = 0; j < width; j++)
+ max = FFMAX(max, abs(t1->data[i][j]));
+ }
+
+ if (max == 0){
+ // XXX: both should be 0, but something goes wrong, when set so
+ // - to be corrected
+ nonzerobits = 1;
+ mask = 1;
+ }
+ else{
+ nonzerobits = av_log2(max) + 1;
+ mask = 1 << (nonzerobits - 1);
+ }
+
+ aec_initenc(&t1->aec, cblk->data);
+
+ cblk->zerobits = s->expn + s->nguardbits - 1 - nonzerobits;
+
+ for (passno = 0; mask != 0; passno++){
+ switch(pass_t){
+ case 0: encode_sigpass(t1, width, height, mask, bandno);
+ break;
+ case 1: encode_refpass(t1, width, height, mask);
+ break;
+ case 2: encode_clnpass(t1, width, height, mask, bandno);
+ break;
+ }
+ if (++pass_t == 3){
+ pass_t = 0;
+ mask = mask >> 1;
+ }
+ }
+ cblk->npassess = passno;
+
+ // TODO: optional flush on each pass
+ cblk->length = aec_flush(&t1->aec);
+}
+
+/* tier-2 routines: */
+
+static void putnumpassess(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 void encode_packet(J2kEncoderContext *s, J2kResLevel *rlevel, int precno)
+{
+ int bandno;
+
+ // init bitstream
+ *s->buf = 0;
+ s->bit_index = 0;
+
+ // header
+
+ // is the packet empty?
+ put_bits(s, 1, 1); // 1 - there are not any empty packets
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ J2kTgtNode *cblkincl, *zerobits;
+ int cblknw, cblknh, yi, xi, pos;
+
+ cblknh = band->prec[precno].yi1 - band->prec[precno].yi0;
+ cblknw = band->prec[precno].xi1 - band->prec[precno].xi0;
+
+ cblkincl = tag_tree_init(cblknw, cblknh);
+ zerobits = tag_tree_init(cblknw, cblknh);
+
+ for (pos=0, yi = band->prec[precno].yi0; yi < band->prec[precno].yi1; yi++){
+ for (xi = band->prec[precno].xi0; xi < band->prec[precno].xi1; xi++, pos++){
+ cblkincl[pos].val = 0;
+ tag_tree_update(cblkincl + pos);
+ zerobits[pos].val = band->cblk[yi * cblknw + xi].zerobits;
+ tag_tree_update(zerobits + pos);
+ }
+ }
+
+ for (pos=0, yi = band->prec[precno].yi0; yi < band->prec[precno].yi1; yi++){
+ for (xi = band->prec[precno].xi0; xi < band->prec[precno].xi1; xi++, pos++){
+ int pad = 0, llen;
+ J2kCblk *cblk = band->cblk + yi * cblknw + xi;
+
+ // inclusion information
+ tag_tree_code(s, cblkincl + pos);
+ // zerobits information
+ tag_tree_code(s, zerobits + pos);
+ // number of passess
+ putnumpassess(s, cblk->npassess);
+
+ llen = av_log2(cblk->length) - av_log2(cblk->npassess) - 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, cblk->length, av_log2(cblk->length)+1+pad);
+ }
+ }
+
+ tag_tree_destroy(cblkincl);
+ tag_tree_destroy(zerobits);
+ }
+ j2k_flush(s);
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ int cblknw, 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;
+ bytestream_put_buffer(&s->buf, cblk->data, cblk->length);
+ }
+ }
+ }
+}
+
+static void encode_tile(J2kEncoderContext *s, int tileno)
+{
+ int compno, reslevelno, bandno;
+ J2kT1Context t1;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = s->tile[tileno].comp + compno;
+
+ av_log(s->avctx, AV_LOG_DEBUG,"dwt\n");
+ dwt_encode53(s, &s->tile[tileno].comp[compno]);
+ av_log(s->avctx, AV_LOG_DEBUG,"after dwt -> tier1\n");
+
+ for (reslevelno = 0; reslevelno < s->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;
+ yy0 = bandno == 0 ? 0 : comp->reslevel[reslevelno-1].y1 - comp->reslevel[reslevelno-1].y0;
+ y0 = yy0;
+ yy1 = FFMIN(ceildiv(band->y0 + 1, band->cblkh) * band->cblkh, band->y1) - band->y0 + yy0;
+
+ for (cblky = 0; cblky < band->cblkny; cblky++){
+ if (reslevelno == 0 || bandno == 1)
+ xx0 = 0;
+ else
+ xx0 = comp->reslevel[reslevelno-1].x1 - comp->reslevel[reslevelno-1].x0;
+ x0 = xx0;
+ xx1 = FFMIN(ceildiv(band->x0 + 1, band->cblkw) * band->cblkw, band->x1) - band->x0 + xx0;
+
+ for (cblkx = 0; cblkx < band->cblknx; cblkx++, cblkno++){
+ int y, x;
+ for (y = yy0; y < yy1; y++){
+ int *ptr = t1.data[y-yy0];
+ for (x = xx0; x < xx1; x++)
+ *ptr++ = comp->data[(comp->x1 - comp->x0) * y + x];
+ }
+ encode_cblk(s, &t1, band->cblk + cblkno, xx1 - xx0, yy1 - yy0, bandno + (reslevelno > 0?1:0));
+ xx0 = xx1;
+ xx1 = FFMIN(xx1 + band->cblkw, band->x1 - band->x0 + x0);
+ }
+ yy0 = yy1;
+ yy1 = FFMIN(yy1 + band->cblkh, band->y1 - band->y0 + y0);
+ }
+ }
+ }
+ av_free(comp->data);
+ av_log(s->avctx, AV_LOG_DEBUG, "after tier1\n");
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "tier2\n");
+ // lay-rlevel-comp-pos progression
+ for (reslevelno = 0; reslevelno < s->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->nprecw * reslevel->nprech; precno++){
+ encode_packet(s, reslevel, precno);
+ }
+ }
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "after tier2\n");
+}
+
+void free(J2kEncoderContext *s)
+{
+ int tileno, compno, reslevelno, bandno;
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = s->tile[tileno].comp + compno;
+
+ for (reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+ av_free(band->cblk);
+ av_free(band->prec);
+ }
+ av_free(reslevel->band);
+ }
+ av_free(comp->reslevel);
+ }
+ av_free(s->tile[tileno].comp);
+ }
+ av_free(s->tile);
+}
+
+static int encode_frame(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size,
+ void *data)
+{
+ int tileno;
+ J2kEncoderContext *s = avctx->priv_data;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "start\n");
+ s->picture = data;
+
+ // defaults:
+ // TODO: implement setting non-standard precinct size
+ s->ppx = 15; s->ppy = 15;
+
+ s->XTsiz = 256; s->YTsiz = 256;
+ s->nreslevels = 7;
+ s->xcb = s->ycb = 4;
+
+ // init:
+ s->buf = s->buf_start = buf;
+ s->buf_end = buf + buf_size;
+ s->Xsiz = avctx->width;
+ s->Ysiz = avctx->height;
+
+
+ // TODO: other pixel formats
+ if (avctx->pix_fmt == PIX_FMT_RGB24){
+ s->ncomponents = 3;
+ s->bpp = 24;
+
+ // XXX: to beverified (after adding quantization)
+ // (now it just works, but i'm not sure why ;-) )
+ s->nguardbits = 1;
+ s->expn = 8;
+ }
+ else{
+ av_log(avctx, AV_LOG_ERROR, "only rgb24 supported\n");
+ }
+
+ put_soc(s);
+ put_siz(s);
+ put_cod(s);
+ put_qcd(s);
+
+ av_log(s->avctx, AV_LOG_DEBUG, "init\n");
+ init_tiles(s);
+ av_log(s->avctx, AV_LOG_DEBUG, "after init\n");
+
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ uint8_t *psotptr;
+ psotptr = put_sot(s, tileno);
+ put_marker(s, J2K_SOD);
+ encode_tile(s, tileno);
+ bytestream_put_be32(&psotptr, s->buf - psotptr + 6);
+ }
+ put_marker(s, J2K_EOC);
+
+ free(s);
+ av_log(s->avctx, AV_LOG_DEBUG, "end\n");
+ return s->buf - s->buf_start;
+}
+
+AVCodec jpeg2000_encoder = {
+ "j2k",
+ CODEC_TYPE_VIDEO,
+ CODEC_ID_JPEG2000,
+ sizeof(J2kEncoderContext),
+ NULL,
+ encode_frame,
+ NULL,
+ NULL,
+ 0,
+ .pix_fmts =
+ (enum PixelFormat[]) {PIX_FMT_RGB24, -1}
+};
More information about the FFmpeg-soc
mailing list