[FFmpeg-devel] [RFC PATCH 4/4] libavcodec/j2kenc: Support for multiple layers

Paul B Mahol onemda at gmail.com
Wed Aug 19 21:56:03 EEST 2020


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 |
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-devel mailing list