From 8cf57efdd7846cce9467e68f6c16abf6d9b4fea2 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Mon, 27 May 2013 22:55:14 +0200 Subject: [PATCH] j2k/jpeg2000: merge lowres code This also fixes lowres use with ffplay Signed-off-by: Michael Niedermayer --- libavcodec/j2k.c | 8 +++--- libavcodec/j2k.h | 4 ++- libavcodec/j2kdec.c | 57 +++++++++++++++++++++++++++++++++------- libavcodec/j2kenc.c | 11 ++++---- libavcodec/jpeg2000dec.c | 11 ++++---- 5 files changed, 66 insertions(+), 25 deletions(-) diff --git a/libavcodec/j2k.c b/libavcodec/j2k.c index e352c4a02e..2a86dcedd4 100644 --- a/libavcodec/j2k.c +++ b/libavcodec/j2k.c @@ -184,7 +184,7 @@ int ff_j2k_init_component(Jpeg2000Component *comp, uint8_t log2_band_prec_width, log2_band_prec_height; int reslevelno, bandno, gbandno = 0, ret, i, j, csize = 1; - if (ret=ff_jpeg2000_dwt_init(&comp->dwt, comp->coord, codsty->nreslevels-1, codsty->transform == FF_DWT53 ? FF_DWT53 : FF_DWT97_INT)) + if (ret=ff_jpeg2000_dwt_init(&comp->dwt, comp->coord, codsty->nreslevels2decode-1, codsty->transform == FF_DWT53 ? FF_DWT53 : FF_DWT97_INT)) return ret; for (i = 0; i < 2; i++) csize *= comp->coord[i][1] - comp->coord[i][0]; @@ -206,7 +206,7 @@ int ff_j2k_init_component(Jpeg2000Component *comp, for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) reslevel->coord[i][j] = - ff_jpeg2000_ceildivpow2(comp->coord[i][j], declvl - 1); + ff_jpeg2000_ceildivpow2(comp->coord_o[i][j], declvl - 1); // update precincts size: 2^n value reslevel->log2_prec_width = codsty->log2_prec_widths[reslevelno]; reslevel->log2_prec_height = codsty->log2_prec_heights[reslevelno]; @@ -300,7 +300,7 @@ int ff_j2k_init_component(Jpeg2000Component *comp, for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) band->coord[i][j] = - ff_jpeg2000_ceildivpow2(comp->coord[i][j] - comp->coord[i][0], + ff_jpeg2000_ceildivpow2(comp->coord_o[i][j] - comp->coord_o[i][0], declvl - 1); log2_band_prec_width = reslevel->log2_prec_width; log2_band_prec_height = reslevel->log2_prec_height; @@ -316,7 +316,7 @@ int ff_j2k_init_component(Jpeg2000Component *comp, for (j = 0; j < 2; j++) /* Formula example for tbx_0 = ceildiv((tcx_0 - 2 ^ (declvl - 1) * x0_b) / declvl) */ band->coord[i][j] = - ff_jpeg2000_ceildivpow2(comp->coord[i][j] - comp->coord[i][0] - + ff_jpeg2000_ceildivpow2(comp->coord_o[i][j] - comp->coord_o[i][0] - (((bandno + 1 >> i) & 1) << declvl - 1), declvl); /* TODO: Manage case of 3 band offsets here or diff --git a/libavcodec/j2k.h b/libavcodec/j2k.h index d5742e19e0..aacd006a1d 100644 --- a/libavcodec/j2k.h +++ b/libavcodec/j2k.h @@ -129,6 +129,7 @@ typedef struct Jpeg2000TgtNode { typedef struct Jpeg2000CodingStyle { uint8_t nreslevels; // number of resolution levels + uint8_t nreslevels2decode; // number of resolution levels to decode uint8_t log2_cblk_width, log2_cblk_height; // exponent of codeblock size uint8_t transform; // DWT type @@ -194,7 +195,8 @@ typedef struct Jpeg2000Component { Jpeg2000ResLevel *reslevel; DWTContext dwt; int *data; - uint16_t coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} + uint16_t coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} -- can be reduced with lowres option + uint16_t coord_o[2][2]; // border coordinates {{x0, x1}, {y0, y1}} -- original values from jpeg2000 headers } Jpeg2000Component; /* misc tools */ diff --git a/libavcodec/j2kdec.c b/libavcodec/j2kdec.c index 28c5f1c6d4..40afced32f 100644 --- a/libavcodec/j2kdec.c +++ b/libavcodec/j2kdec.c @@ -26,12 +26,13 @@ * @author Kamil Nowosad */ +#include "libavutil/common.h" +#include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" #include "internal.h" #include "thread.h" #include "j2k.h" -#include "libavutil/common.h" #define JP2_SIG_TYPE 0x6A502020 #define JP2_SIG_VALUE 0x0D0A870A @@ -74,6 +75,10 @@ typedef struct Jpeg2000DecoderContext { int curtileno; Jpeg2000Tile *tile; + + /*options parameters*/ + int lowres; + int reduction_factor; } Jpeg2000DecoderContext; static int get_bits(Jpeg2000DecoderContext *s, int n) @@ -198,9 +203,11 @@ static int get_siz(Jpeg2000DecoderContext *s) return AVERROR(ENOMEM); } - s->avctx->width = s->width - s->image_offset_x; - s->avctx->height = s->height - s->image_offset_y; - + /* compute image size with reduction factor */ + s->avctx->width = ff_jpeg2000_ceildivpow2(s->width - s->image_offset_x, + s->reduction_factor); + s->avctx->height = ff_jpeg2000_ceildivpow2(s->height - s->image_offset_y, + s->reduction_factor); switch(s->ncomponents) { case 1: if (s->precision > 8) { @@ -244,6 +251,12 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) return AVERROR_INVALIDDATA; } + /* 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->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 @@ -434,10 +447,15 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno) Jpeg2000QuantStyle *qntsty = tile->qntsty + compno; int ret; // global bandno - comp->coord[0][0] = FFMAX(tilex * s->tile_width + s->tile_offset_x, s->image_offset_x); - comp->coord[0][1] = FFMIN((tilex+1)*s->tile_width + s->tile_offset_x, s->width); - comp->coord[1][0] = FFMAX(tiley * s->tile_height + s->tile_offset_y, s->image_offset_y); - comp->coord[1][1] = FFMIN((tiley+1)*s->tile_height + s->tile_offset_y, s->height); + comp->coord_o[0][0] = FFMAX(tilex * s->tile_width + s->tile_offset_x, s->image_offset_x); + comp->coord_o[0][1] = FFMIN((tilex + 1) * s->tile_width + s->tile_offset_x, s->width); + comp->coord_o[1][0] = FFMAX(tiley * s->tile_height + s->tile_offset_y, s->image_offset_y); + comp->coord_o[1][1] = FFMIN((tiley + 1) * s->tile_height + s->tile_offset_y, s->height); + + comp->coord[0][0] = ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], s->reduction_factor); + comp->coord[0][1] = ff_jpeg2000_ceildivpow2(comp->coord_o[0][1], s->reduction_factor); + comp->coord[1][0] = ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], s->reduction_factor); + comp->coord[1][1] = ff_jpeg2000_ceildivpow2(comp->coord_o[1][1], s->reduction_factor); if (ret = ff_j2k_init_component(comp, codsty, qntsty, s->cbps[compno], s->cdx[compno], s->cdy[compno], s->avctx)) return ret; @@ -785,7 +803,7 @@ static int decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile) Jpeg2000CodingStyle *codsty = tile->codsty + compno; /* Loop on resolution levels */ - for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++) { + for (reslevelno = 0; reslevelno < codsty->nreslevels2decode; reslevelno++) { Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno; /* Loop on bands */ for (bandno = 0; bandno < rlevel->nbands; bandno++) { @@ -1025,6 +1043,9 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data, bytestream2_init(&s->g, avpkt->data, avpkt->size); s->curtileno = -1; + // reduction factor, i.e number of resolution levels to skip + s->reduction_factor = avctx->lowres; + if (bytestream2_get_bytes_left(&s->g) < 2) { ret = AVERROR(EINVAL); goto err_out; @@ -1072,6 +1093,15 @@ static void jpeg2000_init_static_data(AVCodec *codec) ff_jpeg2000_init_tier1_luts(); } +#define OFFSET(x) offsetof(Jpeg2000DecoderContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM + +static const AVOption options[] = { + { "lowres", "Lower the decoding resolution by a power of two", + OFFSET(lowres), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, JPEG2000_MAX_RESLEVELS - 1, VD }, + { NULL }, +}; + static const AVProfile profiles[] = { { FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0, "JPEG 2000 codestream restriction 0" }, { FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1, "JPEG 2000 codestream restriction 1" }, @@ -1081,6 +1111,13 @@ static const AVProfile profiles[] = { { FF_PROFILE_UNKNOWN }, }; +static const AVClass class = { + .class_name = "j2k", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_j2k_decoder = { .name = "j2k", .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"), @@ -1090,5 +1127,7 @@ AVCodec ff_j2k_decoder = { .priv_data_size = sizeof(Jpeg2000DecoderContext), .init_static_data = jpeg2000_init_static_data, .decode = jpeg2000_decode_frame, + .priv_class = &class, + .max_lowres = 5, .profiles = NULL_IF_CONFIG_SMALL(profiles) }; diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 528b9a7f16..da5085694a 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -357,14 +357,14 @@ static int init_tiles(Jpeg2000EncoderContext *s) Jpeg2000Component *comp = tile->comp + compno; int ret, i, j; - comp->coord[0][0] = tilex * s->tile_width; - comp->coord[0][1] = FFMIN((tilex+1)*s->tile_width, s->width); - comp->coord[1][0] = tiley * s->tile_height; - comp->coord[1][1] = FFMIN((tiley+1)*s->tile_height, s->height); + comp->coord[0][0] = comp->coord_o[0][0] = tilex * s->tile_width; + comp->coord[0][1] = comp->coord_o[0][1] = FFMIN((tilex+1)*s->tile_width, s->width); + comp->coord[1][0] = comp->coord_o[1][0] = tiley * s->tile_height; + comp->coord[1][1] = comp->coord_o[1][1] = FFMIN((tiley+1)*s->tile_height, s->height); if (compno > 0) for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) - comp->coord[i][j] = ff_jpeg2000_ceildivpow2(comp->coord[i][j], s->chroma_shift[i]); + comp->coord[i][j] = comp->coord_o[i][j] = ff_jpeg2000_ceildivpow2(comp->coord[i][j], s->chroma_shift[i]); if (ret = ff_j2k_init_component(comp, codsty, @@ -982,6 +982,7 @@ static av_cold int j2kenc_init(AVCodecContext *avctx) // TODO: implement setting non-standard precinct size memset(codsty->log2_prec_widths , 15, sizeof(codsty->log2_prec_widths )); memset(codsty->log2_prec_heights, 15, sizeof(codsty->log2_prec_heights)); + codsty->nreslevels2decode= codsty->nreslevels = 7; codsty->log2_cblk_width = 4; codsty->log2_cblk_height = 4; diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 68312a083e..3b0bf65ca9 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -543,12 +543,10 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno) comp->coord_o[1][0] = FFMAX(tiley * s->tile_height + s->tile_offset_y, s->image_offset_y); comp->coord_o[1][1] = FFMIN((tiley + 1) * s->tile_height + s->tile_offset_y, s->height); - // FIXME: add a dcinema profile check ? - // value is guaranteed by profile (orig=0, 1 tile) - comp->coord[0][0] = 0; - comp->coord[0][1] = s->avctx->width; - comp->coord[1][0] = 0; - comp->coord[1][1] = s->avctx->height; + comp->coord[0][0] = ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], s->reduction_factor); + comp->coord[0][1] = ff_jpeg2000_ceildivpow2(comp->coord_o[0][1], s->reduction_factor); + comp->coord[1][0] = ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], s->reduction_factor); + comp->coord[1][1] = ff_jpeg2000_ceildivpow2(comp->coord_o[1][1], s->reduction_factor); if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty, s->cbps[compno], s->cdx[compno], @@ -1369,5 +1367,6 @@ AVCodec ff_jpeg2000_decoder = { .pix_fmts = (enum AVPixelFormat[]) { AV_PIX_FMT_XYZ12, AV_PIX_FMT_GRAY8, -1 }, + .max_lowres = 5, .profiles = NULL_IF_CONFIG_SMALL(profiles) };