diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index d9b9888382..7f94cad4a9 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -28,6 +28,7 @@ #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" @@ -37,6 +38,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 @@ -72,6 +74,9 @@ typedef struct Jpeg2000DecoderContext { int cdx[4], cdy[4]; int precision; int ncomponents; + int colour_space; + uint32_t palette[256]; + int8_t pal8; int tile_width, tile_height; unsigned numXtiles, numYtiles; int maxtilelen; @@ -154,12 +159,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 +#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; @@ -205,13 +272,7 @@ 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; - } + 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); @@ -242,35 +303,46 @@ 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 (s->avctx->pix_fmt == AV_PIX_FMT_NONE) { + 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 0; } @@ -1386,6 +1458,89 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) atom = bytestream2_get_be32u(&s->g); if (atom == JP2_CODESTREAM) { found_codestream = 1; + } else if (atom == JP2_HEADER && + bytestream2_get_bytes_left(&s->g) >= atom_size && + atom_size >= 16) { + uint32_t atom2_size, atom2; + atom_size -= 8; + do { + atom2_size = bytestream2_get_be32u(&s->g); + atom2 = bytestream2_get_be32u(&s->g); + atom_size -= 8; + if (atom2_size < 8 || atom2_size - 8 > atom_size) + break; + atom2_size -= 8; + 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); + atom_size -= 3; + atom2_size -= 3; + if (method == 1) { + s->colour_space = bytestream2_get_be32u(&s->g); + atom_size -= 4; + atom2_size -= 4; + } + bytestream2_skipu(&s->g, atom2_size); + atom_size -= atom2_size; + } 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; + atom_size -= 6; + atom2_size -= 6; + 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_skipu(&s->g, atom2_size); + atom_size -= atom2_size; + 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; + } + atom_size -= size; + atom2_size -= size; + bytestream2_skipu(&s->g, atom2_size); + atom_size -= atom2_size; + } else { + bytestream2_skipu(&s->g, atom2_size); + atom_size -= atom2_size; + } + } while (atom_size >= 8); + bytestream2_skipu(&s->g, atom_size); } else { if (bytestream2_get_bytes_left(&s->g) < atom_size - 8) return 0; @@ -1456,6 +1611,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: