typedef struct Jpeg2000TilePart {
uint8_t tile_index; // Tile index who refers the tile-part
const uint8_t *tp_end;
+ GetByteContext header_tpg; // bit stream of header if PPM header is used
GetByteContext tpg; // bit stream in tile-part
} Jpeg2000TilePart;
Jpeg2000QuantStyle qntsty[4];
Jpeg2000POC poc;
Jpeg2000TilePart tile_part[32];
+ uint8_t has_ppt; // whether this tile has a ppt marker
+ uint8_t *packed_headers; // contains packed headers. Used only along with PPT marker
+ int packed_headers_size; // size in bytes of the packed headers
+ GetByteContext packed_headers_stream; // byte context corresponding to packed headers
uint16_t tp_idx; // Tile-part index
int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}}
} Jpeg2000Tile;
uint8_t cbps[4]; // bits per sample in particular components
uint8_t sgnd[4]; // if a component is signed
uint8_t properties[4];
+
+ uint8_t has_ppm;
+ uint8_t *packed_headers; // contains packed headers. Used only along with PPM marker
+ int packed_headers_size;
+ GetByteContext packed_headers_stream;
+ uint8_t in_tile_headers;
+
int cdx[4], cdy[4];
int precision;
int ncomponents;
Jpeg2000CodingStyle codsty[4];
Jpeg2000QuantStyle qntsty[4];
Jpeg2000POC poc;
+ uint8_t roi_shift[4];
int bit_index;
const enum AVPixelFormat *possible_fmts = NULL;
int possible_fmts_nb = 0;
int ret;
+ int o_dimx, o_dimy; //original image dimensions.
+ int dimx, dimy;
if (bytestream2_get_bytes_left(&s->g) < 36) {
av_log(s->avctx, AV_LOG_ERROR, "Insufficient space for SIZ\n");
s->tile_offset_y = bytestream2_get_be32u(&s->g); // YT0Siz
ncomponents = bytestream2_get_be16u(&s->g); // CSiz
- if (s->image_offset_x || s->image_offset_y) {
- avpriv_request_sample(s->avctx, "Support for image offsets");
- return AVERROR_PATCHWELCOME;
- }
if (av_image_check_size2(s->width, s->height, s->avctx->max_pixels, AV_PIX_FMT_NONE, 0, s->avctx)) {
avpriv_request_sample(s->avctx, "Large Dimensions");
return AVERROR_PATCHWELCOME;
}
/* compute image size with reduction factor */
- ret = ff_set_dimensions(s->avctx,
- ff_jpeg2000_ceildivpow2(s->width - s->image_offset_x,
- s->reduction_factor),
- ff_jpeg2000_ceildivpow2(s->height - s->image_offset_y,
- s->reduction_factor));
+ o_dimx = ff_jpeg2000_ceildivpow2(s->width - s->image_offset_x,
+ s->reduction_factor);
+ o_dimy = ff_jpeg2000_ceildivpow2(s->height - s->image_offset_y,
+ s->reduction_factor);
+ dimx = ff_jpeg2000_ceildiv(o_dimx, s->cdx[0]);
+ dimy = ff_jpeg2000_ceildiv(o_dimy, s->cdy[0]);
+ for (i = 1; i < s->ncomponents; i++) {
+ dimx = FFMAX(dimx, ff_jpeg2000_ceildiv(o_dimx, s->cdx[i]));
+ dimy = FFMAX(dimy, ff_jpeg2000_ceildiv(o_dimy, s->cdy[i]));
+ }
+
+ ret = ff_set_dimensions(s->avctx, dimx, dimy);
if (ret < 0)
return ret;
break;
}
}
- for (i = 0; i < possible_fmts_nb; ++i) {
- if (pix_fmt_match(possible_fmts[i], ncomponents, s->precision, log2_chroma_wh, s->pal8)) {
- s->avctx->pix_fmt = possible_fmts[i];
- break;
+ if ( s->avctx->pix_fmt != AV_PIX_FMT_NONE
+ && !pix_fmt_match(s->avctx->pix_fmt, ncomponents, s->precision, log2_chroma_wh, s->pal8))
+ s->avctx->pix_fmt = AV_PIX_FMT_NONE;
+ if (s->avctx->pix_fmt == AV_PIX_FMT_NONE)
+ for (i = 0; i < possible_fmts_nb; ++i) {
+ if (pix_fmt_match(possible_fmts[i], ncomponents, s->precision, log2_chroma_wh, s->pal8)) {
+ s->avctx->pix_fmt = possible_fmts[i];
+ break;
+ }
}
- }
if (i == possible_fmts_nb) {
if (ncomponents == 4 &&
s->cdef[3] = 3;
i = 0;
}
+ } else if (ncomponents == 3 && s->precision == 8 &&
+ s->cdx[0] == s->cdx[1] && s->cdx[0] == s->cdx[2] &&
+ s->cdy[0] == s->cdy[1] && s->cdy[0] == s->cdy[2]) {
+ s->avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ i = 0;
+ } else if (ncomponents == 2 && s->precision == 8 &&
+ s->cdx[0] == s->cdx[1] && s->cdy[0] == s->cdy[1]) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YA8;
+ i = 0;
+ } else if (ncomponents == 1 && s->precision == 8) {
+ s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ i = 0;
}
}
if ((ret = get_cox(s, &tmp)) < 0)
return ret;
-
+ tmp.init = 1;
for (compno = 0; compno < s->ncomponents; compno++)
if (!(properties[compno] & HAD_COC))
memcpy(c + compno, &tmp, sizeof(tmp));
uint8_t *properties)
{
int compno, ret;
+ uint8_t has_eph, has_sop;
if (bytestream2_get_bytes_left(&s->g) < 2) {
av_log(s->avctx, AV_LOG_ERROR, "Insufficient space for COC\n");
}
c += compno;
+ has_eph = c->csty & JPEG2000_CSTY_EPH;
+ has_sop = c->csty & JPEG2000_CSTY_SOP;
c->csty = bytestream2_get_byteu(&s->g);
+ c->csty |= has_eph; //do not override eph present bits from COD
+ c->csty |= has_sop; //do not override sop present bits from COD
if ((ret = get_cox(s, c)) < 0)
return ret;
properties[compno] |= HAD_COC;
+ c->init = 1;
return 0;
}
+static int get_rgn(Jpeg2000DecoderContext *s, int n)
+{
+ uint16_t compno;
+ compno = (s->ncomponents < 257)? bytestream2_get_byte(&s->g):
+ bytestream2_get_be16u(&s->g);
+ if (bytestream2_get_byte(&s->g)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid RGN header.\n");
+ return AVERROR_INVALIDDATA; // SRgn field value is 0
+ }
+ // SPrgn field
+ // Currently compno cannot be greater than 4.
+ // However, future implementation should support compno up to 65536
+ if (compno < s->ncomponents) {
+ int v;
+ if (s->curtileno == -1) {
+ v = bytestream2_get_byte(&s->g);
+ if (v > 30)
+ return AVERROR_PATCHWELCOME;
+ s->roi_shift[compno] = v;
+ } else {
+ if (s->tile[s->curtileno].tp_idx != 0)
+ return AVERROR_INVALIDDATA; // marker occurs only in first tile part of tile
+ v = bytestream2_get_byte(&s->g);
+ if (v > 30)
+ return AVERROR_PATCHWELCOME;
+ s->tile[s->curtileno].comp[compno].roi_shift = v;
+ }
+ return 0;
+ }
+ return AVERROR_INVALIDDATA;
+}
+
/* Get common part for QCD and QCC segments. */
static int get_qcx(Jpeg2000DecoderContext *s, int n, Jpeg2000QuantStyle *q)
{
return 0;
}
+static int read_crg(Jpeg2000DecoderContext *s, int n)
+{
+ if (s->ncomponents*4 != n - 2) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid CRG marker.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ bytestream2_skip(&s->g, n - 2);
+ return 0;
+}
/* Tile-part lengths: see ISO 15444-1:2002, section A.7.1
* Used to know the number of tile parts and lengths.
* There may be multiple TLMs in the header.
* markers. Parsing the TLM header is needed to increment the input header
* buffer.
* This marker is mandatory for DCI. */
-static uint8_t get_tlm(Jpeg2000DecoderContext *s, int n)
+static int get_tlm(Jpeg2000DecoderContext *s, int n)
{
uint8_t Stlm, ST, SP, tile_tlm, i;
bytestream2_get_byte(&s->g); /* Ztlm: skipped */
// too complex ? ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02);
ST = (Stlm >> 4) & 0x03;
- // TODO: Manage case of ST = 0b11 --> raise error
+ if (ST == 0x03) {
+ av_log(s->avctx, AV_LOG_ERROR, "TLM marker contains invalid ST value.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
SP = (Stlm >> 6) & 0x01;
tile_tlm = (n - 4) / ((SP + 1) * 2 + ST);
for (i = 0; i < tile_tlm; i++) {
return 0;
}
-static uint8_t get_plt(Jpeg2000DecoderContext *s, int n)
+static int get_plt(Jpeg2000DecoderContext *s, int n)
{
int i;
+ int v;
av_log(s->avctx, AV_LOG_DEBUG,
"PLT marker at pos 0x%X\n", bytestream2_tell(&s->g) - 4);
+ if (n < 4)
+ return AVERROR_INVALIDDATA;
+
/*Zplt =*/ bytestream2_get_byte(&s->g);
for (i = 0; i < n - 3; i++) {
- bytestream2_get_byte(&s->g);
+ v = bytestream2_get_byte(&s->g);
}
+ if (v & 0x80)
+ return AVERROR_INVALIDDATA;
+
+ return 0;
+}
+
+static int get_ppm(Jpeg2000DecoderContext *s, int n)
+{
+ void *new;
+
+ if (n < 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid length for PPM data.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ bytestream2_get_byte(&s->g); //Zppm is skipped and not used
+ new = av_realloc(s->packed_headers,
+ s->packed_headers_size + n - 3);
+ if (new) {
+ s->packed_headers = new;
+ } else
+ return AVERROR(ENOMEM);
+ s->has_ppm = 1;
+ memset(&s->packed_headers_stream, 0, sizeof(s->packed_headers_stream));
+ bytestream_get_buffer(&s->g.buffer, s->packed_headers + s->packed_headers_size,
+ n - 3);
+ s->packed_headers_size += n - 3;
+
+ return 0;
+}
+
+static int get_ppt(Jpeg2000DecoderContext *s, int n)
+{
+ Jpeg2000Tile *tile;
+ void *new;
+
+ if (n < 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid length for PPT data.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (s->curtileno < 0)
+ return AVERROR_INVALIDDATA;
+
+ tile = &s->tile[s->curtileno];
+ if (tile->tp_idx != 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "PPT marker can occur only on first tile part of a tile.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ tile->has_ppt = 1; // this tile has a ppt marker
+ bytestream2_get_byte(&s->g); // Zppt is skipped and not used
+ new = av_realloc(tile->packed_headers,
+ tile->packed_headers_size + n - 3);
+ if (new) {
+ tile->packed_headers = new;
+ } else
+ return AVERROR(ENOMEM);
+ memset(&tile->packed_headers_stream, 0, sizeof(tile->packed_headers_stream));
+ memcpy(tile->packed_headers + tile->packed_headers_size,
+ s->g.buffer, n - 3);
+ tile->packed_headers_size += n - 3;
+ bytestream2_skip(&s->g, n - 3);
return 0;
}
comp->coord_o[0][1] = tile->coord[0][1];
comp->coord_o[1][0] = tile->coord[1][0];
comp->coord_o[1][1] = tile->coord[1][1];
- if (compno) {
- comp->coord_o[0][0] /= s->cdx[compno];
- comp->coord_o[0][1] /= s->cdx[compno];
- comp->coord_o[1][0] /= s->cdy[compno];
- comp->coord_o[1][1] /= s->cdy[compno];
- }
+
+ comp->coord_o[0][0] = ff_jpeg2000_ceildiv(comp->coord_o[0][0], s->cdx[compno]);
+ comp->coord_o[0][1] = ff_jpeg2000_ceildiv(comp->coord_o[0][1], s->cdx[compno]);
+ comp->coord_o[1][0] = ff_jpeg2000_ceildiv(comp->coord_o[1][0], s->cdy[compno]);
+ comp->coord_o[1][1] = ff_jpeg2000_ceildiv(comp->coord_o[1][1], s->cdy[compno]);
comp->coord[0][0] = ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], s->reduction_factor);
comp->coord[0][1] = ff_jpeg2000_ceildivpow2(comp->coord_o[0][1], s->reduction_factor);
comp->coord[1][0] = ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], s->reduction_factor);
comp->coord[1][1] = ff_jpeg2000_ceildivpow2(comp->coord_o[1][1], s->reduction_factor);
+ if (!comp->roi_shift)
+ comp->roi_shift = s->roi_shift[compno];
+ if (!codsty->init)
+ return AVERROR_INVALIDDATA;
if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty,
s->cbps[compno], s->cdx[compno],
s->cdy[compno], s->avctx))
return res;
}
+static inline void select_header(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
+ int *tp_index)
+{
+ s->g = tile->tile_part[*tp_index].header_tpg;
+ if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) {
+ if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) {
+ s->g = tile->tile_part[++(*tp_index)].tpg;
+ }
+ }
+}
+
+static inline void select_stream(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
+ int *tp_index, Jpeg2000CodingStyle *codsty)
+{
+ s->g = tile->tile_part[*tp_index].tpg;
+ if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) {
+ if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) {
+ s->g = tile->tile_part[++(*tp_index)].tpg;
+ }
+ }
+ if (codsty->csty & JPEG2000_CSTY_SOP) {
+ if (bytestream2_peek_be32(&s->g) == JPEG2000_SOP_FIXED_BYTES)
+ bytestream2_skip(&s->g, JPEG2000_SOP_BYTE_LENGTH);
+ else
+ av_log(s->avctx, AV_LOG_ERROR, "SOP marker not found. instead %X\n", bytestream2_peek_be32(&s->g));
+ }
+}
+
static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, int *tp_index,
Jpeg2000CodingStyle *codsty,
Jpeg2000ResLevel *rlevel, int precno,
if (layno < rlevel->band[0].prec[precno].decoded_layers)
return 0;
rlevel->band[0].prec[precno].decoded_layers = layno + 1;
-
- if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) {
- if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) {
- s->g = tile->tile_part[++(*tp_index)].tpg;
- }
- }
-
- if (bytestream2_peek_be32(&s->g) == JPEG2000_SOP_FIXED_BYTES)
- bytestream2_skip(&s->g, JPEG2000_SOP_BYTE_LENGTH);
+ // Select stream to read from
+ if (s->has_ppm)
+ select_header(s, tile, tp_index);
+ else if (tile->has_ppt)
+ s->g = tile->packed_headers_stream;
+ else
+ select_stream(s, tile, tp_index, codsty);
if (!(ret = get_bits(s, 1))) {
jpeg2000_flush(s);
- return 0;
+ goto skip_data;
} else if (ret < 0)
return ret;
av_log(s->avctx, AV_LOG_ERROR, "EPH marker not found. instead %X\n", bytestream2_peek_be32(&s->g));
}
+ // Save state of stream
+ if (s->has_ppm) {
+ tile->tile_part[*tp_index].header_tpg = s->g;
+ select_stream(s, tile, tp_index, codsty);
+ } else if (tile->has_ppt) {
+ tile->packed_headers_stream = s->g;
+ select_stream(s, tile, tp_index, codsty);
+ }
for (bandno = 0; bandno < rlevel->nbands; bandno++) {
Jpeg2000Band *band = rlevel->band + bandno;
Jpeg2000Prec *prec = band->prec + precno;
av_freep(&cblk->lengthinc);
}
}
+ // Save state of stream
+ tile->tile_part[*tp_index].tpg = s->g;
+ return 0;
+
+skip_data:
+ if (codsty->csty & JPEG2000_CSTY_EPH) {
+ if (bytestream2_peek_be16(&s->g) == JPEG2000_EPH)
+ bytestream2_skip(&s->g, 2);
+ else
+ av_log(s->avctx, AV_LOG_ERROR, "EPH marker not found. instead %X\n", bytestream2_peek_be32(&s->g));
+ }
+ if (s->has_ppm) {
+ tile->tile_part[*tp_index].header_tpg = s->g;
+ select_stream(s, tile, tp_index, codsty);
+ } else if (tile->has_ppt) {
+ tile->packed_headers_stream = s->g;
+ select_stream(s, tile, tp_index, codsty);
+ }
+ tile->tile_part[*tp_index].tpg = s->g;
return 0;
}
uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r
Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno;
unsigned prcx, prcy;
+ int trx0, try0;
- int xc = x / s->cdx[compno];
- int yc = y / s->cdy[compno];
+ if (!s->cdx[compno] || !s->cdy[compno])
+ return AVERROR_INVALIDDATA;
if (reslevelno >= codsty->nreslevels)
continue;
- if (yc % (1LL << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
+ trx0 = ff_jpeg2000_ceildiv(tile->coord[0][0], (int64_t)s->cdx[compno] << reducedresno);
+ try0 = ff_jpeg2000_ceildiv(tile->coord[1][0], (int64_t)s->cdy[compno] << reducedresno);
+
+ if (!(y % ((uint64_t)s->cdy[compno] << (rlevel->log2_prec_height + reducedresno)) == 0 ||
+ (y == tile->coord[1][0] && ((int64_t)try0 << reducedresno) % (1ULL << (reducedresno + rlevel->log2_prec_height)))))
continue;
- if (xc % (1LL << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
+ if (!(x % ((uint64_t)s->cdx[compno] << (rlevel->log2_prec_width + reducedresno)) == 0 ||
+ (x == tile->coord[0][0] && ((int64_t)trx0 << reducedresno) % (1ULL << (reducedresno + rlevel->log2_prec_width)))))
continue;
// check if a precinct exists
- prcx = ff_jpeg2000_ceildivpow2(xc, reducedresno) >> rlevel->log2_prec_width;
- prcy = ff_jpeg2000_ceildivpow2(yc, reducedresno) >> rlevel->log2_prec_height;
+ prcx = ff_jpeg2000_ceildiv(x, (int64_t)s->cdx[compno] << reducedresno) >> rlevel->log2_prec_width;
+ prcy = ff_jpeg2000_ceildiv(y, (int64_t)s->cdy[compno] << reducedresno) >> rlevel->log2_prec_height;
prcx -= ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], reducedresno) >> rlevel->log2_prec_width;
prcy -= ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], reducedresno) >> rlevel->log2_prec_height;
continue;
}
- for (layno = 0; layno < LYEpoc; layno++) {
- if ((ret = jpeg2000_decode_packet(s, tile, tp_index,
- codsty, rlevel,
- precno, layno,
- qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
- qntsty->nguardbits)) < 0)
- return ret;
- }
+ for (layno = 0; layno < LYEpoc; layno++) {
+ if ((ret = jpeg2000_decode_packet(s, tile, tp_index,
+ codsty, rlevel,
+ precno, layno,
+ qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+ qntsty->nguardbits)) < 0)
+ return ret;
+ }
}
}
}
Jpeg2000Component *comp = tile->comp + compno;
Jpeg2000CodingStyle *codsty = tile->codsty + compno;
Jpeg2000QuantStyle *qntsty = tile->qntsty + compno;
- int xc = x / s->cdx[compno];
- int yc = y / s->cdy[compno];
+
+ if (!s->cdx[compno] || !s->cdy[compno])
+ return AVERROR_INVALIDDATA;
for (reslevelno = RSpoc; reslevelno < FFMIN(codsty->nreslevels, REpoc); reslevelno++) {
unsigned prcx, prcy;
uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r
Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno;
+ int trx0, try0;
- if (yc % (1LL << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
- continue;
+ trx0 = ff_jpeg2000_ceildiv(tile->coord[0][0], (int64_t)s->cdx[compno] << reducedresno);
+ try0 = ff_jpeg2000_ceildiv(tile->coord[1][0], (int64_t)s->cdy[compno] << reducedresno);
- if (xc % (1LL << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
- continue;
+ if (!(y % ((uint64_t)s->cdy[compno] << (rlevel->log2_prec_height + reducedresno)) == 0 ||
+ (y == tile->coord[1][0] && ((int64_t)try0 << reducedresno) % (1ULL << (reducedresno + rlevel->log2_prec_height)))))
+ continue;
+
+ if (!(x % ((uint64_t)s->cdx[compno] << (rlevel->log2_prec_width + reducedresno)) == 0 ||
+ (x == tile->coord[0][0] && ((int64_t)trx0 << reducedresno) % (1ULL << (reducedresno + rlevel->log2_prec_width)))))
+ continue;
// check if a precinct exists
- prcx = ff_jpeg2000_ceildivpow2(xc, reducedresno) >> rlevel->log2_prec_width;
- prcy = ff_jpeg2000_ceildivpow2(yc, reducedresno) >> rlevel->log2_prec_height;
+ prcx = ff_jpeg2000_ceildiv(x, (int64_t)s->cdx[compno] << reducedresno) >> rlevel->log2_prec_width;
+ prcy = ff_jpeg2000_ceildiv(y, (int64_t)s->cdy[compno] << reducedresno) >> rlevel->log2_prec_height;
prcx -= ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], reducedresno) >> rlevel->log2_prec_width;
prcy -= ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], reducedresno) >> rlevel->log2_prec_height;
static int decode_cblk(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty,
Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk,
- int width, int height, int bandpos)
+ int width, int height, int bandpos, uint8_t roi_shift)
{
- int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1;
+ int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + roi_shift;
int pass_cnt = 0;
int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC;
int term_cnt = 0;
ff_mqc_initdec(&t1->mqc, cblk->data, 0, 1);
while (passno--) {
- if (bpno < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "bpno became negative\n");
+ if (bpno < 0 || bpno > 29) {
+ av_log(s->avctx, AV_LOG_ERROR, "bpno became invalid\n");
return AVERROR_INVALIDDATA;
}
switch(pass_t) {
pass_cnt ++;
}
- if (cblk->data + cblk->length - 2*(term_cnt < cblk->nb_terminations) != t1->mqc.bp) {
+ if (cblk->data + cblk->length - 2 > t1->mqc.bp) {
av_log(s->avctx, AV_LOG_WARNING, "End mismatch %"PTRDIFF_SPECIFIER"\n",
- cblk->data + cblk->length - 2*(term_cnt < cblk->nb_terminations) - t1->mqc.bp);
+ cblk->data + cblk->length - 2 - t1->mqc.bp);
+ }
+
+ if (cblk->data + cblk->length < t1->mqc.bp) {
+ av_log(s->avctx, AV_LOG_WARNING, "Synthetic End of Stream Marker Read.\n");
}
return 1;
}
+static inline int roi_shift_param(Jpeg2000Component *comp,
+ int quan_parameter)
+{
+ uint8_t roi_shift;
+ int val;
+ roi_shift = comp->roi_shift;
+ val = (quan_parameter < 0)?-quan_parameter:quan_parameter;
+
+ if (val > (1 << roi_shift))
+ return (quan_parameter < 0)?-(val >> roi_shift):(val >> roi_shift);
+ return quan_parameter;
+}
+
/* TODO: Verify dequantization for lossless case
* comp->data can be float or int
* band->stepsize can be float or int
s->dsp.mct_decode[tile->codsty[0].transform](src[0], src[1], src[2], csize);
}
+static inline void roi_scale_cblk(Jpeg2000Cblk *cblk,
+ Jpeg2000Component *comp,
+ Jpeg2000T1Context *t1)
+{
+ int i, j;
+ int w = cblk->coord[0][1] - cblk->coord[0][0];
+ for (j = 0; j < (cblk->coord[1][1] - cblk->coord[1][0]); ++j) {
+ int *src = t1->data + j*t1->stride;
+ for (i = 0; i < w; ++i)
+ src[i] = roi_shift_param(comp, src[i]);
+ }
+}
+
static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile)
{
Jpeg2000T1Context t1;
int ret = decode_cblk(s, codsty, &t1, cblk,
cblk->coord[0][1] - cblk->coord[0][0],
cblk->coord[1][1] - cblk->coord[1][0],
- bandpos);
+ bandpos, comp->roi_shift);
if (ret)
coded = 1;
else
x = cblk->coord[0][0] - band->coord[0][0];
y = cblk->coord[1][0] - band->coord[1][0];
+ if (comp->roi_shift)
+ roi_scale_cblk(cblk, comp, &t1);
if (codsty->transform == FF_DWT97)
dequantization_float(x, y, cblk, comp, &t1, band);
else if (codsty->transform == FF_DWT97_INT)
float *datap = comp->f_data; \
int32_t *i_datap = comp->i_data; \
int cbps = s->cbps[compno]; \
- int w = tile->comp[compno].coord[0][1] - s->image_offset_x; \
+ int w = tile->comp[compno].coord[0][1] - \
+ ff_jpeg2000_ceildiv(s->image_offset_x, s->cdx[compno]); \
+ int h = tile->comp[compno].coord[1][1] - \
+ ff_jpeg2000_ceildiv(s->image_offset_y, s->cdy[compno]); \
int plane = 0; \
\
if (planar) \
plane = s->cdef[compno] ? s->cdef[compno]-1 : (s->ncomponents-1); \
\
- y = tile->comp[compno].coord[1][0] - s->image_offset_y / s->cdy[compno]; \
+ y = tile->comp[compno].coord[1][0] - \
+ ff_jpeg2000_ceildiv(s->image_offset_y, s->cdy[compno]); \
line = (PIXEL *)picture->data[plane] + y * (picture->linesize[plane] / sizeof(PIXEL));\
- for (; y < tile->comp[compno].coord[1][1] - s->image_offset_y; y++) { \
+ for (; y < h; y++) { \
PIXEL *dst; \
\
- x = tile->comp[compno].coord[0][0] - s->image_offset_x / s->cdx[compno]; \
+ x = tile->comp[compno].coord[0][0] - \
+ ff_jpeg2000_ceildiv(s->image_offset_x, s->cdx[compno]); \
dst = line + x * pixelsize + compno*!planar; \
\
if (codsty->transform == FF_DWT97) { \
ff_jpeg2000_cleanup(comp, codsty);
}
av_freep(&s->tile[tileno].comp);
+ av_freep(&s->tile[tileno].packed_headers);
+ s->tile[tileno].packed_headers_size = 0;
}
}
+ av_freep(&s->packed_headers);
+ s->packed_headers_size = 0;
+ memset(&s->packed_headers_stream, 0, sizeof(s->packed_headers_stream));
av_freep(&s->tile);
memset(s->codsty, 0, sizeof(s->codsty));
memset(s->qntsty, 0, sizeof(s->qntsty));
marker = bytestream2_get_be16u(&s->g);
oldpos = bytestream2_tell(&s->g);
-
+ if (marker >= 0xFF30 && marker <= 0xFF3F)
+ continue;
if (marker == JPEG2000_SOD) {
Jpeg2000Tile *tile;
Jpeg2000TilePart *tp;
av_log(s->avctx, AV_LOG_ERROR, "Invalid tpend\n");
return AVERROR_INVALIDDATA;
}
+
+ if (s->has_ppm) {
+ uint32_t tp_header_size = bytestream2_get_be32(&s->packed_headers_stream);
+ if (bytestream2_get_bytes_left(&s->packed_headers_stream) < tp_header_size)
+ return AVERROR_INVALIDDATA;
+ bytestream2_init(&tp->header_tpg, s->packed_headers_stream.buffer, tp_header_size);
+ bytestream2_skip(&s->packed_headers_stream, tp_header_size);
+ }
+ if (tile->has_ppt && tile->tp_idx == 0) {
+ bytestream2_init(&tile->packed_headers_stream, tile->packed_headers, tile->packed_headers_size);
+ }
+
bytestream2_init(&tp->tpg, s->g.buffer, tp->tp_end - s->g.buffer);
bytestream2_skip(&s->g, tp->tp_end - s->g.buffer);
len = bytestream2_get_be16(&s->g);
if (len < 2 || bytestream2_get_bytes_left(&s->g) < len - 2) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid len %d left=%d\n", len, bytestream2_get_bytes_left(&s->g));
- return AVERROR_INVALIDDATA;
+ if (s->avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid len %d left=%d\n", len, bytestream2_get_bytes_left(&s->g));
+ return AVERROR_INVALIDDATA;
+ }
+ av_log(s->avctx, AV_LOG_WARNING, "Missing EOC Marker.\n");
+ break;
}
switch (marker) {
case JPEG2000_COD:
ret = get_cod(s, codsty, properties);
break;
+ case JPEG2000_RGN:
+ ret = get_rgn(s, len);
+ break;
case JPEG2000_QCC:
ret = get_qcc(s, len, qntsty, properties);
break;
ret = get_poc(s, len, poc);
break;
case JPEG2000_SOT:
+ if (!s->in_tile_headers) {
+ s->in_tile_headers = 1;
+ if (s->has_ppm) {
+ bytestream2_init(&s->packed_headers_stream, s->packed_headers, s->packed_headers_size);
+ }
+ }
if (!(ret = get_sot(s, len))) {
av_assert1(s->curtileno >= 0);
codsty = s->tile[s->curtileno].codsty;
// the comment is ignored
bytestream2_skip(&s->g, len - 2);
break;
+ case JPEG2000_CRG:
+ ret = read_crg(s, len);
+ break;
case JPEG2000_TLM:
// Tile-part lengths
ret = get_tlm(s, len);
// Packet length, tile-part header
ret = get_plt(s, len);
break;
+ case JPEG2000_PPM:
+ // Packed headers, main header
+ if (s->in_tile_headers) {
+ av_log(s->avctx, AV_LOG_ERROR, "PPM Marker can only be in Main header\n");
+ return AVERROR_INVALIDDATA;
+ }
+ ret = get_ppm(s, len);
+ break;
+ case JPEG2000_PPT:
+ // Packed headers, tile-part header
+ if (s->has_ppm) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Cannot have both PPT and PPM marker.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = get_ppt(s, len);
+ break;
default:
av_log(s->avctx, AV_LOG_ERROR,
"unsupported marker 0x%.4"PRIX16" at pos 0x%X\n",
if ((ret = init_tile(s, tileno)) < 0)
return ret;
- s->g = tile->tile_part[0].tpg;
if ((ret = jpeg2000_decode_packets(s, tile)) < 0)
return ret;
}
return 0;
}
atom_size = bytestream2_get_be32u(&s->g);
+ if (atom_size < 16 || (int64_t)bytestream2_tell(&s->g) + atom_size - 16 > INT_MAX)
+ return AVERROR_INVALIDDATA;
atom_end = bytestream2_tell(&s->g) + atom_size - 16;
} else {
+ if (atom_size < 8 || (int64_t)bytestream2_tell(&s->g) + atom_size - 8 > INT_MAX)
+ return AVERROR_INVALIDDATA;
atom_end = bytestream2_tell(&s->g) + atom_size - 8;
}
.version = LIBAVUTIL_VERSION_INT,
};
-AVCodec ff_jpeg2000_decoder = {
+const AVCodec ff_jpeg2000_decoder = {
.name = "jpeg2000",
.long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),
.type = AVMEDIA_TYPE_VIDEO,