[FFmpeg-soc] [soc]: r771 - jpeg2000/j2kdec.c
k.nowosad
subversion at mplayerhq.hu
Tue Aug 14 13:08:52 CEST 2007
Author: k.nowosad
Date: Tue Aug 14 13:08:52 2007
New Revision: 771
Log:
added the decoder
Added:
jpeg2000/j2kdec.c
Added: jpeg2000/j2kdec.c
==============================================================================
--- (empty file)
+++ jpeg2000/j2kdec.c Tue Aug 14 13:08:52 2007
@@ -0,0 +1,1091 @@
+/*
+ * 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 j2kdec.c
+ * @author Kamil Nowosad
+ */
+
+#include <float.h>
+#include "avcodec.h"
+#include "bytestream.h"
+#include "j2k.h"
+#include "common.h"
+
+/** code block */
+typedef struct {
+ uint8_t npassess;
+ uint8_t nonzerobits;
+ uint16_t lengthinc;
+ uint16_t length;
+ uint8_t lblock;
+ uint8_t zero;
+ uint8_t data[8192];
+ uint8_t included;
+} J2kCblk;
+
+/** precinct */
+typedef struct {
+ uint16_t xi0, xi1, yi0, yi1;
+ J2kTgtNode *zerobits;
+ J2kTgtNode *cblkincl;
+} J2kPrec;
+
+/** subband */
+typedef struct {
+ uint16_t x0, x1, y0, y1;
+ uint16_t cblkw, cblkh;
+ uint16_t cblknx, cblkny;
+ J2kPrec *prec;
+ J2kCblk *cblk;
+} J2kBand;
+
+/** resolution level */
+typedef struct {
+ uint16_t x0, x1, y0, y1;
+ uint8_t nbands;
+ uint16_t nprecw, nprech;
+ uint8_t ppx, ppy;
+ J2kBand *band;
+} J2kResLevel;
+
+typedef struct {
+ J2kResLevel *reslevel;
+ int *data;
+ uint16_t x0, x1, y0, y1;
+
+ uint8_t properties;
+
+ /// COx fields
+ int nreslevels;
+ int xcb, ycb;
+ int csty;
+ int ppx, ppy;
+
+ /// QCx fields
+ uint8_t expn[32 * 3];
+ uint8_t bbps[32 * 3];
+ uint8_t nguardbits;
+} J2kComponent;
+
+#define HAD_COC 0x01
+#define HAD_QCC 0x02
+
+typedef struct {
+ J2kComponent *comp;
+ int properties;
+ int nlayers;
+ int progression;
+} J2kTile;
+
+typedef struct {
+ AVCodecContext *avctx;
+ AVFrame picture;
+
+ int Xsiz, Ysiz; ///< image width and height
+ int X0siz, Y0siz;
+ int XT0siz, YT0siz;
+ uint8_t cbps[4]; ///< numbps in components
+ uint8_t sgnd[4]; ///< if a component is signed
+ uint8_t bbps[3 * 32][4]; ///< numbps in bands
+ uint8_t expn[3 * 32][4]; ///< quantization exponents
+ int properties[4];
+
+ int ncomponents;
+ int XTsiz, YTsiz; ///< tile size
+ int numXtiles, numYtiles;
+ int maxtilelen;
+
+ int nguardbits[4];
+
+ int nreslevels[4]; ///< number of resolution levels
+ int xcb[4], ycb[4]; ///< exponent of the code block size
+ int ppx, ppy; ///< exponent of the precinct size
+
+ uint8_t *buf_start;
+ uint8_t *buf;
+ uint8_t *buf_end;
+ int bit_index;
+
+ int16_t curtileno;
+ int nlayers;
+
+ int csty[4]; ///< coding styles for components
+
+ J2kTile *tile;
+} J2kDecoderContext;
+
+static int get_bits(J2kDecoderContext *s, int n)
+{
+ int res = 0;
+ 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;
+}
+
+void j2k_flush(J2kDecoderContext *s)
+{
+ if (s->bit_index != 8){
+ 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, 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 < comp->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
+
+/** 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 (stack[sp]->val >= threshold)
+ return threshold;
+
+ if (node)
+ curval = node->val;
+ else
+ curval = stack[sp]->val;
+
+ while(sp >= 0){
+ while (!get_bits(s, 1)){
+ curval++;
+ if (curval == threshold)
+ break;
+ }
+ stack[sp]->val = curval;
+ if (curval == threshold)
+ break;
+ stack[sp]->vis++;
+ sp--;
+ }
+ return curval;
+}
+
+static void copy_defaults(J2kDecoderContext *s, J2kTile *tile)
+{
+ int compno;
+
+ tile->nlayers = s->nlayers;
+
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ int i;
+
+ comp->nreslevels = s->nreslevels[compno];
+ comp->xcb = s->xcb[compno];
+ comp->ycb = s->ycb[compno];
+ for (i = 0; i < 3*32; i++){
+ comp->expn[i] = s->expn[i][compno];
+ comp->bbps[i] = s->bbps[i][compno];
+ }
+ comp->nguardbits = s->nguardbits[compno];
+ }
+}
+
+/** marker segments */
+static int get_siz(J2kDecoderContext *s)
+{
+ int i;
+
+ bytestream_get_be16(&s->buf); ///< Rsiz (skipped)
+ s->Xsiz = bytestream_get_be32(&s->buf); ///< Xsiz
+ s->Ysiz = bytestream_get_be32(&s->buf); ///< Ysiz
+ s->X0siz = bytestream_get_be32(&s->buf); ///< X0Siz
+ s->Y0siz = bytestream_get_be32(&s->buf); ///< Y0Siz
+
+ s->XTsiz = bytestream_get_be32(&s->buf); ///< XTSiz
+ s->YTsiz = bytestream_get_be32(&s->buf); ///< YTSiz
+ s->XT0siz = bytestream_get_be32(&s->buf); ///< XT0Siz
+ s->YT0siz = bytestream_get_be32(&s->buf); ///< YT0Siz
+ s->ncomponents = bytestream_get_be16(&s->buf); ///< CSiz
+
+ 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->sgnd[i] = (x & 0x80) == 1;
+ if (bytestream_get_byte(&s->buf) != 1)
+ return -1;
+ if (bytestream_get_byte(&s->buf) != 1)
+ return -1;
+ }
+
+ s->numXtiles = ff_j2k_ceildiv(s->Xsiz - s->XT0siz, s->XTsiz);
+ s->numYtiles = ff_j2k_ceildiv(s->Ysiz - s->YT0siz, s->YTsiz);
+
+ s->tile = av_mallocz(s->numXtiles * s->numYtiles * sizeof(J2kTile));
+ for (i = 0; i < s->numXtiles * s->numYtiles; i++){
+ J2kTile *tile = s->tile + i;
+
+ tile->comp = av_mallocz(s->ncomponents * sizeof(J2kComponent));
+ }
+
+ s->avctx->width = s->Xsiz - s->X0siz;
+ s->avctx->height = s->Ysiz - s->Y0siz;
+
+ s->avctx->get_buffer(s->avctx, &s->picture);
+
+ return 0;
+}
+
+#define SETFIELD(field, val)\
+ if (s->curtileno == -1)\
+ s->field = val;\
+ else\
+ s->tile[s->curtileno].field = val;
+
+#define GETFIELD(field)\
+ (s->curtileno == -1 ? s->field : s->tile[s->curtileno].field)
+
+#define SETFIELDC(field, val)\
+ if (s->curtileno == -1)\
+ s->field[compno] = val;\
+ else\
+ s->tile[s->curtileno].comp[compno].field = val;
+
+#define GETFIELDC(field)\
+ (s->curtileno == -1 ? s->field[compno] : s->tile[s->curtileno].comp[compno].field)
+
+static int get_cox(J2kDecoderContext *s, int compno)
+{
+ SETFIELDC(nreslevels, bytestream_get_byte(&s->buf) + 1); ///< num of resolution levels - 1
+ SETFIELDC(xcb, bytestream_get_byte(&s->buf) + 2); ///< cblk width
+ SETFIELDC(ycb, bytestream_get_byte(&s->buf) + 2); ///< cblk height
+ if (bytestream_get_byte(&s->buf) != 0){ ///< cblk style
+ av_log(s->avctx, AV_LOG_ERROR, "no extra cblk styles supported\n");
+ return -1;
+ }
+ if (bytestream_get_byte(&s->buf) != 1){ ///< transformation
+ av_log(s->avctx, AV_LOG_ERROR, "only DWT 5-3 supported\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int get_cod(J2kDecoderContext *s)
+{
+ uint8_t *pos;
+ int compno, csty;
+
+ csty = bytestream_get_byte(&s->buf);
+ for (compno = 0; compno < s->ncomponents; compno++)
+ if (!(GETFIELDC(properties) & HAD_COC)){
+ SETFIELDC(csty, csty); ///< Scod
+ }
+
+ if (bytestream_get_byte(&s->buf)){ ///< progression level
+ av_log(s->avctx, AV_LOG_ERROR, "only LRCP progression supported\n");
+ return -1;
+ }
+
+ SETFIELD(nlayers, bytestream_get_be16(&s->buf));
+ if (bytestream_get_byte(&s->buf)){ ///< multiple component transformation
+ av_log(s->avctx, AV_LOG_ERROR, "MCT not supported\n");
+ }
+ pos = s->buf;
+ for (compno = 0; compno < s->ncomponents; compno++)
+ if (!(GETFIELDC(properties) & HAD_COC)){
+ s->buf = pos;
+ get_cox(s, compno);
+ }
+ return 0;
+}
+
+static int get_coc(J2kDecoderContext *s)
+{
+ int compno = bytestream_get_byte(&s->buf);
+ SETFIELDC(csty, bytestream_get_byte(&s->buf));
+ get_cox(s, compno);
+
+ if (s->curtileno == -1)
+ s->properties[compno] |= HAD_COC;
+ else
+ s->tile[s->curtileno].comp[compno].properties |= HAD_COC;
+ return 0;
+}
+
+static int get_qcx(J2kDecoderContext *s, int n, int compno)
+{
+ int i, x;
+ x = bytestream_get_byte(&s->buf); ///< Sqcd
+ SETFIELDC(nguardbits, x >> 5);
+
+ if (x & 0x1f){
+ av_log(s->avctx, AV_LOG_ERROR, "no quantization supported\n");
+ return -1;
+ }
+ n -= 3;
+
+ for (i = 0; i < n; i++){
+ x = bytestream_get_byte(&s->buf);
+ SETFIELDC(expn[i], x >> 3);
+ SETFIELDC(bbps[i], (x >> 3) + GETFIELDC(nguardbits) - 1);
+ }
+ return 0;
+}
+
+static int get_qcd(J2kDecoderContext *s, int n)
+{
+ uint8_t *pos = s->buf;
+ int compno;
+ for (compno = 0; compno < s->ncomponents; compno++)
+ if (!(GETFIELDC(properties) & HAD_QCC)){
+ s->buf = pos;
+ if (get_qcx(s, n, compno))
+ return -1;
+ }
+ return 0;
+}
+
+static int get_qcc(J2kDecoderContext *s, int n)
+{
+ int compno = bytestream_get_byte(&s->buf);
+ if (s->curtileno == -1)
+ s->properties[compno] |= HAD_QCC;
+ else
+ s->tile[s->curtileno].comp[compno].properties |= HAD_QCC;
+ return get_qcx(s, n-1, compno);
+}
+
+static uint8_t get_sot(J2kDecoderContext *s)
+{
+ s->curtileno = bytestream_get_be16(&s->buf); ///< Isot
+
+ s->buf += 4; ///< Psot (ignored)
+
+ if (!bytestream_get_byte(&s->buf)) ///< TPsot
+ copy_defaults(s, s->tile + s->curtileno);
+ bytestream_get_byte(&s->buf); ///< TNsot
+
+ return 0;
+}
+
+#undef SETFIELDC
+#undef SETFIELD
+#undef GETFIELDC
+#undef GETFIELD
+
+static int init_tile(J2kDecoderContext *s, int tileno)
+{
+ int compno, reslevelno, bandno, p, q;
+ J2kTile *tile = s->tile + tileno;
+
+ p = tileno % s->numXtiles;
+ q = tileno / s->numXtiles;
+
+ if (tile->comp == NULL)
+ return -1;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+
+ comp->x0 = FFMAX(p * s->XTsiz + s->XT0siz, s->X0siz);
+ comp->x1 = FFMIN((p+1)*s->XTsiz + s->XT0siz, s->Xsiz);
+ comp->y0 = FFMAX(q * s->YTsiz + s->YT0siz, s->Y0siz);
+ comp->y1 = FFMIN((q+1)*s->YTsiz + s->YT0siz, 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(comp->nreslevels * sizeof(J2kResLevel));
+ if (comp->reslevel == NULL)
+ return -1;
+ for (reslevelno = 0; reslevelno < comp->nreslevels; reslevelno++){
+ int n = comp->nreslevels - reslevelno;
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ reslevel->x0 = ff_j2k_ceildivpow2(comp->x0, comp->nreslevels - reslevelno - 1);
+ reslevel->x1 = ff_j2k_ceildivpow2(comp->x1, comp->nreslevels - reslevelno - 1);
+ reslevel->y0 = ff_j2k_ceildivpow2(comp->y0, comp->nreslevels - reslevelno - 1);
+ reslevel->y1 = ff_j2k_ceildivpow2(comp->y1, comp->nreslevels - reslevelno - 1);
+
+ if (reslevelno == 0)
+ reslevel->nbands = 1;
+ else
+ reslevel->nbands = 3;
+
+ if (reslevel->x1 == reslevel->x0)
+ reslevel->nprecw = 0;
+ else
+ reslevel->nprecw = ff_j2k_ceildivpow2(reslevel->x1, s->ppx) - reslevel->x0 / (1<<s->ppx);
+
+ if (reslevel->y1 == reslevel->y0)
+ reslevel->nprech = 0;
+ else
+ reslevel->nprech = ff_j2k_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(comp->xcb, s->ppx-1);
+ band->cblkh = 1 << FFMIN(comp->ycb, s->ppy-1);
+
+ band->x0 = ff_j2k_ceildivpow2(comp->x0, n-1);
+ band->x1 = ff_j2k_ceildivpow2(comp->x1, n-1);
+ band->y0 = ff_j2k_ceildivpow2(comp->y0, n-1);
+ band->y1 = ff_j2k_ceildivpow2(comp->y1, n-1);
+ }
+ else{
+ band->cblkw = 1 << FFMIN(comp->xcb, s->ppx);
+ band->cblkh = 1 << FFMIN(comp->ycb, s->ppy);
+
+ band->x0 = ff_j2k_ceildivpow2(comp->x0 - (1 << (n-1)) * ((bandno+1)&1), n);
+ band->x1 = ff_j2k_ceildivpow2(comp->x1 - (1 << (n-1)) * ((bandno+1)&1), n);
+ band->y0 = ff_j2k_ceildivpow2(comp->y0 - (1 << (n-1)) * (((bandno+1)&2)>>1), n);
+ band->y1 = ff_j2k_ceildivpow2(comp->y1 - (1 << (n-1)) * (((bandno+1)&2)>>1), n);
+ }
+ band->cblknx = ff_j2k_ceildiv(band->x1, band->cblkw) - band->x0 / band->cblkw;
+ band->cblkny = ff_j2k_ceildiv(band->y1, band->cblkh) - 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++){
+ J2kCblk *cblk = band->cblk + cblkno;
+ cblk->zero = 0;
+ cblk->lblock = 3;
+ cblk->length = 0;
+ cblk->lengthinc = 0;
+ cblk->npassess = 0;
+ cblk->included = 0;
+ }
+
+ y0 = band->y0;
+ y1 = (band->y0 + (1<<s->ppy))/(1<<s->ppy)*(1<<s->ppy) - band->y0;
+ yi0 = 0;
+ yi1 = ff_j2k_ceildiv(y1 - y0, 1<<comp->ycb) * (1<<comp->ycb);
+ yi1 = FFMIN(yi1, band->cblkny);
+ cblkperprech = 1<<(s->ppy - comp->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 = ff_j2k_ceildiv(x1 - x0, 1<<comp->xcb) * (1<<comp->xcb);
+ xi1 = FFMIN(xi1, band->cblknx);
+
+ cblkperprecw = 1<<(s->ppx - comp->xcb);
+ for (precx = 0, precno = 0; precx < reslevel->nprecw; precx++){
+ for (precy = 0; precy < reslevel->nprech; 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);
+
+ }
+ xi1 += cblkperprecw;
+ xi0 = xi1 - cblkperprecw;
+ xi1 = FFMIN(xi1, band->cblknx);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int getnpassess(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 3 + num;
+ if ((num = get_bits(s, 5)) != 31)
+ return 6 + num;
+ return 37 + get_bits(s, 7);
+}
+
+static int getlblockinc(J2kDecoderContext *s)
+{
+ int res = 0;
+ while (get_bits(s, 1))
+ res++;
+ return res;
+}
+
+static int decode_packet(J2kDecoderContext *s, J2kResLevel *rlevel, int precno, int layno, uint8_t *bandbps)
+{
+ int bandno, cblkny, cblknx, cblkno;
+
+ if (!get_bits(s, 1)){
+ j2k_flush(s);
+ return 0;
+ }
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ J2kBand *band = rlevel->band + bandno;
+ J2kPrec *prec = band->prec + precno;
+ int pos = 0;
+
+ 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, newpassess, llen;
+
+ if (cblk->included)
+ incl = get_bits(s, 1);
+ else{
+ incl = tag_tree_decode(s, prec->cblkincl + pos, layno+1) == layno;
+ }
+ if (!incl){
+ continue;
+ }
+ if (!cblk->included){
+ cblk->included++;
+ cblk->nonzerobits = bandbps[bandno] - tag_tree_decode(s, prec->zerobits + pos, 100);
+ }
+ newpassess = getnpassess(s);
+ llen = getlblockinc(s);
+ cblk->lblock += llen;
+ cblk->lengthinc = get_bits(s, av_log2(newpassess) + cblk->lblock);
+ cblk->npassess += newpassess;
+ }
+ }
+ 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_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 = 1;
+ s->bit_index = 8;
+ for (layno = 0; layno < tile->nlayers; layno++){
+ for (reslevelno = 0; ok_reslevel; reslevelno++){
+ ok_reslevel = 0;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ J2kComponent *comp = tile->comp + compno;
+ if (reslevelno < comp->nreslevels){
+ J2kResLevel *rlevel = tile->comp[compno].reslevel + reslevelno;
+ ok_reslevel = 1;
+ for (precno = 0; precno < rlevel->nprecw * rlevel->nprech; precno++){
+ decode_packet(s, rlevel, precno, layno, comp->bbps + (reslevelno ? 3*(reslevelno-1)+1 : 0));
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/** TIER-1 routines */
+static void decode_sigpass(J2kT1Context *t1, int width, int height, int bpno, int bandno)
+{
+ int mask = 3 << (bpno - 1), 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_NB)
+ && !(t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS))){
+ if (ff_aec_decode(&t1->aec, ff_j2k_getnbctxno(t1->flags[k+1][j+1], bandno))){
+ int xorbit, ctxno = ff_j2k_getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+
+ t1->data[k][j] = (ff_aec_decode(&t1->aec, ctxno) ^ xorbit) ? -mask : mask;
+
+ ff_j2k_set_significant(t1, j, k);
+ }
+ t1->flags[k+1][j+1] |= J2K_T1_VIS;
+ }
+ }
+}
+
+static void decode_refpass(J2kT1Context *t1, int width, int height, int bpno)
+{
+ int phalf, nhalf;
+ int i, j, k;
+
+ phalf = 1 << (bpno - 1);
+ nhalf = -phalf;
+
+ 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 = ff_j2k_getrefctxno(t1->flags[k+1][j+1]);
+ int r = ff_aec_decode(&t1->aec, ctxno) ? phalf : nhalf;
+ t1->data[k][j] += t1->data[k][j] < 0 ? -r : r;
+ t1->flags[k+1][j+1] |= J2K_T1_REF;
+ }
+ }
+}
+
+static void decode_clnpass(J2kT1Context *t1, int width, int height, int bpno, int bandno)
+{
+ int mask = 3 << (bpno - 1), i, j, k, runlen, dec;
+
+ 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)))){
+ if (!ff_aec_decode(&t1->aec, AEC_CX_RL))
+ continue;
+ runlen = ff_aec_decode(&t1->aec, AEC_CX_UNI);
+ runlen = (runlen << 1) | ff_aec_decode(&t1->aec, AEC_CX_UNI);
+ dec = 1;
+ }
+ else{
+ runlen = 0;
+ dec = 0;
+ }
+
+ for (k = i + runlen; k < i + 4 && k < height; k++){
+ if (!dec){
+ if (!(t1->flags[k+1][j+1] & (J2K_T1_SIG | J2K_T1_VIS)))
+ dec = ff_aec_decode(&t1->aec, ff_j2k_getnbctxno(t1->flags[k+1][j+1], bandno));
+ }
+ if (dec){
+ int xorbit, ctxno = ff_j2k_getsgnctxno(t1->flags[k+1][j+1], &xorbit);
+ t1->data[k][j] = (ff_aec_decode(&t1->aec, ctxno) ^ xorbit) ? -mask : mask;
+ ff_j2k_set_significant(t1, j, k);
+ }
+ dec = 0;
+ t1->flags[k+1][j+1] &= ~J2K_T1_VIS;
+ }
+ }
+}
+
+static int decode_cblk(J2kDecoderContext *s, J2kT1Context *t1, J2kCblk *cblk, int width, int height, int bandpos)
+{
+ int passno = cblk->npassess, pass_t = 2, bpno = cblk->nonzerobits - 1, i;
+
+ for (i = 0; i < height+2; i++)
+ bzero(t1->flags[i], (width+2)*sizeof(int));
+
+ for (i = 0; i < height; i++)
+ bzero(t1->data[i], width*sizeof(int));
+
+ ff_aec_initdec(&t1->aec, 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(t1, width, height, bpno+1, bandpos);
+ break;
+ }
+
+ pass_t++;
+ if (pass_t == 3){
+ bpno--;
+ pass_t = 0;
+ }
+ }
+ return 0;
+}
+
+/** inverse discrete wavelet transform routines */
+static void sr_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;
+
+ if (i1 == i0 + 1)
+ return;
+
+ 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/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;
+#undef PSE
+}
+
+static int dwt_decode53(J2kDecoderContext *s, J2kComponent *comp, int nreslevels)
+{
+ int lev = nreslevels, i,
+ *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;
+
+ for (i = 1; i < lev; i++){
+ int u0 = comp->reslevel[i].x0,
+ u1 = comp->reslevel[i].x1,
+ v0 = comp->reslevel[i].y0,
+ v1 = comp->reslevel[i].y1,
+ u = u0, v = v0;
+ const static int tileft[2] = {1, 2}, tiright[2] = {2, 1};
+ u = u0;
+ v = v0;
+
+ /// HOR_SD
+ while (v < v1){
+ int i, j;
+ /// copy with interleaving
+ for (i = u0 + (u0 & 1), j = 0; i < u1; i+=2, j++){
+ pu[i] = t[w*(v-v0) + j];
+ }
+ for (i = u0 + 1 - (u0 % 2); i < u1; i+=2, j++){
+ pu[i] = t[w*(v-v0) + j];
+ }
+
+ sr_1d(pu, u0, u1, tileft[u0&1], tiright[u1&1]);
+
+ for (i = u0; i < u1; i++)
+ t[w*(v-v0) + i-u0] = pu[i];
+
+ v++;
+ }
+ /// VER_SD
+ while (u < u1){
+ int i, j;
+ /// copy with interleaving
+ for (i = v0 + (v0 & 1), j = 0; i < v1; i+=2, j++){
+ pv[i] = t[w*j + u-u0];
+ }
+ for (i = v0 + 1 - (v0 % 2); i < v1; i+=2, j++){
+ pv[i] = t[w*j + u-u0];
+ }
+
+ sr_1d(pv, v0, v1, tileft[v0&1], tiright[v1&1]);
+
+ for (i = v0; i < v1; i++)
+ t[w*(i-v0) + u-u0] = pv[i];
+
+ u++;
+ }
+ }
+ av_free(ppv);
+ av_free(ppu);
+ return 0;
+}
+
+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;
+
+ for (reslevelno = 0; reslevelno < comp->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].y1 - comp->reslevel[reslevelno-1].y0;
+ y0 = yy0;
+ yy1 = FFMIN(ff_j2k_ceildiv(band->y0 + 1, band->cblkh) * band->cblkh, band->y1) - band->y0 + yy0;
+
+ if (band->x0 == band->x1 || band->y0 == band->y1)
+ continue;
+
+ 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(ff_j2k_ceildiv(band->x0 + 1, band->cblkw) * band->cblkw, band->x1) - band->x0 + xx0;
+
+ for (cblkx = 0; cblkx < band->cblknx; cblkx++, cblkno++){
+ int y, x;
+ decode_cblk(s, &t1, band->cblk + cblkno, xx1 - xx0, yy1 - yy0, bandpos);
+ for (y = yy0; y < yy1; y++){
+ int *ptr = t1.data[y-yy0];
+ for (x = xx0; x < xx1; x++){
+ comp->data[(comp->x1 - comp->x0) * y + x] = *ptr++ >> 1;
+ }
+ }
+ xx0 = xx1;
+ xx1 = FFMIN(xx1 + band->cblkw, band->x1 - band->x0 + x0);
+ }
+ yy0 = yy1;
+ yy1 = FFMIN(yy1 + band->cblkh, band->y1 - band->y0 + y0);
+ }
+ }
+ }
+ dwt_decode53(s, comp, comp->nreslevels);
+ src[compno] = comp->data;
+ }
+
+ y = tile->comp[0].y0 - s->Y0siz;
+
+ line = s->picture.data[0] + y * s->picture.linesize[0];
+
+ for (; y < tile->comp[0].y1 - s->Y0siz; y++){
+ uint8_t *dst;
+
+ x = tile->comp[0].x0 - s->X0siz;
+ dst = line + x * s->ncomponents;
+
+ for (; x < tile->comp[0].x1 - s->X0siz; x++)
+ for (compno = 0; compno < s->ncomponents; 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]++;
+ }
+
+ line += s->picture.linesize[0];
+ }
+ return 0;
+}
+
+static void cleanup(J2kDecoderContext *s)
+{
+ int tileno, compno, reslevelno, bandno, precno;
+ 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 < comp->nreslevels; reslevelno++){
+ J2kResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ J2kBand *band = reslevel->band + bandno;
+
+ for (precno = 0; precno < reslevel->nprecw * reslevel->nprech; precno++){
+ J2kPrec *prec = band->prec + precno;
+ ff_j2k_tag_tree_destroy(prec->zerobits);
+ ff_j2k_tag_tree_destroy(prec->cblkincl);
+ }
+ 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 decode_frame(AVCodecContext *avctx,
+ void *data, int *data_size,
+ uint8_t *buf, int buf_size)
+{
+ J2kDecoderContext *s = avctx->priv_data;
+ AVFrame *picture = data;
+ int tileno;
+
+ s->avctx = avctx;
+ av_log(s->avctx, AV_LOG_DEBUG, "start\n");
+
+ /// init
+ s->buf = s->buf_start = buf;
+ s->buf_end = buf + buf_size;
+ s->curtileno = -1;
+
+ avcodec_get_frame_defaults((AVFrame*)&s->picture);
+ avctx->coded_frame = (AVFrame*)&s->picture;
+
+ s->ppx = s->ppy = 15;
+
+ if (bytestream_get_be16(&s->buf) != J2K_SOC){
+ av_log(avctx, AV_LOG_ERROR, "SOC marker not present\n");
+ return -1;
+ }
+
+ for (;;){
+ int marker = bytestream_get_be16(&s->buf), len;
+ uint8_t *oldbuf = s->buf;
+
+ if (marker == J2K_SOD){
+ J2kTile *tile = s->tile + s->curtileno;
+ init_tile(s, s->curtileno);
+ decode_packets(s, tile);
+ continue;
+ }
+ if (marker == J2K_EOC)
+ break;
+
+ len = bytestream_get_be16(&s->buf);
+ switch(marker){
+ case J2K_SIZ:
+ get_siz(s); break;
+ case J2K_COC:
+ get_coc(s); break;
+ case J2K_COD:
+ get_cod(s); break;
+ case J2K_QCC:
+ get_qcc(s, len); break;
+ case J2K_QCD:
+ get_qcd(s, len); break;
+ case J2K_SOT:
+ get_sot(s); break;
+ case J2K_COM:
+ /// the comment is ignored
+ s->buf += len - 2; break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "unsupported marker 0x%.4X at pos 0x%x\n", marker, s->buf - s->buf_start - 4);
+ return -1;
+ }
+ if (s->buf - oldbuf != len){
+ av_log(avctx, AV_LOG_ERROR, "error during processing marker segment %.4x\n", marker);
+ return -1;
+ }
+ }
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++)
+ decode_tile(s, s->tile + tileno);
+
+ cleanup(s);
+ av_log(s->avctx, AV_LOG_DEBUG, "end\n");
+
+ *data_size = sizeof(AVPicture);
+ *picture = s->picture;
+
+ return s->buf - s->buf_start;
+}
+
+AVCodec jpeg2000_decoder = {
+ "j2k",
+ CODEC_TYPE_VIDEO,
+ CODEC_ID_JPEG2000,
+ sizeof(J2kDecoderContext),
+ NULL,
+ NULL,
+ NULL,
+ decode_frame,
+ 0,
+ .pix_fmts =
+ (enum PixelFormat[]) {PIX_FMT_GRAY8, PIX_FMT_RGB24, -1}
+};
More information about the FFmpeg-soc
mailing list