libavcodec/j2kenc: Support for multiple layers

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.

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
Gautam Ramakrishnan 2020-08-28 00:15:35 +05:30 committed by Michael Niedermayer
parent 3c06045a8b
commit f0e33119e4
13 changed files with 475 additions and 107 deletions

View File

@ -1401,6 +1401,22 @@ Possible values are:
@end table
Set to @code{lrcp} by default.
@item layer_rates @var{string}
By default, when this option is not used, compression is done using the quality metric.
This option allows for compression using compression ratio. The compression ratio for each
level could be specified. The compression ratio of a layer @code{l} species the what ratio of
total file size is contained in the first @code{l} layers.
Example usage:
@example
ffmpeg -i input.bmp -c:v jpeg2000 -layer_rates "100,10,1" output.j2k
@end example
This would compress the image to contain 3 layers, where the data contained in the
first layer would be compressed by 1000 times, compressed by 100 in the first two layers,
and shall contain all data while using all 3 layers.
@end table
@section librav1e

View File

@ -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@haxxed.com>
* Copyright (c) 2020, Gautam Ramakrishnan <gautamramk@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -72,6 +73,7 @@
#include "libavutil/pixdesc.h"
#include "libavutil/opt.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/avstring.h"
#define NMSEDEC_BITS 7
#define NMSEDEC_FRACBITS (NMSEDEC_BITS-1)
@ -100,6 +102,7 @@ static const int dwt_norms[2][4][10] = { // [dwt_type][band][rlevel] (multiplied
typedef struct {
Jpeg2000Component *comp;
double *layer_rates;
} Jpeg2000Tile;
typedef struct {
@ -126,12 +129,16 @@ typedef struct {
Jpeg2000QuantStyle qntsty;
Jpeg2000Tile *tile;
int layer_rates[100];
uint8_t compression_rate_enc; ///< Is compression done using compression ratio?
int format;
int pred;
int sop;
int eph;
int prog;
int nlayers;
char *lr_str;
} Jpeg2000EncoderContext;
@ -334,7 +341,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{
@ -413,6 +420,31 @@ static uint8_t *put_sot(Jpeg2000EncoderContext *s, int tileno)
return psotptr;
}
static void compute_rates(Jpeg2000EncoderContext* s)
{
int i, j;
int layno, compno;
for (i = 0; i < s->numYtiles; i++) {
for (j = 0; j < s->numXtiles; j++) {
Jpeg2000Tile *tile = &s->tile[s->numXtiles * i + j];
for (compno = 0; compno < s->ncomponents; compno++) {
int tilew = tile->comp[compno].coord[0][1] - tile->comp[compno].coord[0][0];
int tileh = tile->comp[compno].coord[1][1] - tile->comp[compno].coord[1][0];
int scale = (compno?1 << s->chroma_shift[0]:1) * (compno?1 << s->chroma_shift[1]:1);
for (layno = 0; layno < s->nlayers; layno++) {
if (s->layer_rates[layno] > 0) {
tile->layer_rates[layno] += (double)(tilew * tileh) * s->ncomponents * s->cbps[compno] /
(double)(s->layer_rates[layno] * 8 * scale);
} else {
tile->layer_rates[layno] = 0.0;
}
}
}
}
}
}
/**
* compute the sizes of tiles, resolution levels, bands, etc.
* allocate memory for them
@ -437,6 +469,11 @@ static int init_tiles(Jpeg2000EncoderContext *s)
tile->comp = av_mallocz_array(s->ncomponents, sizeof(Jpeg2000Component));
if (!tile->comp)
return AVERROR(ENOMEM);
tile->layer_rates = av_mallocz_array(s->nlayers, sizeof(*tile->layer_rates));
if (!tile->layer_rates)
return AVERROR(ENOMEM);
for (compno = 0; compno < s->ncomponents; compno++){
Jpeg2000Component *comp = tile->comp + compno;
int ret, i, j;
@ -461,6 +498,7 @@ static int init_tiles(Jpeg2000EncoderContext *s)
return ret;
}
}
compute_rates(s);
return 0;
}
@ -703,6 +741,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;
@ -714,8 +754,10 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20
cblk->npasses = passno;
cblk->ninclpasses = passno;
if (passno)
if (passno) {
cblk->passes[passno-1].rate = ff_mqc_flush_to(&t1->mqc, cblk->passes[passno-1].flushed, &cblk->passes[passno-1].flushed_len);
cblk->passes[passno-1].rate -= cblk->passes[passno-1].flushed_len;
}
}
/* tier-2 routines: */
@ -735,10 +777,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;
@ -750,22 +794,65 @@ 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 (band->coord[0][0] < band->coord[0][1]
&& band->coord[1][0] < band->coord[1][1]) {
Jpeg2000Prec *prec = band->prec + precno;
int nb_cblks = prec->nb_codeblocks_height * prec->nb_codeblocks_width;
int pos;
ff_tag_tree_zero(prec->zerobits, prec->nb_codeblocks_width, prec->nb_codeblocks_height);
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++){
if (rlevel->band[bandno].coord[0][0] < rlevel->band[bandno].coord[0][1]
&& rlevel->band[bandno].coord[1][0] < rlevel->band[bandno].coord[1][1]){
empty = 0;
break;
Jpeg2000Band *band = rlevel->band + bandno;
if (band->coord[0][0] < band->coord[0][1]
&& band->coord[1][0] < band->coord[1][1]) {
Jpeg2000Prec *prec = band->prec + precno;
int nb_cblks = prec->nb_codeblocks_height * prec->nb_codeblocks_width;
int pos;
for (pos = 0; pos < nb_cblks; pos++) {
Jpeg2000Cblk *cblk = &prec->cblk[pos];
if (cblk->layers[layno].npasses) {
empty = 0;
break;
}
}
if (!empty)
break;
}
}
put_bits(s, !empty, 1);
if (empty){
j2k_flush(s);
if (s->eph)
bytestream_put_be16(&s->buf, JPEG2000_EPH);
return 0;
}
for (bandno = 0; bandno < rlevel->nbands; bandno++){
for (bandno = 0; bandno < rlevel->nbands; bandno++) {
Jpeg2000Band *band = rlevel->band + bandno;
Jpeg2000Prec *prec = band->prec + precno;
int yi, xi, pos;
@ -775,42 +862,46 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in
|| band->coord[1][0] == band->coord[1][1])
continue;
for (pos=0, yi = 0; yi < prec->nb_codeblocks_height; yi++){
for (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)
continue;
// zerobits information
tag_tree_code(s, prec->zerobits + pos, 100);
// number of passes
putnumpasses(s, cblk->ninclpasses);
length = cblk->passes[cblk->ninclpasses-1].rate;
llen = av_log2(length) - av_log2(cblk->ninclpasses) - 2;
if (llen < 0){
pad = -llen;
llen = 0;
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
if (!cblk->incl) {
tag_tree_code(s, prec->zerobits + pos, 100);
cblk->incl = 1;
}
// number of passes
putnumpasses(s, cblk->layers[layno].npasses);
length = cblk->layers[layno].data_len;
if (layno == nlayers - 1 && cblk->layers[layno].cum_passes){
length += cblk->passes[cblk->layers[layno].cum_passes-1].flushed_len;
}
if (cblk->lblock + av_log2(cblk->layers[layno].npasses) < av_log2(length) + 1) {
llen = av_log2(length) + 1 - cblk->lblock - av_log2(cblk->layers[layno].npasses);
}
// length of code block
cblk->lblock += llen;
put_bits(s, 1, llen);
put_bits(s, 0, 1);
put_num(s, length, av_log2(length)+1+pad);
put_num(s, length, cblk->lblock + av_log2(cblk->layers[layno].npasses));
}
}
}
@ -819,21 +910,22 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in
bytestream_put_be16(&s->buf, JPEG2000_EPH);
}
for (bandno = 0; bandno < rlevel->nbands; bandno++){
for (bandno = 0; bandno < rlevel->nbands; bandno++) {
Jpeg2000Band *band = rlevel->band + bandno;
Jpeg2000Prec *prec = band->prec + precno;
int yi, cblknw = prec->nb_codeblocks_width;
for (yi =0; yi < prec->nb_codeblocks_height; yi++){
for (yi =0; yi < prec->nb_codeblocks_height; yi++) {
int xi;
for (xi = 0; xi < cblknw; xi++){
Jpeg2000Cblk *cblk = prec->cblk + yi * cblknw + xi;
if (cblk->ninclpasses){
if (s->buf_end - s->buf < cblk->passes[cblk->ninclpasses-1].rate)
if (cblk->layers[layno].npasses) {
if (s->buf_end - s->buf < cblk->layers[layno].data_len + 2)
return -1;
bytestream_put_buffer(&s->buf, cblk->data + 1, cblk->passes[cblk->ninclpasses-1].rate
- cblk->passes[cblk->ninclpasses-1].flushed_len);
bytestream_put_buffer(&s->buf, cblk->passes[cblk->ninclpasses-1].flushed,
cblk->passes[cblk->ninclpasses-1].flushed_len);
bytestream_put_buffer(&s->buf, cblk->layers[layno].data_start + 1, cblk->layers[layno].data_len);
if (layno == nlayers - 1 && cblk->layers[layno].cum_passes) {
bytestream_put_buffer(&s->buf, cblk->passes[cblk->layers[layno].cum_passes-1].flushed,
cblk->passes[cblk->layers[layno].cum_passes-1].flushed_len);
}
}
}
}
@ -841,9 +933,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;
@ -862,27 +954,31 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til
// lay-rlevel-comp-pos progression
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;
}
}
}
}
@ -937,10 +1033,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;
}
}
}
}
@ -1003,9 +1100,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;
}
}
}
}
@ -1064,9 +1163,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;
}
}
}
}
@ -1078,6 +1179,174 @@ static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int til
return 0;
}
static void makelayer(Jpeg2000EncoderContext *s, int layno, double thresh, Jpeg2000Tile* tile, int final)
{
int compno, resno, bandno, precno, cblkno;
int passno;
for (compno = 0; compno < s->ncomponents; compno++) {
Jpeg2000Component *comp = &tile->comp[compno];
for (resno = 0; resno < s->codsty.nreslevels; resno++) {
Jpeg2000ResLevel *reslevel = comp->reslevel + resno;
for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
for (bandno = 0; bandno < reslevel->nbands ; bandno++){
Jpeg2000Band *band = reslevel->band + bandno;
Jpeg2000Prec *prec = band->prec + precno;
for (cblkno = 0; cblkno < prec->nb_codeblocks_height * prec->nb_codeblocks_width; cblkno++){
Jpeg2000Cblk *cblk = prec->cblk + cblkno;
Jpeg2000Layer *layer = &cblk->layers[layno];
int n;
if (layno == 0) {
cblk->ninclpasses = 0;
}
n = cblk->ninclpasses;
if (thresh < 0) {
n = cblk->npasses;
} else {
for (passno = cblk->ninclpasses; passno < cblk->npasses; passno++) {
int32_t dr;
double dd;
Jpeg2000Pass *pass = &cblk->passes[passno];
if (n == 0) {
dr = pass->rate;
dd = pass->disto;
} else {
dr = pass->rate - cblk->passes[n - 1].rate;
dd = pass->disto - cblk->passes[n-1].disto;
}
if (!dr) {
if (dd != 0.0) {
n = passno + 1;
}
continue;
}
if (thresh - (dd / dr) < DBL_EPSILON)
n = passno + 1;
}
}
layer->npasses = n - cblk->ninclpasses;
layer->cum_passes = n;
if (layer->npasses == 0) {
layer->disto = 0;
layer->data_len = 0;
continue;
}
if (cblk->ninclpasses == 0) {
layer->data_len = cblk->passes[n - 1].rate;
layer->data_start = cblk->data;
layer->disto = cblk->passes[n - 1].disto;
} else {
layer->data_len = cblk->passes[n - 1].rate - cblk->passes[cblk->ninclpasses - 1].rate;
layer->data_start = cblk->data + cblk->passes[cblk->ninclpasses - 1].rate;
layer->disto = cblk->passes[n - 1].disto -
cblk->passes[cblk->ninclpasses - 1].disto;
}
if (final) {
cblk->ninclpasses = n;
}
}
}
}
}
}
}
static void makelayers(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile)
{
int precno, compno, reslevelno, bandno, cblkno, lev, passno, layno;
int i;
double min = DBL_MAX;
double max = 0;
double thresh;
int tile_disto = 0;
Jpeg2000CodingStyle *codsty = &s->codsty;
for (compno = 0; compno < s->ncomponents; compno++){
Jpeg2000Component *comp = tile->comp + compno;
for (reslevelno = 0, lev = codsty->nreslevels-1; reslevelno < codsty->nreslevels; reslevelno++, lev--){
Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno;
for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
for (bandno = 0; bandno < reslevel->nbands ; bandno++){
Jpeg2000Band *band = reslevel->band + bandno;
Jpeg2000Prec *prec = band->prec + precno;
for (cblkno = 0; cblkno < prec->nb_codeblocks_height * prec->nb_codeblocks_width; cblkno++){
Jpeg2000Cblk *cblk = prec->cblk + cblkno;
for (passno = 0; passno < cblk->npasses; passno++) {
Jpeg2000Pass *pass = &cblk->passes[passno];
int dr;
double dd, drslope;
tile_disto += pass->disto;
if (passno == 0) {
dr = (int32_t)pass->rate;
dd = pass->disto;
} else {
dr = (int32_t)(pass->rate - cblk->passes[passno - 1].rate);
dd = pass->disto - cblk->passes[passno - 1].disto;
}
if (dr <= 0)
continue;
drslope = dd / dr;
if (drslope < min)
min = drslope;
if (drslope > max)
max = drslope;
}
}
}
}
}
}
for (layno = 0; layno < s->nlayers; layno++) {
double lo = min;
double hi = max;
double stable_thresh = 0.0;
double good_thresh = 0.0;
if (!s->layer_rates[layno]) {
good_thresh = -1.0;
} else {
for (i = 0; i < 128; i++) {
uint8_t *stream_pos = s->buf;
int ret;
thresh = (lo + hi) / 2;
makelayer(s, layno, thresh, tile, 0);
ret = encode_packets(s, tile, (int)(tile - s->tile), layno + 1);
memset(stream_pos, 0, s->buf - stream_pos);
if ((s->buf - stream_pos > ceil(tile->layer_rates[layno])) || ret < 0) {
lo = thresh;
s->buf = stream_pos;
continue;
}
hi = thresh;
stable_thresh = thresh;
s->buf = stream_pos;
}
}
if (good_thresh >= 0.0)
good_thresh = stable_thresh == 0.0 ? thresh : stable_thresh;
makelayer(s, layno, good_thresh, tile, 1);
}
}
static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm)
{
int passno, res = 0;
@ -1086,9 +1355,9 @@ static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm)
int64_t dd;
dr = cblk->passes[passno].rate
- (res ? cblk->passes[res-1].rate:0);
- (res ? cblk->passes[res-1].rate : 0);
dd = cblk->passes[passno].disto
- (res ? cblk->passes[res-1].disto:0);
- (res ? cblk->passes[res-1].disto : 0);
if (((dd * dwt_norm) >> WMSEDEC_SHIFT) * dwt_norm >= dr * lambda)
res = passno+1;
@ -1118,6 +1387,11 @@ static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile)
cblk->ninclpasses = getcut(cblk, s->lambda,
(int64_t)dwt_norms[codsty->transform == FF_DWT53][bandpos][lev] * (int64_t)band->i_stepsize >> 15);
cblk->layers[0].data_start = cblk->data;
cblk->layers[0].cum_passes = cblk->ninclpasses;
cblk->layers[0].npasses = cblk->ninclpasses;
if (cblk->ninclpasses)
cblk->layers[0].data_len = cblk->passes[cblk->ninclpasses - 1].rate;
}
}
}
@ -1205,8 +1479,12 @@ static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno
}
av_log(s->avctx, AV_LOG_DEBUG, "rate control\n");
truncpasses(s, tile);
if ((ret = encode_packets(s, tile, tileno)) < 0)
if (s->compression_rate_enc)
makelayers(s, tile);
else
truncpasses(s, tile);
if ((ret = encode_packets(s, tile, tileno, s->nlayers)) < 0)
return ret;
av_log(s->avctx, AV_LOG_DEBUG, "after rate control\n");
return 0;
@ -1223,6 +1501,7 @@ static void cleanup(Jpeg2000EncoderContext *s)
ff_jpeg2000_cleanup(comp, codsty);
}
av_freep(&s->tile[tileno].comp);
av_freep(&s->tile[tileno].layer_rates);
}
av_freep(&s->tile);
}
@ -1381,6 +1660,53 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
static int parse_layer_rates(Jpeg2000EncoderContext *s)
{
int i;
char *token;
char *saveptr = NULL;
int rate;
int nlayers = 0;
if (!s->lr_str) {
s->nlayers = 1;
s->layer_rates[0] = 0;
s->compression_rate_enc = 0;
return 0;
}
token = av_strtok(s->lr_str, ",", &saveptr);
if (rate = strtol(token, NULL, 10)) {
s->layer_rates[0] = rate <= 1 ? 0:rate;
nlayers++;
} else {
return AVERROR_INVALIDDATA;
}
while (1) {
token = av_strtok(NULL, ",", &saveptr);
if (!token)
break;
if (rate = strtol(token, NULL, 10)) {
if (nlayers >= 100) {
return AVERROR_INVALIDDATA;
}
s->layer_rates[nlayers] = rate <= 1 ? 0:rate;
nlayers++;
} else {
return AVERROR_INVALIDDATA;
}
}
for (i = 1; i < nlayers; i++) {
if (s->layer_rates[i] >= s->layer_rates[i-1]) {
return AVERROR_INVALIDDATA;
}
}
s->nlayers = nlayers;
s->compression_rate_enc = 1;
return 0;
}
static av_cold int j2kenc_init(AVCodecContext *avctx)
{
int i, ret;
@ -1390,6 +1716,12 @@ 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. Encoding with 1 layer based on quality metric.\n");
s->nlayers = 1;
s->layer_rates[0] = 0;
s->compression_rate_enc = 0;
}
#if FF_API_PRIVATE_OPT
FF_DISABLE_DEPRECATION_WARNINGS
@ -1410,6 +1742,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;
@ -1491,6 +1824,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 }
};

View File

@ -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,7 @@ void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty)
av_freep(&cblk->passes);
av_freep(&cblk->lengthinc);
av_freep(&cblk->data_start);
av_freep(&cblk->layers);
}
av_freep(&prec->cblk);
}

View File

@ -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

View File

@ -29,7 +29,7 @@
#define LIBAVCODEC_VERSION_MAJOR 58
#define LIBAVCODEC_VERSION_MINOR 101
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \

View File

@ -1,4 +1,4 @@
d2a06ad916711d29b30977a06335bb76 *tests/data/fate/vsynth1-jpeg2000.avi
2265698 tests/data/fate/vsynth1-jpeg2000.avi
15a8e49f6fd014193bbafd72f84936c7 *tests/data/fate/vsynth1-jpeg2000.out.rawvideo
stddev: 5.36 PSNR: 33.55 MAXDIFF: 61 bytes: 7603200/ 7603200
dd66b25f2ebc965eae4c29cfacdd960f *tests/data/fate/vsynth1-jpeg2000.avi
2274950 tests/data/fate/vsynth1-jpeg2000.avi
b7f48a8965f78011c76483277befc6fc *tests/data/fate/vsynth1-jpeg2000.out.rawvideo
stddev: 5.35 PSNR: 33.56 MAXDIFF: 59 bytes: 7603200/ 7603200

View File

@ -1,4 +1,4 @@
8bb707e596f97451fd325dec2dd610a7 *tests/data/fate/vsynth1-jpeg2000-97.avi
3654620 tests/data/fate/vsynth1-jpeg2000-97.avi
5073771a78e1f5366a7eb0df341662fc *tests/data/fate/vsynth1-jpeg2000-97.out.rawvideo
f22ad99de77f8f4382c6cf10d5af42b5 *tests/data/fate/vsynth1-jpeg2000-97.avi
3661422 tests/data/fate/vsynth1-jpeg2000-97.avi
a2262f1da2f49bc196b780a6b47ec4e8 *tests/data/fate/vsynth1-jpeg2000-97.out.rawvideo
stddev: 4.23 PSNR: 35.59 MAXDIFF: 53 bytes: 7603200/ 7603200

View File

@ -1,4 +1,4 @@
6c2f979e4a33a36f36aec86f2d464143 *tests/data/fate/vsynth2-jpeg2000.avi
1494516 tests/data/fate/vsynth2-jpeg2000.avi
36afd96d6e55bc83166fd615351ba366 *tests/data/fate/vsynth2-jpeg2000.out.rawvideo
stddev: 5.00 PSNR: 34.15 MAXDIFF: 59 bytes: 7603200/ 7603200
49df1372d20dae57b4ff28ac4d81bb78 *tests/data/fate/vsynth2-jpeg2000.avi
1551520 tests/data/fate/vsynth2-jpeg2000.avi
64fadc87447268cf90503cb294db7f61 *tests/data/fate/vsynth2-jpeg2000.out.rawvideo
stddev: 4.91 PSNR: 34.29 MAXDIFF: 55 bytes: 7603200/ 7603200

View File

@ -1,4 +1,4 @@
2e43f004a55f4a55a19c4b79fc8e8743 *tests/data/fate/vsynth2-jpeg2000-97.avi
2448706 tests/data/fate/vsynth2-jpeg2000-97.avi
a6e2453118a0de135836a868b2ca0e60 *tests/data/fate/vsynth2-jpeg2000-97.out.rawvideo
stddev: 3.23 PSNR: 37.94 MAXDIFF: 29 bytes: 7603200/ 7603200
8443e3ae43675212be9a8274cfe5d5be *tests/data/fate/vsynth2-jpeg2000-97.avi
2484530 tests/data/fate/vsynth2-jpeg2000-97.avi
1f63c8b065e847e4c63d57ce23442ea8 *tests/data/fate/vsynth2-jpeg2000-97.out.rawvideo
stddev: 3.21 PSNR: 37.99 MAXDIFF: 26 bytes: 7603200/ 7603200

View File

@ -1,4 +1,4 @@
0b8aa8113c10772cffff60f9c8ffd902 *tests/data/fate/vsynth3-jpeg2000.avi
65548 tests/data/fate/vsynth3-jpeg2000.avi
2d8bd94d558755c47d7e23fd9556e164 *tests/data/fate/vsynth3-jpeg2000.out.rawvideo
stddev: 5.48 PSNR: 33.34 MAXDIFF: 47 bytes: 86700/ 86700
548df443acb32593455bbcd8f531c00b *tests/data/fate/vsynth3-jpeg2000.avi
67658 tests/data/fate/vsynth3-jpeg2000.avi
098f5980667e1fcd50452b1dc1a74f61 *tests/data/fate/vsynth3-jpeg2000.out.rawvideo
stddev: 5.47 PSNR: 33.36 MAXDIFF: 48 bytes: 86700/ 86700

View File

@ -1,4 +1,4 @@
b6c88a623c3296ca945346d2203f0af0 *tests/data/fate/vsynth3-jpeg2000-97.avi
83870 tests/data/fate/vsynth3-jpeg2000-97.avi
0cd707bfb1bbe5312b00c094f695b1fa *tests/data/fate/vsynth3-jpeg2000-97.out.rawvideo
stddev: 4.52 PSNR: 35.02 MAXDIFF: 47 bytes: 86700/ 86700
494464d224d5aa2726bc6a8630a390aa *tests/data/fate/vsynth3-jpeg2000-97.avi
86016 tests/data/fate/vsynth3-jpeg2000-97.avi
8def36ad1413ab3a5c2af2e1af4603f9 *tests/data/fate/vsynth3-jpeg2000-97.out.rawvideo
stddev: 4.51 PSNR: 35.04 MAXDIFF: 47 bytes: 86700/ 86700

View File

@ -1,4 +1,4 @@
1f2cf6061c78905b8011091a9a7c425f *tests/data/fate/vsynth_lena-jpeg2000.avi
1138054 tests/data/fate/vsynth_lena-jpeg2000.avi
955653ca7a08447e7b1501b444f24562 *tests/data/fate/vsynth_lena-jpeg2000.out.rawvideo
stddev: 4.40 PSNR: 35.25 MAXDIFF: 58 bytes: 7603200/ 7603200
e4cf380b198e6bcb00ec338914f6ebb3 *tests/data/fate/vsynth_lena-jpeg2000.avi
1202516 tests/data/fate/vsynth_lena-jpeg2000.avi
39a2c5b61cd0cf2821c6fb4cceba2fa8 *tests/data/fate/vsynth_lena-jpeg2000.out.rawvideo
stddev: 4.30 PSNR: 35.45 MAXDIFF: 45 bytes: 7603200/ 7603200

View File

@ -1,4 +1,4 @@
e5a756e97910420c90e76259c56261cb *tests/data/fate/vsynth_lena-jpeg2000-97.avi
1918956 tests/data/fate/vsynth_lena-jpeg2000-97.avi
93a4ba0c230f2430a813df594676e58a *tests/data/fate/vsynth_lena-jpeg2000-97.out.rawvideo
stddev: 2.84 PSNR: 39.04 MAXDIFF: 28 bytes: 7603200/ 7603200
29dd43765363e17179c2de4167b32399 *tests/data/fate/vsynth_lena-jpeg2000-97.avi
1958334 tests/data/fate/vsynth_lena-jpeg2000-97.avi
1b97333a8dc115a5ba609b0070d89d4d *tests/data/fate/vsynth_lena-jpeg2000-97.out.rawvideo
stddev: 2.82 PSNR: 39.10 MAXDIFF: 24 bytes: 7603200/ 7603200