@@ -83,8 +83,12 @@ typedef struct Jpeg2000Tile {
Jpeg2000QuantStyle qntsty[4];
Jpeg2000POC poc;
Jpeg2000TilePart tile_part[32];
- uint16_t tp_idx; // Tile-part index
- int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}}
+ 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;
typedef struct Jpeg2000DecoderContext {
@@ -851,6 +855,38 @@ static int get_plt(Jpeg2000DecoderContext *s, int n)
return 0;
}
+static int get_ppt(Jpeg2000DecoderContext *s, int n)
+{
+ Jpeg2000Tile *tile;
+
+ tile = &s->tile[s->curtileno];
+
+ av_assert1(s->curtileno >= 0);
+ 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
+/* Zppt = */ bytestream2_get_byte(&s->g);
+ if (!tile->packed_headers) {
+ tile->packed_headers = av_malloc_array(n - 3, sizeof(uint8_t));
+ memcpy(tile->packed_headers, s->g.buffer, sizeof(uint8_t)*(n - 3));
+ tile->packed_headers_size = n - 3;
+ } else {
+ tile->packed_headers = av_realloc_array(tile->packed_headers,
+ tile->packed_headers_size + n - 3,
+ sizeof(uint8_t));
+ memcpy(tile->packed_headers + tile->packed_headers_size,
+ s->g.buffer, sizeof(uint8_t)*(n - 3));
+ tile->packed_headers_size += n - 3;
+ }
+ bytestream2_skip(&s->g, n - 3);
+
+ return 0;
+}
+
static int init_tile(Jpeg2000DecoderContext *s, int tileno)
{
int compno;
@@ -923,6 +959,216 @@ static int getlblockinc(Jpeg2000DecoderContext *s)
return res;
}
+static int jpeg2000_decode_packet_header(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
+ int *tp_index,
+ Jpeg2000CodingStyle *codsty,
+ Jpeg2000ResLevel *rlevel, int precno,
+ int layno, uint8_t *expn, int numgbits,
+ int *process_data)
+{
+ int bandno, cblkno, ret, nb_code_blocks;
+
+ if (layno < rlevel->band[0].prec[precno].decoded_layers) {
+ *process_data = 0;
+ return 0;
+ }
+ rlevel->band[0].prec[precno].decoded_layers = layno + 1;
+
+ if (tile->has_ppt) {
+ s->g = tile->packed_headers_stream;
+ } else {
+ 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 (bytestream2_peek_be32(&s->g) == JPEG2000_SOP_FIXED_BYTES)
+ bytestream2_skip(&s->g, JPEG2000_SOP_BYTE_LENGTH);
+ }
+
+ if (!(ret = get_bits(s, 1))) {
+ jpeg2000_flush(s);
+ *process_data = 0;
+ goto end;
+ } else if (ret < 0)
+ return ret;
+
+ for (bandno = 0; bandno < rlevel->nbands; bandno++) {
+ Jpeg2000Band *band = rlevel->band + bandno;
+ Jpeg2000Prec *prec = band->prec + precno;
+
+ if (band->coord[0][0] == band->coord[0][1] ||
+ band->coord[1][0] == band->coord[1][1])
+ continue;
+ nb_code_blocks = prec->nb_codeblocks_height *
+ prec->nb_codeblocks_width;
+ for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) {
+ Jpeg2000Cblk *cblk = prec->cblk + cblkno;
+ int incl, newpasses, llen;
+ void *tmp;
+
+ if (cblk->npasses)
+ incl = get_bits(s, 1);
+ else
+ incl = tag_tree_decode(s, prec->cblkincl + cblkno, layno + 1) == layno;
+ if (!incl)
+ continue;
+ else if (incl < 0)
+ return incl;
+
+ if (!cblk->npasses) {
+ int v = expn[bandno] + numgbits - 1 -
+ tag_tree_decode(s, prec->zerobits + cblkno, 100);
+ if (v < 0 || v > 30) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "nonzerobits %d invalid or unsupported\n", v);
+ return AVERROR_INVALIDDATA;
+ }
+ cblk->nonzerobits = v;
+ }
+ if ((newpasses = getnpasses(s)) < 0)
+ return newpasses;
+ av_assert2(newpasses > 0);
+ if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) {
+ avpriv_request_sample(s->avctx, "Too many passes");
+ return AVERROR_PATCHWELCOME;
+ }
+ if ((llen = getlblockinc(s)) < 0)
+ return llen;
+ if (cblk->lblock + llen + av_log2(newpasses) > 16) {
+ avpriv_request_sample(s->avctx,
+ "Block with length beyond 16 bits");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ cblk->lblock += llen;
+
+ cblk->nb_lengthinc = 0;
+ cblk->nb_terminationsinc = 0;
+ av_free(cblk->lengthinc);
+ cblk->lengthinc = av_mallocz_array(newpasses , sizeof(*cblk->lengthinc));
+ if (!cblk->lengthinc)
+ return AVERROR(ENOMEM);
+ tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ cblk->data_start = tmp;
+ do {
+ int newpasses1 = 0;
+
+ while (newpasses1 < newpasses) {
+ newpasses1 ++;
+ if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) {
+ cblk->nb_terminationsinc ++;
+ break;
+ }
+ }
+
+ if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0)
+ return ret;
+ if (ret > cblk->data_allocated) {
+ size_t new_size = FFMAX(2*cblk->data_allocated, ret);
+ void *new = av_realloc(cblk->data, new_size);
+ if (new) {
+ cblk->data = new;
+ cblk->data_allocated = new_size;
+ }
+ }
+ if (ret > cblk->data_allocated) {
+ avpriv_request_sample(s->avctx,
+ "Block with lengthinc greater than %"SIZE_SPECIFIER"",
+ cblk->data_allocated);
+ return AVERROR_PATCHWELCOME;
+ }
+ cblk->lengthinc[cblk->nb_lengthinc++] = ret;
+ cblk->npasses += newpasses1;
+ newpasses -= newpasses1;
+ } while(newpasses);
+ }
+ }
+ jpeg2000_flush(s);
+
+ 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));
+ }
+end:
+ if (tile->has_ppt)
+ tile->packed_headers_stream = s->g;
+ else
+ tile->tile_part[*tp_index].tpg = s->g;
+ return 0;
+}
+
+static int jpeg2000_decode_packet_data(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
+ int *tp_index,
+ Jpeg2000CodingStyle *codsty,
+ Jpeg2000ResLevel *rlevel, int precno,
+ int layno, uint8_t *expn, int numgbits)
+{
+ int bandno, cblkno, nb_code_blocks;
+ int cwsno;
+
+ s->g = tile->tile_part[*tp_index].tpg;
+ if (tile->has_ppt) {
+ 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);
+ }
+
+
+ for (bandno = 0; bandno < rlevel->nbands; bandno++) {
+ Jpeg2000Band *band = rlevel->band + bandno;
+ Jpeg2000Prec *prec = band->prec + precno;
+
+ nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width;
+ for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) {
+ Jpeg2000Cblk *cblk = prec->cblk + cblkno;
+ if (!cblk->nb_terminationsinc && !cblk->lengthinc)
+ continue;
+ for (cwsno = 0; cwsno < cblk->nb_lengthinc; cwsno ++) {
+ if (cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4) {
+ size_t new_size = FFMAX(2*cblk->data_allocated, cblk->length + cblk->lengthinc[cwsno] + 4);
+ void *new = av_realloc(cblk->data, new_size);
+ if (new) {
+ cblk->data = new;
+ cblk->data_allocated = new_size;
+ }
+ }
+ if ( bytestream2_get_bytes_left(&s->g) < cblk->lengthinc[cwsno]
+ || cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4
+ ) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Block length %"PRIu16" or lengthinc %d is too large, left %d\n",
+ cblk->length, cblk->lengthinc[cwsno], bytestream2_get_bytes_left(&s->g));
+ return AVERROR_INVALIDDATA;
+ }
+
+ bytestream2_get_bufferu(&s->g, cblk->data + cblk->length, cblk->lengthinc[cwsno]);
+ cblk->length += cblk->lengthinc[cwsno];
+ cblk->lengthinc[cwsno] = 0;
+ if (cblk->nb_terminationsinc) {
+ cblk->nb_terminationsinc--;
+ cblk->nb_terminations++;
+ cblk->data[cblk->length++] = 0xFF;
+ cblk->data[cblk->length++] = 0xFF;
+ cblk->data_start[cblk->nb_terminations] = cblk->length;
+ }
+ }
+ av_freep(&cblk->lengthinc);
+ }
+ }
+ tile->tile_part[*tp_index].tpg = s->g;
+ return 0;
+}
+
static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, int *tp_index,
Jpeg2000CodingStyle *codsty,
Jpeg2000ResLevel *rlevel, int precno,
@@ -1120,13 +1366,25 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel +
reslevelno;
ok_reslevel = 1;
- for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++)
- if ((ret = jpeg2000_decode_packet(s, tile, tp_index,
+ for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++) {
+ int process_data = 1;
+ if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+ codsty, rlevel,
+ precno, layno,
+ qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+ qntsty->nguardbits, &process_data)) < 0)
+ return ret;
+
+ if (!process_data)
+ continue;
+
+ if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
codsty, rlevel,
precno, layno,
qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
qntsty->nguardbits)) < 0)
return ret;
+ }
}
}
}
@@ -1146,13 +1404,25 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel +
reslevelno;
ok_reslevel = 1;
- for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++)
- if ((ret = jpeg2000_decode_packet(s, tile, tp_index,
+ for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++) {
+ int process_data = 1;
+ if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+ codsty, rlevel,
+ precno, layno,
+ qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+ qntsty->nguardbits, &process_data)) < 0)
+ return ret;
+
+ if (!process_data)
+ continue;
+
+ if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
codsty, rlevel,
precno, layno,
qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
qntsty->nguardbits)) < 0)
return ret;
+ }
}
}
}
@@ -1214,7 +1484,19 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
}
for (layno = 0; layno < LYEpoc; layno++) {
- if ((ret = jpeg2000_decode_packet(s, tile, tp_index, codsty, rlevel,
+ int process_data = 1;
+ if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+ codsty, rlevel,
+ precno, layno,
+ qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+ qntsty->nguardbits, &process_data)) < 0)
+ return ret;
+
+ if (!process_data)
+ continue;
+
+ if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
+ codsty, rlevel,
precno, layno,
qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
qntsty->nguardbits)) < 0)
@@ -1284,14 +1566,25 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
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++) {
+ int process_data = 1;
+ if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+ codsty, rlevel,
+ precno, layno,
+ qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+ qntsty->nguardbits, &process_data)) < 0)
+ return ret;
+
+ if (!process_data)
+ continue;
+
+ if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
+ codsty, rlevel,
+ precno, layno,
+ qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+ qntsty->nguardbits)) < 0)
+ return ret;
+ }
}
}
}
@@ -1355,7 +1648,19 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2
}
for (layno = 0; layno < LYEpoc; layno++) {
- if ((ret = jpeg2000_decode_packet(s, tile, tp_index, codsty, rlevel,
+ int process_data = 1;
+ if ((ret = jpeg2000_decode_packet_header(s, tile, tp_index,
+ codsty, rlevel,
+ precno, layno,
+ qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
+ qntsty->nguardbits, &process_data)) < 0)
+ return ret;
+
+ if (!process_data)
+ continue;
+
+ if ((ret = jpeg2000_decode_packet_data(s, tile, tp_index,
+ codsty, rlevel,
precno, layno,
qntsty->expn + (reslevelno ? 3 * (reslevelno - 1) + 1 : 0),
qntsty->nguardbits)) < 0)
@@ -1381,6 +1686,7 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile
int tp_index = 0;
s->bit_index = 8;
+
if (tile->poc.nb_poc) {
for (i=0; i<tile->poc.nb_poc; i++) {
Jpeg2000POCEntry *e = &tile->poc.poc[i];
@@ -1925,6 +2231,11 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
av_log(s->avctx, AV_LOG_ERROR, "Invalid tpend\n");
return AVERROR_INVALIDDATA;
}
+
+ 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);
@@ -1987,6 +2298,10 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
// Packet length, tile-part header
ret = get_plt(s, len);
break;
+ case JPEG2000_PPT:
+ // Packed headers, tile-part header
+ ret = get_ppt(s, len);
+ break;
default:
av_log(s->avctx, AV_LOG_ERROR,
"unsupported marker 0x%.4"PRIX16" at pos 0x%X\n",
@@ -2016,7 +2331,6 @@ static int jpeg2000_read_bitstream_packets(Jpeg2000DecoderContext *s)
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;
}
From: Gautam Ramakrishnan <gautamramk@gmail.com> This patch adds support for the JPEG2000 PPT marker. This patch hence, fixes #4610. The patch was tested on the samples posted along with ticket #4610. --- libavcodec/jpeg2000dec.c | 348 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 331 insertions(+), 17 deletions(-)