X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fj2kenc.c;h=c51adadd137db457e0460264372fc297cde7ce3c;hb=a247ac640df3da573cd661065bf53f37863e2b46;hp=e91d932bb7f24834b2dc09887a01b5b6b37b831f;hpb=14fe81b3a88dfe4dbac12e8715f9a3f05b5ef1bf;p=ffmpeg diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index e91d932bb7f..c51adadd137 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -32,6 +32,7 @@ * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2007, Callum Lerwick + * Copyright (c) 2020, Gautam Ramakrishnan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,6 +73,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" +#include "libavutil/avstring.h" #define NMSEDEC_BITS 7 #define NMSEDEC_FRACBITS (NMSEDEC_BITS-1) @@ -100,6 +102,7 @@ static const int dwt_norms[2][4][10] = { // [dwt_type][band][rlevel] (multiplied typedef struct { Jpeg2000Component *comp; + double *layer_rates; } Jpeg2000Tile; typedef struct { @@ -126,9 +129,16 @@ typedef struct { Jpeg2000QuantStyle qntsty; Jpeg2000Tile *tile; + int layer_rates[100]; + uint8_t compression_rate_enc; ///< Is compression done using compression ratio? int format; int pred; + int sop; + int eph; + int prog; + int nlayers; + char *lr_str; } Jpeg2000EncoderContext; @@ -239,27 +249,36 @@ static void j2k_flush(Jpeg2000EncoderContext *s) static void tag_tree_code(Jpeg2000EncoderContext *s, Jpeg2000TgtNode *node, int threshold) { Jpeg2000TgtNode *stack[30]; - int sp = 1, curval = 0; - stack[0] = node; + int sp = -1, curval = 0; - node = node->parent; - while(node){ - if (node->vis){ - curval = node->val; - break; - } - node->vis++; - stack[sp++] = node; + while(node->parent){ + stack[++sp] = node; node = node->parent; } - while(--sp >= 0){ - if (stack[sp]->val >= threshold){ + + while (1) { + if (curval > node->temp_val) + node->temp_val = curval; + else { + curval = node->temp_val; + } + + if (node->val >= threshold) { put_bits(s, 0, threshold - curval); - break; + curval = threshold; + } else { + put_bits(s, 0, node->val - curval); + curval = node->val; + if (!node->vis) { + put_bits(s, 1, 1); + node->vis = 1; + } } - put_bits(s, 0, stack[sp]->val - curval); - put_bits(s, 1, 1); - curval = stack[sp]->val; + + node->temp_val = curval; + if (sp < 0) + break; + node = stack[sp--]; } } @@ -298,7 +317,7 @@ static int put_siz(Jpeg2000EncoderContext *s) bytestream_put_be16(&s->buf, s->ncomponents); // CSiz for (i = 0; i < s->ncomponents; i++){ // Ssiz_i XRsiz_i, YRsiz_i - bytestream_put_byte(&s->buf, 7); + bytestream_put_byte(&s->buf, s->cbps[i] - 1); bytestream_put_byte(&s->buf, i?1<chroma_shift[0]:1); bytestream_put_byte(&s->buf, i?1<chroma_shift[1]:1); } @@ -308,16 +327,21 @@ static int put_siz(Jpeg2000EncoderContext *s) static int put_cod(Jpeg2000EncoderContext *s) { Jpeg2000CodingStyle *codsty = &s->codsty; + uint8_t scod = 0; if (s->buf_end - s->buf < 14) return -1; bytestream_put_be16(&s->buf, JPEG2000_COD); bytestream_put_be16(&s->buf, 12); // Lcod - bytestream_put_byte(&s->buf, 0); // Scod + if (s->sop) + scod |= JPEG2000_CSTY_SOP; + if (s->eph) + scod |= JPEG2000_CSTY_EPH; + bytestream_put_byte(&s->buf, scod); // Scod // SGcod - bytestream_put_byte(&s->buf, 0); // progression level - bytestream_put_be16(&s->buf, 1); // num of layers + bytestream_put_byte(&s->buf, s->prog); // progression level + bytestream_put_be16(&s->buf, s->nlayers); // num of layers if(s->avctx->pix_fmt == AV_PIX_FMT_YUV444P){ bytestream_put_byte(&s->buf, 0); // unspecified }else{ @@ -396,6 +420,31 @@ static uint8_t *put_sot(Jpeg2000EncoderContext *s, int tileno) return psotptr; } +static void compute_rates(Jpeg2000EncoderContext* s) +{ + int i, j; + int layno, compno; + for (i = 0; i < s->numYtiles; i++) { + for (j = 0; j < s->numXtiles; j++) { + Jpeg2000Tile *tile = &s->tile[s->numXtiles * i + j]; + for (compno = 0; compno < s->ncomponents; compno++) { + int tilew = tile->comp[compno].coord[0][1] - tile->comp[compno].coord[0][0]; + int tileh = tile->comp[compno].coord[1][1] - tile->comp[compno].coord[1][0]; + int scale = (compno?1 << s->chroma_shift[0]:1) * (compno?1 << s->chroma_shift[1]:1); + for (layno = 0; layno < s->nlayers; layno++) { + if (s->layer_rates[layno] > 0) { + tile->layer_rates[layno] += (double)(tilew * tileh) * s->ncomponents * s->cbps[compno] / + (double)(s->layer_rates[layno] * 8 * scale); + } else { + tile->layer_rates[layno] = 0.0; + } + } + } + } + } + +} + /** * compute the sizes of tiles, resolution levels, bands, etc. * allocate memory for them @@ -410,7 +459,7 @@ static int init_tiles(Jpeg2000EncoderContext *s) s->numXtiles = ff_jpeg2000_ceildiv(s->width, s->tile_width); s->numYtiles = ff_jpeg2000_ceildiv(s->height, s->tile_height); - s->tile = av_malloc_array(s->numXtiles, s->numYtiles * sizeof(Jpeg2000Tile)); + s->tile = av_calloc(s->numXtiles, s->numYtiles * sizeof(Jpeg2000Tile)); if (!s->tile) return AVERROR(ENOMEM); for (tileno = 0, tiley = 0; tiley < s->numYtiles; tiley++) @@ -420,6 +469,11 @@ static int init_tiles(Jpeg2000EncoderContext *s) tile->comp = av_mallocz_array(s->ncomponents, sizeof(Jpeg2000Component)); if (!tile->comp) return AVERROR(ENOMEM); + + tile->layer_rates = av_mallocz_array(s->nlayers, sizeof(*tile->layer_rates)); + if (!tile->layer_rates) + return AVERROR(ENOMEM); + for (compno = 0; compno < s->ncomponents; compno++){ Jpeg2000Component *comp = tile->comp + compno; int ret, i, j; @@ -444,46 +498,53 @@ static int init_tiles(Jpeg2000EncoderContext *s) return ret; } } + compute_rates(s); return 0; } -static void copy_frame(Jpeg2000EncoderContext *s) -{ - int tileno, compno, i, y, x; - uint8_t *line; - for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){ - Jpeg2000Tile *tile = s->tile + tileno; - if (s->planar){ - for (compno = 0; compno < s->ncomponents; compno++){ - Jpeg2000Component *comp = tile->comp + compno; - int *dst = comp->i_data; - line = s->picture->data[compno] - + comp->coord[1][0] * s->picture->linesize[compno] - + comp->coord[0][0]; - for (y = comp->coord[1][0]; y < comp->coord[1][1]; y++){ - uint8_t *ptr = line; - for (x = comp->coord[0][0]; x < comp->coord[0][1]; x++) - *dst++ = *ptr++ - (1 << 7); - line += s->picture->linesize[compno]; - } - } - } else{ - line = s->picture->data[0] + tile->comp[0].coord[1][0] * s->picture->linesize[0] - + tile->comp[0].coord[0][0] * s->ncomponents; - - i = 0; - for (y = tile->comp[0].coord[1][0]; y < tile->comp[0].coord[1][1]; y++){ - uint8_t *ptr = line; - for (x = tile->comp[0].coord[0][0]; x < tile->comp[0].coord[0][1]; x++, i++){ - for (compno = 0; compno < s->ncomponents; compno++){ - tile->comp[compno].i_data[i] = *ptr++ - (1 << 7); - } - } - line += s->picture->linesize[0]; - } - } +#define COPY_FRAME(D, PIXEL) \ + static void copy_frame_ ##D(Jpeg2000EncoderContext *s) \ + { \ + int tileno, compno, i, y, x; \ + PIXEL *line; \ + for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){ \ + Jpeg2000Tile *tile = s->tile + tileno; \ + if (s->planar){ \ + for (compno = 0; compno < s->ncomponents; compno++){ \ + Jpeg2000Component *comp = tile->comp + compno; \ + int *dst = comp->i_data; \ + int cbps = s->cbps[compno]; \ + line = (PIXEL*)s->picture->data[compno] \ + + comp->coord[1][0] * (s->picture->linesize[compno] / sizeof(PIXEL)) \ + + comp->coord[0][0]; \ + for (y = comp->coord[1][0]; y < comp->coord[1][1]; y++){ \ + PIXEL *ptr = line; \ + for (x = comp->coord[0][0]; x < comp->coord[0][1]; x++) \ + *dst++ = *ptr++ - (1 << (cbps - 1)); \ + line += s->picture->linesize[compno] / sizeof(PIXEL); \ + } \ + } \ + } else{ \ + line = (PIXEL*)s->picture->data[0] + tile->comp[0].coord[1][0] * (s->picture->linesize[0] / sizeof(PIXEL)) \ + + tile->comp[0].coord[0][0] * s->ncomponents; \ + \ + i = 0; \ + for (y = tile->comp[0].coord[1][0]; y < tile->comp[0].coord[1][1]; y++){ \ + PIXEL *ptr = line; \ + for (x = tile->comp[0].coord[0][0]; x < tile->comp[0].coord[0][1]; x++, i++){ \ + for (compno = 0; compno < s->ncomponents; compno++){ \ + int cbps = s->cbps[compno]; \ + tile->comp[compno].i_data[i] = *ptr++ - (1 << (cbps - 1)); \ + } \ + } \ + line += s->picture->linesize[0] / sizeof(PIXEL); \ + } \ + } \ + } \ } -} + +COPY_FRAME(8, uint8_t) +COPY_FRAME(16, uint16_t) static void init_quantization(Jpeg2000EncoderContext *s) { @@ -521,13 +582,13 @@ static void init_luts(void) mask = ~((1<> (NMSEDEC_BITS-2)&2) + 1; - lut_nmsedec_ref[i] = FFMAX((-2*i + (1<passes[passno].rate = ff_mqc_flush_to(&t1->mqc, cblk->passes[passno].flushed, &cblk->passes[passno].flushed_len); + cblk->passes[passno].rate -= cblk->passes[passno].flushed_len; + wmsedec += (int64_t)nmsedec << (2*bpno); cblk->passes[passno].disto = wmsedec; @@ -691,8 +754,10 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20 cblk->npasses = passno; cblk->ninclpasses = passno; - if (passno) + if (passno) { cblk->passes[passno-1].rate = ff_mqc_flush_to(&t1->mqc, cblk->passes[passno-1].flushed, &cblk->passes[passno-1].flushed_len); + cblk->passes[passno-1].rate -= cblk->passes[passno-1].flushed_len; + } } /* tier-2 routines: */ @@ -712,33 +777,82 @@ static void putnumpasses(Jpeg2000EncoderContext *s, int n) } -static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, int precno, - uint8_t *expn, int numgbits) +static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, int layno, + int precno, uint8_t *expn, int numgbits, int packetno, + int nlayers) { int bandno, empty = 1; - + int i; // init bitstream *s->buf = 0; s->bit_index = 0; + if (s->sop) { + bytestream_put_be16(&s->buf, JPEG2000_SOP); + bytestream_put_be16(&s->buf, 4); + bytestream_put_be16(&s->buf, packetno); + } // header + if (!layno) { + for (bandno = 0; bandno < rlevel->nbands; bandno++) { + Jpeg2000Band *band = rlevel->band + bandno; + if (band->coord[0][0] < band->coord[0][1] + && band->coord[1][0] < band->coord[1][1]) { + Jpeg2000Prec *prec = band->prec + precno; + int nb_cblks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; + int pos; + ff_tag_tree_zero(prec->zerobits, prec->nb_codeblocks_width, prec->nb_codeblocks_height, 99); + ff_tag_tree_zero(prec->cblkincl, prec->nb_codeblocks_width, prec->nb_codeblocks_height, 99); + for (pos = 0; pos < nb_cblks; pos++) { + Jpeg2000Cblk *cblk = &prec->cblk[pos]; + prec->zerobits[pos].val = expn[bandno] + numgbits - 1 - cblk->nonzerobits; + cblk->incl = 0; + cblk->lblock = 3; + tag_tree_update(prec->zerobits + pos); + for (i = 0; i < nlayers; i++) { + if (cblk->layers[i].npasses > 0) { + prec->cblkincl[pos].val = i; + break; + } + } + if (i == nlayers) + prec->cblkincl[pos].val = i; + tag_tree_update(prec->cblkincl + pos); + } + } + } + } + // is the packet empty? for (bandno = 0; bandno < rlevel->nbands; bandno++){ - if (rlevel->band[bandno].coord[0][0] < rlevel->band[bandno].coord[0][1] - && rlevel->band[bandno].coord[1][0] < rlevel->band[bandno].coord[1][1]){ - empty = 0; - break; + Jpeg2000Band *band = rlevel->band + bandno; + if (band->coord[0][0] < band->coord[0][1] + && band->coord[1][0] < band->coord[1][1]) { + Jpeg2000Prec *prec = band->prec + precno; + int nb_cblks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; + int pos; + for (pos = 0; pos < nb_cblks; pos++) { + Jpeg2000Cblk *cblk = &prec->cblk[pos]; + if (cblk->layers[layno].npasses) { + empty = 0; + break; + } + } + if (!empty) + break; } } put_bits(s, !empty, 1); if (empty){ j2k_flush(s); + if (s->eph) + bytestream_put_be16(&s->buf, JPEG2000_EPH); return 0; } - for (bandno = 0; bandno < rlevel->nbands; bandno++){ + for (bandno = 0; bandno < rlevel->nbands; bandno++) { Jpeg2000Band *band = rlevel->band + bandno; Jpeg2000Prec *prec = band->prec + precno; int yi, xi, pos; @@ -748,61 +862,70 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in || band->coord[1][0] == band->coord[1][1]) continue; - for (pos=0, yi = 0; yi < prec->nb_codeblocks_height; yi++){ - for (xi = 0; xi < cblknw; xi++, pos++){ - prec->cblkincl[pos].val = prec->cblk[yi * cblknw + xi].ninclpasses == 0; - tag_tree_update(prec->cblkincl + pos); - prec->zerobits[pos].val = expn[bandno] + numgbits - 1 - prec->cblk[yi * cblknw + xi].nonzerobits; - tag_tree_update(prec->zerobits + pos); - } - } - - for (pos=0, yi = 0; yi < prec->nb_codeblocks_height; yi++){ + for (pos=0, yi = 0; yi < prec->nb_codeblocks_height; yi++) { for (xi = 0; xi < cblknw; xi++, pos++){ - int pad = 0, llen, length; + int llen = 0, length; Jpeg2000Cblk *cblk = prec->cblk + yi * cblknw + xi; if (s->buf_end - s->buf < 20) // approximately return -1; // inclusion information - tag_tree_code(s, prec->cblkincl + pos, 1); - if (!cblk->ninclpasses) + if (!cblk->incl) + tag_tree_code(s, prec->cblkincl + pos, layno + 1); + else { + put_bits(s, cblk->layers[layno].npasses > 0, 1); + } + + if (!cblk->layers[layno].npasses) continue; + // zerobits information - tag_tree_code(s, prec->zerobits + pos, 100); + if (!cblk->incl) { + tag_tree_code(s, prec->zerobits + pos, 100); + cblk->incl = 1; + } + // number of passes - putnumpasses(s, cblk->ninclpasses); + putnumpasses(s, cblk->layers[layno].npasses); - length = cblk->passes[cblk->ninclpasses-1].rate; - llen = av_log2(length) - av_log2(cblk->ninclpasses) - 2; - if (llen < 0){ - pad = -llen; - llen = 0; + length = cblk->layers[layno].data_len; + if (layno == nlayers - 1 && cblk->layers[layno].cum_passes){ + length += cblk->passes[cblk->layers[layno].cum_passes-1].flushed_len; + } + if (cblk->lblock + av_log2(cblk->layers[layno].npasses) < av_log2(length) + 1) { + llen = av_log2(length) + 1 - cblk->lblock - av_log2(cblk->layers[layno].npasses); } + // length of code block + cblk->lblock += llen; put_bits(s, 1, llen); put_bits(s, 0, 1); - put_num(s, length, av_log2(length)+1+pad); + put_num(s, length, cblk->lblock + av_log2(cblk->layers[layno].npasses)); } } } j2k_flush(s); - for (bandno = 0; bandno < rlevel->nbands; bandno++){ + if (s->eph) { + bytestream_put_be16(&s->buf, JPEG2000_EPH); + } + + for (bandno = 0; bandno < rlevel->nbands; bandno++) { Jpeg2000Band *band = rlevel->band + bandno; Jpeg2000Prec *prec = band->prec + precno; int yi, cblknw = prec->nb_codeblocks_width; - for (yi =0; yi < prec->nb_codeblocks_height; yi++){ + for (yi =0; yi < prec->nb_codeblocks_height; yi++) { int xi; for (xi = 0; xi < cblknw; xi++){ Jpeg2000Cblk *cblk = prec->cblk + yi * cblknw + xi; - if (cblk->ninclpasses){ - if (s->buf_end - s->buf < cblk->passes[cblk->ninclpasses-1].rate) + if (cblk->layers[layno].npasses) { + if (s->buf_end - s->buf < cblk->layers[layno].data_len + 2) return -1; - bytestream_put_buffer(&s->buf, cblk->data + 1, cblk->passes[cblk->ninclpasses-1].rate - - cblk->passes[cblk->ninclpasses-1].flushed_len); - bytestream_put_buffer(&s->buf, cblk->passes[cblk->ninclpasses-1].flushed, - cblk->passes[cblk->ninclpasses-1].flushed_len); + bytestream_put_buffer(&s->buf, cblk->layers[layno].data_start + 1, cblk->layers[layno].data_len); + if (layno == nlayers - 1 && cblk->layers[layno].cum_passes) { + bytestream_put_buffer(&s->buf, cblk->passes[cblk->layers[layno].cum_passes-1].flushed, + cblk->passes[cblk->layers[layno].cum_passes-1].flushed_len); + } } } } @@ -810,29 +933,420 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in return 0; } -static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno) +static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno, int nlayers) { - int compno, reslevelno, ret; + int compno, reslevelno, layno, ret; Jpeg2000CodingStyle *codsty = &s->codsty; Jpeg2000QuantStyle *qntsty = &s->qntsty; + int packetno = 0; + int step_x, step_y; + int x, y; + int tile_coord[2][2]; + int col = tileno % s->numXtiles; + int row = tileno / s->numXtiles; + + tile_coord[0][0] = col * s->tile_width; + tile_coord[0][1] = FFMIN(tile_coord[0][0] + s->tile_width, s->width); + tile_coord[1][0] = row * s->tile_height; + tile_coord[1][1] = FFMIN(tile_coord[1][0] + s->tile_height, s->height); av_log(s->avctx, AV_LOG_DEBUG, "tier2\n"); // lay-rlevel-comp-pos progression + switch (s->prog) { + case JPEG2000_PGOD_LRCP: + for (layno = 0; layno < nlayers; layno++) { + for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){ + for (compno = 0; compno < s->ncomponents; compno++){ + int precno; + Jpeg2000ResLevel *reslevel = s->tile[tileno].comp[compno].reslevel + reslevelno; + for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ + if ((ret = encode_packet(s, reslevel, layno, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), + qntsty->nguardbits, packetno++, nlayers)) < 0) + return ret; + } + } + } + } + break; + case JPEG2000_PGOD_RLCP: for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){ - for (compno = 0; compno < s->ncomponents; compno++){ - int precno; - Jpeg2000ResLevel *reslevel = s->tile[tileno].comp[compno].reslevel + reslevelno; - for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ - if ((ret = encode_packet(s, reslevel, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), - qntsty->nguardbits)) < 0) - return ret; + for (layno = 0; layno < nlayers; layno++) { + for (compno = 0; compno < s->ncomponents; compno++){ + int precno; + Jpeg2000ResLevel *reslevel = s->tile[tileno].comp[compno].reslevel + reslevelno; + for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ + if ((ret = encode_packet(s, reslevel, layno, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), + qntsty->nguardbits, packetno++, nlayers)) < 0) + return ret; + } } } } + break; + case JPEG2000_PGOD_RPCL: + for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++) { + int precno; + step_x = 30; + step_y = 30; + for (compno = 0; compno < s->ncomponents; compno++) { + Jpeg2000Component *comp = tile->comp + compno; + if (reslevelno < codsty->nreslevels) { + uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r + Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno; + step_x = FFMIN(step_x, rlevel->log2_prec_width + reducedresno); + step_y = FFMIN(step_y, rlevel->log2_prec_height + reducedresno); + } + } + + step_x = 1<ncomponents; compno++) { + Jpeg2000Component *comp = tile->comp + compno; + uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r + Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno; + int log_subsampling[2] = { compno?s->chroma_shift[0]:0, compno?s->chroma_shift[1]:0}; + unsigned prcx, prcy; + int trx0, try0; + + trx0 = ff_jpeg2000_ceildivpow2(tile_coord[0][0], log_subsampling[0] + reducedresno); + try0 = ff_jpeg2000_ceildivpow2(tile_coord[1][0], log_subsampling[1] + reducedresno); + + if (!(y % ((uint64_t)1 << (reslevel->log2_prec_height + reducedresno + log_subsampling[1])) == 0 || + (y == tile_coord[1][0] && (try0 << reducedresno) % (1U << (reducedresno + reslevel->log2_prec_height))))) + continue; + + if (!(x % ((uint64_t)1 << (reslevel->log2_prec_width + reducedresno + log_subsampling[0])) == 0 || + (x == tile_coord[0][0] && (trx0 << reducedresno) % (1U << (reducedresno + reslevel->log2_prec_width))))) + continue; + + // check if a precinct exists + prcx = ff_jpeg2000_ceildivpow2(x, log_subsampling[0] + reducedresno) >> reslevel->log2_prec_width; + prcy = ff_jpeg2000_ceildivpow2(y, log_subsampling[1] + reducedresno) >> reslevel->log2_prec_height; + prcx -= ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], reducedresno) >> reslevel->log2_prec_width; + prcy -= ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], reducedresno) >> reslevel->log2_prec_height; + precno = prcx + reslevel->num_precincts_x * prcy; + + if (prcx >= reslevel->num_precincts_x || prcy >= reslevel->num_precincts_y) { + av_log(s->avctx, AV_LOG_WARNING, "prc %d %d outside limits %d %d\n", + prcx, prcy, reslevel->num_precincts_x, reslevel->num_precincts_y); + continue; + } + for (layno = 0; layno < nlayers; layno++) { + if ((ret = encode_packet(s, reslevel, layno, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), + qntsty->nguardbits, packetno++, nlayers)) < 0) + return ret; + } + } + } + } + } + break; + case JPEG2000_PGOD_PCRL: + step_x = 32; + step_y = 32; + for (compno = 0; compno < s->ncomponents; compno++) { + Jpeg2000Component *comp = tile->comp + compno; + + for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++) { + uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r + Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno; + step_x = FFMIN(step_x, rlevel->log2_prec_width + reducedresno); + step_y = FFMIN(step_y, rlevel->log2_prec_height + reducedresno); + } + } + if (step_x >= 31 || step_y >= 31){ + avpriv_request_sample(s->avctx, "PCRL with large step"); + return AVERROR_PATCHWELCOME; + } + step_x = 1<ncomponents; compno++) { + Jpeg2000Component *comp = tile->comp + compno; + int log_subsampling[2] = { compno?s->chroma_shift[0]:0, compno?s->chroma_shift[1]:0}; + + for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++) { + unsigned prcx, prcy; + int precno; + uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r + Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno; + int trx0, try0; + + trx0 = ff_jpeg2000_ceildivpow2(tile_coord[0][0], log_subsampling[0] + reducedresno); + try0 = ff_jpeg2000_ceildivpow2(tile_coord[1][0], log_subsampling[1] + reducedresno); + + if (!(y % ((uint64_t)1 << (reslevel->log2_prec_height + reducedresno + log_subsampling[1])) == 0 || + (y == tile_coord[1][0] && (try0 << reducedresno) % (1U << (reducedresno + reslevel->log2_prec_height))))) + continue; + + if (!(x % ((uint64_t)1 << (reslevel->log2_prec_width + reducedresno + log_subsampling[0])) == 0 || + (x == tile_coord[0][0] && (trx0 << reducedresno) % (1U << (reducedresno + reslevel->log2_prec_width))))) + continue; + + // check if a precinct exists + prcx = ff_jpeg2000_ceildivpow2(x, log_subsampling[0] + reducedresno) >> reslevel->log2_prec_width; + prcy = ff_jpeg2000_ceildivpow2(y, log_subsampling[1] + reducedresno) >> reslevel->log2_prec_height; + prcx -= ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], reducedresno) >> reslevel->log2_prec_width; + prcy -= ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], reducedresno) >> reslevel->log2_prec_height; + + precno = prcx + reslevel->num_precincts_x * prcy; + + if (prcx >= reslevel->num_precincts_x || prcy >= reslevel->num_precincts_y) { + av_log(s->avctx, AV_LOG_WARNING, "prc %d %d outside limits %d %d\n", + prcx, prcy, reslevel->num_precincts_x, reslevel->num_precincts_y); + continue; + } + for (layno = 0; layno < nlayers; layno++) { + if ((ret = encode_packet(s, reslevel, layno, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), + qntsty->nguardbits, packetno++, nlayers)) < 0) + return ret; + } + } + } + } + } + break; + case JPEG2000_PGOD_CPRL: + for (compno = 0; compno < s->ncomponents; compno++) { + Jpeg2000Component *comp = tile->comp + compno; + int log_subsampling[2] = { compno?s->chroma_shift[0]:0, compno?s->chroma_shift[1]:0}; + step_x = 32; + step_y = 32; + + for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++) { + uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r + Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno; + step_x = FFMIN(step_x, rlevel->log2_prec_width + reducedresno); + step_y = FFMIN(step_y, rlevel->log2_prec_height + reducedresno); + } + if (step_x >= 31 || step_y >= 31){ + avpriv_request_sample(s->avctx, "CPRL with large step"); + return AVERROR_PATCHWELCOME; + } + step_x = 1<nreslevels; reslevelno++) { + unsigned prcx, prcy; + int precno; + int trx0, try0; + uint8_t reducedresno = codsty->nreslevels - 1 -reslevelno; // ==> N_L - r + Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno; + + trx0 = ff_jpeg2000_ceildivpow2(tile_coord[0][0], log_subsampling[0] + reducedresno); + try0 = ff_jpeg2000_ceildivpow2(tile_coord[1][0], log_subsampling[1] + reducedresno); + + if (!(y % ((uint64_t)1 << (reslevel->log2_prec_height + reducedresno + log_subsampling[1])) == 0 || + (y == tile_coord[1][0] && (try0 << reducedresno) % (1U << (reducedresno + reslevel->log2_prec_height))))) + continue; + + if (!(x % ((uint64_t)1 << (reslevel->log2_prec_width + reducedresno + log_subsampling[0])) == 0 || + (x == tile_coord[0][0] && (trx0 << reducedresno) % (1U << (reducedresno + reslevel->log2_prec_width))))) + continue; + + // check if a precinct exists + prcx = ff_jpeg2000_ceildivpow2(x, log_subsampling[0] + reducedresno) >> reslevel->log2_prec_width; + prcy = ff_jpeg2000_ceildivpow2(y, log_subsampling[1] + reducedresno) >> reslevel->log2_prec_height; + prcx -= ff_jpeg2000_ceildivpow2(comp->coord_o[0][0], reducedresno) >> reslevel->log2_prec_width; + prcy -= ff_jpeg2000_ceildivpow2(comp->coord_o[1][0], reducedresno) >> reslevel->log2_prec_height; + + precno = prcx + reslevel->num_precincts_x * prcy; + + if (prcx >= reslevel->num_precincts_x || prcy >= reslevel->num_precincts_y) { + av_log(s->avctx, AV_LOG_WARNING, "prc %d %d outside limits %d %d\n", + prcx, prcy, reslevel->num_precincts_x, reslevel->num_precincts_y); + continue; + } + for (layno = 0; layno < nlayers; layno++) { + if ((ret = encode_packet(s, reslevel, layno, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), + qntsty->nguardbits, packetno++, nlayers)) < 0) + return ret; + } + } + } + } + } + + } + av_log(s->avctx, AV_LOG_DEBUG, "after tier2\n"); return 0; } +static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2000Tile* tile, int final) +{ + int compno, resno, bandno, precno, cblkno; + int passno; + + for (compno = 0; compno < s->ncomponents; compno++) { + Jpeg2000Component *comp = &tile->comp[compno]; + + for (resno = 0; resno < s->codsty.nreslevels; resno++) { + Jpeg2000ResLevel *reslevel = comp->reslevel + resno; + + for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ + for (bandno = 0; bandno < reslevel->nbands ; bandno++){ + Jpeg2000Band *band = reslevel->band + bandno; + Jpeg2000Prec *prec = band->prec + precno; + + for (cblkno = 0; cblkno < prec->nb_codeblocks_height * prec->nb_codeblocks_width; cblkno++){ + Jpeg2000Cblk *cblk = prec->cblk + cblkno; + Jpeg2000Layer *layer = &cblk->layers[layno]; + int n; + + if (layno == 0) { + cblk->ninclpasses = 0; + } + + n = cblk->ninclpasses; + + if (thresh < 0) { + n = cblk->npasses; + } else { + for (passno = cblk->ninclpasses; passno < cblk->npasses; passno++) { + int32_t dr; + double dd; + Jpeg2000Pass *pass = &cblk->passes[passno]; + + if (n == 0) { + dr = pass->rate; + dd = pass->disto; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = pass->disto - cblk->passes[n-1].disto; + } + + if (!dr) { + if (dd != 0.0) { + n = passno + 1; + } + continue; + } + + if (thresh - (dd / dr) < DBL_EPSILON) + n = passno + 1; + } + } + layer->npasses = n - cblk->ninclpasses; + layer->cum_passes = n; + + if (layer->npasses == 0) { + layer->disto = 0; + layer->data_len = 0; + continue; + } + + if (cblk->ninclpasses == 0) { + layer->data_len = cblk->passes[n - 1].rate; + layer->data_start = cblk->data; + layer->disto = cblk->passes[n - 1].disto; + } else { + layer->data_len = cblk->passes[n - 1].rate - cblk->passes[cblk->ninclpasses - 1].rate; + layer->data_start = cblk->data + cblk->passes[cblk->ninclpasses - 1].rate; + layer->disto = cblk->passes[n - 1].disto - + cblk->passes[cblk->ninclpasses - 1].disto; + } + if (final) { + cblk->ninclpasses = n; + } + } + } + } + } + } +} + +static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) +{ + int precno, compno, reslevelno, bandno, cblkno, lev, passno, layno; + int i; + double min = DBL_MAX; + double max = 0; + double thresh; + int tile_disto = 0; + + Jpeg2000CodingStyle *codsty = &s->codsty; + + for (compno = 0; compno < s->ncomponents; compno++){ + Jpeg2000Component *comp = tile->comp + compno; + + for (reslevelno = 0, lev = codsty->nreslevels-1; reslevelno < codsty->nreslevels; reslevelno++, lev--){ + Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno; + + for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ + for (bandno = 0; bandno < reslevel->nbands ; bandno++){ + Jpeg2000Band *band = reslevel->band + bandno; + Jpeg2000Prec *prec = band->prec + precno; + + for (cblkno = 0; cblkno < prec->nb_codeblocks_height * prec->nb_codeblocks_width; cblkno++){ + Jpeg2000Cblk *cblk = prec->cblk + cblkno; + for (passno = 0; passno < cblk->npasses; passno++) { + Jpeg2000Pass *pass = &cblk->passes[passno]; + int dr; + double dd, drslope; + + tile_disto += pass->disto; + if (passno == 0) { + dr = (int32_t)pass->rate; + dd = pass->disto; + } else { + dr = (int32_t)(pass->rate - cblk->passes[passno - 1].rate); + dd = pass->disto - cblk->passes[passno - 1].disto; + } + + if (dr <= 0) + continue; + + drslope = dd / dr; + if (drslope < min) + min = drslope; + + if (drslope > max) + max = drslope; + } + } + } + } + } + } + + for (layno = 0; layno < s->nlayers; layno++) { + double lo = min; + double hi = max; + double stable_thresh = 0.0; + double good_thresh = 0.0; + if (!s->layer_rates[layno]) { + good_thresh = -1.0; + } else { + for (i = 0; i < 128; i++) { + uint8_t *stream_pos = s->buf; + int ret; + thresh = (lo + hi) / 2; + makelayer(s, layno, thresh, tile, 0); + ret = encode_packets(s, tile, (int)(tile - s->tile), layno + 1); + memset(stream_pos, 0, s->buf - stream_pos); + if ((s->buf - stream_pos > ceil(tile->layer_rates[layno])) || ret < 0) { + lo = thresh; + s->buf = stream_pos; + continue; + } + hi = thresh; + stable_thresh = thresh; + s->buf = stream_pos; + } + } + if (good_thresh >= 0.0) + good_thresh = stable_thresh == 0.0 ? thresh : stable_thresh; + makelayer(s, layno, good_thresh, tile, 1); + } +} + static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm) { int passno, res = 0; @@ -841,9 +1355,9 @@ static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm) int64_t dd; dr = cblk->passes[passno].rate - - (res ? cblk->passes[res-1].rate:0); + - (res ? cblk->passes[res-1].rate : 0); dd = cblk->passes[passno].disto - - (res ? cblk->passes[res-1].disto:0); + - (res ? cblk->passes[res-1].disto : 0); if (((dd * dwt_norm) >> WMSEDEC_SHIFT) * dwt_norm >= dr * lambda) res = passno+1; @@ -873,6 +1387,11 @@ static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) cblk->ninclpasses = getcut(cblk, s->lambda, (int64_t)dwt_norms[codsty->transform == FF_DWT53][bandpos][lev] * (int64_t)band->i_stepsize >> 15); + cblk->layers[0].data_start = cblk->data; + cblk->layers[0].cum_passes = cblk->ninclpasses; + cblk->layers[0].npasses = cblk->ninclpasses; + if (cblk->ninclpasses) + cblk->layers[0].data_len = cblk->passes[cblk->ninclpasses - 1].rate; } } } @@ -927,7 +1446,7 @@ static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno for (y = yy0; y < yy1; y++){ int *ptr = t1.data + (y-yy0)*t1.stride; for (x = xx0; x < xx1; x++){ - *ptr++ = comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] << NMSEDEC_FRACBITS; + *ptr++ = comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] * (1 << NMSEDEC_FRACBITS); } } } else{ @@ -960,8 +1479,12 @@ static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno } av_log(s->avctx, AV_LOG_DEBUG, "rate control\n"); - truncpasses(s, tile); - if ((ret = encode_packets(s, tile, tileno)) < 0) + if (s->compression_rate_enc) + makelayers(s, tile); + else + truncpasses(s, tile); + + if ((ret = encode_packets(s, tile, tileno, s->nlayers)) < 0) return ret; av_log(s->avctx, AV_LOG_DEBUG, "after rate control\n"); return 0; @@ -972,12 +1495,17 @@ static void cleanup(Jpeg2000EncoderContext *s) int tileno, compno; Jpeg2000CodingStyle *codsty = &s->codsty; + if (!s->tile) + return; for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){ - for (compno = 0; compno < s->ncomponents; compno++){ - Jpeg2000Component *comp = s->tile[tileno].comp + compno; - ff_jpeg2000_cleanup(comp, codsty); + if (s->tile[tileno].comp) { + for (compno = 0; compno < s->ncomponents; compno++){ + Jpeg2000Component *comp = s->tile[tileno].comp + compno; + ff_jpeg2000_cleanup(comp, codsty); + } + av_freep(&s->tile[tileno].comp); } - av_freep(&s->tile[tileno].comp); + av_freep(&s->tile[tileno].layer_rates); } av_freep(&s->tile); } @@ -1015,7 +1543,11 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, s->lambda = s->picture->quality * LAMBDA_SCALE; - copy_frame(s); + if (avctx->pix_fmt == AV_PIX_FMT_BGR48 || avctx->pix_fmt == AV_PIX_FMT_GRAY16) + copy_frame_16(s); + else + copy_frame_8(s); + reinit(s); if (s->format == CODEC_JP2) { @@ -1132,6 +1664,53 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } +static int parse_layer_rates(Jpeg2000EncoderContext *s) +{ + int i; + char *token; + char *saveptr = NULL; + int rate; + int nlayers = 0; + if (!s->lr_str) { + s->nlayers = 1; + s->layer_rates[0] = 0; + s->compression_rate_enc = 0; + return 0; + } + + token = av_strtok(s->lr_str, ",", &saveptr); + if (rate = strtol(token, NULL, 10)) { + s->layer_rates[0] = rate <= 1 ? 0:rate; + nlayers++; + } else { + return AVERROR_INVALIDDATA; + } + + while (1) { + token = av_strtok(NULL, ",", &saveptr); + if (!token) + break; + if (rate = strtol(token, NULL, 10)) { + if (nlayers >= 100) { + return AVERROR_INVALIDDATA; + } + s->layer_rates[nlayers] = rate <= 1 ? 0:rate; + nlayers++; + } else { + return AVERROR_INVALIDDATA; + } + } + + for (i = 1; i < nlayers; i++) { + if (s->layer_rates[i] >= s->layer_rates[i-1]) { + return AVERROR_INVALIDDATA; + } + } + s->nlayers = nlayers; + s->compression_rate_enc = 1; + return 0; +} + static av_cold int j2kenc_init(AVCodecContext *avctx) { int i, ret; @@ -1141,13 +1720,12 @@ static av_cold int j2kenc_init(AVCodecContext *avctx) s->avctx = avctx; av_log(s->avctx, AV_LOG_DEBUG, "init\n"); - -#if FF_API_PRIVATE_OPT -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->prediction_method) - s->pred = avctx->prediction_method; -FF_ENABLE_DEPRECATION_WARNINGS -#endif + if (parse_layer_rates(s)) { + av_log(s, AV_LOG_WARNING, "Layer rates invalid. Encoding with 1 layer based on quality metric.\n"); + s->nlayers = 1; + s->layer_rates[0] = 0; + s->compression_rate_enc = 0; + } if (avctx->pix_fmt == AV_PIX_FMT_PAL8 && (s->pred != FF_DWT97_INT || s->format != CODEC_JP2)) { av_log(s->avctx, AV_LOG_WARNING, "Forcing lossless jp2 for pal8\n"); @@ -1161,6 +1739,7 @@ FF_ENABLE_DEPRECATION_WARNINGS memset(codsty->log2_prec_heights, 15, sizeof(codsty->log2_prec_heights)); codsty->nreslevels2decode= codsty->nreslevels = 7; + codsty->nlayers = s->nlayers; codsty->log2_cblk_width = 4; codsty->log2_cblk_height = 4; codsty->transform = s->pred ? FF_DWT53 : FF_DWT97_INT; @@ -1180,12 +1759,16 @@ FF_ENABLE_DEPRECATION_WARNINGS s->width = avctx->width; s->height = avctx->height; - for (i = 0; i < 3; i++) - s->cbps[i] = 8; + for (i = 0; i < 3; i++) { + if (avctx->pix_fmt == AV_PIX_FMT_GRAY16 || avctx->pix_fmt == AV_PIX_FMT_RGB48) + s->cbps[i] = 16; + else + s->cbps[i] = 8; + } - if (avctx->pix_fmt == AV_PIX_FMT_RGB24){ + if (avctx->pix_fmt == AV_PIX_FMT_RGB24 || avctx->pix_fmt == AV_PIX_FMT_RGB48){ s->ncomponents = 3; - } else if (avctx->pix_fmt == AV_PIX_FMT_GRAY8 || avctx->pix_fmt == AV_PIX_FMT_PAL8){ + } else if (avctx->pix_fmt == AV_PIX_FMT_GRAY8 || avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY16){ s->ncomponents = 1; } else{ // planar YUV s->planar = 1; @@ -1230,7 +1813,15 @@ static const AVOption options[] = { { "pred", "DWT Type", OFFSET(pred), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, "pred" }, { "dwt97int", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "pred" }, { "dwt53", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "pred" }, - + { "sop", "SOP marker", OFFSET(sop), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, }, + { "eph", "EPH marker", OFFSET(eph), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, }, + { "prog", "Progression Order", OFFSET(prog), AV_OPT_TYPE_INT, { .i64 = 0 }, JPEG2000_PGOD_LRCP, JPEG2000_PGOD_CPRL, VE, "prog" }, + { "lrcp", NULL, OFFSET(prog), AV_OPT_TYPE_CONST, { .i64 = JPEG2000_PGOD_LRCP }, 0, 0, VE, "prog" }, + { "rlcp", NULL, OFFSET(prog), AV_OPT_TYPE_CONST, { .i64 = JPEG2000_PGOD_RLCP }, 0, 0, VE, "prog" }, + { "rpcl", NULL, OFFSET(prog), AV_OPT_TYPE_CONST, { .i64 = JPEG2000_PGOD_RPCL }, 0, 0, VE, "prog" }, + { "pcrl", NULL, OFFSET(prog), AV_OPT_TYPE_CONST, { .i64 = JPEG2000_PGOD_PCRL }, 0, 0, VE, "prog" }, + { "cprl", NULL, OFFSET(prog), AV_OPT_TYPE_CONST, { .i64 = JPEG2000_PGOD_CPRL }, 0, 0, VE, "prog" }, + { "layer_rates", "Layer Rates", OFFSET(lr_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE }, { NULL } }; @@ -1241,7 +1832,7 @@ static const AVClass j2k_class = { .version = LIBAVUTIL_VERSION_INT, }; -AVCodec ff_jpeg2000_encoder = { +const AVCodec ff_jpeg2000_encoder = { .name = "jpeg2000", .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"), .type = AVMEDIA_TYPE_VIDEO, @@ -1255,7 +1846,9 @@ AVCodec ff_jpeg2000_encoder = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_PAL8, + AV_PIX_FMT_RGB48, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }, .priv_class = &j2k_class, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, };