[FFmpeg-devel] [RFC PATCH 4/4] libavcodec/j2kenc: Support for multiple layers
Gautam Ramakrishnan
gautamramk at gmail.com
Thu Aug 20 21:47:33 EEST 2020
On Thu, Aug 20, 2020 at 12:55 AM Paul B Mahol <onemda at gmail.com> wrote:
>
> On 8/19/20, Gautam Ramakrishnan <gautamramk at gmail.com> wrote:
> > On Wed, Aug 19, 2020 at 5:51 PM <gautamramk at gmail.com> wrote:
> >>
> >> From: Gautam Ramakrishnan <gautamramk at gmail.com>
> >>
> >> 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 | 443 ++++++++++++++++++++++++++++++++++--------
> >> libavcodec/jpeg2000.c | 13 +-
> >> libavcodec/jpeg2000.h | 10 +
> >> 3 files changed, 384 insertions(+), 82 deletions(-)
> >>
> >> diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c
> >> index 8699296434..b09db36c14 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 <seg at haxxed.com>
> >> + * Copyright (c) 2020, Gautam Ramakrishnan <gautamramk at gmail.com>
> >> * All rights reserved.
> >> *
> >> * Redistribution and use in source and binary forms, with or without
> >> @@ -100,6 +101,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 +128,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;
> >>
> >>
> >> @@ -332,7 +337,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 +416,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.0f) {
> >> + 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.0f;
> >> + }
> >> + }
> >> + }
> >> + }
> >> + }
> >> +
> >> +}
> >> +
> >> /**
> >> * compute the sizes of tiles, resolution levels, bands, etc.
> >> * allocate memory for them
> >> @@ -448,6 +478,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 +493,7 @@ static int init_tiles(Jpeg2000EncoderContext *s)
> >> return ret;
> >> }
> >> }
> >> + compute_rates(s);
> >> return 0;
> >> }
> >>
> >> @@ -701,6 +736,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 +770,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 +787,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;
> >> + ff_tag_tree_zero(prec->zerobits,
> >> prec->nb_codeblocks_width, prec->nb_codeblocks_height);
> >> + ff_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 +857,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 +911,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 +926,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 +945,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 +1026,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 +1093,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 +1156,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 +1172,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 +1274,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;
> >>
> >> - cblk->ninclpasses = getcut(cblk, s->lambda,
> >> - (int64_t)dwt_norms[codsty->transform ==
> >> FF_DWT53][bandpos][lev] * (int64_t)band->i_stepsize >> 15);
> >> + 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;
> >> + 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 +1420,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 +1438,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 +1597,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 +1664,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 +1689,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 +1771,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 70c25a0ca2..1c294ad9e6 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,11 @@ 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 +446,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 +621,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 fee9607e86..3c6e8ede16 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
> >>
> >> --
> >> 2.17.1
> >>
> >
> > This patch seems to be breaking FATE.
> > I believe that the error is because the patch modifies the encoder
> > such that the encoded files will be slightly different now.
> > How can this be handled?
>
> Run fate. Make sure that you have SAMPLES set and rsynced with server.
>
> make fate-name-of-target GEN=1
>
> To generate new hashes for encodes.
>
> Please read http://ffmpeg.org/fate.html
>
>
> > --
> > -------------
> > Gautam |
I made all the changes as per suggestions and tried to generate new
hashes for the encodes.
However, when I run make fate with GEN=1 for target fate-vsynth1-jpeg2000,
the file tests/ref/vsynth/vsynth1-jpeg2000 becomes empty instead of
being filled with new data.
The file tests/data/fate/vsynth1-jpeg2000.avi, which is to be encoded
by this test seems to be
encoded correctly. What am I missing here?
--
-------------
Gautam |
More information about the ffmpeg-devel
mailing list