From patchwork Tue Aug 18 19:40:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gautam Ramakrishnan X-Patchwork-Id: 21715 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 3E67644BD10 for ; Tue, 18 Aug 2020 23:07:19 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1E46D6880DE; Tue, 18 Aug 2020 23:07:19 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-oi1-f196.google.com (mail-oi1-f196.google.com [209.85.167.196]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B26D968080C for ; Tue, 18 Aug 2020 23:07:11 +0300 (EEST) Received: by mail-oi1-f196.google.com with SMTP id k4so19043032oik.2 for ; Tue, 18 Aug 2020 13:07:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=lM4xY2gszfFIP5DIlX20v5r21wUTgmEP725JL4lruBI=; b=LQBGVa+E2AAV8yWlt6dncHISpv7zEWFY0gMvTziBowpdfgWH2jtOujilB2T439wQwn fbHbaeomISOcgObKzYhjFzYT4OUJgPgXDTmbEK3ypVXocYCl1T/aGcCajU58yXJpJMDP 3sWU4ge6BysfFDV8mkOKyIwWkOOYn5leDK2PkBQtGp317dkHim95X9ZX2MbMsaY5Y5Nb Ay47P2c+9WwfMX3Xv6HyvJA7Bck8Yt8nnXPPiF1Xp6tNIlQDPMEUcr0eJIyv4vx6dZqg gzV1MvJ70YKTn+ATox8XvYisnzr1fhH2gKNyQAKbH453pFCJluY56cRaNYbrTsbxMujP QRBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=lM4xY2gszfFIP5DIlX20v5r21wUTgmEP725JL4lruBI=; b=deWkB3T3MzBi5dDE1FyN8c6c79dRdD2wug/oNO6AwjC8aDeDCbasa24qEjK6Ukdd9X f3S4rwDa1nZBivB9DgrmXkiNE/+RVVS4E9FVJXaq+mCoNUfSwp9HkOauhjwKpN2dco8+ +BYkkBFl61KRFcdBkG87IjsJYkQxIIxvD0FQQb14yGINfY8oF8fFA/8/bxErF0PbVhMx UGiYtyV37Zo/J6t9Tj3xlcE4sPqyJmb78ITFAcbX9LKG0VKbPNTUxe7GvA3JRivCqspN N/KoIjF7lkH/Kw3sfqwLyuMUOPvo2D/woSzVnvUDytnQDuYwF9kg0VLf9CYqHXaxS9NC K1Ng== X-Gm-Message-State: AOAM531wsCZYN4WiYwUIYNTftWJcNS20JAnlR5kyUldKJb6t/B6Zzl88 efilBhxVFh9U1MMdhKnsn2mV1p3Y+Gk= X-Google-Smtp-Source: ABdhPJxiKlAHgSxCqeRGMCsLOnEok7KTF0lulbe/s+qosFCkhkcrYUXBxrwohrHybLcjphrpm5GJGA== X-Received: by 2002:a17:90a:f2c7:: with SMTP id gt7mr1154874pjb.204.1597779653571; Tue, 18 Aug 2020 12:40:53 -0700 (PDT) Received: from localhost.localdomain ([122.166.129.193]) by smtp.gmail.com with ESMTPSA id z77sm27140885pfc.199.2020.08.18.12.40.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Aug 2020 12:40:53 -0700 (PDT) From: gautamramk@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Wed, 19 Aug 2020 01:10:37 +0530 Message-Id: <20200818194037.25422-4-gautamramk@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200818194037.25422-1-gautamramk@gmail.com> References: <20200818194037.25422-1-gautamramk@gmail.com> Subject: [FFmpeg-devel] [PATCH 4/4] libavcodec/j2kenc: Support for multiple layers X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Gautam Ramakrishnan MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Gautam Ramakrishnan This patch allows setting a compression ratio and to set multiple layers. The user has to input a compression ratio for each layer. The per layer compression ration can be set as follows: -layer_rates "r1,r2,...rn" for to create 'n' layers. --- libavcodec/j2kenc.c | 441 ++++++++++++++++++++++++++++++++++-------- libavcodec/jpeg2000.c | 14 +- libavcodec/jpeg2000.h | 10 + 3 files changed, 382 insertions(+), 83 deletions(-) diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 264bae3f73..3882fa8474 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -100,6 +100,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,12 +127,15 @@ typedef struct { Jpeg2000QuantStyle qntsty; Jpeg2000Tile *tile; + int layer_rates[100]; int format; int pred; int sop; int eph; int prog; + int nlayers; + char *lr_str; } Jpeg2000EncoderContext; @@ -239,7 +243,7 @@ static void j2k_flush(Jpeg2000EncoderContext *s) /* tag tree routines */ /** code the value stored in node */ -static void tag_tree_code(Jpeg2000EncoderContext *s, Jpeg2000TgtNode *node, int threshold, int log) +static void tag_tree_code(Jpeg2000EncoderContext *s, Jpeg2000TgtNode *node, int threshold) { Jpeg2000TgtNode *stack[30]; int sp = -1, curval = 0; @@ -332,7 +336,7 @@ static int put_cod(Jpeg2000EncoderContext *s) bytestream_put_byte(&s->buf, scod); // Scod // SGcod bytestream_put_byte(&s->buf, s->prog); // progression level - bytestream_put_be16(&s->buf, 1); // num of layers + 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{ @@ -411,6 +415,28 @@ static uint8_t *put_sot(Jpeg2000EncoderContext *s, int tileno) return psotptr; } +static void compute_rates(Jpeg2000EncoderContext* s) +{ + int i, j; + int layno; + for (i = 0; i < s->numYtiles; i++) { + for (j = 0; j < s->numXtiles; j++) { + Jpeg2000Tile *tile = &s->tile[s->numXtiles * i + j]; + int tilew = tile->comp->coord[0][1] - tile->comp->coord[0][0]; + int tileh = tile->comp->coord[1][1] - tile->comp->coord[1][0]; + for (layno = 0; layno < s->nlayers; layno++) { + if (s->layer_rates[layno] > 0.0f) { + tile->layer_rates[layno] = (double)(tilew * tileh) * s->ncomponents * s->cbps[0] / (s->layer_rates[layno] * 8); + //av_log(s, AV_LOG_WARNING, "Layer %d rate is %lf\n", layno, tile->layer_rates[layno]); + } else { + tile->layer_rates[layno] = 0; + } + } + } + } + +} + /** * compute the sizes of tiles, resolution levels, bands, etc. * allocate memory for them @@ -448,6 +474,10 @@ static int init_tiles(Jpeg2000EncoderContext *s) for (j = 0; j < 2; j++) comp->coord[i][j] = comp->coord_o[i][j] = ff_jpeg2000_ceildivpow2(comp->coord[i][j], s->chroma_shift[i]); + tile->layer_rates = av_mallocz_array(s->ncomponents, sizeof(*tile->layer_rates)); + if (!tile->layer_rates) + return AVERROR(ENOMEM); + if ((ret = ff_jpeg2000_init_component(comp, codsty, qntsty, @@ -459,6 +489,7 @@ static int init_tiles(Jpeg2000EncoderContext *s) return ret; } } + compute_rates(s); return 0; } @@ -701,6 +732,8 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20 } cblk->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; @@ -733,10 +766,12 @@ static void putnumpasses(Jpeg2000EncoderContext *s, int n) } -static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, int precno, - uint8_t *expn, int numgbits, int packetno) +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; @@ -748,18 +783,61 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in } // header + if (!layno) { + for (bandno = 0; bandno < rlevel->nbands; bandno++){ + Jpeg2000Band *band = rlevel->band + 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]){ + Jpeg2000Prec *prec = band->prec + precno; + int nb_cblks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; + int pos; + tag_tree_zero(prec->zerobits, prec->nb_codeblocks_width, prec->nb_codeblocks_height); + tag_tree_zero(prec->cblkincl, prec->nb_codeblocks_width, prec->nb_codeblocks_height); + 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++){ + Jpeg2000Band *band = rlevel->band + 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; + 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; } @@ -775,40 +853,44 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in 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 (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->cum_passes){ + length += cblk->passes[cblk->layers->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)); } } } @@ -825,13 +907,14 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in 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->cum_passes){ + bytestream_put_buffer(&s->buf, cblk->passes[cblk->layers->cum_passes-1].flushed, + cblk->passes[cblk->layers->cum_passes-1].flushed_len); + } } } } @@ -839,9 +922,9 @@ 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; @@ -858,29 +941,33 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til av_log(s->avctx, AV_LOG_DEBUG, "tier2\n"); // lay-rlevel-comp-pos progression - switch (s->prog) { + switch (s->prog) { case JPEG2000_PGOD_LRCP: - 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, packetno++)) < 0) - return ret; + 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, packetno++)) < 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; + } } } } @@ -935,10 +1022,11 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til prcx, prcy, reslevel->num_precincts_x, reslevel->num_precincts_y); continue; } - - if ((ret = encode_packet(s, reslevel, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), - qntsty->nguardbits, packetno++)) < 0) - return ret; + 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; + } } } } @@ -1001,9 +1089,11 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til prcx, prcy, reslevel->num_precincts_x, reslevel->num_precincts_y); continue; } - if ((ret = encode_packet(s, reslevel, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), - qntsty->nguardbits, packetno++)) < 0) - return ret; + 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; + } } } } @@ -1062,9 +1152,11 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til prcx, prcy, reslevel->num_precincts_x, reslevel->num_precincts_y); continue; } - if ((ret = encode_packet(s, reslevel, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0), - qntsty->nguardbits, packetno++)) < 0) - return ret; + 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; + } } } } @@ -1076,27 +1168,98 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til return 0; } -static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm) +static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2000Tile* tile, int final) { - int passno, res = 0; - for (passno = 0; passno < cblk->npasses; passno++){ - int dr; - int64_t dd; - - dr = cblk->passes[passno].rate - - (res ? cblk->passes[res-1].rate:0); - dd = cblk->passes[passno].disto - - (res ? cblk->passes[res-1].disto:0); - - if (((dd * dwt_norm) >> WMSEDEC_SHIFT) * dwt_norm >= dr * lambda) - res = passno+1; + 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 = (double)pass->disto; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = (double)pass->disto - (double)cblk->passes[n-1].disto; + } + + if (!dr) { + if (dd) { + 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; + } + } + } + } + } } - return res; } -static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) +static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) { - int precno, compno, reslevelno, bandno, cblkno, lev; + 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++){ @@ -1107,20 +1270,70 @@ static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile) for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){ for (bandno = 0; bandno < reslevel->nbands ; bandno++){ - int bandpos = bandno + (reslevelno > 0); 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 = (double)pass->disto; + } else { + dr = (int32_t)(pass->rate) - cblk->passes[passno - 1].rate; + dd = (double)pass->disto - (double)cblk->passes[passno - 1].disto; + } + + if (dr <= 0) + continue; + + drslope = dd / dr; + if (drslope < min) + min = drslope; - cblk->ninclpasses = getcut(cblk, s->lambda, - (int64_t)dwt_norms[codsty->transform == FF_DWT53][bandpos][lev] * (int64_t)band->i_stepsize >> 15); + if (drslope > max) + max = drslope; + } } } } } } + + for (layno = 0; layno < s->nlayers; layno++) { + double lo = min; + double hi = max; + double stable_thresh = 0; + double good_thresh = 0; + if (!s->layer_rates[layno]) { + good_thresh = -1; + } 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) + good_thresh = stable_thresh == 0 ? thresh : stable_thresh; + makelayer(s, layno, good_thresh, tile, 1); + } } static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno) @@ -1203,8 +1416,8 @@ 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) + makelayers(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; @@ -1221,6 +1434,7 @@ static void cleanup(Jpeg2000EncoderContext *s) ff_jpeg2000_cleanup(comp, codsty, 1); } av_freep(&s->tile[tileno].comp); + av_freep(&s->tile[tileno].layer_rates); } av_freep(&s->tile); } @@ -1379,6 +1593,64 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; } +static int inline check_number(char* st, int* ret) { + int stlen = strlen(st); + int i; + *ret = 0; + if (stlen <= 0) { + return AVERROR_INVALIDDATA; + } + for (i = 0; i < stlen; i++) { + if (st[i] >= '0' && st[i] <= '9') { + *ret = (*ret) * 10 + (st[i] - '0'); + } else { + return AVERROR_INVALIDDATA; + } + } + return 0; +} + +static int parse_layer_rates(Jpeg2000EncoderContext *s) +{ + int i; + char* token; + int rate; + int nlayers = 0; + if (!s->lr_str) { + s->nlayers = 1; + s->layer_rates[0] = 0; + return 0; + } + + token = strtok(s->lr_str, ","); + if (!check_number(token, &rate)) { + s->layer_rates[0] = rate <= 1 ? 0:rate; + nlayers++; + } else { + return AVERROR_INVALIDDATA; + } + + while (1) { + token = strtok(NULL, ","); + if (!token) + break; + if (!check_number(token, &rate)) { + 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; + return 0; +} + static av_cold int j2kenc_init(AVCodecContext *avctx) { int i, ret; @@ -1388,6 +1660,11 @@ static av_cold int j2kenc_init(AVCodecContext *avctx) s->avctx = avctx; av_log(s->avctx, AV_LOG_DEBUG, "init\n"); + if (parse_layer_rates(s)) { + av_log(s, AV_LOG_WARNING, "Layer rates invalid. Shall encode with 1 layer.\n"); + s->nlayers = 1; + s->layer_rates[0] = 0; + } #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS @@ -1408,6 +1685,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; @@ -1489,6 +1767,7 @@ static const AVOption options[] = { { "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 } }; diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c index 88e6ebc8b3..7c5261e995 100644 --- a/libavcodec/jpeg2000.c +++ b/libavcodec/jpeg2000.c @@ -261,9 +261,11 @@ static void init_band_stepsize(AVCodecContext *avctx, band->f_stepsize *= 0.5; } -static int init_prec(Jpeg2000Band *band, +static int init_prec(AVCodecContext *avctx, + Jpeg2000Band *band, Jpeg2000ResLevel *reslevel, Jpeg2000Component *comp, + Jpeg2000CodingStyle *codsty, int precno, int bandno, int reslevelno, int log2_band_prec_width, int log2_band_prec_height) @@ -366,6 +368,12 @@ static int init_prec(Jpeg2000Band *band, cblk->lblock = 3; cblk->length = 0; cblk->npasses = 0; + if (av_codec_is_encoder(avctx->codec)) { + cblk->layers = av_mallocz_array(codsty->nlayers, sizeof(*cblk->layers)); + if (!cblk->layers) + return AVERROR(ENOMEM); + } + } return 0; @@ -439,7 +447,7 @@ static int init_band(AVCodecContext *avctx, return AVERROR(ENOMEM); for (precno = 0; precno < nb_precincts; precno++) { - ret = init_prec(band, reslevel, comp, + ret = init_prec(avctx, band, reslevel, comp, codsty, precno, bandno, reslevelno, log2_band_prec_width, log2_band_prec_height); if (ret < 0) @@ -614,6 +622,8 @@ void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty, i av_freep(&cblk->passes); av_freep(&cblk->lengthinc); av_freep(&cblk->data_start); + if (isencoder) + av_freep(&cblk->layers); } av_freep(&prec->cblk); } diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index 611aea1665..b338ba6bc9 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -162,10 +162,19 @@ typedef struct Jpeg2000Pass { int flushed_len; } Jpeg2000Pass; +typedef struct Jpeg2000Layer { + uint8_t *data_start; + int data_len; + int npasses; + double disto; + int cum_passes; +} Jpeg2000Layer; + typedef struct Jpeg2000Cblk { uint8_t npasses; uint8_t ninclpasses; // number coding of passes included in codestream uint8_t nonzerobits; + uint8_t incl; uint16_t length; uint16_t *lengthinc; uint8_t nb_lengthinc; @@ -176,6 +185,7 @@ typedef struct Jpeg2000Cblk { int nb_terminationsinc; int *data_start; Jpeg2000Pass *passes; + Jpeg2000Layer *layers; int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} } Jpeg2000Cblk; // code block