diff options
Diffstat (limited to 'libavcodec/jpeg2000dec.c')
-rw-r--r-- | libavcodec/jpeg2000dec.c | 471 |
1 files changed, 346 insertions, 125 deletions
diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 5135297..ecb6393 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -3,20 +3,20 @@ * Copyright (c) 2007 Kamil Nowosad * Copyright (c) 2013 Nicolas Bertrand <nicoinattendu@gmail.com> * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * 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. * - * Libav is distributed in the hope that it will be useful, + * 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -28,8 +28,10 @@ #include <inttypes.h> #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" #include "bytestream.h" #include "internal.h" @@ -40,6 +42,7 @@ #define JP2_SIG_TYPE 0x6A502020 #define JP2_SIG_VALUE 0x0D0A870A #define JP2_CODESTREAM 0x6A703263 +#define JP2_HEADER 0x6A703268 #define HAD_COC 0x01 #define HAD_QCC 0x02 @@ -57,14 +60,14 @@ typedef struct Jpeg2000Tile { uint8_t properties[4]; Jpeg2000CodingStyle codsty[4]; Jpeg2000QuantStyle qntsty[4]; - Jpeg2000TilePart tile_part[3]; + Jpeg2000TilePart tile_part[4]; uint16_t tp_idx; // Tile-part index } Jpeg2000Tile; typedef struct Jpeg2000DecoderContext { AVClass *class; AVCodecContext *avctx; - GetByteContext g; + GetByteContext g; int width, height; int image_offset_x, image_offset_y; @@ -75,6 +78,10 @@ typedef struct Jpeg2000DecoderContext { int cdx[4], cdy[4]; int precision; int ncomponents; + int colour_space; + uint32_t palette[256]; + int8_t pal8; + int cdef[4]; int tile_width, tile_height; unsigned numXtiles, numYtiles; int maxtilelen; @@ -84,7 +91,8 @@ typedef struct Jpeg2000DecoderContext { int bit_index; - int16_t curtileno; + int curtileno; + Jpeg2000Tile *tile; Jpeg2000DSPContext dsp; @@ -99,6 +107,7 @@ typedef struct Jpeg2000DecoderContext { static int get_bits(Jpeg2000DecoderContext *s, int n) { int res = 0; + while (--n >= 0) { res <<= 1; if (s->bit_index == 0) { @@ -156,12 +165,74 @@ static int tag_tree_decode(Jpeg2000DecoderContext *s, Jpeg2000TgtNode *node, return curval; } +static int pix_fmt_match(enum AVPixelFormat pix_fmt, int components, + int bpc, uint32_t log2_chroma_wh, int pal8) +{ + int match = 1; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + + if (desc->nb_components != components) { + return 0; + } + + switch (components) { + case 4: + match = match && desc->comp[3].depth_minus1 + 1 >= bpc && + (log2_chroma_wh >> 14 & 3) == 0 && + (log2_chroma_wh >> 12 & 3) == 0; + case 3: + match = match && desc->comp[2].depth_minus1 + 1 >= bpc && + (log2_chroma_wh >> 10 & 3) == desc->log2_chroma_w && + (log2_chroma_wh >> 8 & 3) == desc->log2_chroma_h; + case 2: + match = match && desc->comp[1].depth_minus1 + 1 >= bpc && + (log2_chroma_wh >> 6 & 3) == desc->log2_chroma_w && + (log2_chroma_wh >> 4 & 3) == desc->log2_chroma_h; + + case 1: + match = match && desc->comp[0].depth_minus1 + 1 >= bpc && + (log2_chroma_wh >> 2 & 3) == 0 && + (log2_chroma_wh & 3) == 0 && + (desc->flags & AV_PIX_FMT_FLAG_PAL) == pal8 * AV_PIX_FMT_FLAG_PAL; + } + return match; +} + +// pix_fmts with lower bpp have to be listed before +// similar pix_fmts with higher bpp. +#define RGB_PIXEL_FORMATS AV_PIX_FMT_PAL8,AV_PIX_FMT_RGB24,AV_PIX_FMT_RGBA,AV_PIX_FMT_RGB48,AV_PIX_FMT_RGBA64 +#define GRAY_PIXEL_FORMATS AV_PIX_FMT_GRAY8,AV_PIX_FMT_GRAY8A,AV_PIX_FMT_GRAY16,AV_PIX_FMT_YA16 +#define YUV_PIXEL_FORMATS AV_PIX_FMT_YUV410P,AV_PIX_FMT_YUV411P,AV_PIX_FMT_YUVA420P, \ + AV_PIX_FMT_YUV420P,AV_PIX_FMT_YUV422P,AV_PIX_FMT_YUVA422P, \ + AV_PIX_FMT_YUV440P,AV_PIX_FMT_YUV444P,AV_PIX_FMT_YUVA444P, \ + AV_PIX_FMT_YUV420P9,AV_PIX_FMT_YUV422P9,AV_PIX_FMT_YUV444P9, \ + AV_PIX_FMT_YUVA420P9,AV_PIX_FMT_YUVA422P9,AV_PIX_FMT_YUVA444P9, \ + AV_PIX_FMT_YUV420P10,AV_PIX_FMT_YUV422P10,AV_PIX_FMT_YUV444P10, \ + AV_PIX_FMT_YUVA420P10,AV_PIX_FMT_YUVA422P10,AV_PIX_FMT_YUVA444P10, \ + AV_PIX_FMT_YUV420P12,AV_PIX_FMT_YUV422P12,AV_PIX_FMT_YUV444P12, \ + AV_PIX_FMT_YUV420P14,AV_PIX_FMT_YUV422P14,AV_PIX_FMT_YUV444P14, \ + AV_PIX_FMT_YUV420P16,AV_PIX_FMT_YUV422P16,AV_PIX_FMT_YUV444P16, \ + AV_PIX_FMT_YUVA420P16,AV_PIX_FMT_YUVA422P16,AV_PIX_FMT_YUVA444P16 +#define XYZ_PIXEL_FORMATS AV_PIX_FMT_XYZ12 + +static const enum AVPixelFormat rgb_pix_fmts[] = {RGB_PIXEL_FORMATS}; +static const enum AVPixelFormat gray_pix_fmts[] = {GRAY_PIXEL_FORMATS}; +static const enum AVPixelFormat yuv_pix_fmts[] = {YUV_PIXEL_FORMATS}; +static const enum AVPixelFormat xyz_pix_fmts[] = {XYZ_PIXEL_FORMATS}; +static const enum AVPixelFormat all_pix_fmts[] = {RGB_PIXEL_FORMATS, + GRAY_PIXEL_FORMATS, + YUV_PIXEL_FORMATS, + XYZ_PIXEL_FORMATS}; + /* marker segments */ /* get sizes and offsets of image, tiles; number of components */ static int get_siz(Jpeg2000DecoderContext *s) { int i; int ncomponents; + uint32_t log2_chroma_wh = 0; + const enum AVPixelFormat *possible_fmts = NULL; + int possible_fmts_nb = 0; if (bytestream2_get_bytes_left(&s->g) < 36) return AVERROR_INVALIDDATA; @@ -177,6 +248,11 @@ static int get_siz(Jpeg2000DecoderContext *s) 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 (ncomponents <= 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid number of components: %d\n", s->ncomponents); @@ -191,8 +267,7 @@ static int get_siz(Jpeg2000DecoderContext *s) s->ncomponents = ncomponents; - if (s->tile_width <= 0 || s->tile_height <= 0 || - s->tile_width > s->width || s->tile_height > s->height) { + if (s->tile_width <= 0 || s->tile_height <= 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid tile dimension %dx%d.\n", s->tile_width, s->tile_height); return AVERROR_INVALIDDATA; @@ -208,21 +283,22 @@ static int get_siz(Jpeg2000DecoderContext *s) s->sgnd[i] = !!(x & 0x80); s->cdx[i] = bytestream2_get_byteu(&s->g); s->cdy[i] = bytestream2_get_byteu(&s->g); - - if (s->cdx[i] != 1 || s->cdy[i] != 1) { - avpriv_request_sample(s->avctx, - "CDxy values %d %d for component %d", - s->cdx[i], s->cdy[i], i); - if (!s->cdx[i] || !s->cdy[i]) - return AVERROR_INVALIDDATA; - else - return AVERROR_PATCHWELCOME; + if ( !s->cdx[i] || s->cdx[i] == 3 || s->cdx[i] > 4 + || !s->cdy[i] || s->cdy[i] == 3 || s->cdy[i] > 4) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid sample separation %d/%d\n", s->cdx[i], s->cdy[i]); + return AVERROR_INVALIDDATA; } + log2_chroma_wh |= s->cdy[i] >> 1 << i * 4 | s->cdx[i] >> 1 << i * 4 + 2; } 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)) { + s->numXtiles = s->numYtiles = 0; + return AVERROR(EINVAL); + } + s->tile = av_mallocz_array(s->numXtiles * s->numYtiles, sizeof(*s->tile)); if (!s->tile) { s->numXtiles = s->numYtiles = 0; @@ -243,36 +319,49 @@ static int get_siz(Jpeg2000DecoderContext *s) s->avctx->height = ff_jpeg2000_ceildivpow2(s->height - s->image_offset_y, s->reduction_factor); - switch (s->ncomponents) { - case 1: - if (s->precision > 8) - s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; - else - s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; - break; - case 3: - switch (s->avctx->profile) { - case FF_PROFILE_JPEG2000_DCINEMA_2K: - case FF_PROFILE_JPEG2000_DCINEMA_4K: - /* XYZ color-space for digital cinema profiles */ - s->avctx->pix_fmt = AV_PIX_FMT_XYZ12; + if (s->avctx->profile == FF_PROFILE_JPEG2000_DCINEMA_2K || + s->avctx->profile == FF_PROFILE_JPEG2000_DCINEMA_4K) { + possible_fmts = xyz_pix_fmts; + possible_fmts_nb = FF_ARRAY_ELEMS(xyz_pix_fmts); + } else { + switch (s->colour_space) { + case 16: + possible_fmts = rgb_pix_fmts; + possible_fmts_nb = FF_ARRAY_ELEMS(rgb_pix_fmts); + break; + case 17: + possible_fmts = gray_pix_fmts; + possible_fmts_nb = FF_ARRAY_ELEMS(gray_pix_fmts); + break; + case 18: + possible_fmts = yuv_pix_fmts; + possible_fmts_nb = FF_ARRAY_ELEMS(yuv_pix_fmts); break; default: - if (s->precision > 8) - s->avctx->pix_fmt = AV_PIX_FMT_RGB48; - else - s->avctx->pix_fmt = AV_PIX_FMT_RGB24; + possible_fmts = all_pix_fmts; + possible_fmts_nb = FF_ARRAY_ELEMS(all_pix_fmts); break; } - break; - case 4: - s->avctx->pix_fmt = AV_PIX_FMT_RGBA; - break; - default: - /* pixel format can not be identified */ - s->avctx->pix_fmt = AV_PIX_FMT_NONE; - 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 (i == possible_fmts_nb) { + av_log(s->avctx, AV_LOG_ERROR, + "Unknown pix_fmt, profile: %d, colour_space: %d, " + "components: %d, precision: %d, " + "cdx[1]: %d, cdy[1]: %d, cdx[2]: %d, cdy[2]: %d\n", + s->avctx->profile, s->colour_space, ncomponents, s->precision, + ncomponents > 2 ? s->cdx[1] : 0, + ncomponents > 2 ? s->cdy[1] : 0, + ncomponents > 2 ? s->cdx[2] : 0, + ncomponents > 2 ? s->cdy[2] : 0); + return AVERROR_PATCHWELCOME; + } + s->avctx->bits_per_raw_sample = s->precision; return 0; } @@ -287,18 +376,26 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) /* nreslevels = number of resolution levels = number of decomposition level +1 */ c->nreslevels = bytestream2_get_byteu(&s->g) + 1; - - if (c->nreslevels > JPEG2000_MAX_RESLEVELS) + if (c->nreslevels >= JPEG2000_MAX_RESLEVELS) { + av_log(s->avctx, AV_LOG_ERROR, "nreslevels %d is invalid\n", c->nreslevels); return AVERROR_INVALIDDATA; + } + + if (c->nreslevels <= s->reduction_factor) { + /* we are forced to update reduction_factor as its requested value is + not compatible with this bitstream, and as we might have used it + already in setup earlier we have to fail this frame until + reinitialization is implemented */ + av_log(s->avctx, AV_LOG_ERROR, "reduction_factor too large for this bitstream, max is %d\n", c->nreslevels - 1); + s->reduction_factor = c->nreslevels - 1; + return AVERROR(EINVAL); + } /* compute number of resolution levels to decode */ - if (c->nreslevels < s->reduction_factor) - c->nreslevels2decode = 1; - else - c->nreslevels2decode = c->nreslevels - s->reduction_factor; + c->nreslevels2decode = c->nreslevels - s->reduction_factor; - c->log2_cblk_width = bytestream2_get_byteu(&s->g) + 2; // cblk width - c->log2_cblk_height = bytestream2_get_byteu(&s->g) + 2; // cblk height + c->log2_cblk_width = (bytestream2_get_byteu(&s->g) & 15) + 2; // cblk width + c->log2_cblk_height = (bytestream2_get_byteu(&s->g) & 15) + 2; // cblk height if (c->log2_cblk_width > 10 || c->log2_cblk_height > 10 || c->log2_cblk_width + c->log2_cblk_height > 12) { @@ -306,10 +403,14 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) return AVERROR_INVALIDDATA; } + if (c->log2_cblk_width > 6 || c->log2_cblk_height > 6) { + avpriv_request_sample(s->avctx, "cblk size > 64"); + return AVERROR_PATCHWELCOME; + } + c->cblk_style = bytestream2_get_byteu(&s->g); if (c->cblk_style != 0) { // cblk style - avpriv_request_sample(s->avctx, "Support for extra cblk styles"); - return AVERROR_PATCHWELCOME; + av_log(s->avctx, AV_LOG_WARNING, "extra cblk styles %X\n", c->cblk_style); } c->transform = bytestream2_get_byteu(&s->g); // DWT transformation type /* set integer 9/7 DWT in case of BITEXACT flag */ @@ -409,7 +510,7 @@ static int get_qcx(Jpeg2000DecoderContext *s, int n, Jpeg2000QuantStyle *q) if (q->quantsty == JPEG2000_QSTY_NONE) { n -= 3; if (bytestream2_get_bytes_left(&s->g) < n || - n > JPEG2000_MAX_DECLEVELS) + n > JPEG2000_MAX_DECLEVELS*3) return AVERROR_INVALIDDATA; for (i = 0; i < n; i++) q->expn[i] = bytestream2_get_byteu(&s->g) >> 3; @@ -427,7 +528,7 @@ static int get_qcx(Jpeg2000DecoderContext *s, int n, Jpeg2000QuantStyle *q) } else { n = (n - 3) >> 1; if (bytestream2_get_bytes_left(&s->g) < 2 * n || - n > JPEG2000_MAX_DECLEVELS) + n > JPEG2000_MAX_DECLEVELS*3) return AVERROR_INVALIDDATA; for (i = 0; i < n; i++) { x = bytestream2_get_be16u(&s->g); @@ -445,6 +546,8 @@ static int get_qcd(Jpeg2000DecoderContext *s, int n, Jpeg2000QuantStyle *q, Jpeg2000QuantStyle tmp; int compno, ret; + memset(&tmp, 0, sizeof(tmp)); + if ((ret = get_qcx(s, n, &tmp)) < 0) return ret; for (compno = 0; compno < s->ncomponents; compno++) @@ -487,14 +590,12 @@ static int get_sot(Jpeg2000DecoderContext *s, int n) if (bytestream2_get_bytes_left(&s->g) < 8) return AVERROR_INVALIDDATA; + s->curtileno = 0; Isot = bytestream2_get_be16u(&s->g); // Isot if (Isot >= s->numXtiles * s->numYtiles) return AVERROR_INVALIDDATA; - if (Isot) { - avpriv_request_sample(s->avctx, "Support for more than one tile"); - return AVERROR_PATCHWELCOME; - } + s->curtileno = Isot; Psot = bytestream2_get_be32u(&s->g); // Psot TPsot = bytestream2_get_byteu(&s->g); // TPsot @@ -684,7 +785,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, return ret; if (ret > sizeof(cblk->data)) { avpriv_request_sample(s->avctx, - "Block with lengthinc greater than %zu", + "Block with lengthinc greater than %"SIZE_SPECIFIER"", sizeof(cblk->data)); return AVERROR_PATCHWELCOME; } @@ -708,25 +809,18 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, 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 (bytestream2_get_bytes_left(&s->g) < cblk->lengthinc) + if ( bytestream2_get_bytes_left(&s->g) < cblk->lengthinc + || sizeof(cblk->data) < cblk->length + cblk->lengthinc + 2 + ) { + av_log(s->avctx, AV_LOG_ERROR, + "Block length %"PRIu16" or lengthinc %d is too large\n", + cblk->length, cblk->lengthinc); return AVERROR_INVALIDDATA; - /* Code-block data can be empty. In that case initialize data - * with 0xFFFF. */ - if (cblk->lengthinc > 0) { - bytestream2_get_bufferu(&s->g, cblk->data, cblk->lengthinc); - } else { - cblk->data[0] = 0xFF; - cblk->data[1] = 0xFF; } + + bytestream2_get_bufferu(&s->g, cblk->data + cblk->length, cblk->lengthinc); cblk->length += cblk->lengthinc; cblk->lengthinc = 0; - - if (cblk->length > sizeof(cblk->data)) { - av_log(s->avctx, AV_LOG_ERROR, - "Block length %"PRIu16" > data size %zd\n", - cblk->length, sizeof(cblk->data)); - return AVERROR_INVALIDDATA; - } } } return 0; @@ -740,6 +834,9 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile s->bit_index = 8; switch (tile->codsty[0].prog_order) { + case JPEG2000_PGOD_RLCP: + avpriv_request_sample(s->avctx, "Progression order RLCP"); + case JPEG2000_PGOD_LRCP: for (layno = 0; layno < tile->codsty[0].nlayers; layno++) { ok_reslevel = 1; @@ -750,7 +847,7 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile Jpeg2000QuantStyle *qntsty = tile->qntsty + compno; if (reslevelno < codsty->nreslevels) { Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel + - reslevelno; + reslevelno; ok_reslevel = 1; for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++) if ((ret = jpeg2000_decode_packet(s, @@ -800,6 +897,10 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile prcx = ff_jpeg2000_ceildivpow2(x, reducedresno) >> rlevel->log2_prec_width; prcy = ff_jpeg2000_ceildivpow2(y, reducedresno) >> rlevel->log2_prec_height; precno = prcx + rlevel->num_precincts_x * prcy; + + if (prcx >= rlevel->num_precincts_x || prcy >= rlevel->num_precincts_y) + return AVERROR_PATCHWELCOME; + for (layno = 0; layno < tile->codsty[0].nlayers; layno++) { if ((ret = jpeg2000_decode_packet(s, codsty, rlevel, precno, layno, @@ -813,11 +914,6 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile } break; - case JPEG2000_PGOD_RLCP: - avpriv_request_sample(s->avctx, "Progression order RLCP"); - ret = AVERROR_PATCHWELCOME; - break; - case JPEG2000_PGOD_RPCL: avpriv_request_sample(s->avctx, "Progression order RPCL"); ret = AVERROR_PATCHWELCOME; @@ -963,21 +1059,25 @@ static int decode_cblk(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, int bpass_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_BYPASS; int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC; + av_assert0(width <= JPEG2000_MAX_CBLKW); + av_assert0(height <= JPEG2000_MAX_CBLKH); + for (y = 0; y < height; y++) memset(t1->data[y], 0, width * sizeof(**t1->data)); /* If code-block contains no compressed data: nothing to do. */ if (!cblk->length) return 0; + for (y = 0; y < height + 2; y++) memset(t1->flags[y], 0, (width + 2) * sizeof(**t1->flags)); + cblk->data[cblk->length] = 0xff; + cblk->data[cblk->length+1] = 0xff; ff_mqc_initdec(&t1->mqc, cblk->data); - cblk->data[cblk->length] = 0xff; - cblk->data[cblk->length + 1] = 0xff; while (passno--) { - switch (pass_t) { + switch(pass_t) { case 0: decode_sigpass(t1, width, height, bpno + 1, bandpos, bpass_csty_symbol && (clnpass_cnt >= 4), @@ -1039,7 +1139,7 @@ static void dequantization_int(int x, int y, Jpeg2000Cblk *cblk, int32_t *datap = &comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x]; int *src = t1->data[j]; for (i = 0; i < w; ++i) - datap[i] = (src[i] * band->i_stepsize + (1 << 15)) >> 16; + datap[i] = (src[i] * band->i_stepsize + (1 << 14)) >> 15; } } @@ -1048,6 +1148,12 @@ static inline void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) int i, csize = 1; void *src[3]; + for (i = 1; i < 3; i++) + if (tile->codsty[0].transform != tile->codsty[i].transform) { + av_log(s->avctx, AV_LOG_ERROR, "Transforms mismatch, MCT not supported\n"); + return; + } + for (i = 0; i < 3; i++) if (tile->codsty[0].transform == FF_DWT97) src[i] = tile->comp[i].f_data; @@ -1063,24 +1169,29 @@ static inline void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, AVFrame *picture) { + const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(s->avctx->pix_fmt); int compno, reslevelno, bandno; int x, y; + int planar = !!(pixdesc->flags & AV_PIX_FMT_FLAG_PLANAR); + int pixelsize = planar ? 1 : pixdesc->nb_components; uint8_t *line; Jpeg2000T1Context t1; - /* Loop on tile components */ + /* Loop on tile components */ for (compno = 0; compno < s->ncomponents; compno++) { Jpeg2000Component *comp = tile->comp + compno; Jpeg2000CodingStyle *codsty = tile->codsty + compno; + /* Loop on resolution levels */ for (reslevelno = 0; reslevelno < codsty->nreslevels2decode; reslevelno++) { Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno; /* Loop on bands */ for (bandno = 0; bandno < rlevel->nbands; bandno++) { - uint16_t nb_precincts, precno; + int nb_precincts, precno; Jpeg2000Band *band = rlevel->band + bandno; int cblkno = 0, bandpos; + bandpos = bandno + (reslevelno > 0); if (band->coord[0][0] == band->coord[0][1] || @@ -1121,6 +1232,13 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, if (tile->codsty[0].mct) mct_decode(s, tile); + if (s->cdef[0] < 0) { + for (x = 0; x < s->ncomponents; x++) + s->cdef[x] = x + 1; + if ((s->ncomponents & 1) == 0) + s->cdef[s->ncomponents-1] = 0; + } + if (s->precision <= 8) { for (compno = 0; compno < s->ncomponents; compno++) { Jpeg2000Component *comp = tile->comp + compno; @@ -1129,14 +1247,19 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, 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 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; - line = picture->data[0] + y * picture->linesize[0]; + line = picture->data[plane] + y / s->cdy[compno] * picture->linesize[plane]; for (; y < tile->comp[compno].coord[1][1] - s->image_offset_y; y += s->cdy[compno]) { uint8_t *dst; x = tile->comp[compno].coord[0][0] - s->image_offset_x; - dst = line + x * s->ncomponents + compno; + dst = line + x / s->cdx[compno] * pixelsize + compno*!planar; if (codsty->transform == FF_DWT97) { for (; x < w; x += s->cdx[compno]) { @@ -1145,7 +1268,7 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, val = av_clip(val, 0, (1 << cbps) - 1); *dst = val << (8 - cbps); datap++; - dst += s->ncomponents; + dst += pixelsize; } } else { for (; x < w; x += s->cdx[compno]) { @@ -1154,10 +1277,10 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, val = av_clip(val, 0, (1 << cbps) - 1); *dst = val << (8 - cbps); i_datap++; - dst += s->ncomponents; + dst += pixelsize; } } - line += picture->linesize[0]; + line += picture->linesize[plane]; } } } else { @@ -1169,13 +1292,18 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, uint16_t *linel; int cbps = s->cbps[compno]; int w = tile->comp[compno].coord[0][1] - s->image_offset_x; + 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; - linel = (uint16_t *)picture->data[0] + y * (picture->linesize[0] >> 1); + linel = (uint16_t *)picture->data[plane] + y / s->cdy[compno] * (picture->linesize[plane] >> 1); for (; y < tile->comp[compno].coord[1][1] - s->image_offset_y; y += s->cdy[compno]) { uint16_t *dst; + x = tile->comp[compno].coord[0][0] - s->image_offset_x; - dst = linel + (x * s->ncomponents + compno); + dst = linel + (x / s->cdx[compno] * pixelsize + compno*!planar); if (codsty->transform == FF_DWT97) { for (; x < w; x += s-> cdx[compno]) { int val = lrintf(*datap) + (1 << (cbps - 1)); @@ -1184,7 +1312,7 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, /* align 12 bit values in little-endian mode */ *dst = val << (16 - cbps); datap++; - dst += s->ncomponents; + dst += pixelsize; } } else { for (; x < w; x += s-> cdx[compno]) { @@ -1194,10 +1322,10 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, /* align 12 bit values in little-endian mode */ *dst = val << (16 - cbps); i_datap++; - dst += s->ncomponents; + dst += pixelsize; } } - linel += picture->linesize[0] >> 1; + linel += picture->linesize[plane] >> 1; } } } @@ -1209,15 +1337,19 @@ static void jpeg2000_dec_cleanup(Jpeg2000DecoderContext *s) { int tileno, compno; for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++) { - for (compno = 0; compno < s->ncomponents; compno++) { - Jpeg2000Component *comp = s->tile[tileno].comp + compno; - Jpeg2000CodingStyle *codsty = s->tile[tileno].codsty + compno; + if (s->tile[tileno].comp) { + for (compno = 0; compno < s->ncomponents; compno++) { + Jpeg2000Component *comp = s->tile[tileno].comp + compno; + Jpeg2000CodingStyle *codsty = s->tile[tileno].codsty + compno; - ff_jpeg2000_cleanup(comp, codsty); + ff_jpeg2000_cleanup(comp, codsty); + } + av_freep(&s->tile[tileno].comp); } - av_freep(&s->tile[tileno].comp); } av_freep(&s->tile); + memset(s->codsty, 0, sizeof(s->codsty)); + memset(s->qntsty, 0, sizeof(s->qntsty)); s->numXtiles = s->numYtiles = 0; } @@ -1244,17 +1376,21 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) Jpeg2000Tile *tile; Jpeg2000TilePart *tp; - if (s->curtileno < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Missing SOT\n"); - return AVERROR_INVALIDDATA; - } if (!s->tile) { av_log(s->avctx, AV_LOG_ERROR, "Missing SIZ\n"); return AVERROR_INVALIDDATA; } + if (s->curtileno < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Missing SOT\n"); + return AVERROR_INVALIDDATA; + } tile = s->tile + s->curtileno; tp = tile->tile_part + tile->tp_idx; + if (tp->tp_end < s->g.buffer) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid tpend\n"); + return AVERROR_INVALIDDATA; + } bytestream2_init(&tp->tpg, s->g.buffer, tp->tp_end - s->g.buffer); bytestream2_skip(&s->g, tp->tp_end - s->g.buffer); @@ -1263,13 +1399,15 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) if (marker == JPEG2000_EOC) break; - len = bytestream2_get_be16u(&s->g); + len = bytestream2_get_be16(&s->g); if (len < 2 || bytestream2_get_bytes_left(&s->g) < len - 2) return AVERROR_INVALIDDATA; switch (marker) { case JPEG2000_SIZ: ret = get_siz(s); + if (!s->tile) + s->numXtiles = s->numYtiles = 0; break; case JPEG2000_COC: ret = get_coc(s, codsty, properties); @@ -1285,6 +1423,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) break; case JPEG2000_SOT: if (!(ret = get_sot(s, len))) { + av_assert1(s->curtileno >= 0); codsty = s->tile[s->curtileno].codsty; qntsty = s->tile[s->curtileno].qntsty; properties = s->tile[s->curtileno].properties; @@ -1337,26 +1476,101 @@ static int jpeg2000_read_bitstream_packets(Jpeg2000DecoderContext *s) static int jp2_find_codestream(Jpeg2000DecoderContext *s) { - uint32_t atom_size, atom; - int found_codestream = 0, search_range = 10; + uint32_t atom_size, atom, atom_end; + int search_range = 10; - while(!found_codestream && search_range - && - bytestream2_get_bytes_left(&s->g) >= 8) { + while (search_range + && + bytestream2_get_bytes_left(&s->g) >= 8) { atom_size = bytestream2_get_be32u(&s->g); atom = bytestream2_get_be32u(&s->g); - if (atom == JP2_CODESTREAM) { - found_codestream = 1; + atom_end = bytestream2_tell(&s->g) + atom_size - 8; + + if (atom == JP2_CODESTREAM) + return 1; + + if (bytestream2_get_bytes_left(&s->g) < atom_size || atom_end < atom_size) + return 0; + + if (atom == JP2_HEADER && + atom_size >= 16) { + uint32_t atom2_size, atom2, atom2_end; + do { + atom2_size = bytestream2_get_be32u(&s->g); + atom2 = bytestream2_get_be32u(&s->g); + atom2_end = bytestream2_tell(&s->g) + atom2_size - 8; + if (atom2_size < 8 || atom2_end > atom_end || atom2_end < atom2_size) + break; + if (atom2 == JP2_CODESTREAM) { + return 1; + } else if (atom2 == MKBETAG('c','o','l','r') && atom2_size >= 7) { + int method = bytestream2_get_byteu(&s->g); + bytestream2_skipu(&s->g, 2); + if (method == 1) { + s->colour_space = bytestream2_get_be32u(&s->g); + } + } 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 + colour_depth[0] = (bytestream2_get_byteu(&s->g) & 0x7f) + 1; + colour_depth[1] = (bytestream2_get_byteu(&s->g) & 0x7f) + 1; + colour_depth[2] = (bytestream2_get_byteu(&s->g) & 0x7f) + 1; + 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 || + colour_channels != 3 || + colour_depth[0] > 16 || + colour_depth[1] > 16 || + colour_depth[2] > 16 || + atom2_size < size) { + avpriv_request_sample(s->avctx, "Unknown palette"); + bytestream2_seek(&s->g, atom2_end, SEEK_SET); + continue; + } + s->pal8 = 1; + for (i = 0; i < colour_count; i++) { + if (colour_depth[0] <= 8) { + r = bytestream2_get_byteu(&s->g) << 8 - colour_depth[0]; + r |= r >> colour_depth[0]; + } else { + r = bytestream2_get_be16u(&s->g) >> colour_depth[0] - 8; + } + if (colour_depth[1] <= 8) { + g = bytestream2_get_byteu(&s->g) << 8 - colour_depth[1]; + r |= r >> colour_depth[1]; + } else { + g = bytestream2_get_be16u(&s->g) >> colour_depth[1] - 8; + } + if (colour_depth[2] <= 8) { + b = bytestream2_get_byteu(&s->g) << 8 - colour_depth[2]; + r |= r >> colour_depth[2]; + } else { + b = bytestream2_get_be16u(&s->g) >> colour_depth[2] - 8; + } + s->palette[i] = 0xffu << 24 | r << 16 | g << 8 | b; + } + } else if (atom2 == MKBETAG('c','d','e','f') && atom2_size >= 2) { + int n = bytestream2_get_be16u(&s->g); + for (; n>0; n--) { + int cn = bytestream2_get_be16(&s->g); + int av_unused typ = bytestream2_get_be16(&s->g); + int asoc = bytestream2_get_be16(&s->g); + if (cn < 4 || asoc < 4) + s->cdef[cn] = asoc; + } + } + bytestream2_seek(&s->g, atom2_end, SEEK_SET); + } while (atom_end - atom2_end >= 8); } else { - if (bytestream2_get_bytes_left(&s->g) < atom_size - 8) - return 0; - bytestream2_skipu(&s->g, atom_size - 8); search_range--; } + bytestream2_seek(&s->g, atom_end, SEEK_SET); } - if (found_codestream) - return 1; return 0; } @@ -1379,7 +1593,8 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data, s->avctx = avctx; bytestream2_init(&s->g, avpkt->data, avpkt->size); - s->curtileno = 0; // TODO: only one tile in DCI JP2K. to implement for more tiles + s->curtileno = -1; + memset(s->cdef, -1, sizeof(s->cdef)); if (bytestream2_get_bytes_left(&s->g) < 2) { ret = AVERROR_INVALIDDATA; @@ -1401,6 +1616,9 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data, bytestream2_seek(&s->g, 0, SEEK_SET); } + while (bytestream2_get_bytes_left(&s->g) >= 3 && bytestream2_peek_be16(&s->g) != JPEG2000_SOC) + bytestream2_skip(&s->g, 1); + if (bytestream2_get_be16u(&s->g) != JPEG2000_SOC) { av_log(avctx, AV_LOG_ERROR, "SOC marker not present\n"); ret = AVERROR_INVALIDDATA; @@ -1410,15 +1628,14 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data, goto end; /* get picture buffer */ - if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) { - av_log(avctx, AV_LOG_ERROR, "ff_thread_get_buffer() failed.\n"); + if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) goto end; - } picture->pict_type = AV_PICTURE_TYPE_I; picture->key_frame = 1; if (ret = jpeg2000_read_bitstream_packets(s)) goto end; + for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++) if (ret = jpeg2000_decode_tile(s, s->tile + tileno, picture)) goto end; @@ -1427,6 +1644,9 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data, *got_frame = 1; + if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8) + memcpy(picture->data[1], s->palette, 256 * sizeof(uint32_t)); + return bytestream2_tell(&s->g); end: @@ -1458,7 +1678,7 @@ static const AVProfile profiles[] = { { FF_PROFILE_UNKNOWN }, }; -static const AVClass class = { +static const AVClass jpeg2000_class = { .class_name = "jpeg2000", .item_name = av_default_item_name, .option = options, @@ -1475,6 +1695,7 @@ AVCodec ff_jpeg2000_decoder = { .init_static_data = jpeg2000_init_static_data, .init = jpeg2000_decode_init, .decode = jpeg2000_decode_frame, - .priv_class = &class, + .priv_class = &jpeg2000_class, + .max_lowres = 5, .profiles = NULL_IF_CONFIG_SMALL(profiles) }; |