[FFmpeg-devel] [PATCH v3 1/3] libavcodec/jpeg2000dec.c: Add functions and modify structs for PPT marker support
gautamramk at gmail.com
gautamramk at gmail.com
Sat Mar 28 06:19:17 EET 2020
From: Gautam Ramakrishnan <gautamramk at gmail.com>
This patch modifies the Jpeg2000Tile struct and breaks the
jpeg2000_decode_packet() function into two to decode packet
header and data separately.
---
libavcodec/jpeg2000dec.c | 250 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 248 insertions(+), 2 deletions(-)
diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
index 7103cd6ceb..001bc8d057 100644
--- a/libavcodec/jpeg2000dec.c
+++ b/libavcodec/jpeg2000dec.c
@@ -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 {
@@ -855,6 +859,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;
@@ -927,6 +963,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,
--
2.17.1
More information about the ffmpeg-devel
mailing list