blob: 8e0cd26850dad519ce058a8424ef0eb3b034772b [file] [log] [blame]
/*
* Copyright (c) 1999-2000 Image Power, Inc. and the University of
* British Columbia.
* Copyright (c) 2001-2003 Michael David Adams.
* All rights reserved.
*/
/* __START_OF_JASPER_LICENSE__
*
* JasPer Software License
*
* IMAGE POWER JPEG-2000 PUBLIC LICENSE
* ************************************
*
* GRANT:
*
* Permission is hereby granted, free of charge, to any person (the "User")
* obtaining a copy of this software and associated documentation, to deal
* in the JasPer Software without restriction, including without limitation
* the right to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the JasPer Software (in source and binary forms),
* and to permit persons to whom the JasPer Software is furnished to do so,
* provided further that the License Conditions below are met.
*
* License Conditions
* ******************
*
* A. Redistributions of source code must retain the above copyright notice,
* and this list of conditions, and the following disclaimer.
*
* B. Redistributions in binary form must reproduce the above copyright
* notice, and this list of conditions, and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
*
* C. Neither the name of Image Power, Inc. nor any other contributor
* (including, but not limited to, the University of British Columbia and
* Michael David Adams) may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* D. User agrees that it shall not commence any action against Image Power,
* Inc., the University of British Columbia, Michael David Adams, or any
* other contributors (collectively "Licensors") for infringement of any
* intellectual property rights ("IPR") held by the User in respect of any
* technology that User owns or has a right to license or sublicense and
* which is an element required in order to claim compliance with ISO/IEC
* 15444-1 (i.e., JPEG-2000 Part 1). "IPR" means all intellectual property
* rights worldwide arising under statutory or common law, and whether
* or not perfected, including, without limitation, all (i) patents and
* patent applications owned or licensable by User; (ii) rights associated
* with works of authorship including copyrights, copyright applications,
* copyright registrations, mask work rights, mask work applications,
* mask work registrations; (iii) rights relating to the protection of
* trade secrets and confidential information; (iv) any right analogous
* to those set forth in subsections (i), (ii), or (iii) and any other
* proprietary rights relating to intangible property (other than trademark,
* trade dress, or service mark rights); and (v) divisions, continuations,
* renewals, reissues and extensions of the foregoing (as and to the extent
* applicable) now existing, hereafter filed, issued or acquired.
*
* E. If User commences an infringement action against any Licensor(s) then
* such Licensor(s) shall have the right to terminate User's license and
* all sublicenses that have been granted hereunder by User to other parties.
*
* F. This software is for use only in hardware or software products that
* are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1). No license
* or right to this Software is granted for products that do not comply
* with ISO/IEC 15444-1. The JPEG-2000 Part 1 standard can be purchased
* from the ISO.
*
* THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
* NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
* THIS DISCLAIMER. THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
* CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY
* OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
* WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE,
* IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING. THOSE INTENDING
* TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE
* OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING
* PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS.
* THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE
* IS WITH THE USER. SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE
* IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY
* OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY
* OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING,
* REPAIR OR CORRECTION. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
* WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE
* INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC.,
* MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE
* JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
* THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION,
* DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
* MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF
* SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY
* OF SUCH DAMAGES. THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT
* FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR
* RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING
* FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES,
* AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT
* LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
* JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY
* TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE
* ("HIGH RISK ACTIVITIES"). LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS
* OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. USER WILL NOT
* KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING
* TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
* CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
* NOTICE SPECIFIED IN THIS SECTION.
*
* __END_OF_JASPER_LICENSE__
*/
/*
* $Id$
*/
/******************************************************************************\
* Includes.
\******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include "jasper/jas_string.h"
#include "jasper/jas_malloc.h"
#include "jasper/jas_image.h"
#include "jasper/jas_fix.h"
#include "jasper/jas_tvp.h"
#include "jasper/jas_version.h"
#include "jasper/jas_math.h"
#include "jasper/jas_debug.h"
#include "jpc_flt.h"
#include "jpc_fix.h"
#include "jpc_tagtree.h"
#include "jpc_enc.h"
#include "jpc_cs.h"
#include "jpc_mct.h"
#include "jpc_tsfb.h"
#include "jpc_qmfb.h"
#include "jpc_t1enc.h"
#include "jpc_t2enc.h"
#include "jpc_cod.h"
#include "jpc_math.h"
#include "jpc_util.h"
/******************************************************************************\
*
\******************************************************************************/
#define JPC_POW2(n) \
(1 << (n))
#define JPC_FLOORTOMULTPOW2(x, n) \
(((n) > 0) ? ((x) & (~((1 << n) - 1))) : (x))
/* Round to the nearest multiple of the specified power of two in the
direction of negative infinity. */
#define JPC_CEILTOMULTPOW2(x, n) \
(((n) > 0) ? JPC_FLOORTOMULTPOW2(((x) + (1 << (n)) - 1), n) : (x))
/* Round to the nearest multiple of the specified power of two in the
direction of positive infinity. */
#define JPC_POW2(n) \
(1 << (n))
jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno);
void jpc_enc_tile_destroy(jpc_enc_tile_t *tile);
static jpc_enc_tcmpt_t *tcmpt_create(jpc_enc_tcmpt_t *tcmpt, jpc_enc_cp_t *cp,
jas_image_t *image, jpc_enc_tile_t *tile);
static void tcmpt_destroy(jpc_enc_tcmpt_t *tcmpt);
static jpc_enc_rlvl_t *rlvl_create(jpc_enc_rlvl_t *rlvl, jpc_enc_cp_t *cp,
jpc_enc_tcmpt_t *tcmpt, jpc_tsfb_band_t *bandinfos);
static void rlvl_destroy(jpc_enc_rlvl_t *rlvl);
static jpc_enc_band_t *band_create(jpc_enc_band_t *band, jpc_enc_cp_t *cp,
jpc_enc_rlvl_t *rlvl, jpc_tsfb_band_t *bandinfos);
static void band_destroy(jpc_enc_band_t *bands);
static jpc_enc_prc_t *prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp,
jpc_enc_band_t *band);
static void prc_destroy(jpc_enc_prc_t *prcs);
static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp,
jpc_enc_prc_t *prc);
static void cblk_destroy(jpc_enc_cblk_t *cblks);
int ratestrtosize(char *s, uint_fast32_t rawsize, uint_fast32_t *size);
static void pass_destroy(jpc_enc_pass_t *pass);
void jpc_enc_dump(jpc_enc_t *enc);
/******************************************************************************\
* Local prototypes.
\******************************************************************************/
int dump_passes(jpc_enc_pass_t *passes, int numpasses, jpc_enc_cblk_t *cblk);
void calcrdslopes(jpc_enc_cblk_t *cblk);
void dump_layeringinfo(jpc_enc_t *enc);
static int jpc_calcssexp(jpc_fix_t stepsize);
static int jpc_calcssmant(jpc_fix_t stepsize);
void quantize(jas_matrix_t *data, jpc_fix_t stepsize);
static int jpc_enc_encodemainhdr(jpc_enc_t *enc);
static int jpc_enc_encodemainbody(jpc_enc_t *enc);
int jpc_enc_encodetiledata(jpc_enc_t *enc);
jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image);
void jpc_enc_destroy(jpc_enc_t *enc);
static int jpc_enc_encodemainhdr(jpc_enc_t *enc);
static int jpc_enc_encodemainbody(jpc_enc_t *enc);
int jpc_enc_encodetiledata(jpc_enc_t *enc);
int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens);
int setins(int numvalues, jpc_flt_t *values, jpc_flt_t value);
static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image);
void jpc_enc_cp_destroy(jpc_enc_cp_t *cp);
static uint_fast32_t jpc_abstorelstepsize(jpc_fix_t absdelta, int scaleexpn);
static uint_fast32_t jpc_abstorelstepsize(jpc_fix_t absdelta, int scaleexpn)
{
int p;
uint_fast32_t mant;
uint_fast32_t expn;
int n;
if (absdelta < 0) {
abort();
}
p = jpc_firstone(absdelta) - JPC_FIX_FRACBITS;
n = 11 - jpc_firstone(absdelta);
mant = ((n < 0) ? (absdelta >> (-n)) : (absdelta << n)) & 0x7ff;
expn = scaleexpn - p;
if (scaleexpn < p) {
abort();
}
return JPC_QCX_EXPN(expn) | JPC_QCX_MANT(mant);
}
typedef enum {
OPT_DEBUG,
OPT_IMGAREAOFFX,
OPT_IMGAREAOFFY,
OPT_TILEGRDOFFX,
OPT_TILEGRDOFFY,
OPT_TILEWIDTH,
OPT_TILEHEIGHT,
OPT_PRCWIDTH,
OPT_PRCHEIGHT,
OPT_CBLKWIDTH,
OPT_CBLKHEIGHT,
OPT_MODE,
OPT_PRG,
OPT_NOMCT,
OPT_MAXRLVLS,
OPT_SOP,
OPT_EPH,
OPT_LAZY,
OPT_TERMALL,
OPT_SEGSYM,
OPT_VCAUSAL,
OPT_RESET,
OPT_PTERM,
OPT_NUMGBITS,
OPT_RATE,
OPT_ILYRRATES,
OPT_JP2OVERHEAD
} optid_t;
jas_taginfo_t encopts[] = {
{OPT_DEBUG, "debug"},
{OPT_IMGAREAOFFX, "imgareatlx"},
{OPT_IMGAREAOFFY, "imgareatly"},
{OPT_TILEGRDOFFX, "tilegrdtlx"},
{OPT_TILEGRDOFFY, "tilegrdtly"},
{OPT_TILEWIDTH, "tilewidth"},
{OPT_TILEHEIGHT, "tileheight"},
{OPT_PRCWIDTH, "prcwidth"},
{OPT_PRCHEIGHT, "prcheight"},
{OPT_CBLKWIDTH, "cblkwidth"},
{OPT_CBLKHEIGHT, "cblkheight"},
{OPT_MODE, "mode"},
{OPT_PRG, "prg"},
{OPT_NOMCT, "nomct"},
{OPT_MAXRLVLS, "numrlvls"},
{OPT_SOP, "sop"},
{OPT_EPH, "eph"},
{OPT_LAZY, "lazy"},
{OPT_TERMALL, "termall"},
{OPT_SEGSYM, "segsym"},
{OPT_VCAUSAL, "vcausal"},
{OPT_PTERM, "pterm"},
{OPT_RESET, "resetprob"},
{OPT_NUMGBITS, "numgbits"},
{OPT_RATE, "rate"},
{OPT_ILYRRATES, "ilyrrates"},
{OPT_JP2OVERHEAD, "_jp2overhead"},
{-1, 0}
};
typedef enum {
PO_L = 0,
PO_R
} poid_t;
jas_taginfo_t prgordtab[] = {
{JPC_COD_LRCPPRG, "lrcp"},
{JPC_COD_RLCPPRG, "rlcp"},
{JPC_COD_RPCLPRG, "rpcl"},
{JPC_COD_PCRLPRG, "pcrl"},
{JPC_COD_CPRLPRG, "cprl"},
{-1, 0}
};
typedef enum {
MODE_INT,
MODE_REAL
} modeid_t;
jas_taginfo_t modetab[] = {
{MODE_INT, "int"},
{MODE_REAL, "real"},
{-1, 0}
};
/******************************************************************************\
* The main encoder entry point.
\******************************************************************************/
int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
{
jpc_enc_t *enc;
jpc_enc_cp_t *cp;
enc = 0;
cp = 0;
jpc_initluts();
if (!(cp = cp_create(optstr, image))) {
fprintf(stderr, "invalid JP encoder options\n");
goto error;
}
if (!(enc = jpc_enc_create(cp, out, image))) {
goto error;
}
cp = 0;
/* Encode the main header. */
if (jpc_enc_encodemainhdr(enc)) {
goto error;
}
/* Encode the main body. This constitutes most of the encoding work. */
if (jpc_enc_encodemainbody(enc)) {
goto error;
}
/* Write EOC marker segment. */
if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) {
goto error;
}
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write EOI marker\n");
goto error;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
if (jas_stream_flush(enc->out)) {
goto error;
}
jpc_enc_destroy(enc);
return 0;
error:
if (cp) {
jpc_enc_cp_destroy(cp);
}
if (enc) {
jpc_enc_destroy(enc);
}
return -1;
}
/******************************************************************************\
* Option parsing code.
\******************************************************************************/
static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image)
{
jpc_enc_cp_t *cp;
jas_tvparser_t *tvp;
int ret;
int numilyrrates;
double *ilyrrates;
int i;
int tagid;
jpc_enc_tcp_t *tcp;
jpc_enc_tccp_t *tccp;
jpc_enc_ccp_t *ccp;
int cmptno;
uint_fast16_t rlvlno;
uint_fast16_t prcwidthexpn;
uint_fast16_t prcheightexpn;
bool enablemct;
uint_fast32_t jp2overhead;
uint_fast16_t lyrno;
uint_fast32_t hsteplcm;
uint_fast32_t vsteplcm;
bool mctvalid;
tvp = 0;
cp = 0;
ilyrrates = 0;
numilyrrates = 0;
if (!(cp = jas_malloc(sizeof(jpc_enc_cp_t)))) {
goto error;
}
prcwidthexpn = 15;
prcheightexpn = 15;
enablemct = true;
jp2overhead = 0;
cp->ccps = 0;
cp->debug = 0;
cp->imgareatlx = UINT_FAST32_MAX;
cp->imgareatly = UINT_FAST32_MAX;
cp->refgrdwidth = 0;
cp->refgrdheight = 0;
cp->tilegrdoffx = UINT_FAST32_MAX;
cp->tilegrdoffy = UINT_FAST32_MAX;
cp->tilewidth = 0;
cp->tileheight = 0;
cp->numcmpts = jas_image_numcmpts(image);
hsteplcm = 1;
vsteplcm = 1;
for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
if (jas_image_cmptbrx(image, cmptno) + jas_image_cmpthstep(image, cmptno) <=
jas_image_brx(image) || jas_image_cmptbry(image, cmptno) +
jas_image_cmptvstep(image, cmptno) <= jas_image_bry(image)) {
fprintf(stderr, "unsupported image type\n");
goto error;
}
/* Note: We ought to be calculating the LCMs here. Fix some day. */
hsteplcm *= jas_image_cmpthstep(image, cmptno);
vsteplcm *= jas_image_cmptvstep(image, cmptno);
}
if (!(cp->ccps = jas_malloc(cp->numcmpts * sizeof(jpc_enc_ccp_t)))) {
goto error;
}
for (cmptno = 0, ccp = cp->ccps; cmptno < JAS_CAST(int, cp->numcmpts); ++cmptno,
++ccp) {
ccp->sampgrdstepx = jas_image_cmpthstep(image, cmptno);
ccp->sampgrdstepy = jas_image_cmptvstep(image, cmptno);
/* XXX - this isn't quite correct for more general image */
ccp->sampgrdsubstepx = 0;
ccp->sampgrdsubstepx = 0;
ccp->prec = jas_image_cmptprec(image, cmptno);
ccp->sgnd = jas_image_cmptsgnd(image, cmptno);
ccp->numstepsizes = 0;
memset(ccp->stepsizes, 0, sizeof(ccp->stepsizes));
}
cp->rawsize = jas_image_rawsize(image);
cp->totalsize = UINT_FAST32_MAX;
tcp = &cp->tcp;
tcp->csty = 0;
tcp->intmode = true;
tcp->prg = JPC_COD_LRCPPRG;
tcp->numlyrs = 1;
tcp->ilyrrates = 0;
tccp = &cp->tccp;
tccp->csty = 0;
tccp->maxrlvls = 6;
tccp->cblkwidthexpn = 6;
tccp->cblkheightexpn = 6;
tccp->cblksty = 0;
tccp->numgbits = 2;
if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
goto error;
}
while (!(ret = jas_tvparser_next(tvp))) {
switch (jas_taginfo_nonull(jas_taginfos_lookup(encopts,
jas_tvparser_gettag(tvp)))->id) {
case OPT_DEBUG:
cp->debug = atoi(jas_tvparser_getval(tvp));
break;
case OPT_IMGAREAOFFX:
cp->imgareatlx = atoi(jas_tvparser_getval(tvp));
break;
case OPT_IMGAREAOFFY:
cp->imgareatly = atoi(jas_tvparser_getval(tvp));
break;
case OPT_TILEGRDOFFX:
cp->tilegrdoffx = atoi(jas_tvparser_getval(tvp));
break;
case OPT_TILEGRDOFFY:
cp->tilegrdoffy = atoi(jas_tvparser_getval(tvp));
break;
case OPT_TILEWIDTH:
cp->tilewidth = atoi(jas_tvparser_getval(tvp));
break;
case OPT_TILEHEIGHT:
cp->tileheight = atoi(jas_tvparser_getval(tvp));
break;
case OPT_PRCWIDTH:
prcwidthexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
break;
case OPT_PRCHEIGHT:
prcheightexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
break;
case OPT_CBLKWIDTH:
tccp->cblkwidthexpn =
jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
break;
case OPT_CBLKHEIGHT:
tccp->cblkheightexpn =
jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
break;
case OPT_MODE:
if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(modetab,
jas_tvparser_getval(tvp)))->id) < 0) {
fprintf(stderr,
"ignoring invalid mode %s\n",
jas_tvparser_getval(tvp));
} else {
tcp->intmode = (tagid == MODE_INT);
}
break;
case OPT_PRG:
if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(prgordtab,
jas_tvparser_getval(tvp)))->id) < 0) {
fprintf(stderr,
"ignoring invalid progression order %s\n",
jas_tvparser_getval(tvp));
} else {
tcp->prg = tagid;
}
break;
case OPT_NOMCT:
enablemct = false;
break;
case OPT_MAXRLVLS:
tccp->maxrlvls = atoi(jas_tvparser_getval(tvp));
break;
case OPT_SOP:
cp->tcp.csty |= JPC_COD_SOP;
break;
case OPT_EPH:
cp->tcp.csty |= JPC_COD_EPH;
break;
case OPT_LAZY:
tccp->cblksty |= JPC_COX_LAZY;
break;
case OPT_TERMALL:
tccp->cblksty |= JPC_COX_TERMALL;
break;
case OPT_SEGSYM:
tccp->cblksty |= JPC_COX_SEGSYM;
break;
case OPT_VCAUSAL:
tccp->cblksty |= JPC_COX_VSC;
break;
case OPT_RESET:
tccp->cblksty |= JPC_COX_RESET;
break;
case OPT_PTERM:
tccp->cblksty |= JPC_COX_PTERM;
break;
case OPT_NUMGBITS:
cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp));
break;
case OPT_RATE:
if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
&cp->totalsize)) {
fprintf(stderr,
"ignoring bad rate specifier %s\n",
jas_tvparser_getval(tvp));
}
break;
case OPT_ILYRRATES:
if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates,
&ilyrrates)) {
fprintf(stderr,
"warning: invalid intermediate layer rates specifier ignored (%s)\n",
jas_tvparser_getval(tvp));
}
break;
case OPT_JP2OVERHEAD:
jp2overhead = atoi(jas_tvparser_getval(tvp));
break;
default:
fprintf(stderr, "warning: ignoring invalid option %s\n",
jas_tvparser_gettag(tvp));
break;
}
}
jas_tvparser_destroy(tvp);
tvp = 0;
if (cp->totalsize != UINT_FAST32_MAX) {
cp->totalsize = (cp->totalsize > jp2overhead) ?
(cp->totalsize - jp2overhead) : 0;
}
if (cp->imgareatlx == UINT_FAST32_MAX) {
cp->imgareatlx = 0;
} else {
if (hsteplcm != 1) {
fprintf(stderr, "warning: overriding imgareatlx value\n");
}
cp->imgareatlx *= hsteplcm;
}
if (cp->imgareatly == UINT_FAST32_MAX) {
cp->imgareatly = 0;
} else {
if (vsteplcm != 1) {
fprintf(stderr, "warning: overriding imgareatly value\n");
}
cp->imgareatly *= vsteplcm;
}
cp->refgrdwidth = cp->imgareatlx + jas_image_width(image);
cp->refgrdheight = cp->imgareatly + jas_image_height(image);
if (cp->tilegrdoffx == UINT_FAST32_MAX) {
cp->tilegrdoffx = cp->imgareatlx;
}
if (cp->tilegrdoffy == UINT_FAST32_MAX) {
cp->tilegrdoffy = cp->imgareatly;
}
if (!cp->tilewidth) {
cp->tilewidth = cp->refgrdwidth - cp->tilegrdoffx;
}
if (!cp->tileheight) {
cp->tileheight = cp->refgrdheight - cp->tilegrdoffy;
}
if (cp->numcmpts == 3) {
mctvalid = true;
for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
if (jas_image_cmptprec(image, cmptno) != jas_image_cmptprec(image, 0) ||
jas_image_cmptsgnd(image, cmptno) != jas_image_cmptsgnd(image, 0) ||
jas_image_cmptwidth(image, cmptno) != jas_image_cmptwidth(image, 0) ||
jas_image_cmptheight(image, cmptno) != jas_image_cmptheight(image, 0)) {
mctvalid = false;
}
}
} else {
mctvalid = false;
}
if (mctvalid && enablemct && jas_clrspc_fam(jas_image_clrspc(image)) != JAS_CLRSPC_FAM_RGB) {
fprintf(stderr, "warning: color space apparently not RGB\n");
}
if (mctvalid && enablemct && jas_clrspc_fam(jas_image_clrspc(image)) == JAS_CLRSPC_FAM_RGB) {
tcp->mctid = (tcp->intmode) ? (JPC_MCT_RCT) : (JPC_MCT_ICT);
} else {
tcp->mctid = JPC_MCT_NONE;
}
tccp->qmfbid = (tcp->intmode) ? (JPC_COX_RFT) : (JPC_COX_INS);
for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
tccp->prcwidthexpns[rlvlno] = prcwidthexpn;
tccp->prcheightexpns[rlvlno] = prcheightexpn;
}
if (prcwidthexpn != 15 || prcheightexpn != 15) {
tccp->csty |= JPC_COX_PRT;
}
/* Ensure that the tile width and height is valid. */
if (!cp->tilewidth) {
fprintf(stderr, "invalid tile width %lu\n", (unsigned long)
cp->tilewidth);
goto error;
}
if (!cp->tileheight) {
fprintf(stderr, "invalid tile height %lu\n", (unsigned long)
cp->tileheight);
goto error;
}
/* Ensure that the tile grid offset is valid. */
if (cp->tilegrdoffx > cp->imgareatlx ||
cp->tilegrdoffy > cp->imgareatly ||
cp->tilegrdoffx + cp->tilewidth < cp->imgareatlx ||
cp->tilegrdoffy + cp->tileheight < cp->imgareatly) {
fprintf(stderr, "invalid tile grid offset (%lu, %lu)\n",
(unsigned long) cp->tilegrdoffx, (unsigned long)
cp->tilegrdoffy);
goto error;
}
cp->numhtiles = JPC_CEILDIV(cp->refgrdwidth - cp->tilegrdoffx,
cp->tilewidth);
cp->numvtiles = JPC_CEILDIV(cp->refgrdheight - cp->tilegrdoffy,
cp->tileheight);
cp->numtiles = cp->numhtiles * cp->numvtiles;
if (ilyrrates && numilyrrates > 0) {
tcp->numlyrs = numilyrrates + 1;
if (!(tcp->ilyrrates = jas_malloc((tcp->numlyrs - 1) *
sizeof(jpc_fix_t)))) {
goto error;
}
for (i = 0; i < JAS_CAST(int, tcp->numlyrs - 1); ++i) {
tcp->ilyrrates[i] = jpc_dbltofix(ilyrrates[i]);
}
}
/* Ensure that the integer mode is used in the case of lossless
coding. */
if (cp->totalsize == UINT_FAST32_MAX && (!cp->tcp.intmode)) {
fprintf(stderr, "cannot use real mode for lossless coding\n");
goto error;
}
/* Ensure that the precinct width is valid. */
if (prcwidthexpn > 15) {
fprintf(stderr, "invalid precinct width\n");
goto error;
}
/* Ensure that the precinct height is valid. */
if (prcheightexpn > 15) {
fprintf(stderr, "invalid precinct height\n");
goto error;
}
/* Ensure that the code block width is valid. */
if (cp->tccp.cblkwidthexpn < 2 || cp->tccp.cblkwidthexpn > 12) {
fprintf(stderr, "invalid code block width %d\n",
JPC_POW2(cp->tccp.cblkwidthexpn));
goto error;
}
/* Ensure that the code block height is valid. */
if (cp->tccp.cblkheightexpn < 2 || cp->tccp.cblkheightexpn > 12) {
fprintf(stderr, "invalid code block height %d\n",
JPC_POW2(cp->tccp.cblkheightexpn));
goto error;
}
/* Ensure that the code block size is not too large. */
if (cp->tccp.cblkwidthexpn + cp->tccp.cblkheightexpn > 12) {
fprintf(stderr, "code block size too large\n");
goto error;
}
/* Ensure that the number of layers is valid. */
if (cp->tcp.numlyrs > 16384) {
fprintf(stderr, "too many layers\n");
goto error;
}
/* There must be at least one resolution level. */
if (cp->tccp.maxrlvls < 1) {
fprintf(stderr, "must be at least one resolution level\n");
goto error;
}
/* Ensure that the number of guard bits is valid. */
if (cp->tccp.numgbits > 8) {
fprintf(stderr, "invalid number of guard bits\n");
goto error;
}
/* Ensure that the rate is within the legal range. */
if (cp->totalsize != UINT_FAST32_MAX && cp->totalsize > cp->rawsize) {
fprintf(stderr, "warning: specified rate is unreasonably large (%lu > %lu)\n", (unsigned long) cp->totalsize, (unsigned long) cp->rawsize);
}
/* Ensure that the intermediate layer rates are valid. */
if (tcp->numlyrs > 1) {
/* The intermediate layers rates must increase monotonically. */
for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) {
if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) {
fprintf(stderr, "intermediate layer rates must increase monotonically\n");
goto error;
}
}
/* The intermediate layer rates must be less than the overall rate. */
if (cp->totalsize != UINT_FAST32_MAX) {
for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) {
if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) > ((double) cp->totalsize)
/ cp->rawsize) {
fprintf(stderr, "warning: intermediate layer rates must be less than overall rate\n");
goto error;
}
}
}
}
if (ilyrrates) {
jas_free(ilyrrates);
}
return cp;
error:
if (ilyrrates) {
jas_free(ilyrrates);
}
if (tvp) {
jas_tvparser_destroy(tvp);
}
if (cp) {
jpc_enc_cp_destroy(cp);
}
return 0;
}
void jpc_enc_cp_destroy(jpc_enc_cp_t *cp)
{
if (cp->ccps) {
if (cp->tcp.ilyrrates) {
jas_free(cp->tcp.ilyrrates);
}
jas_free(cp->ccps);
}
jas_free(cp);
}
int ratestrtosize(char *s, uint_fast32_t rawsize, uint_fast32_t *size)
{
char *cp;
jpc_flt_t f;
/* Note: This function must not modify output size on failure. */
if ((cp = strchr(s, 'B'))) {
*size = atoi(s);
} else {
f = atof(s);
if (f < 0) {
*size = 0;
} else if (f > 1.0) {
*size = rawsize + 1;
} else {
*size = (unsigned int)(f * rawsize);
}
}
return 0;
}
/******************************************************************************\
* Encoder constructor and destructor.
\******************************************************************************/
jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image)
{
jpc_enc_t *enc;
enc = 0;
if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) {
goto error;
}
enc->image = image;
enc->out = out;
enc->cp = cp;
enc->cstate = 0;
enc->tmpstream = 0;
enc->mrk = 0;
enc->curtile = 0;
if (!(enc->cstate = jpc_cstate_create())) {
goto error;
}
enc->len = 0;
enc->mainbodysize = 0;
return enc;
error:
if (enc) {
jpc_enc_destroy(enc);
}
return 0;
}
void jpc_enc_destroy(jpc_enc_t *enc)
{
/* The image object (i.e., enc->image) and output stream object
(i.e., enc->out) are created outside of the encoder.
Therefore, they must not be destroyed here. */
if (enc->curtile) {
jpc_enc_tile_destroy(enc->curtile);
}
if (enc->cp) {
jpc_enc_cp_destroy(enc->cp);
}
if (enc->cstate) {
jpc_cstate_destroy(enc->cstate);
}
if (enc->tmpstream) {
jas_stream_close(enc->tmpstream);
}
jas_free(enc);
}
/******************************************************************************\
* Code.
\******************************************************************************/
static int jpc_calcssmant(jpc_fix_t stepsize)
{
int n;
int e;
int m;
n = jpc_firstone(stepsize);
e = n - JPC_FIX_FRACBITS;
if (n >= 11) {
m = (stepsize >> (n - 11)) & 0x7ff;
} else {
m = (stepsize & ((1 << n) - 1)) << (11 - n);
}
return m;
}
static int jpc_calcssexp(jpc_fix_t stepsize)
{
return jpc_firstone(stepsize) - JPC_FIX_FRACBITS;
}
static int jpc_enc_encodemainhdr(jpc_enc_t *enc)
{
jpc_siz_t *siz;
jpc_cod_t *cod;
jpc_qcd_t *qcd;
int i;
long startoff;
long mainhdrlen;
jpc_enc_cp_t *cp;
jpc_qcc_t *qcc;
jpc_enc_tccp_t *tccp;
uint_fast16_t cmptno;
jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];
jpc_fix_t mctsynweight;
jpc_enc_tcp_t *tcp;
jpc_tsfb_t *tsfb;
jpc_tsfb_band_t *bandinfo;
uint_fast16_t numbands;
uint_fast16_t bandno;
uint_fast16_t rlvlno;
uint_fast16_t analgain;
jpc_fix_t absstepsize;
char buf[1024];
jpc_com_t *com;
cp = enc->cp;
startoff = jas_stream_getrwcount(enc->out);
/* Write SOC marker segment. */
if (!(enc->mrk = jpc_ms_create(JPC_MS_SOC))) {
return -1;
}
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write SOC marker\n");
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
/* Write SIZ marker segment. */
if (!(enc->mrk = jpc_ms_create(JPC_MS_SIZ))) {
return -1;
}
siz = &enc->mrk->parms.siz;
siz->caps = 0;
siz->xoff = cp->imgareatlx;
siz->yoff = cp->imgareatly;
siz->width = cp->refgrdwidth;
siz->height = cp->refgrdheight;
siz->tilexoff = cp->tilegrdoffx;
siz->tileyoff = cp->tilegrdoffy;
siz->tilewidth = cp->tilewidth;
siz->tileheight = cp->tileheight;
siz->numcomps = cp->numcmpts;
siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t));
assert(siz->comps);
for (i = 0; i < JAS_CAST(int, cp->numcmpts); ++i) {
siz->comps[i].prec = cp->ccps[i].prec;
siz->comps[i].sgnd = cp->ccps[i].sgnd;
siz->comps[i].hsamp = cp->ccps[i].sampgrdstepx;
siz->comps[i].vsamp = cp->ccps[i].sampgrdstepy;
}
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write SIZ marker\n");
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
if (!(enc->mrk = jpc_ms_create(JPC_MS_COM))) {
return -1;
}
sprintf(buf, "Creator: JasPer Version %s", jas_getversion());
com = &enc->mrk->parms.com;
com->len = strlen(buf);
com->regid = JPC_COM_LATIN;
if (!(com->data = JAS_CAST(uchar *, jas_strdup(buf)))) {
abort();
}
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write COM marker\n");
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
#if 0
if (!(enc->mrk = jpc_ms_create(JPC_MS_CRG))) {
return -1;
}
crg = &enc->mrk->parms.crg;
crg->comps = jas_malloc(crg->numcomps * sizeof(jpc_crgcomp_t));
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write CRG marker\n");
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
#endif
tcp = &cp->tcp;
tccp = &cp->tccp;
for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
tsfb = jpc_cod_gettsfb(tccp->qmfbid, tccp->maxrlvls - 1);
jpc_tsfb_getbands(tsfb, 0, 0, 1 << tccp->maxrlvls, 1 << tccp->maxrlvls,
bandinfos);
jpc_tsfb_destroy(tsfb);
mctsynweight = jpc_mct_getsynweight(tcp->mctid, cmptno);
numbands = 3 * tccp->maxrlvls - 2;
for (bandno = 0, bandinfo = bandinfos; bandno < numbands;
++bandno, ++bandinfo) {
rlvlno = (bandno) ? ((bandno - 1) / 3 + 1) : 0;
analgain = JPC_NOMINALGAIN(tccp->qmfbid, tccp->maxrlvls,
rlvlno, bandinfo->orient);
if (!tcp->intmode) {
absstepsize = jpc_fix_div(jpc_inttofix(1 <<
(analgain + 1)), bandinfo->synenergywt);
} else {
absstepsize = jpc_inttofix(1);
}
cp->ccps[cmptno].stepsizes[bandno] =
jpc_abstorelstepsize(absstepsize,
cp->ccps[cmptno].prec + analgain);
}
cp->ccps[cmptno].numstepsizes = numbands;
}
if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
return -1;
}
cod = &enc->mrk->parms.cod;
cod->csty = cp->tccp.csty | cp->tcp.csty;
cod->compparms.csty = cp->tccp.csty | cp->tcp.csty;
cod->compparms.numdlvls = cp->tccp.maxrlvls - 1;
cod->compparms.numrlvls = cp->tccp.maxrlvls;
cod->prg = cp->tcp.prg;
cod->numlyrs = cp->tcp.numlyrs;
cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkwidthexpn);
cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkheightexpn);
cod->compparms.cblksty = cp->tccp.cblksty;
cod->compparms.qmfbid = cp->tccp.qmfbid;
cod->mctrans = (cp->tcp.mctid != JPC_MCT_NONE);
if (tccp->csty & JPC_COX_PRT) {
for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
cod->compparms.rlvls[rlvlno].parwidthval = tccp->prcwidthexpns[rlvlno];
cod->compparms.rlvls[rlvlno].parheightval = tccp->prcheightexpns[rlvlno];
}
}
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write COD marker\n");
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
if (!(enc->mrk = jpc_ms_create(JPC_MS_QCD))) {
return -1;
}
qcd = &enc->mrk->parms.qcd;
qcd->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
JPC_QCX_SEQNT : JPC_QCX_NOQNT;
qcd->compparms.numstepsizes = cp->ccps[0].numstepsizes;
qcd->compparms.numguard = cp->tccp.numgbits;
qcd->compparms.stepsizes = cp->ccps[0].stepsizes;
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
return -1;
}
/* We do not want the step size array to be freed! */
qcd->compparms.stepsizes = 0;
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
tccp = &cp->tccp;
for (cmptno = 1; cmptno < cp->numcmpts; ++cmptno) {
if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
return -1;
}
qcc = &enc->mrk->parms.qcc;
qcc->compno = cmptno;
qcc->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
JPC_QCX_SEQNT : JPC_QCX_NOQNT;
qcc->compparms.numstepsizes = cp->ccps[cmptno].numstepsizes;
qcc->compparms.numguard = cp->tccp.numgbits;
qcc->compparms.stepsizes = cp->ccps[cmptno].stepsizes;
if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
return -1;
}
/* We do not want the step size array to be freed! */
qcc->compparms.stepsizes = 0;
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
}
#define MAINTLRLEN 2
mainhdrlen = jas_stream_getrwcount(enc->out) - startoff;
enc->len += mainhdrlen;
if (enc->cp->totalsize != UINT_FAST32_MAX) {
uint_fast32_t overhead;
overhead = mainhdrlen + MAINTLRLEN;
enc->mainbodysize = (enc->cp->totalsize >= overhead) ?
(enc->cp->totalsize - overhead) : 0;
} else {
enc->mainbodysize = UINT_FAST32_MAX;
}
return 0;
}
static int jpc_enc_encodemainbody(jpc_enc_t *enc)
{
int tileno;
int tilex;
int tiley;
int i;
jpc_sot_t *sot;
jpc_enc_tcmpt_t *comp;
jpc_enc_tcmpt_t *endcomps;
jpc_enc_band_t *band;
jpc_enc_band_t *endbands;
jpc_enc_rlvl_t *lvl;
int rlvlno;
jpc_qcc_t *qcc;
jpc_cod_t *cod;
int adjust;
int j;
int absbandno;
long numbytes;
long tilehdrlen;
long tilelen;
jpc_enc_tile_t *tile;
jpc_enc_cp_t *cp;
double rho;
int lyrno;
int cmptno;
int samestepsizes;
jpc_enc_ccp_t *ccps;
jpc_enc_tccp_t *tccp;
int bandno;
uint_fast32_t x;
uint_fast32_t y;
int mingbits;
int actualnumbps;
jpc_fix_t mxmag;
jpc_fix_t mag;
int numgbits;
cp = enc->cp;
/* Avoid compile warnings. */
numbytes = 0;
for (tileno = 0; tileno < JAS_CAST(int, cp->numtiles); ++tileno) {
tilex = tileno % cp->numhtiles;
tiley = tileno / cp->numhtiles;
if (!(enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno))) {
abort();
}
tile = enc->curtile;
if (jas_getdbglevel() >= 10) {
jpc_enc_dump(enc);
}
endcomps = &tile->tcmpts[tile->numtcmpts];
for (cmptno = 0, comp = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno, ++comp) {
if (!cp->ccps[cmptno].sgnd) {
adjust = 1 << (cp->ccps[cmptno].prec - 1);
for (i = 0; i < jas_matrix_numrows(comp->data); ++i) {
for (j = 0; j < jas_matrix_numcols(comp->data); ++j) {
*jas_matrix_getref(comp->data, i, j) -= adjust;
}
}
}
}
if (!tile->intmode) {
endcomps = &tile->tcmpts[tile->numtcmpts];
for (comp = tile->tcmpts; comp != endcomps; ++comp) {
jas_matrix_asl(comp->data, JPC_FIX_FRACBITS);
}
}
switch (tile->mctid) {
case JPC_MCT_RCT:
assert(jas_image_numcmpts(enc->image) == 3);
jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data,
tile->tcmpts[2].data);
break;
case JPC_MCT_ICT:
assert(jas_image_numcmpts(enc->image) == 3);
jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data,
tile->tcmpts[2].data);
break;
default:
break;
}
for (i = 0; i < jas_image_numcmpts(enc->image); ++i) {
comp = &tile->tcmpts[i];
jpc_tsfb_analyze(comp->tsfb, ((comp->qmfbid == JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), comp->data);
}
endcomps = &tile->tcmpts[tile->numtcmpts];
for (cmptno = 0, comp = tile->tcmpts; comp != endcomps; ++cmptno, ++comp) {
mingbits = 0;
absbandno = 0;
/* All bands must have a corresponding quantizer step size,
even if they contain no samples and are never coded. */
/* Some bands may not be hit by the loop below, so we must
initialize all of the step sizes to a sane value. */
memset(comp->stepsizes, 0, sizeof(comp->stepsizes));
for (rlvlno = 0, lvl = comp->rlvls; rlvlno < comp->numrlvls; ++rlvlno, ++lvl) {
if (!lvl->bands) {
absbandno += rlvlno ? 3 : 1;
continue;
}
endbands = &lvl->bands[lvl->numbands];
for (band = lvl->bands; band != endbands; ++band) {
if (!band->data) {
++absbandno;
continue;
}
actualnumbps = 0;
mxmag = 0;
for (y = 0; y < JAS_CAST(uint_fast32_t, jas_matrix_numrows(band->data)); ++y) {
for (x = 0; x < JAS_CAST(uint_fast32_t, jas_matrix_numcols(band->data)); ++x) {
mag = abs(jas_matrix_get(band->data, y, x));
if (mag > mxmag) {
mxmag = mag;
}
}
}
if (tile->intmode) {
actualnumbps = jpc_firstone(mxmag) + 1;
} else {
actualnumbps = jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS;
}
numgbits = actualnumbps - (cp->ccps[cmptno].prec - 1 +
band->analgain);
#if 0
fprintf(stderr, "%d %d mag=%d actual=%d numgbits=%d\n", cp->ccps[cmptno].prec, band->analgain, mxmag, actualnumbps, numgbits);
#endif
if (numgbits > mingbits) {
mingbits = numgbits;
}
if (!tile->intmode) {
band->absstepsize = jpc_fix_div(jpc_inttofix(1
<< (band->analgain + 1)),
band->synweight);
} else {
band->absstepsize = jpc_inttofix(1);
}
band->stepsize = jpc_abstorelstepsize(
band->absstepsize, cp->ccps[cmptno].prec +
band->analgain);
band->numbps = cp->tccp.numgbits +
JPC_QCX_GETEXPN(band->stepsize) - 1;
if ((!tile->intmode) && band->data) {
quantize(band->data, band->absstepsize);
}
comp->stepsizes[absbandno] = band->stepsize;
++absbandno;
}
}
assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS);
if (!tile->intmode) {
jas_matrix_divpow2(comp->data, JPC_FIX_FRACBITS - JPC_NUMEXTRABITS);
} else {
jas_matrix_asl(comp->data, JPC_NUMEXTRABITS);
}
#if 0
fprintf(stderr, "mingbits %d\n", mingbits);
#endif
if (mingbits > cp->tccp.numgbits) {
fprintf(stderr, "error: too few guard bits (need at least %d)\n",
mingbits);
return -1;
}
}
if (!(enc->tmpstream = jas_stream_memopen(0, 0))) {
fprintf(stderr, "cannot open tmp file\n");
return -1;
}
/* Write the tile header. */
if (!(enc->mrk = jpc_ms_create(JPC_MS_SOT))) {
return -1;
}
sot = &enc->mrk->parms.sot;
sot->len = 0;
sot->tileno = tileno;
sot->partno = 0;
sot->numparts = 1;
if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write SOT marker\n");
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
/************************************************************************/
/************************************************************************/
/************************************************************************/
tccp = &cp->tccp;
for (cmptno = 0; cmptno < JAS_CAST(int, cp->numcmpts); ++cmptno) {
comp = &tile->tcmpts[cmptno];
if (comp->numrlvls != tccp->maxrlvls) {
if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
return -1;
}
/* XXX = this is not really correct. we are using comp #0's precint sizes
and other characteristics */
comp = &tile->tcmpts[0];
cod = &enc->mrk->parms.cod;
cod->compparms.csty = 0;
cod->compparms.numdlvls = comp->numrlvls - 1;
cod->prg = tile->prg;
cod->numlyrs = tile->numlyrs;
cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(comp->cblkwidthexpn);
cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(comp->cblkheightexpn);
cod->compparms.cblksty = comp->cblksty;
cod->compparms.qmfbid = comp->qmfbid;
cod->mctrans = (tile->mctid != JPC_MCT_NONE);
for (i = 0; i < comp->numrlvls; ++i) {
cod->compparms.rlvls[i].parwidthval = comp->rlvls[i].prcwidthexpn;
cod->compparms.rlvls[i].parheightval = comp->rlvls[i].prcheightexpn;
}
if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
}
}
for (cmptno = 0, comp = tile->tcmpts; cmptno < JAS_CAST(int, cp->numcmpts); ++cmptno, ++comp) {
ccps = &cp->ccps[cmptno];
if (JAS_CAST(int, ccps->numstepsizes) == comp->numstepsizes) {
samestepsizes = 1;
for (bandno = 0; bandno < JAS_CAST(int, ccps->numstepsizes); ++bandno) {
if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) {
samestepsizes = 0;
break;
}
}
} else {
samestepsizes = 0;
}
if (!samestepsizes) {
if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
return -1;
}
qcc = &enc->mrk->parms.qcc;
qcc->compno = cmptno;
qcc->compparms.numguard = cp->tccp.numgbits;
qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ?
JPC_QCX_SEQNT : JPC_QCX_NOQNT;
qcc->compparms.numstepsizes = comp->numstepsizes;
qcc->compparms.stepsizes = comp->stepsizes;
if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
return -1;
}
qcc->compparms.stepsizes = 0;
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
}
}
/* Write a SOD marker to indicate the end of the tile header. */
if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) {
return -1;
}
if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
fprintf(stderr, "cannot write SOD marker\n");
return -1;
}
jpc_ms_destroy(enc->mrk);
enc->mrk = 0;
tilehdrlen = jas_stream_getrwcount(enc->tmpstream);
/************************************************************************/
/************************************************************************/
/************************************************************************/
if (jpc_enc_enccblks(enc)) {
abort();
return -1;
}
cp = enc->cp;
rho = (double) (tile->brx - tile->tlx) * (tile->bry - tile->tly) /
((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight -
cp->imgareatly));
tile->rawsize = (unsigned int)(cp->rawsize * rho);
for (lyrno = 0; lyrno < tile->numlyrs - 1; ++lyrno) {
tile->lyrsizes[lyrno] = (unsigned int)(tile->rawsize * jpc_fixtodbl(
cp->tcp.ilyrrates[lyrno]));
}
tile->lyrsizes[tile->numlyrs - 1] = (cp->totalsize != UINT_FAST32_MAX) ?
(unsigned int)(rho * enc->mainbodysize) : UINT_FAST32_MAX;
for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
if (tile->lyrsizes[lyrno] != UINT_FAST32_MAX) {
if (tilehdrlen <= JAS_CAST(long, tile->lyrsizes[lyrno])) {
tile->lyrsizes[lyrno] -= tilehdrlen;
} else {
tile->lyrsizes[lyrno] = 0;
}
}
}
if (rateallocate(enc, tile->numlyrs, tile->lyrsizes)) {
return -1;
}
#if 0
fprintf(stderr, "ENCODE TILE DATA\n");
#endif
if (jpc_enc_encodetiledata(enc)) {
fprintf(stderr, "dotile failed\n");
return -1;
}
/************************************************************************/
/************************************************************************/
/************************************************************************/
/************************************************************************/
/************************************************************************/
/************************************************************************/
tilelen = jas_stream_tell(enc->tmpstream);
if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) {
return -1;
}
jpc_putuint32(enc->tmpstream, tilelen);
if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) {
return -1;
}
if (jpc_putdata(enc->out, enc->tmpstream, -1)) {
return -1;
}
enc->len += tilelen;
jas_stream_close(enc->tmpstream);
enc->tmpstream = 0;
jpc_enc_tile_destroy(enc->curtile);
enc->curtile = 0;
}
return 0;
}
int jpc_enc_encodetiledata(jpc_enc_t *enc)
{
assert(enc->tmpstream);
if (jpc_enc_encpkts(enc, enc->tmpstream)) {
return -1;
}
return 0;
}
int dump_passes(jpc_enc_pass_t *passes, int numpasses, jpc_enc_cblk_t *cblk)
{
jpc_enc_pass_t *pass;
int i;
jas_stream_memobj_t *smo;
smo = cblk->stream->obj_;
pass = passes;
for (i = 0; i < numpasses; ++i) {
fprintf(stderr, "start=%d end=%d type=%d term=%d lyrno=%d firstchar=%02x size=%ld pos=%ld\n",
(int)pass->start, (int)pass->end, (int)pass->type, (int)pass->term, (int)pass->lyrno,
smo->buf_[pass->start], (long)smo->len_, (long)smo->pos_);
#if 0
jas_memdump(stderr, &smo->buf_[pass->start], pass->end - pass->start);
#endif
++pass;
}
return 0;
}
void quantize(jas_matrix_t *data, jpc_fix_t stepsize)
{
int i;
int j;
jpc_fix_t t;
if (stepsize == jpc_inttofix(1)) {
return;
}
for (i = 0; i < jas_matrix_numrows(data); ++i) {
for (j = 0; j < jas_matrix_numcols(data); ++j) {
t = jas_matrix_get(data, i, j);
{
if (t < 0) {
t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize));
} else {
t = jpc_fix_div(t, stepsize);
}
}
jas_matrix_set(data, i, j, t);
}
}
}
void calcrdslopes(jpc_enc_cblk_t *cblk)
{
jpc_enc_pass_t *endpasses;
jpc_enc_pass_t *pass0;
jpc_enc_pass_t *pass1;
jpc_enc_pass_t *pass2;
jpc_flt_t slope0;
jpc_flt_t slope;
jpc_flt_t dd;
long dr;
endpasses = &cblk->passes[cblk->numpasses];
pass2 = cblk->passes;
slope0 = 0;
while (pass2 != endpasses) {
pass0 = 0;
for (pass1 = cblk->passes; pass1 != endpasses; ++pass1) {
dd = pass1->cumwmsedec;
dr = pass1->end;
if (pass0) {
dd -= pass0->cumwmsedec;
dr -= pass0->end;
}
if (dd <= 0) {
pass1->rdslope = JPC_BADRDSLOPE;
if (pass1 >= pass2) {
pass2 = &pass1[1];
}
continue;
}
if (pass1 < pass2 && pass1->rdslope <= 0) {
continue;
}
if (!dr) {
assert(pass0);
pass0->rdslope = 0;
break;
}
slope = dd / dr;
if (pass0 && slope >= slope0) {
pass0->rdslope = 0;
break;
}
pass1->rdslope = slope;
if (pass1 >= pass2) {
pass2 = &pass1[1];
}
pass0 = pass1;
slope0 = slope;
}
}
#if 0
for (pass0 = cblk->passes; pass0 != endpasses; ++pass0) {
if (pass0->rdslope > 0.0) {
fprintf(stderr, "pass %02d nmsedec=%lf dec=%lf end=%d %lf\n", pass0 - cblk->passes,
fixtodbl(pass0->nmsedec), pass0->wmsedec, pass0->end, pass0->rdslope);
}
}
#endif
}
void dump_layeringinfo(jpc_enc_t *enc)
{
jpc_enc_tcmpt_t *tcmpt;
int tcmptno;
jpc_enc_rlvl_t *rlvl;
int rlvlno;
jpc_enc_band_t *band;
int bandno;
jpc_enc_prc_t *prc;
int prcno;
jpc_enc_cblk_t *cblk;
int cblkno;
jpc_enc_pass_t *pass;
int passno;
int lyrno;
jpc_enc_tile_t *tile;
tile = enc->curtile;
for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
fprintf(stderr, "lyrno = %02d\n", lyrno);
for (tcmptno = 0, tcmpt = tile->tcmpts; tcmptno < tile->numtcmpts;
++tcmptno, ++tcmpt) {
for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
++rlvlno, ++rlvl) {
if (!rlvl->bands) {
continue;
}
for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
++bandno, ++band) {
if (!band->data) {
continue;
}
for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
++prcno, ++prc) {
if (!prc->cblks) {
continue;
}
for (cblkno = 0, cblk = prc->cblks; cblkno <
prc->numcblks; ++cblkno, ++cblk) {
for (passno = 0, pass = cblk->passes; passno <
cblk->numpasses && pass->lyrno == lyrno;
++passno, ++pass) {
fprintf(stderr, "lyrno=%02d cmptno=%02d rlvlno=%02d bandno=%02d prcno=%02d cblkno=%03d passno=%03d\n", lyrno, tcmptno, rlvlno, bandno, prcno, cblkno, passno);
}
}
}
}
}
}
}
}
int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens)
{
jpc_flt_t lo;
jpc_flt_t hi;
jas_stream_t *out;
long cumlen;
int lyrno;
jpc_flt_t thresh;
jpc_flt_t goodthresh;
int success;
long pos;
long oldpos;
int numiters;
jpc_enc_tcmpt_t *comp;
jpc_enc_tcmpt_t *endcomps;
jpc_enc_rlvl_t *lvl;
jpc_enc_rlvl_t *endlvls;
jpc_enc_band_t *band;
jpc_enc_band_t *endbands;
jpc_enc_cblk_t *cblk;
jpc_enc_cblk_t *endcblks;
jpc_enc_pass_t *pass;
jpc_enc_pass_t *endpasses;
jpc_enc_pass_t *pass1;
jpc_flt_t mxrdslope;
jpc_flt_t mnrdslope;
jpc_enc_tile_t *tile;
jpc_enc_prc_t *prc;
int prcno;
tile = enc->curtile;
for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) {
if (cumlens[lyrno - 1] > cumlens[lyrno]) {
abort();
}
}
if (!(out = jas_stream_memopen(0, 0))) {
return -1;
}
/* Find minimum and maximum R-D slope values. */
mnrdslope = DBL_MAX;
mxrdslope = 0;
endcomps = &tile->tcmpts[tile->numtcmpts];
for (comp = tile->tcmpts; comp != endcomps; ++comp) {
endlvls = &comp->rlvls[comp->numrlvls];
for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
if (!lvl->bands) {
continue;
}
endbands = &lvl->bands[lvl->numbands];
for (band = lvl->bands; band != endbands; ++band) {
if (!band->data) {
continue;
}
for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
if (!prc->cblks) {
continue;
}
endcblks = &prc->cblks[prc->numcblks];
for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
calcrdslopes(cblk);
endpasses = &cblk->passes[cblk->numpasses];
for (pass = cblk->passes; pass != endpasses; ++pass) {
if (pass->rdslope > 0) {
if (pass->rdslope < mnrdslope) {
mnrdslope = pass->rdslope;
}
if (pass->rdslope > mxrdslope) {
mxrdslope = pass->rdslope;
}
}
}
}
}
}
}
}
if (jas_getdbglevel()) {
fprintf(stderr, "min rdslope = %f max rdslope = %f\n", mnrdslope, mxrdslope);
}
jpc_init_t2state(enc, 1);
for (lyrno = 0; lyrno < numlyrs; ++lyrno) {
lo = mnrdslope;
hi = mxrdslope;
success = 0;
goodthresh = 0;
numiters = 0;
do {
cumlen = cumlens[lyrno];
if (cumlen == UINT_FAST32_MAX) {
/* Only the last layer can be free of a rate
constraint (e.g., for lossless coding). */
assert(lyrno == numlyrs - 1);
goodthresh = -1;
success = 1;
break;
}
thresh = (lo + hi) / 2;
/* Save the tier 2 coding state. */
jpc_save_t2state(enc);
oldpos = jas_stream_tell(out);
assert(oldpos >= 0);
/* Assign all passes with R-D slopes greater than or
equal to the current threshold to this layer. */
endcomps = &tile->tcmpts[tile->numtcmpts];
for (comp = tile->tcmpts; comp != endcomps; ++comp) {
endlvls = &comp->rlvls[comp->numrlvls];
for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
if (!lvl->bands) {
continue;
}
endbands = &lvl->bands[lvl->numbands];
for (band = lvl->bands; band != endbands; ++band) {
if (!band->data) {
continue;
}
for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
if (!prc->cblks) {
continue;
}
endcblks = &prc->cblks[prc->numcblks];
for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
if (cblk->curpass) {
endpasses = &cblk->passes[cblk->numpasses];
pass1 = cblk->curpass;
for (pass = cblk->curpass; pass != endpasses; ++pass) {
if (pass->rdslope >= thresh) {
pass1 = &pass[1];
}
}
for (pass = cblk->curpass; pass != pass1; ++pass) {
pass->lyrno = lyrno;
}
for (; pass != endpasses; ++pass) {
pass->lyrno = -1;
}
}
}
}
}
}
}
/* Perform tier 2 coding. */
endcomps = &tile->tcmpts[tile->numtcmpts];
for (comp = tile->tcmpts; comp != endcomps; ++comp) {
endlvls = &comp->rlvls[comp->numrlvls];
for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
if (!lvl->bands) {
continue;
}
for (prcno = 0; prcno < lvl->numprcs; ++prcno) {
if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) {
return -1;
}
}
}
}
pos = jas_stream_tell(out);
/* Check the rate constraint. */
assert(pos >= 0);
if (pos > cumlen) {
/* The rate is too high. */
lo = thresh;
} else if (pos <= cumlen) {
/* The rate is low enough, so try higher. */
hi = thresh;
if (!success || thresh < goodthresh) {
goodthresh = thresh;
success = 1;
}
}
/* Save the tier 2 coding state. */
jpc_restore_t2state(enc);
if (jas_stream_seek(out, oldpos, SEEK_SET) < 0) {
abort();
}
if (jas_getdbglevel()) {
fprintf(stderr, "maxlen=%08ld actuallen=%08ld thresh=%f\n", cumlen, pos, thresh);
}
++numiters;
} while (lo < hi - 1e-3 && numiters < 32);
if (!success) {
fprintf(stderr, "warning: empty layer generated\n");
}
if (jas_getdbglevel()) {
fprintf(stderr, "success %d goodthresh %f\n", success, goodthresh);
}
/* Assign all passes with R-D slopes greater than or
equal to the selected threshold to this layer. */
endcomps = &tile->tcmpts[tile->numtcmpts];
for (comp = tile->tcmpts; comp != endcomps; ++comp) {
endlvls = &comp->rlvls[comp->numrlvls];
for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
if (!lvl->bands) {
continue;
}
endbands = &lvl->bands[lvl->numbands];
for (band = lvl->bands; band != endbands; ++band) {
if (!band->data) {
continue;
}
for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
if (!prc->cblks) {
continue;
}
endcblks = &prc->cblks[prc->numcblks];
for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
if (cblk->curpass) {
endpasses = &cblk->passes[cblk->numpasses];
pass1 = cblk->curpass;
if (success) {
for (pass = cblk->curpass; pass != endpasses; ++pass) {
if (pass->rdslope >= goodthresh) {
pass1 = &pass[1];
}
}
}
for (pass = cblk->curpass; pass != pass1; ++pass) {
pass->lyrno = lyrno;
}
for (; pass != endpasses; ++pass) {
pass->lyrno = -1;
}
}
}
}
}
}
}
/* Perform tier 2 coding. */
endcomps = &tile->tcmpts[tile->numtcmpts];
for (comp = tile->tcmpts; comp != endcomps; ++comp) {
endlvls = &comp->rlvls[comp->numrlvls];
for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
if (!lvl->bands) {
continue;
}
for (prcno = 0; prcno < lvl->numprcs; ++prcno) {
if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) {
return -1;
}
}
}
}
}
if (jas_getdbglevel() >= 5) {
dump_layeringinfo(enc);
}
jas_stream_close(out);
JAS_DBGLOG(10, ("done doing rateallocation\n"));
#if 0
fprintf(stderr, "DONE RATE ALLOCATE\n");
#endif
return 0;
}
/******************************************************************************\
* Tile constructors and destructors.
\******************************************************************************/
jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno)
{
jpc_enc_tile_t *tile;
uint_fast32_t htileno;
uint_fast32_t vtileno;
uint_fast16_t lyrno;
uint_fast16_t cmptno;
jpc_enc_tcmpt_t *tcmpt;
if (!(tile = jas_malloc(sizeof(jpc_enc_tile_t)))) {
goto error;
}
/* Initialize a few members used in error recovery. */
tile->tcmpts = 0;
tile->lyrsizes = 0;
tile->numtcmpts = cp->numcmpts;
tile->pi = 0;
tile->tileno = tileno;
htileno = tileno % cp->numhtiles;
vtileno = tileno / cp->numhtiles;
/* Calculate the coordinates of the top-left and bottom-right
corners of the tile. */
tile->tlx = JAS_MAX(cp->tilegrdoffx + htileno * cp->tilewidth,
cp->imgareatlx);
tile->tly = JAS_MAX(cp->tilegrdoffy + vtileno * cp->tileheight,
cp->imgareatly);
tile->brx = JAS_MIN(cp->tilegrdoffx + (htileno + 1) * cp->tilewidth,
cp->refgrdwidth);
tile->bry = JAS_MIN(cp->tilegrdoffy + (vtileno + 1) * cp->tileheight,
cp->refgrdheight);
/* Initialize some tile coding parameters. */
tile->intmode = cp->tcp.intmode;
tile->csty = cp->tcp.csty;
tile->prg = cp->tcp.prg;
tile->mctid = cp->tcp.mctid;
tile->numlyrs = cp->tcp.numlyrs;
if (!(tile->lyrsizes = jas_malloc(tile->numlyrs *
sizeof(uint_fast32_t)))) {
goto error;
}
for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
tile->lyrsizes[lyrno] = 0;
}
/* Allocate an array for the per-tile-component information. */
if (!(tile->tcmpts = jas_malloc(cp->numcmpts * sizeof(jpc_enc_tcmpt_t)))) {
goto error;
}
/* Initialize a few members critical for error recovery. */
for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
++cmptno, ++tcmpt) {
tcmpt->rlvls = 0;
tcmpt->tsfb = 0;
tcmpt->data = 0;
}
/* Initialize the per-tile-component information. */
for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
++cmptno, ++tcmpt) {
if (!tcmpt_create(tcmpt, cp, image, tile)) {
goto error;
}
}
/* Initialize the synthesis weights for the MCT. */
switch (tile->mctid) {
case JPC_MCT_RCT:
tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0));
tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(0.6875));
tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(0.6875));
break;
case JPC_MCT_ICT:
tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0000));
tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(3.2584));
tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(2.4755));
break;
default:
case JPC_MCT_NONE:
for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
++cmptno, ++tcmpt) {
tcmpt->synweight = JPC_FIX_ONE;
}
break;
}
if (!(tile->pi = jpc_enc_pi_create(cp, tile))) {
goto error;
}
return tile;
error:
if (tile) {
jpc_enc_tile_destroy(tile);
}
return 0;
}
void jpc_enc_tile_destroy(jpc_enc_tile_t *tile)
{
jpc_enc_tcmpt_t *tcmpt;
uint_fast16_t cmptno;
if (tile->tcmpts) {
for (cmptno = 0, tcmpt = tile->tcmpts; cmptno <
tile->numtcmpts; ++cmptno, ++tcmpt) {
tcmpt_destroy(tcmpt);
}
jas_free(tile->tcmpts);
}
if (tile->lyrsizes) {
jas_free(tile->lyrsizes);
}
if (tile->pi) {
jpc_pi_destroy(tile->pi);
}
jas_free(tile);
}
static jpc_enc_tcmpt_t *tcmpt_create(jpc_enc_tcmpt_t *tcmpt, jpc_enc_cp_t *cp,
jas_image_t *image, jpc_enc_tile_t *tile)
{
uint_fast16_t cmptno;
uint_fast16_t rlvlno;
jpc_enc_rlvl_t *rlvl;
uint_fast32_t tlx;
uint_fast32_t tly;
uint_fast32_t brx;
uint_fast32_t bry;
uint_fast32_t cmpttlx;
uint_fast32_t cmpttly;
jpc_enc_ccp_t *ccp;
jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];
tcmpt->tile = tile;
tcmpt->tsfb = 0;
tcmpt->data = 0;
tcmpt->rlvls = 0;
/* Deduce the component number. */
cmptno = tcmpt - tile->tcmpts;
ccp = &cp->ccps[cmptno];
/* Compute the coordinates of the top-left and bottom-right
corners of this tile-component. */
tlx = JPC_CEILDIV(tile->tlx, ccp->sampgrdstepx);
tly = JPC_CEILDIV(tile->tly, ccp->sampgrdstepy);
brx = JPC_CEILDIV(tile->brx, ccp->sampgrdstepx);
bry = JPC_CEILDIV(tile->bry, ccp->sampgrdstepy);
/* Create a sequence to hold the tile-component sample data. */
if (!(tcmpt->data = jas_seq2d_create(tlx, tly, brx, bry))) {
goto error;
}
/* Get the image data associated with this tile-component. */
cmpttlx = JPC_CEILDIV(cp->imgareatlx, ccp->sampgrdstepx);
cmpttly = JPC_CEILDIV(cp->imgareatly, ccp->sampgrdstepy);
if (jas_image_readcmpt(image, cmptno, tlx - cmpttlx, tly - cmpttly,
brx - tlx, bry - tly, tcmpt->data)) {
goto error;
}
tcmpt->synweight = 0;
tcmpt->qmfbid = cp->tccp.qmfbid;
tcmpt->numrlvls = cp->tccp.maxrlvls;
tcmpt->numbands = 3 * tcmpt->numrlvls - 2;
if (!(tcmpt->tsfb = jpc_cod_gettsfb(tcmpt->qmfbid, tcmpt->numrlvls - 1))) {
goto error;
}
for (rlvlno = 0; rlvlno < tcmpt->numrlvls; ++rlvlno) {
tcmpt->prcwidthexpns[rlvlno] = cp->tccp.prcwidthexpns[rlvlno];
tcmpt->prcheightexpns[rlvlno] = cp->tccp.prcheightexpns[rlvlno];
}
tcmpt->cblkwidthexpn = cp->tccp.cblkwidthexpn;
tcmpt->cblkheightexpn = cp->tccp.cblkheightexpn;
tcmpt->cblksty = cp->tccp.cblksty;
tcmpt->csty = cp->tccp.csty;
tcmpt->numstepsizes = tcmpt->numbands;
assert(tcmpt->numstepsizes <= JPC_MAXBANDS);
memset(tcmpt->stepsizes, 0, sizeof(tcmpt->numstepsizes *
sizeof(uint_fast16_t)));
/* Retrieve information about the various bands. */
jpc_tsfb_getbands(tcmpt->tsfb, jas_seq2d_xstart(tcmpt->data),
jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data),
jas_seq2d_yend(tcmpt->data), bandinfos);
if (!(tcmpt->rlvls = jas_malloc(tcmpt->numrlvls * sizeof(jpc_enc_rlvl_t)))) {
goto error;
}
for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
++rlvlno, ++rlvl) {
rlvl->bands = 0;
rlvl->tcmpt = tcmpt;
}
for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
++rlvlno, ++rlvl) {
if (!rlvl_create(rlvl, cp, tcmpt, bandinfos)) {
goto error;
}
}
return tcmpt;
error:
tcmpt_destroy(tcmpt);
return 0;
}
static void tcmpt_destroy(jpc_enc_tcmpt_t *tcmpt)
{
jpc_enc_rlvl_t *rlvl;
uint_fast16_t rlvlno;
if (tcmpt->rlvls) {
for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
++rlvlno, ++rlvl) {
rlvl_destroy(rlvl);
}
jas_free(tcmpt->rlvls);
}
if (tcmpt->data) {
jas_seq2d_destroy(tcmpt->data);
}
if (tcmpt->tsfb) {
jpc_tsfb_destroy(tcmpt->tsfb);
}
}
static jpc_enc_rlvl_t *rlvl_create(jpc_enc_rlvl_t *rlvl, jpc_enc_cp_t *cp,
jpc_enc_tcmpt_t *tcmpt, jpc_tsfb_band_t *bandinfos)
{
uint_fast16_t rlvlno;
uint_fast32_t tlprctlx;
uint_fast32_t tlprctly;
uint_fast32_t brprcbrx;
uint_fast32_t brprcbry;
uint_fast16_t bandno;
jpc_enc_band_t *band;
/* Deduce the resolution level. */
rlvlno = rlvl - tcmpt->rlvls;
/* Initialize members required for error recovery. */
rlvl->bands = 0;
rlvl->tcmpt = tcmpt;
/* Compute the coordinates of the top-left and bottom-right
corners of the tile-component at this resolution. */
rlvl->tlx = JPC_CEILDIVPOW2(jas_seq2d_xstart(tcmpt->data), tcmpt->numrlvls -
1 - rlvlno);
rlvl->tly = JPC_CEILDIVPOW2(jas_seq2d_ystart(tcmpt->data), tcmpt->numrlvls -
1 - rlvlno);
rlvl->brx = JPC_CEILDIVPOW2(jas_seq2d_xend(tcmpt->data), tcmpt->numrlvls -
1 - rlvlno);
rlvl->bry = JPC_CEILDIVPOW2(jas_seq2d_yend(tcmpt->data), tcmpt->numrlvls -
1 - rlvlno);
if (rlvl->tlx >= rlvl->brx || rlvl->tly >= rlvl->bry) {
rlvl->numhprcs = 0;
rlvl->numvprcs = 0;
rlvl->numprcs = 0;
return rlvl;
}
rlvl->numbands = (!rlvlno) ? 1 : 3;
rlvl->prcwidthexpn = cp->tccp.prcwidthexpns[rlvlno];
rlvl->prcheightexpn = cp->tccp.prcheightexpns[rlvlno];
if (!rlvlno) {
rlvl->cbgwidthexpn = rlvl->prcwidthexpn;
rlvl->cbgheightexpn = rlvl->prcheightexpn;
} else {
rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1;
rlvl->cbgheightexpn = rlvl->prcheightexpn - 1;
}
rlvl->cblkwidthexpn = JAS_MIN(cp->tccp.cblkwidthexpn, rlvl->cbgwidthexpn);
rlvl->cblkheightexpn = JAS_MIN(cp->tccp.cblkheightexpn, rlvl->cbgheightexpn);
/* Compute the number of precincts. */
tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn);
tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn);
brprcbrx = JPC_CEILTOMULTPOW2(rlvl->brx, rlvl->prcwidthexpn);
brprcbry = JPC_CEILTOMULTPOW2(rlvl->bry, rlvl->prcheightexpn);
rlvl->numhprcs = JPC_FLOORDIVPOW2(brprcbrx - tlprctlx, rlvl->prcwidthexpn);
rlvl->numvprcs = JPC_FLOORDIVPOW2(brprcbry - tlprctly, rlvl->prcheightexpn);
rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs;
if (!(rlvl->bands = jas_malloc(rlvl->numbands * sizeof(jpc_enc_band_t)))) {
goto error;
}
for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
++bandno, ++band) {
band->prcs = 0;
band->data = 0;
band->rlvl = rlvl;
}
for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
++bandno, ++band) {
if (!band_create(band, cp, rlvl, bandinfos)) {
goto error;
}
}
return rlvl;
error:
rlvl_destroy(rlvl);
return 0;
}
static void rlvl_destroy(jpc_enc_rlvl_t *rlvl)
{
jpc_enc_band_t *band;
uint_fast16_t bandno;
if (rlvl->bands) {
for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
++bandno, ++band) {
band_destroy(band);
}
jas_free(rlvl->bands);
}
}
static jpc_enc_band_t *band_create(jpc_enc_band_t *band, jpc_enc_cp_t *cp,
jpc_enc_rlvl_t *rlvl, jpc_tsfb_band_t *bandinfos)
{
uint_fast16_t bandno;
uint_fast16_t gblbandno;
uint_fast16_t rlvlno;
jpc_tsfb_band_t *bandinfo;
jpc_enc_tcmpt_t *tcmpt;
uint_fast32_t prcno;
jpc_enc_prc_t *prc;
tcmpt = rlvl->tcmpt;
band->data = 0;
band->prcs = 0;
band->rlvl = rlvl;
/* Deduce the resolution level and band number. */
rlvlno = rlvl - rlvl->tcmpt->rlvls;
bandno = band - rlvl->bands;
gblbandno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + bandno + 1);
bandinfo = &bandinfos[gblbandno];
if (bandinfo->xstart != bandinfo->xend && bandinfo->ystart != bandinfo->yend) {
if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) {
goto error;
}
jas_seq2d_bindsub(band->data, tcmpt->data, bandinfo->locxstart,
bandinfo->locystart, bandinfo->locxend, bandinfo->locyend);
jas_seq2d_setshift(band->data, bandinfo->xstart, bandinfo->ystart);
}
band->orient = bandinfo->orient;
band->analgain = JPC_NOMINALGAIN(cp->tccp.qmfbid, tcmpt->numrlvls, rlvlno,
band->orient);
band->numbps = 0;
band->absstepsize = 0;
band->stepsize = 0;
band->synweight = bandinfo->synenergywt;
if (band->data) {
if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_enc_prc_t)))) {
goto error;
}
for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
++prc) {
prc->cblks = 0;
prc->incltree = 0;
prc->nlibtree = 0;
prc->savincltree = 0;
prc->savnlibtree = 0;
prc->band = band;
}
for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
++prc) {
if (!prc_create(prc, cp, band)) {
goto error;
}
}
}
return band;
error:
band_destroy(band);
return 0;
}
static void band_destroy(jpc_enc_band_t *band)
{
jpc_enc_prc_t *prc;
jpc_enc_rlvl_t *rlvl;
uint_fast32_t prcno;
if (band->prcs) {
rlvl = band->rlvl;
for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
++prcno, ++prc) {
prc_destroy(prc);
}
jas_free(band->prcs);
}
if (band->data) {
jas_seq2d_destroy(band->data);
}
}
static jpc_enc_prc_t *prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp, jpc_enc_band_t *band)
{
uint_fast32_t prcno;
uint_fast32_t prcxind;
uint_fast32_t prcyind;
uint_fast32_t cbgtlx;
uint_fast32_t cbgtly;
uint_fast32_t tlprctlx;
uint_fast32_t tlprctly;
uint_fast32_t tlcbgtlx;
uint_fast32_t tlcbgtly;
uint_fast16_t rlvlno;
jpc_enc_rlvl_t *rlvl;
uint_fast32_t tlcblktlx;
uint_fast32_t tlcblktly;
uint_fast32_t brcblkbrx;
uint_fast32_t brcblkbry;
uint_fast32_t cblkno;
jpc_enc_cblk_t *cblk;
jpc_enc_tcmpt_t *tcmpt;
prc->cblks = 0;
prc->incltree = 0;
prc->savincltree = 0;
prc->nlibtree = 0;
prc->savnlibtree = 0;
rlvl = band->rlvl;
tcmpt = rlvl->tcmpt;
rlvlno = rlvl - tcmpt->rlvls;
prcno = prc - band->prcs;
prcxind = prcno % rlvl->numhprcs;
prcyind = prcno / rlvl->numhprcs;
prc->band = band;
tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn);
tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn);
if (!rlvlno) {
tlcbgtlx = tlprctlx;
tlcbgtly = tlprctly;
} else {
tlcbgtlx = JPC_CEILDIVPOW2(tlprctlx, 1);
tlcbgtly = JPC_CEILDIVPOW2(tlprctly, 1);
}
/* Compute the coordinates of the top-left and bottom-right
corners of the precinct. */
cbgtlx = tlcbgtlx + (prcxind << rlvl->cbgwidthexpn);
cbgtly = tlcbgtly + (prcyind << rlvl->cbgheightexpn);
prc->tlx = JAS_MAX(jas_seq2d_xstart(band->data), cbgtlx);
prc->tly = JAS_MAX(jas_seq2d_ystart(band->data), cbgtly);
prc->brx = JAS_MIN(jas_seq2d_xend(band->data), cbgtlx +
(1 << rlvl->cbgwidthexpn));
prc->bry = JAS_MIN(jas_seq2d_yend(band->data), cbgtly +
(1 << rlvl->cbgheightexpn));
if (prc->tlx < prc->brx && prc->tly < prc->bry) {
/* The precinct contains at least one code block. */
tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
brcblkbrx = JPC_CEILTOMULTPOW2(prc->brx, rlvl->cblkwidthexpn);
brcblkbry = JPC_CEILTOMULTPOW2(prc->bry, rlvl->cblkheightexpn);
prc->numhcblks = JPC_FLOORDIVPOW2(brcblkbrx - tlcblktlx,
rlvl->cblkwidthexpn);
prc->numvcblks = JPC_FLOORDIVPOW2(brcblkbry - tlcblktly,
rlvl->cblkheightexpn);
prc->numcblks = prc->numhcblks * prc->numvcblks;
if (!(prc->incltree = jpc_tagtree_create(prc->numhcblks,
prc->numvcblks))) {
goto error;
}
if (!(prc->nlibtree = jpc_tagtree_create(prc->numhcblks,
prc->numvcblks))) {
goto error;
}
if (!(prc->savincltree = jpc_tagtree_create(prc->numhcblks,
prc->numvcblks))) {
goto error;
}
if (!(prc->savnlibtree = jpc_tagtree_create(prc->numhcblks,
prc->numvcblks))) {
goto error;
}
if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_enc_cblk_t)))) {
goto error;
}
for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
++cblkno, ++cblk) {
cblk->passes = 0;
cblk->stream = 0;
cblk->mqenc = 0;
cblk->data = 0;
cblk->flags = 0;
cblk->prc = prc;
}
for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
++cblkno, ++cblk) {
if (!cblk_create(cblk, cp, prc)) {
goto error;
}
}
} else {
/* The precinct does not contain any code blocks. */
prc->tlx = prc->brx;
prc->tly = prc->bry;
prc->numcblks = 0;
prc->numhcblks = 0;
prc->numvcblks = 0;
prc->cblks = 0;
prc->incltree = 0;
prc->nlibtree = 0;
prc->savincltree = 0;
prc->savnlibtree = 0;
}
return prc;
error:
prc_destroy(prc);
return 0;
}
static void prc_destroy(jpc_enc_prc_t *prc)
{
jpc_enc_cblk_t *cblk;
uint_fast32_t cblkno;
if (prc->cblks) {
for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
++cblkno, ++cblk) {
cblk_destroy(cblk);
}
jas_free(prc->cblks);
}
if (prc->incltree) {
jpc_tagtree_destroy(prc->incltree);
}
if (prc->nlibtree) {
jpc_tagtree_destroy(prc->nlibtree);
}
if (prc->savincltree) {
jpc_tagtree_destroy(prc->savincltree);
}
if (prc->savnlibtree) {
jpc_tagtree_destroy(prc->savnlibtree);
}
}
static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp, jpc_enc_prc_t *prc)
{
jpc_enc_band_t *band;
uint_fast32_t cblktlx;
uint_fast32_t cblktly;
uint_fast32_t cblkbrx;
uint_fast32_t cblkbry;
jpc_enc_rlvl_t *rlvl;
uint_fast32_t cblkxind;
uint_fast32_t cblkyind;
uint_fast32_t cblkno;
uint_fast32_t tlcblktlx;
uint_fast32_t tlcblktly;
cblkno = cblk - prc->cblks;
cblkxind = cblkno % prc->numhcblks;
cblkyind = cblkno / prc->numhcblks;
rlvl = prc->band->rlvl;
cblk->prc = prc;
cblk->numpasses = 0;
cblk->passes = 0;
cblk->numencpasses = 0;
cblk->numimsbs = 0;
cblk->numlenbits = 0;
cblk->stream = 0;
cblk->mqenc = 0;
cblk->flags = 0;
cblk->numbps = 0;
cblk->curpass = 0;
cblk->data = 0;
cblk->savedcurpass = 0;
cblk->savednumlenbits = 0;
cblk->savednumencpasses = 0;
band = prc->band;
tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
cblktlx = JAS_MAX(tlcblktlx + (cblkxind << rlvl->cblkwidthexpn), prc->tlx);
cblktly = JAS_MAX(tlcblktly + (cblkyind << rlvl->cblkheightexpn), prc->tly);
cblkbrx = JAS_MIN(tlcblktlx + ((cblkxind + 1) << rlvl->cblkwidthexpn),
prc->brx);
cblkbry = JAS_MIN(tlcblktly + ((cblkyind + 1) << rlvl->cblkheightexpn),
prc->bry);
assert(cblktlx < cblkbrx && cblktly < cblkbry);
if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) {
goto error;
}
jas_seq2d_bindsub(cblk->data, band->data, cblktlx, cblktly, cblkbrx, cblkbry);
return cblk;
error:
cblk_destroy(cblk);
return 0;
}
static void cblk_destroy(jpc_enc_cblk_t *cblk)
{
uint_fast16_t passno;
jpc_enc_pass_t *pass;
if (cblk->passes) {
for (passno = 0, pass = cblk->passes; passno < cblk->numpasses;
++passno, ++pass) {
pass_destroy(pass);
}
jas_free(cblk->passes);
}
if (cblk->stream) {
jas_stream_close(cblk->stream);
}
if (cblk->mqenc) {
jpc_mqenc_destroy(cblk->mqenc);
}
if (cblk->data) {
jas_seq2d_destroy(cblk->data);
}
if (cblk->flags) {
jas_seq2d_destroy(cblk->flags);
}
}
static void pass_destroy(jpc_enc_pass_t *pass)
{
/* XXX - need to free resources here */
}
void jpc_enc_dump(jpc_enc_t *enc)
{
jpc_enc_tile_t *tile;
jpc_enc_tcmpt_t *tcmpt;
jpc_enc_rlvl_t *rlvl;
jpc_enc_band_t *band;
jpc_enc_prc_t *prc;
jpc_enc_cblk_t *cblk;
uint_fast16_t cmptno;
uint_fast16_t rlvlno;
uint_fast16_t bandno;
uint_fast32_t prcno;
uint_fast32_t cblkno;
tile = enc->curtile;
for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno,
++tcmpt) {
fprintf(stderr, " tcmpt %5d %5d %5d %5d\n", jas_seq2d_xstart(tcmpt->data), jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data), jas_seq2d_yend(tcmpt->data));
for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
++rlvlno, ++rlvl) {
fprintf(stderr, " rlvl %5d %5d %5d %5d\n", rlvl->tlx, rlvl->tly, rlvl->brx, rlvl->bry);
for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
++bandno, ++band) {
if (!band->data) {
continue;
}
fprintf(stderr, " band %5d %5d %5d %5d\n", jas_seq2d_xstart(band->data), jas_seq2d_ystart(band->data), jas_seq2d_xend(band->data), jas_seq2d_yend(band->data));
for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
++prcno, ++prc) {
fprintf(stderr, " prc %5d %5d %5d %5d (%5d %5d)\n", prc->tlx, prc->tly, prc->brx, prc->bry, prc->brx - prc->tlx, prc->bry - prc->tly);
if (!prc->cblks) {
continue;
}
for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
++cblkno, ++cblk) {
fprintf(stderr, " cblk %5d %5d %5d %5d\n", jas_seq2d_xstart(cblk->data), jas_seq2d_ystart(cblk->data), jas_seq2d_xend(cblk->data), jas_seq2d_yend(cblk->data));
}
}
}
}
}
}