+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);
+ }
+}
+