#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/thread.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
Jpeg2000CodingStyle codsty[4];
Jpeg2000QuantStyle qntsty[4];
Jpeg2000POC poc;
- Jpeg2000TilePart tile_part[256];
+ Jpeg2000TilePart tile_part[32];
uint16_t tp_idx; // Tile-part index
int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}}
} Jpeg2000Tile;
avpriv_request_sample(s->avctx, "Support for image offsets");
return AVERROR_PATCHWELCOME;
}
- if (av_image_check_size(s->width, s->height, 0, s->avctx)) {
+ 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;
}
s->numXtiles = ff_jpeg2000_ceildiv(s->width - s->tile_offset_x, s->tile_width);
s->numYtiles = ff_jpeg2000_ceildiv(s->height - s->tile_offset_y, s->tile_height);
- if (s->numXtiles * (uint64_t)s->numYtiles > INT_MAX/sizeof(*s->tile)) {
+ // There must be at least a SOT and SOD per tile, their minimum size is 14
+ if (s->numXtiles * (uint64_t)s->numYtiles > INT_MAX/sizeof(*s->tile) ||
+ s->numXtiles * s->numYtiles * 14LL > bytestream2_size(&s->g)
+ ) {
s->numXtiles = s->numYtiles = 0;
return AVERROR(EINVAL);
}
return AVERROR_INVALIDDATA;
}
- av_assert0(TPsot < FF_ARRAY_ELEMS(s->tile[Isot].tile_part));
+ if (TPsot >= FF_ARRAY_ELEMS(s->tile[Isot].tile_part)) {
+ avpriv_request_sample(s->avctx, "Too many tile parts");
+ return AVERROR_PATCHWELCOME;
+ }
s->tile[Isot].tp_idx = TPsot;
tp = s->tile[Isot].tile_part + TPsot;
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);
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;
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);
cblk->data_start[cblk->nb_terminations] = cblk->length;
}
}
+ av_freep(&cblk->lengthinc);
}
}
return 0;
step_x = 32;
step_y = 32;
+ if (RSpoc > FFMIN(codsty->nreslevels, REpoc))
+ continue;
+
for (reslevelno = RSpoc; reslevelno < FFMIN(codsty->nreslevels, REpoc); reslevelno++) {
uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r
Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno;
int xc = x / s->cdx[compno];
int yc = y / s->cdy[compno];
- if (yc % (1 << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
+ if (yc % (1LL << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
continue;
- if (xc % (1 << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
+ if (xc % (1LL << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
continue;
// check if a precinct exists
if (reslevelno >= codsty->nreslevels)
continue;
- if (yc % (1 << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
+ if (yc % (1LL << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
continue;
- if (xc % (1 << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
+ if (xc % (1LL << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
continue;
// check if a precinct exists
uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r
Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno;
- if (yc % (1 << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
+ if (yc % (1LL << (rlevel->log2_prec_height + reducedresno)) && y != tile->coord[1][0]) //FIXME this is a subset of the check
continue;
- if (xc % (1 << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
+ if (xc % (1LL << (rlevel->log2_prec_width + reducedresno)) && x != tile->coord[0][0]) //FIXME this is a subset of the check
continue;
// check if a precinct exists
bytestream2_get_bytes_left(&s->g) >= 8) {
atom_size = bytestream2_get_be32u(&s->g);
atom = bytestream2_get_be32u(&s->g);
- atom_end = bytestream2_tell(&s->g) + atom_size - 8;
+ if (atom_size == 1) {
+ if (bytestream2_get_be32u(&s->g)) {
+ avpriv_request_sample(s->avctx, "Huge atom");
+ return 0;
+ }
+ atom_size = bytestream2_get_be32u(&s->g);
+ atom_end = bytestream2_tell(&s->g) + atom_size - 16;
+ } else {
+ atom_end = bytestream2_tell(&s->g) + atom_size - 8;
+ }
if (atom == JP2_CODESTREAM)
return 1;
}
} else if (atom2 == MKBETAG('p','c','l','r') && atom2_size >= 6) {
int i, size, colour_count, colour_channels, colour_depth[3];
- uint32_t r, g, b;
colour_count = bytestream2_get_be16u(&s->g);
colour_channels = bytestream2_get_byteu(&s->g);
// FIXME: Do not ignore channel_sign
size = (colour_depth[0] + 7 >> 3) * colour_count +
(colour_depth[1] + 7 >> 3) * colour_count +
(colour_depth[2] + 7 >> 3) * colour_count;
- if (colour_count > 256 ||
+ if (colour_count > AVPALETTE_COUNT ||
colour_channels != 3 ||
colour_depth[0] > 16 ||
colour_depth[1] > 16 ||
}
s->pal8 = 1;
for (i = 0; i < colour_count; i++) {
+ uint32_t r, g, b;
if (colour_depth[0] <= 8) {
r = bytestream2_get_byteu(&s->g) << 8 - colour_depth[0];
r |= r >> colour_depth[0];
return 0;
}
+static av_cold void jpeg2000_init_static_data(void)
+{
+ ff_jpeg2000_init_tier1_luts();
+ ff_mqc_init_context_tables();
+}
+
static av_cold int jpeg2000_decode_init(AVCodecContext *avctx)
{
+ static AVOnce init_static_once = AV_ONCE_INIT;
Jpeg2000DecoderContext *s = avctx->priv_data;
+ ff_thread_once(&init_static_once, jpeg2000_init_static_data);
ff_jpeg2000dsp_init(&s->dsp);
return 0;
return ret;
}
-static av_cold void jpeg2000_init_static_data(AVCodec *codec)
-{
- ff_jpeg2000_init_tier1_luts();
- ff_mqc_init_context_tables();
-}
-
#define OFFSET(x) offsetof(Jpeg2000DecoderContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
.id = AV_CODEC_ID_JPEG2000,
.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_DR1,
.priv_data_size = sizeof(Jpeg2000DecoderContext),
- .init_static_data = jpeg2000_init_static_data,
.init = jpeg2000_decode_init,
.decode = jpeg2000_decode_frame,
.priv_class = &jpeg2000_class,