mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2305 lines
59 KiB
2305 lines
59 KiB
/* |
|
* 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 License Version 2.0 |
|
* |
|
* Copyright (c) 2001-2006 Michael David Adams |
|
* Copyright (c) 1999-2000 Image Power, Inc. |
|
* Copyright (c) 1999-2000 The University of British Columbia |
|
* |
|
* All rights reserved. |
|
* |
|
* Permission is hereby granted, free of charge, to any person (the |
|
* "User") obtaining a copy of this software and associated documentation |
|
* files (the "Software"), to deal in the Software without restriction, |
|
* including without limitation the rights to use, copy, modify, merge, |
|
* publish, distribute, and/or sell copies of the Software, and to permit |
|
* persons to whom the Software is furnished to do so, subject to the |
|
* following conditions: |
|
* |
|
* 1. The above copyright notices and this permission notice (which |
|
* includes the disclaimer below) shall be included in all copies or |
|
* substantial portions of the Software. |
|
* |
|
* 2. The name of a copyright holder shall not be used to endorse or |
|
* promote products derived from the Software without specific prior |
|
* written permission. |
|
* |
|
* THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS |
|
* LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
|
* THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS |
|
* "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
|
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
|
* PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO |
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL |
|
* INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING |
|
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE |
|
* PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE |
|
* THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. |
|
* EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS |
|
* BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL |
|
* PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS |
|
* GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE |
|
* ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE |
|
* IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL |
|
* SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, |
|
* AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL |
|
* SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH |
|
* THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, |
|
* PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH |
|
* RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY |
|
* EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. |
|
* |
|
* __END_OF_JASPER_LICENSE__ |
|
*/ |
|
|
|
/* |
|
* $Id: jpc_dec.c,v 1.2 2008-05-26 09:40:52 vp153 Exp $ |
|
*/ |
|
|
|
/******************************************************************************\ |
|
* Includes. |
|
\******************************************************************************/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <assert.h> |
|
|
|
#include "jasper/jas_types.h" |
|
#include "jasper/jas_math.h" |
|
#include "jasper/jas_tvp.h" |
|
#include "jasper/jas_malloc.h" |
|
#include "jasper/jas_debug.h" |
|
|
|
#include "jpc_fix.h" |
|
#include "jpc_dec.h" |
|
#include "jpc_cs.h" |
|
#include "jpc_mct.h" |
|
#include "jpc_t2dec.h" |
|
#include "jpc_t1dec.h" |
|
#include "jpc_math.h" |
|
|
|
/******************************************************************************\ |
|
* |
|
\******************************************************************************/ |
|
|
|
#define JPC_MHSOC 0x0001 |
|
/* In the main header, expecting a SOC marker segment. */ |
|
#define JPC_MHSIZ 0x0002 |
|
/* In the main header, expecting a SIZ marker segment. */ |
|
#define JPC_MH 0x0004 |
|
/* In the main header, expecting "other" marker segments. */ |
|
#define JPC_TPHSOT 0x0008 |
|
/* In a tile-part header, expecting a SOT marker segment. */ |
|
#define JPC_TPH 0x0010 |
|
/* In a tile-part header, expecting "other" marker segments. */ |
|
#define JPC_MT 0x0020 |
|
/* In the main trailer. */ |
|
|
|
typedef struct { |
|
|
|
uint_fast16_t id; |
|
/* The marker segment type. */ |
|
|
|
int validstates; |
|
/* The states in which this type of marker segment can be |
|
validly encountered. */ |
|
|
|
int (*action)(jpc_dec_t *dec, jpc_ms_t *ms); |
|
/* The action to take upon encountering this type of marker segment. */ |
|
|
|
} jpc_dec_mstabent_t; |
|
|
|
/******************************************************************************\ |
|
* |
|
\******************************************************************************/ |
|
|
|
/* COD/COC parameters have been specified. */ |
|
#define JPC_CSET 0x0001 |
|
/* QCD/QCC parameters have been specified. */ |
|
#define JPC_QSET 0x0002 |
|
/* COD/COC parameters set from a COC marker segment. */ |
|
#define JPC_COC 0x0004 |
|
/* QCD/QCC parameters set from a QCC marker segment. */ |
|
#define JPC_QCC 0x0008 |
|
|
|
/******************************************************************************\ |
|
* Local function prototypes. |
|
\******************************************************************************/ |
|
|
|
static int jpc_dec_dump(jpc_dec_t *dec, FILE *out); |
|
|
|
jpc_ppxstab_t *jpc_ppxstab_create(void); |
|
void jpc_ppxstab_destroy(jpc_ppxstab_t *tab); |
|
int jpc_ppxstab_grow(jpc_ppxstab_t *tab, int maxents); |
|
int jpc_ppxstab_insert(jpc_ppxstab_t *tab, jpc_ppxstabent_t *ent); |
|
jpc_streamlist_t *jpc_ppmstabtostreams(jpc_ppxstab_t *tab); |
|
int jpc_pptstabwrite(jas_stream_t *out, jpc_ppxstab_t *tab); |
|
jpc_ppxstabent_t *jpc_ppxstabent_create(void); |
|
void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent); |
|
|
|
int jpc_streamlist_numstreams(jpc_streamlist_t *streamlist); |
|
jpc_streamlist_t *jpc_streamlist_create(void); |
|
int jpc_streamlist_insert(jpc_streamlist_t *streamlist, int streamno, |
|
jas_stream_t *stream); |
|
jas_stream_t *jpc_streamlist_remove(jpc_streamlist_t *streamlist, int streamno); |
|
void jpc_streamlist_destroy(jpc_streamlist_t *streamlist); |
|
jas_stream_t *jpc_streamlist_get(jpc_streamlist_t *streamlist, int streamno); |
|
|
|
static void jpc_dec_cp_resetflags(jpc_dec_cp_t *cp); |
|
static jpc_dec_cp_t *jpc_dec_cp_create(uint_fast16_t numcomps); |
|
static int jpc_dec_cp_isvalid(jpc_dec_cp_t *cp); |
|
static jpc_dec_cp_t *jpc_dec_cp_copy(jpc_dec_cp_t *cp); |
|
static int jpc_dec_cp_setfromcod(jpc_dec_cp_t *cp, jpc_cod_t *cod); |
|
static int jpc_dec_cp_setfromcoc(jpc_dec_cp_t *cp, jpc_coc_t *coc); |
|
static int jpc_dec_cp_setfromcox(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp, |
|
jpc_coxcp_t *compparms, int flags); |
|
static int jpc_dec_cp_setfromqcd(jpc_dec_cp_t *cp, jpc_qcd_t *qcd); |
|
static int jpc_dec_cp_setfromqcc(jpc_dec_cp_t *cp, jpc_qcc_t *qcc); |
|
static int jpc_dec_cp_setfromqcx(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp, |
|
jpc_qcxcp_t *compparms, int flags); |
|
static int jpc_dec_cp_setfromrgn(jpc_dec_cp_t *cp, jpc_rgn_t *rgn); |
|
static int jpc_dec_cp_prepare(jpc_dec_cp_t *cp); |
|
static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp); |
|
static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset); |
|
static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc); |
|
|
|
static int jpc_dec_decode(jpc_dec_t *dec); |
|
static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in); |
|
static void jpc_dec_destroy(jpc_dec_t *dec); |
|
static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize); |
|
static void jpc_undo_roi(jas_matrix_t *x, int roishift, int bgshift, int numbps); |
|
static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits); |
|
static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile); |
|
static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile); |
|
static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile); |
|
static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms); |
|
static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts); |
|
|
|
static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id); |
|
|
|
/******************************************************************************\ |
|
* Global data. |
|
\******************************************************************************/ |
|
|
|
jpc_dec_mstabent_t jpc_dec_mstab[] = { |
|
{JPC_MS_SOC, JPC_MHSOC, jpc_dec_process_soc}, |
|
{JPC_MS_SOT, JPC_MH | JPC_TPHSOT, jpc_dec_process_sot}, |
|
{JPC_MS_SOD, JPC_TPH, jpc_dec_process_sod}, |
|
{JPC_MS_EOC, JPC_TPHSOT, jpc_dec_process_eoc}, |
|
{JPC_MS_SIZ, JPC_MHSIZ, jpc_dec_process_siz}, |
|
{JPC_MS_COD, JPC_MH | JPC_TPH, jpc_dec_process_cod}, |
|
{JPC_MS_COC, JPC_MH | JPC_TPH, jpc_dec_process_coc}, |
|
{JPC_MS_RGN, JPC_MH | JPC_TPH, jpc_dec_process_rgn}, |
|
{JPC_MS_QCD, JPC_MH | JPC_TPH, jpc_dec_process_qcd}, |
|
{JPC_MS_QCC, JPC_MH | JPC_TPH, jpc_dec_process_qcc}, |
|
{JPC_MS_POC, JPC_MH | JPC_TPH, jpc_dec_process_poc}, |
|
{JPC_MS_TLM, JPC_MH, 0}, |
|
{JPC_MS_PLM, JPC_MH, 0}, |
|
{JPC_MS_PLT, JPC_TPH, 0}, |
|
{JPC_MS_PPM, JPC_MH, jpc_dec_process_ppm}, |
|
{JPC_MS_PPT, JPC_TPH, jpc_dec_process_ppt}, |
|
{JPC_MS_SOP, 0, 0}, |
|
{JPC_MS_CRG, JPC_MH, jpc_dec_process_crg}, |
|
{JPC_MS_COM, JPC_MH | JPC_TPH, jpc_dec_process_com}, |
|
{0, JPC_MH | JPC_TPH, jpc_dec_process_unk} |
|
}; |
|
|
|
/******************************************************************************\ |
|
* The main entry point for the JPEG-2000 decoder. |
|
\******************************************************************************/ |
|
|
|
jas_image_t *jpc_decode(jas_stream_t *in, char *optstr) |
|
{ |
|
jpc_dec_importopts_t opts; |
|
jpc_dec_t *dec; |
|
jas_image_t *image; |
|
|
|
dec = 0; |
|
|
|
if (jpc_dec_parseopts(optstr, &opts)) { |
|
goto error; |
|
} |
|
|
|
jpc_initluts(); |
|
|
|
if (!(dec = jpc_dec_create(&opts, in))) { |
|
goto error; |
|
} |
|
|
|
/* Do most of the work. */ |
|
if (jpc_dec_decode(dec)) { |
|
goto error; |
|
} |
|
|
|
if (jas_image_numcmpts(dec->image) >= 3) { |
|
jas_image_setclrspc(dec->image, JAS_CLRSPC_SRGB); |
|
jas_image_setcmpttype(dec->image, 0, |
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); |
|
jas_image_setcmpttype(dec->image, 1, |
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); |
|
jas_image_setcmpttype(dec->image, 2, |
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); |
|
} else { |
|
jas_image_setclrspc(dec->image, JAS_CLRSPC_SGRAY); |
|
jas_image_setcmpttype(dec->image, 0, |
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); |
|
} |
|
|
|
/* Save the return value. */ |
|
image = dec->image; |
|
|
|
/* Stop the image from being discarded. */ |
|
dec->image = 0; |
|
|
|
/* Destroy decoder. */ |
|
jpc_dec_destroy(dec); |
|
|
|
return image; |
|
|
|
error: |
|
if (dec) { |
|
jpc_dec_destroy(dec); |
|
} |
|
return 0; |
|
} |
|
|
|
typedef enum { |
|
OPT_MAXLYRS, |
|
OPT_MAXPKTS, |
|
OPT_DEBUG |
|
} optid_t; |
|
|
|
jas_taginfo_t decopts[] = { |
|
{OPT_MAXLYRS, "maxlyrs"}, |
|
{OPT_MAXPKTS, "maxpkts"}, |
|
{OPT_DEBUG, "debug"}, |
|
{-1, 0} |
|
}; |
|
|
|
static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts) |
|
{ |
|
jas_tvparser_t *tvp; |
|
|
|
opts->debug = 0; |
|
opts->maxlyrs = JPC_MAXLYRS; |
|
opts->maxpkts = -1; |
|
|
|
if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) { |
|
return -1; |
|
} |
|
|
|
while (!jas_tvparser_next(tvp)) { |
|
switch (jas_taginfo_nonull(jas_taginfos_lookup(decopts, |
|
jas_tvparser_gettag(tvp)))->id) { |
|
case OPT_MAXLYRS: |
|
opts->maxlyrs = atoi(jas_tvparser_getval(tvp)); |
|
break; |
|
case OPT_DEBUG: |
|
opts->debug = atoi(jas_tvparser_getval(tvp)); |
|
break; |
|
case OPT_MAXPKTS: |
|
opts->maxpkts = atoi(jas_tvparser_getval(tvp)); |
|
break; |
|
default: |
|
jas_eprintf("warning: ignoring invalid option %s\n", |
|
jas_tvparser_gettag(tvp)); |
|
break; |
|
} |
|
} |
|
|
|
jas_tvparser_destroy(tvp); |
|
|
|
return 0; |
|
} |
|
|
|
/******************************************************************************\ |
|
* Code for table-driven code stream decoder. |
|
\******************************************************************************/ |
|
|
|
static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id) |
|
{ |
|
jpc_dec_mstabent_t *mstabent; |
|
for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) { |
|
if (mstabent->id == id) { |
|
break; |
|
} |
|
} |
|
return mstabent; |
|
} |
|
|
|
static int jpc_dec_decode(jpc_dec_t *dec) |
|
{ |
|
jpc_ms_t *ms; |
|
jpc_dec_mstabent_t *mstabent; |
|
int ret; |
|
jpc_cstate_t *cstate; |
|
|
|
if (!(cstate = jpc_cstate_create())) { |
|
return -1; |
|
} |
|
dec->cstate = cstate; |
|
|
|
/* Initially, we should expect to encounter a SOC marker segment. */ |
|
dec->state = JPC_MHSOC; |
|
|
|
for (;;) { |
|
|
|
/* Get the next marker segment in the code stream. */ |
|
if (!(ms = jpc_getms(dec->in, cstate))) { |
|
jas_eprintf("cannot get marker segment\n"); |
|
return -1; |
|
} |
|
|
|
mstabent = jpc_dec_mstab_lookup(ms->id); |
|
assert(mstabent); |
|
|
|
/* Ensure that this type of marker segment is permitted |
|
at this point in the code stream. */ |
|
if (!(dec->state & mstabent->validstates)) { |
|
jas_eprintf("unexpected marker segment type\n"); |
|
jpc_ms_destroy(ms); |
|
return -1; |
|
} |
|
|
|
/* Process the marker segment. */ |
|
if (mstabent->action) { |
|
ret = (*mstabent->action)(dec, ms); |
|
} else { |
|
/* No explicit action is required. */ |
|
ret = 0; |
|
} |
|
|
|
/* Destroy the marker segment. */ |
|
jpc_ms_destroy(ms); |
|
|
|
if (ret < 0) { |
|
return -1; |
|
} else if (ret > 0) { |
|
break; |
|
} |
|
|
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
int cmptno; |
|
jpc_dec_cmpt_t *cmpt; |
|
jpc_crg_t *crg; |
|
|
|
crg = &ms->parms.crg; |
|
for (cmptno = 0, cmpt = dec->cmpts; cmptno < dec->numcomps; ++cmptno, |
|
++cmpt) { |
|
/* Ignore the information in the CRG marker segment for now. |
|
This information serves no useful purpose for decoding anyhow. |
|
Some other parts of the code need to be changed if these lines |
|
are uncommented. |
|
cmpt->hsubstep = crg->comps[cmptno].hoff; |
|
cmpt->vsubstep = crg->comps[cmptno].voff; |
|
*/ |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
/* Eliminate warnings about unused variables. */ |
|
ms = 0; |
|
|
|
/* We should expect to encounter a SIZ marker segment next. */ |
|
dec->state = JPC_MHSIZ; |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_dec_tile_t *tile; |
|
jpc_sot_t *sot = &ms->parms.sot; |
|
jas_image_cmptparm_t *compinfos; |
|
jas_image_cmptparm_t *compinfo; |
|
jpc_dec_cmpt_t *cmpt; |
|
int cmptno; |
|
|
|
if (dec->state == JPC_MH) { |
|
|
|
compinfos = jas_malloc(dec->numcomps * sizeof(jas_image_cmptparm_t)); |
|
assert(compinfos); |
|
for (cmptno = 0, cmpt = dec->cmpts, compinfo = compinfos; |
|
cmptno < dec->numcomps; ++cmptno, ++cmpt, ++compinfo) { |
|
compinfo->tlx = 0; |
|
compinfo->tly = 0; |
|
compinfo->prec = cmpt->prec; |
|
compinfo->sgnd = cmpt->sgnd; |
|
compinfo->width = cmpt->width; |
|
compinfo->height = cmpt->height; |
|
compinfo->hstep = cmpt->hstep; |
|
compinfo->vstep = cmpt->vstep; |
|
} |
|
|
|
if (!(dec->image = jas_image_create(dec->numcomps, compinfos, |
|
JAS_CLRSPC_UNKNOWN))) { |
|
return -1; |
|
} |
|
jas_free(compinfos); |
|
|
|
/* Is the packet header information stored in PPM marker segments in |
|
the main header? */ |
|
if (dec->ppmstab) { |
|
/* Convert the PPM marker segment data into a collection of streams |
|
(one stream per tile-part). */ |
|
if (!(dec->pkthdrstreams = jpc_ppmstabtostreams(dec->ppmstab))) { |
|
abort(); |
|
} |
|
jpc_ppxstab_destroy(dec->ppmstab); |
|
dec->ppmstab = 0; |
|
} |
|
} |
|
|
|
if (sot->len > 0) { |
|
dec->curtileendoff = jas_stream_getrwcount(dec->in) - ms->len - |
|
4 + sot->len; |
|
} else { |
|
dec->curtileendoff = 0; |
|
} |
|
|
|
if (JAS_CAST(int, sot->tileno) > dec->numtiles) { |
|
jas_eprintf("invalid tile number in SOT marker segment\n"); |
|
return -1; |
|
} |
|
/* Set the current tile. */ |
|
dec->curtile = &dec->tiles[sot->tileno]; |
|
tile = dec->curtile; |
|
/* Ensure that this is the expected part number. */ |
|
if (sot->partno != tile->partno) { |
|
return -1; |
|
} |
|
if (tile->numparts > 0 && sot->partno >= tile->numparts) { |
|
return -1; |
|
} |
|
if (!tile->numparts && sot->numparts > 0) { |
|
tile->numparts = sot->numparts; |
|
} |
|
|
|
tile->pptstab = 0; |
|
|
|
switch (tile->state) { |
|
case JPC_TILE_INIT: |
|
/* This is the first tile-part for this tile. */ |
|
tile->state = JPC_TILE_ACTIVE; |
|
assert(!tile->cp); |
|
if (!(tile->cp = jpc_dec_cp_copy(dec->cp))) { |
|
return -1; |
|
} |
|
jpc_dec_cp_resetflags(dec->cp); |
|
break; |
|
default: |
|
if (sot->numparts == sot->partno - 1) { |
|
tile->state = JPC_TILE_ACTIVELAST; |
|
} |
|
break; |
|
} |
|
|
|
/* Note: We do not increment the expected tile-part number until |
|
all processing for this tile-part is complete. */ |
|
|
|
/* We should expect to encounter other tile-part header marker |
|
segments next. */ |
|
dec->state = JPC_TPH; |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_dec_tile_t *tile; |
|
int pos; |
|
|
|
/* Eliminate compiler warnings about unused variables. */ |
|
ms = 0; |
|
|
|
if (!(tile = dec->curtile)) { |
|
return -1; |
|
} |
|
|
|
if (!tile->partno) { |
|
if (!jpc_dec_cp_isvalid(tile->cp)) { |
|
return -1; |
|
} |
|
jpc_dec_cp_prepare(tile->cp); |
|
if (jpc_dec_tileinit(dec, tile)) { |
|
return -1; |
|
} |
|
} |
|
|
|
/* Are packet headers stored in the main header or tile-part header? */ |
|
if (dec->pkthdrstreams) { |
|
/* Get the stream containing the packet header data for this |
|
tile-part. */ |
|
if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) { |
|
return -1; |
|
} |
|
} |
|
|
|
if (tile->pptstab) { |
|
if (!tile->pkthdrstream) { |
|
if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) { |
|
return -1; |
|
} |
|
} |
|
pos = jas_stream_tell(tile->pkthdrstream); |
|
jas_stream_seek(tile->pkthdrstream, 0, SEEK_END); |
|
if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) { |
|
return -1; |
|
} |
|
jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET); |
|
jpc_ppxstab_destroy(tile->pptstab); |
|
tile->pptstab = 0; |
|
} |
|
|
|
if (jas_getdbglevel() >= 10) { |
|
jpc_dec_dump(dec, stderr); |
|
} |
|
|
|
if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream : |
|
dec->in, dec->in)) { |
|
jas_eprintf("jpc_dec_decodepkts failed\n"); |
|
return -1; |
|
} |
|
|
|
/* Gobble any unconsumed tile data. */ |
|
if (dec->curtileendoff > 0) { |
|
long curoff; |
|
uint_fast32_t n; |
|
curoff = jas_stream_getrwcount(dec->in); |
|
if (curoff < dec->curtileendoff) { |
|
n = dec->curtileendoff - curoff; |
|
jas_eprintf("warning: ignoring trailing garbage (%lu bytes)\n", |
|
(unsigned long) n); |
|
|
|
while (n-- > 0) { |
|
if (jas_stream_getc(dec->in) == EOF) { |
|
jas_eprintf("read error\n"); |
|
return -1; |
|
} |
|
} |
|
} else if (curoff > dec->curtileendoff) { |
|
jas_eprintf("warning: not enough tile data (%lu bytes)\n", |
|
(unsigned long) curoff - dec->curtileendoff); |
|
} |
|
|
|
} |
|
|
|
if (tile->numparts > 0 && tile->partno == tile->numparts - 1) { |
|
if (jpc_dec_tiledecode(dec, tile)) { |
|
return -1; |
|
} |
|
jpc_dec_tilefini(dec, tile); |
|
} |
|
|
|
dec->curtile = 0; |
|
|
|
/* Increment the expected tile-part number. */ |
|
++tile->partno; |
|
|
|
/* We should expect to encounter a SOT marker segment next. */ |
|
dec->state = JPC_TPHSOT; |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile) |
|
{ |
|
jpc_dec_tcomp_t *tcomp; |
|
int compno; |
|
int rlvlno; |
|
jpc_dec_rlvl_t *rlvl; |
|
jpc_dec_band_t *band; |
|
jpc_dec_prc_t *prc; |
|
int bndno; |
|
jpc_tsfb_band_t *bnd; |
|
int bandno; |
|
jpc_dec_ccp_t *ccp; |
|
int prccnt; |
|
jpc_dec_cblk_t *cblk; |
|
int cblkcnt; |
|
uint_fast32_t tlprcxstart; |
|
uint_fast32_t tlprcystart; |
|
uint_fast32_t brprcxend; |
|
uint_fast32_t brprcyend; |
|
uint_fast32_t tlcbgxstart; |
|
uint_fast32_t tlcbgystart; |
|
uint_fast32_t brcbgxend; |
|
uint_fast32_t brcbgyend; |
|
uint_fast32_t cbgxstart; |
|
uint_fast32_t cbgystart; |
|
uint_fast32_t cbgxend; |
|
uint_fast32_t cbgyend; |
|
uint_fast32_t tlcblkxstart; |
|
uint_fast32_t tlcblkystart; |
|
uint_fast32_t brcblkxend; |
|
uint_fast32_t brcblkyend; |
|
uint_fast32_t cblkxstart; |
|
uint_fast32_t cblkystart; |
|
uint_fast32_t cblkxend; |
|
uint_fast32_t cblkyend; |
|
uint_fast32_t tmpxstart; |
|
uint_fast32_t tmpystart; |
|
uint_fast32_t tmpxend; |
|
uint_fast32_t tmpyend; |
|
jpc_dec_cp_t *cp; |
|
jpc_tsfb_band_t bnds[64]; |
|
jpc_pchg_t *pchg; |
|
int pchgno; |
|
jpc_dec_cmpt_t *cmpt; |
|
|
|
cp = tile->cp; |
|
tile->realmode = 0; |
|
if (cp->mctid == JPC_MCT_ICT) { |
|
tile->realmode = 1; |
|
} |
|
|
|
for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < |
|
dec->numcomps; ++compno, ++tcomp, ++cmpt) { |
|
ccp = &tile->cp->ccps[compno]; |
|
if (ccp->qmfbid == JPC_COX_INS) { |
|
tile->realmode = 1; |
|
} |
|
tcomp->numrlvls = ccp->numrlvls; |
|
if (!(tcomp->rlvls = jas_malloc(tcomp->numrlvls * |
|
sizeof(jpc_dec_rlvl_t)))) { |
|
return -1; |
|
} |
|
if (!(tcomp->data = jas_seq2d_create(JPC_CEILDIV(tile->xstart, |
|
cmpt->hstep), JPC_CEILDIV(tile->ystart, cmpt->vstep), |
|
JPC_CEILDIV(tile->xend, cmpt->hstep), JPC_CEILDIV(tile->yend, |
|
cmpt->vstep)))) { |
|
return -1; |
|
} |
|
if (!(tcomp->tsfb = jpc_cod_gettsfb(ccp->qmfbid, |
|
tcomp->numrlvls - 1))) { |
|
return -1; |
|
} |
|
{ |
|
jpc_tsfb_getbands(tcomp->tsfb, jas_seq2d_xstart(tcomp->data), jas_seq2d_ystart(tcomp->data), jas_seq2d_xend(tcomp->data), jas_seq2d_yend(tcomp->data), bnds); |
|
} |
|
for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; |
|
++rlvlno, ++rlvl) { |
|
rlvl->bands = 0; |
|
rlvl->xstart = JPC_CEILDIVPOW2(tcomp->xstart, |
|
tcomp->numrlvls - 1 - rlvlno); |
|
rlvl->ystart = JPC_CEILDIVPOW2(tcomp->ystart, |
|
tcomp->numrlvls - 1 - rlvlno); |
|
rlvl->xend = JPC_CEILDIVPOW2(tcomp->xend, |
|
tcomp->numrlvls - 1 - rlvlno); |
|
rlvl->yend = JPC_CEILDIVPOW2(tcomp->yend, |
|
tcomp->numrlvls - 1 - rlvlno); |
|
rlvl->prcwidthexpn = ccp->prcwidthexpns[rlvlno]; |
|
rlvl->prcheightexpn = ccp->prcheightexpns[rlvlno]; |
|
tlprcxstart = JPC_FLOORDIVPOW2(rlvl->xstart, |
|
rlvl->prcwidthexpn) << rlvl->prcwidthexpn; |
|
tlprcystart = JPC_FLOORDIVPOW2(rlvl->ystart, |
|
rlvl->prcheightexpn) << rlvl->prcheightexpn; |
|
brprcxend = JPC_CEILDIVPOW2(rlvl->xend, |
|
rlvl->prcwidthexpn) << rlvl->prcwidthexpn; |
|
brprcyend = JPC_CEILDIVPOW2(rlvl->yend, |
|
rlvl->prcheightexpn) << rlvl->prcheightexpn; |
|
rlvl->numhprcs = (brprcxend - tlprcxstart) >> |
|
rlvl->prcwidthexpn; |
|
rlvl->numvprcs = (brprcyend - tlprcystart) >> |
|
rlvl->prcheightexpn; |
|
rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs; |
|
|
|
if (rlvl->xstart >= rlvl->xend || rlvl->ystart >= rlvl->yend) { |
|
rlvl->bands = 0; |
|
rlvl->numprcs = 0; |
|
rlvl->numhprcs = 0; |
|
rlvl->numvprcs = 0; |
|
continue; |
|
} |
|
if (!rlvlno) { |
|
tlcbgxstart = tlprcxstart; |
|
tlcbgystart = tlprcystart; |
|
brcbgxend = brprcxend; |
|
brcbgyend = brprcyend; |
|
rlvl->cbgwidthexpn = rlvl->prcwidthexpn; |
|
rlvl->cbgheightexpn = rlvl->prcheightexpn; |
|
} else { |
|
tlcbgxstart = JPC_CEILDIVPOW2(tlprcxstart, 1); |
|
tlcbgystart = JPC_CEILDIVPOW2(tlprcystart, 1); |
|
brcbgxend = JPC_CEILDIVPOW2(brprcxend, 1); |
|
brcbgyend = JPC_CEILDIVPOW2(brprcyend, 1); |
|
rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1; |
|
rlvl->cbgheightexpn = rlvl->prcheightexpn - 1; |
|
} |
|
rlvl->cblkwidthexpn = JAS_MIN(ccp->cblkwidthexpn, |
|
rlvl->cbgwidthexpn); |
|
rlvl->cblkheightexpn = JAS_MIN(ccp->cblkheightexpn, |
|
rlvl->cbgheightexpn); |
|
|
|
rlvl->numbands = (!rlvlno) ? 1 : 3; |
|
if (!(rlvl->bands = jas_malloc(rlvl->numbands * |
|
sizeof(jpc_dec_band_t)))) { |
|
return -1; |
|
} |
|
for (bandno = 0, band = rlvl->bands; |
|
bandno < rlvl->numbands; ++bandno, ++band) { |
|
bndno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + |
|
bandno + 1); |
|
bnd = &bnds[bndno]; |
|
|
|
band->orient = bnd->orient; |
|
band->stepsize = ccp->stepsizes[bndno]; |
|
band->analgain = JPC_NOMINALGAIN(ccp->qmfbid, |
|
tcomp->numrlvls - 1, rlvlno, band->orient); |
|
band->absstepsize = jpc_calcabsstepsize(band->stepsize, |
|
cmpt->prec + band->analgain); |
|
band->numbps = ccp->numguardbits + |
|
JPC_QCX_GETEXPN(band->stepsize) - 1; |
|
band->roishift = (ccp->roishift + band->numbps >= JPC_PREC) ? |
|
(JPC_PREC - 1 - band->numbps) : ccp->roishift; |
|
band->data = 0; |
|
band->prcs = 0; |
|
if (bnd->xstart == bnd->xend || bnd->ystart == bnd->yend) { |
|
continue; |
|
} |
|
if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) { |
|
return -1; |
|
} |
|
jas_seq2d_bindsub(band->data, tcomp->data, bnd->locxstart, bnd->locystart, bnd->locxend, bnd->locyend); |
|
jas_seq2d_setshift(band->data, bnd->xstart, bnd->ystart); |
|
|
|
assert(rlvl->numprcs); |
|
|
|
if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_dec_prc_t)))) { |
|
return -1; |
|
} |
|
|
|
/************************************************/ |
|
cbgxstart = tlcbgxstart; |
|
cbgystart = tlcbgystart; |
|
for (prccnt = rlvl->numprcs, prc = band->prcs; |
|
prccnt > 0; --prccnt, ++prc) { |
|
cbgxend = cbgxstart + (1 << rlvl->cbgwidthexpn); |
|
cbgyend = cbgystart + (1 << rlvl->cbgheightexpn); |
|
prc->xstart = JAS_MAX(cbgxstart, JAS_CAST(uint_fast32_t, jas_seq2d_xstart(band->data))); |
|
prc->ystart = JAS_MAX(cbgystart, JAS_CAST(uint_fast32_t, jas_seq2d_ystart(band->data))); |
|
prc->xend = JAS_MIN(cbgxend, JAS_CAST(uint_fast32_t, jas_seq2d_xend(band->data))); |
|
prc->yend = JAS_MIN(cbgyend, JAS_CAST(uint_fast32_t, jas_seq2d_yend(band->data))); |
|
if (prc->xend > prc->xstart && prc->yend > prc->ystart) { |
|
tlcblkxstart = JPC_FLOORDIVPOW2(prc->xstart, |
|
rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn; |
|
tlcblkystart = JPC_FLOORDIVPOW2(prc->ystart, |
|
rlvl->cblkheightexpn) << rlvl->cblkheightexpn; |
|
brcblkxend = JPC_CEILDIVPOW2(prc->xend, |
|
rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn; |
|
brcblkyend = JPC_CEILDIVPOW2(prc->yend, |
|
rlvl->cblkheightexpn) << rlvl->cblkheightexpn; |
|
prc->numhcblks = (brcblkxend - tlcblkxstart) >> |
|
rlvl->cblkwidthexpn; |
|
prc->numvcblks = (brcblkyend - tlcblkystart) >> |
|
rlvl->cblkheightexpn; |
|
prc->numcblks = prc->numhcblks * prc->numvcblks; |
|
assert(prc->numcblks > 0); |
|
|
|
if (!(prc->incltagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) { |
|
return -1; |
|
} |
|
if (!(prc->numimsbstagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) { |
|
return -1; |
|
} |
|
if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_dec_cblk_t)))) { |
|
return -1; |
|
} |
|
|
|
cblkxstart = cbgxstart; |
|
cblkystart = cbgystart; |
|
for (cblkcnt = prc->numcblks, cblk = prc->cblks; cblkcnt > 0;) { |
|
cblkxend = cblkxstart + (1 << rlvl->cblkwidthexpn); |
|
cblkyend = cblkystart + (1 << rlvl->cblkheightexpn); |
|
tmpxstart = JAS_MAX(cblkxstart, prc->xstart); |
|
tmpystart = JAS_MAX(cblkystart, prc->ystart); |
|
tmpxend = JAS_MIN(cblkxend, prc->xend); |
|
tmpyend = JAS_MIN(cblkyend, prc->yend); |
|
if (tmpxend > tmpxstart && tmpyend > tmpystart) { |
|
cblk->firstpassno = -1; |
|
cblk->mqdec = 0; |
|
cblk->nulldec = 0; |
|
cblk->flags = 0; |
|
cblk->numpasses = 0; |
|
cblk->segs.head = 0; |
|
cblk->segs.tail = 0; |
|
cblk->curseg = 0; |
|
cblk->numimsbs = 0; |
|
cblk->numlenbits = 3; |
|
cblk->flags = 0; |
|
if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) { |
|
return -1; |
|
} |
|
jas_seq2d_bindsub(cblk->data, band->data, tmpxstart, tmpystart, tmpxend, tmpyend); |
|
++cblk; |
|
--cblkcnt; |
|
} |
|
cblkxstart += 1 << rlvl->cblkwidthexpn; |
|
if (cblkxstart >= cbgxend) { |
|
cblkxstart = cbgxstart; |
|
cblkystart += 1 << rlvl->cblkheightexpn; |
|
} |
|
} |
|
|
|
} else { |
|
prc->cblks = 0; |
|
prc->incltagtree = 0; |
|
prc->numimsbstagtree = 0; |
|
} |
|
cbgxstart += 1 << rlvl->cbgwidthexpn; |
|
if (cbgxstart >= brcbgxend) { |
|
cbgxstart = tlcbgxstart; |
|
cbgystart += 1 << rlvl->cbgheightexpn; |
|
} |
|
|
|
} |
|
/********************************************/ |
|
} |
|
} |
|
} |
|
|
|
if (!(tile->pi = jpc_dec_pi_create(dec, tile))) |
|
{ |
|
return -1; |
|
} |
|
|
|
for (pchgno = 0; pchgno < jpc_pchglist_numpchgs(tile->cp->pchglist); |
|
++pchgno) { |
|
pchg = jpc_pchg_copy(jpc_pchglist_get(tile->cp->pchglist, pchgno)); |
|
assert(pchg); |
|
jpc_pi_addpchg(tile->pi, pchg); |
|
} |
|
jpc_pi_init(tile->pi); |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile) |
|
{ |
|
jpc_dec_tcomp_t *tcomp; |
|
int compno; |
|
int bandno; |
|
int rlvlno; |
|
jpc_dec_band_t *band; |
|
jpc_dec_rlvl_t *rlvl; |
|
int prcno; |
|
jpc_dec_prc_t *prc; |
|
jpc_dec_seg_t *seg; |
|
jpc_dec_cblk_t *cblk; |
|
int cblkno; |
|
|
|
if (tile->tcomps) { |
|
|
|
for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; |
|
++compno, ++tcomp) { |
|
for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; |
|
++rlvlno, ++rlvl) { |
|
if (!rlvl->bands) { |
|
continue; |
|
} |
|
for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; ++bandno, ++band) { |
|
if (band->prcs) { |
|
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) { |
|
|
|
while (cblk->segs.head) { |
|
seg = cblk->segs.head; |
|
jpc_seglist_remove(&cblk->segs, seg); |
|
jpc_seg_destroy(seg); |
|
} |
|
jas_matrix_destroy(cblk->data); |
|
if (cblk->mqdec) { |
|
jpc_mqdec_destroy(cblk->mqdec); |
|
} |
|
if (cblk->nulldec) { |
|
jpc_bitstream_close(cblk->nulldec); |
|
} |
|
if (cblk->flags) { |
|
jas_matrix_destroy(cblk->flags); |
|
} |
|
} |
|
if (prc->incltagtree) { |
|
jpc_tagtree_destroy(prc->incltagtree); |
|
} |
|
if (prc->numimsbstagtree) { |
|
jpc_tagtree_destroy(prc->numimsbstagtree); |
|
} |
|
if (prc->cblks) { |
|
jas_free(prc->cblks); |
|
} |
|
} |
|
} |
|
if (band->data) { |
|
jas_matrix_destroy(band->data); |
|
} |
|
if (band->prcs) { |
|
jas_free(band->prcs); |
|
} |
|
} |
|
if (rlvl->bands) { |
|
jas_free(rlvl->bands); |
|
} |
|
} |
|
if (tcomp->rlvls) { |
|
jas_free(tcomp->rlvls); |
|
} |
|
if (tcomp->data) { |
|
jas_matrix_destroy(tcomp->data); |
|
} |
|
if (tcomp->tsfb) { |
|
jpc_tsfb_destroy(tcomp->tsfb); |
|
} |
|
} |
|
} |
|
if (tile->cp) { |
|
jpc_dec_cp_destroy(tile->cp); |
|
tile->cp = 0; |
|
} |
|
if (tile->tcomps) { |
|
jas_free(tile->tcomps); |
|
tile->tcomps = 0; |
|
} |
|
if (tile->pi) { |
|
jpc_pi_destroy(tile->pi); |
|
tile->pi = 0; |
|
} |
|
if (tile->pkthdrstream) { |
|
jas_stream_close(tile->pkthdrstream); |
|
tile->pkthdrstream = 0; |
|
} |
|
if (tile->pptstab) { |
|
jpc_ppxstab_destroy(tile->pptstab); |
|
tile->pptstab = 0; |
|
} |
|
|
|
tile->state = JPC_TILE_DONE; |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile) |
|
{ |
|
int i; |
|
int j; |
|
jpc_dec_tcomp_t *tcomp; |
|
jpc_dec_rlvl_t *rlvl; |
|
jpc_dec_band_t *band; |
|
int compno; |
|
int rlvlno; |
|
int bandno; |
|
int adjust; |
|
int v; |
|
jpc_dec_ccp_t *ccp; |
|
jpc_dec_cmpt_t *cmpt; |
|
|
|
if (jpc_dec_decodecblks(dec, tile)) { |
|
jas_eprintf("jpc_dec_decodecblks failed\n"); |
|
return -1; |
|
} |
|
|
|
/* Perform dequantization. */ |
|
for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; |
|
++compno, ++tcomp) { |
|
ccp = &tile->cp->ccps[compno]; |
|
for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; |
|
++rlvlno, ++rlvl) { |
|
if (!rlvl->bands) { |
|
continue; |
|
} |
|
for (bandno = 0, band = rlvl->bands; |
|
bandno < rlvl->numbands; ++bandno, ++band) { |
|
if (!band->data) { |
|
continue; |
|
} |
|
jpc_undo_roi(band->data, band->roishift, ccp->roishift - |
|
band->roishift, band->numbps); |
|
if (tile->realmode) { |
|
jas_matrix_asl(band->data, JPC_FIX_FRACBITS); |
|
jpc_dequantize(band->data, band->absstepsize); |
|
} |
|
|
|
} |
|
} |
|
} |
|
|
|
/* Apply an inverse wavelet transform if necessary. */ |
|
for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; |
|
++compno, ++tcomp) { |
|
ccp = &tile->cp->ccps[compno]; |
|
jpc_tsfb_synthesize(tcomp->tsfb, tcomp->data); |
|
} |
|
|
|
|
|
/* Apply an inverse intercomponent transform if necessary. */ |
|
switch (tile->cp->mctid) { |
|
case JPC_MCT_RCT: |
|
assert(dec->numcomps == 3); |
|
jpc_irct(tile->tcomps[0].data, tile->tcomps[1].data, |
|
tile->tcomps[2].data); |
|
break; |
|
case JPC_MCT_ICT: |
|
assert(dec->numcomps == 3); |
|
jpc_iict(tile->tcomps[0].data, tile->tcomps[1].data, |
|
tile->tcomps[2].data); |
|
break; |
|
} |
|
|
|
/* Perform rounding and convert to integer values. */ |
|
if (tile->realmode) { |
|
for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; |
|
++compno, ++tcomp) { |
|
for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) { |
|
for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) { |
|
v = jas_matrix_get(tcomp->data, i, j); |
|
v = jpc_fix_round(v); |
|
jas_matrix_set(tcomp->data, i, j, jpc_fixtoint(v)); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/* Perform level shift. */ |
|
for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < |
|
dec->numcomps; ++compno, ++tcomp, ++cmpt) { |
|
adjust = cmpt->sgnd ? 0 : (1 << (cmpt->prec - 1)); |
|
for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) { |
|
for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) { |
|
*jas_matrix_getref(tcomp->data, i, j) += adjust; |
|
} |
|
} |
|
} |
|
|
|
/* Perform clipping. */ |
|
for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < |
|
dec->numcomps; ++compno, ++tcomp, ++cmpt) { |
|
jpc_fix_t mn; |
|
jpc_fix_t mx; |
|
mn = cmpt->sgnd ? (-(1 << (cmpt->prec - 1))) : (0); |
|
mx = cmpt->sgnd ? ((1 << (cmpt->prec - 1)) - 1) : ((1 << |
|
cmpt->prec) - 1); |
|
jas_matrix_clip(tcomp->data, mn, mx); |
|
} |
|
|
|
/* XXX need to free tsfb struct */ |
|
|
|
/* Write the data for each component of the image. */ |
|
for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < |
|
dec->numcomps; ++compno, ++tcomp, ++cmpt) { |
|
if (jas_image_writecmpt(dec->image, compno, tcomp->xstart - |
|
JPC_CEILDIV(dec->xstart, cmpt->hstep), tcomp->ystart - |
|
JPC_CEILDIV(dec->ystart, cmpt->vstep), jas_matrix_numcols( |
|
tcomp->data), jas_matrix_numrows(tcomp->data), tcomp->data)) { |
|
jas_eprintf("write component failed\n"); |
|
return -4; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
int tileno; |
|
jpc_dec_tile_t *tile; |
|
|
|
/* Eliminate compiler warnings about unused variables. */ |
|
ms = 0; |
|
|
|
for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno, |
|
++tile) { |
|
if (tile->state == JPC_TILE_ACTIVE) { |
|
if (jpc_dec_tiledecode(dec, tile)) { |
|
return -1; |
|
} |
|
} |
|
jpc_dec_tilefini(dec, tile); |
|
} |
|
|
|
/* We are done processing the code stream. */ |
|
dec->state = JPC_MT; |
|
|
|
return 1; |
|
} |
|
|
|
static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_siz_t *siz = &ms->parms.siz; |
|
int compno; |
|
int tileno; |
|
jpc_dec_tile_t *tile; |
|
jpc_dec_tcomp_t *tcomp; |
|
int htileno; |
|
int vtileno; |
|
jpc_dec_cmpt_t *cmpt; |
|
|
|
dec->xstart = siz->xoff; |
|
dec->ystart = siz->yoff; |
|
dec->xend = siz->width; |
|
dec->yend = siz->height; |
|
dec->tilewidth = siz->tilewidth; |
|
dec->tileheight = siz->tileheight; |
|
dec->tilexoff = siz->tilexoff; |
|
dec->tileyoff = siz->tileyoff; |
|
dec->numcomps = siz->numcomps; |
|
if (!(dec->cp = jpc_dec_cp_create(dec->numcomps))) { |
|
return -1; |
|
} |
|
|
|
if (!(dec->cmpts = jas_malloc(dec->numcomps * sizeof(jpc_dec_cmpt_t)))) { |
|
return -1; |
|
} |
|
|
|
for (compno = 0, cmpt = dec->cmpts; compno < dec->numcomps; ++compno, |
|
++cmpt) { |
|
cmpt->prec = siz->comps[compno].prec; |
|
cmpt->sgnd = siz->comps[compno].sgnd; |
|
cmpt->hstep = siz->comps[compno].hsamp; |
|
cmpt->vstep = siz->comps[compno].vsamp; |
|
cmpt->width = JPC_CEILDIV(dec->xend, cmpt->hstep) - |
|
JPC_CEILDIV(dec->xstart, cmpt->hstep); |
|
cmpt->height = JPC_CEILDIV(dec->yend, cmpt->vstep) - |
|
JPC_CEILDIV(dec->ystart, cmpt->vstep); |
|
cmpt->hsubstep = 0; |
|
cmpt->vsubstep = 0; |
|
} |
|
|
|
dec->image = 0; |
|
|
|
dec->numhtiles = JPC_CEILDIV(dec->xend - dec->tilexoff, dec->tilewidth); |
|
dec->numvtiles = JPC_CEILDIV(dec->yend - dec->tileyoff, dec->tileheight); |
|
dec->numtiles = dec->numhtiles * dec->numvtiles; |
|
if (!(dec->tiles = jas_malloc(dec->numtiles * sizeof(jpc_dec_tile_t)))) { |
|
return -1; |
|
} |
|
|
|
for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno, |
|
++tile) { |
|
htileno = tileno % dec->numhtiles; |
|
vtileno = tileno / dec->numhtiles; |
|
tile->realmode = 0; |
|
tile->state = JPC_TILE_INIT; |
|
tile->xstart = JAS_MAX(dec->tilexoff + htileno * dec->tilewidth, |
|
dec->xstart); |
|
tile->ystart = JAS_MAX(dec->tileyoff + vtileno * dec->tileheight, |
|
dec->ystart); |
|
tile->xend = JAS_MIN(dec->tilexoff + (htileno + 1) * |
|
dec->tilewidth, dec->xend); |
|
tile->yend = JAS_MIN(dec->tileyoff + (vtileno + 1) * |
|
dec->tileheight, dec->yend); |
|
tile->numparts = 0; |
|
tile->partno = 0; |
|
tile->pkthdrstream = 0; |
|
tile->pkthdrstreampos = 0; |
|
tile->pptstab = 0; |
|
tile->cp = 0; |
|
if (!(tile->tcomps = jas_malloc(dec->numcomps * |
|
sizeof(jpc_dec_tcomp_t)))) { |
|
return -1; |
|
} |
|
for (compno = 0, cmpt = dec->cmpts, tcomp = tile->tcomps; |
|
compno < dec->numcomps; ++compno, ++cmpt, ++tcomp) { |
|
tcomp->rlvls = 0; |
|
tcomp->data = 0; |
|
tcomp->xstart = JPC_CEILDIV(tile->xstart, cmpt->hstep); |
|
tcomp->ystart = JPC_CEILDIV(tile->ystart, cmpt->vstep); |
|
tcomp->xend = JPC_CEILDIV(tile->xend, cmpt->hstep); |
|
tcomp->yend = JPC_CEILDIV(tile->yend, cmpt->vstep); |
|
tcomp->tsfb = 0; |
|
} |
|
} |
|
|
|
dec->pkthdrstreams = 0; |
|
|
|
/* We should expect to encounter other main header marker segments |
|
or an SOT marker segment next. */ |
|
dec->state = JPC_MH; |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_cod_t *cod = &ms->parms.cod; |
|
jpc_dec_tile_t *tile; |
|
|
|
switch (dec->state) { |
|
case JPC_MH: |
|
jpc_dec_cp_setfromcod(dec->cp, cod); |
|
break; |
|
case JPC_TPH: |
|
if (!(tile = dec->curtile)) { |
|
return -1; |
|
} |
|
if (tile->partno != 0) { |
|
return -1; |
|
} |
|
jpc_dec_cp_setfromcod(tile->cp, cod); |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_coc_t *coc = &ms->parms.coc; |
|
jpc_dec_tile_t *tile; |
|
|
|
if (JAS_CAST(int, coc->compno) > dec->numcomps) { |
|
jas_eprintf("invalid component number in COC marker segment\n"); |
|
return -1; |
|
} |
|
switch (dec->state) { |
|
case JPC_MH: |
|
jpc_dec_cp_setfromcoc(dec->cp, coc); |
|
break; |
|
case JPC_TPH: |
|
if (!(tile = dec->curtile)) { |
|
return -1; |
|
} |
|
if (tile->partno > 0) { |
|
return -1; |
|
} |
|
jpc_dec_cp_setfromcoc(tile->cp, coc); |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_rgn_t *rgn = &ms->parms.rgn; |
|
jpc_dec_tile_t *tile; |
|
|
|
if (JAS_CAST(int, rgn->compno) > dec->numcomps) { |
|
jas_eprintf("invalid component number in RGN marker segment\n"); |
|
return -1; |
|
} |
|
switch (dec->state) { |
|
case JPC_MH: |
|
jpc_dec_cp_setfromrgn(dec->cp, rgn); |
|
break; |
|
case JPC_TPH: |
|
if (!(tile = dec->curtile)) { |
|
return -1; |
|
} |
|
if (tile->partno > 0) { |
|
return -1; |
|
} |
|
jpc_dec_cp_setfromrgn(tile->cp, rgn); |
|
break; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_qcd_t *qcd = &ms->parms.qcd; |
|
jpc_dec_tile_t *tile; |
|
|
|
switch (dec->state) { |
|
case JPC_MH: |
|
jpc_dec_cp_setfromqcd(dec->cp, qcd); |
|
break; |
|
case JPC_TPH: |
|
if (!(tile = dec->curtile)) { |
|
return -1; |
|
} |
|
if (tile->partno > 0) { |
|
return -1; |
|
} |
|
jpc_dec_cp_setfromqcd(tile->cp, qcd); |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_qcc_t *qcc = &ms->parms.qcc; |
|
jpc_dec_tile_t *tile; |
|
|
|
if (JAS_CAST(int, qcc->compno) > dec->numcomps) { |
|
jas_eprintf("invalid component number in QCC marker segment\n"); |
|
return -1; |
|
} |
|
switch (dec->state) { |
|
case JPC_MH: |
|
jpc_dec_cp_setfromqcc(dec->cp, qcc); |
|
break; |
|
case JPC_TPH: |
|
if (!(tile = dec->curtile)) { |
|
return -1; |
|
} |
|
if (tile->partno > 0) { |
|
return -1; |
|
} |
|
jpc_dec_cp_setfromqcc(tile->cp, qcc); |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_poc_t *poc = &ms->parms.poc; |
|
jpc_dec_tile_t *tile; |
|
switch (dec->state) { |
|
case JPC_MH: |
|
if (jpc_dec_cp_setfrompoc(dec->cp, poc, 1)) { |
|
return -1; |
|
} |
|
break; |
|
case JPC_TPH: |
|
if (!(tile = dec->curtile)) { |
|
return -1; |
|
} |
|
if (!tile->partno) { |
|
if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) { |
|
return -1; |
|
} |
|
} else { |
|
jpc_pi_addpchgfrompoc(tile->pi, poc); |
|
} |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_ppm_t *ppm = &ms->parms.ppm; |
|
jpc_ppxstabent_t *ppmstabent; |
|
|
|
if (!dec->ppmstab) { |
|
if (!(dec->ppmstab = jpc_ppxstab_create())) { |
|
return -1; |
|
} |
|
} |
|
|
|
if (!(ppmstabent = jpc_ppxstabent_create())) { |
|
return -1; |
|
} |
|
ppmstabent->ind = ppm->ind; |
|
ppmstabent->data = ppm->data; |
|
ppm->data = 0; |
|
ppmstabent->len = ppm->len; |
|
if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) { |
|
return -1; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
jpc_ppt_t *ppt = &ms->parms.ppt; |
|
jpc_dec_tile_t *tile; |
|
jpc_ppxstabent_t *pptstabent; |
|
|
|
tile = dec->curtile; |
|
if (!tile->pptstab) { |
|
if (!(tile->pptstab = jpc_ppxstab_create())) { |
|
return -1; |
|
} |
|
} |
|
if (!(pptstabent = jpc_ppxstabent_create())) { |
|
return -1; |
|
} |
|
pptstabent->ind = ppt->ind; |
|
pptstabent->data = ppt->data; |
|
ppt->data = 0; |
|
pptstabent->len = ppt->len; |
|
if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) { |
|
return -1; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
/* Eliminate compiler warnings about unused variables. */ |
|
dec = 0; |
|
ms = 0; |
|
|
|
return 0; |
|
} |
|
|
|
static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms) |
|
{ |
|
/* Eliminate compiler warnings about unused variables. */ |
|
dec = 0; |
|
|
|
jas_eprintf("warning: ignoring unknown marker segment\n"); |
|
jpc_ms_dump(ms, stderr); |
|
return 0; |
|
} |
|
|
|
/******************************************************************************\ |
|
* |
|
\******************************************************************************/ |
|
|
|
static jpc_dec_cp_t *jpc_dec_cp_create(uint_fast16_t numcomps) |
|
{ |
|
jpc_dec_cp_t *cp; |
|
jpc_dec_ccp_t *ccp; |
|
int compno; |
|
|
|
if (!(cp = jas_malloc(sizeof(jpc_dec_cp_t)))) { |
|
return 0; |
|
} |
|
cp->flags = 0; |
|
cp->numcomps = numcomps; |
|
cp->prgord = 0; |
|
cp->numlyrs = 0; |
|
cp->mctid = 0; |
|
cp->csty = 0; |
|
if (!(cp->ccps = jas_malloc(cp->numcomps * sizeof(jpc_dec_ccp_t)))) { |
|
return 0; |
|
} |
|
if (!(cp->pchglist = jpc_pchglist_create())) { |
|
jas_free(cp->ccps); |
|
return 0; |
|
} |
|
for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; |
|
++compno, ++ccp) { |
|
ccp->flags = 0; |
|
ccp->numrlvls = 0; |
|
ccp->cblkwidthexpn = 0; |
|
ccp->cblkheightexpn = 0; |
|
ccp->qmfbid = 0; |
|
ccp->numstepsizes = 0; |
|
ccp->numguardbits = 0; |
|
ccp->roishift = 0; |
|
ccp->cblkctx = 0; |
|
} |
|
return cp; |
|
} |
|
|
|
static jpc_dec_cp_t *jpc_dec_cp_copy(jpc_dec_cp_t *cp) |
|
{ |
|
jpc_dec_cp_t *newcp; |
|
jpc_dec_ccp_t *newccp; |
|
jpc_dec_ccp_t *ccp; |
|
int compno; |
|
|
|
if (!(newcp = jpc_dec_cp_create(cp->numcomps))) { |
|
return 0; |
|
} |
|
newcp->flags = cp->flags; |
|
newcp->prgord = cp->prgord; |
|
newcp->numlyrs = cp->numlyrs; |
|
newcp->mctid = cp->mctid; |
|
newcp->csty = cp->csty; |
|
jpc_pchglist_destroy(newcp->pchglist); |
|
newcp->pchglist = 0; |
|
if (!(newcp->pchglist = jpc_pchglist_copy(cp->pchglist))) { |
|
jas_free(newcp); |
|
return 0; |
|
} |
|
for (compno = 0, newccp = newcp->ccps, ccp = cp->ccps; |
|
compno < cp->numcomps; |
|
++compno, ++newccp, ++ccp) { |
|
*newccp = *ccp; |
|
} |
|
return newcp; |
|
} |
|
|
|
static void jpc_dec_cp_resetflags(jpc_dec_cp_t *cp) |
|
{ |
|
int compno; |
|
jpc_dec_ccp_t *ccp; |
|
cp->flags &= (JPC_CSET | JPC_QSET); |
|
for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; |
|
++compno, ++ccp) { |
|
ccp->flags = 0; |
|
} |
|
} |
|
|
|
static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp) |
|
{ |
|
if (cp->ccps) { |
|
jas_free(cp->ccps); |
|
} |
|
if (cp->pchglist) { |
|
jpc_pchglist_destroy(cp->pchglist); |
|
} |
|
jas_free(cp); |
|
} |
|
|
|
static int jpc_dec_cp_isvalid(jpc_dec_cp_t *cp) |
|
{ |
|
uint_fast16_t compcnt; |
|
jpc_dec_ccp_t *ccp; |
|
|
|
if (!(cp->flags & JPC_CSET) || !(cp->flags & JPC_QSET)) { |
|
return 0; |
|
} |
|
for (compcnt = cp->numcomps, ccp = cp->ccps; compcnt > 0; --compcnt, |
|
++ccp) { |
|
/* Is there enough step sizes for the number of bands? */ |
|
if ((ccp->qsty != JPC_QCX_SIQNT && JAS_CAST(int, ccp->numstepsizes) < 3 * |
|
ccp->numrlvls - 2) || (ccp->qsty == JPC_QCX_SIQNT && |
|
ccp->numstepsizes != 1)) { |
|
return 0; |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
static void calcstepsizes(uint_fast16_t refstepsize, int numrlvls, |
|
uint_fast16_t *stepsizes) |
|
{ |
|
int bandno; |
|
int numbands; |
|
uint_fast16_t expn; |
|
uint_fast16_t mant; |
|
expn = JPC_QCX_GETEXPN(refstepsize); |
|
mant = JPC_QCX_GETMANT(refstepsize); |
|
numbands = 3 * numrlvls - 2; |
|
for (bandno = 0; bandno < numbands; ++bandno) { |
|
stepsizes[bandno] = JPC_QCX_MANT(mant) | JPC_QCX_EXPN(expn + |
|
(numrlvls - 1) - (numrlvls - 1 - ((bandno > 0) ? ((bandno + 2) / 3) : (0)))); |
|
} |
|
} |
|
|
|
static int jpc_dec_cp_prepare(jpc_dec_cp_t *cp) |
|
{ |
|
jpc_dec_ccp_t *ccp; |
|
int compno; |
|
int i; |
|
for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; |
|
++compno, ++ccp) { |
|
if (!(ccp->csty & JPC_COX_PRT)) { |
|
for (i = 0; i < JPC_MAXRLVLS; ++i) { |
|
ccp->prcwidthexpns[i] = 15; |
|
ccp->prcheightexpns[i] = 15; |
|
} |
|
} |
|
if (ccp->qsty == JPC_QCX_SIQNT) { |
|
calcstepsizes(ccp->stepsizes[0], ccp->numrlvls, ccp->stepsizes); |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_cp_setfromcod(jpc_dec_cp_t *cp, jpc_cod_t *cod) |
|
{ |
|
jpc_dec_ccp_t *ccp; |
|
int compno; |
|
cp->flags |= JPC_CSET; |
|
cp->prgord = cod->prg; |
|
if (cod->mctrans) { |
|
cp->mctid = (cod->compparms.qmfbid == JPC_COX_INS) ? (JPC_MCT_ICT) : (JPC_MCT_RCT); |
|
} else { |
|
cp->mctid = JPC_MCT_NONE; |
|
} |
|
cp->numlyrs = cod->numlyrs; |
|
cp->csty = cod->csty & (JPC_COD_SOP | JPC_COD_EPH); |
|
for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; |
|
++compno, ++ccp) { |
|
jpc_dec_cp_setfromcox(cp, ccp, &cod->compparms, 0); |
|
} |
|
cp->flags |= JPC_CSET; |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_cp_setfromcoc(jpc_dec_cp_t *cp, jpc_coc_t *coc) |
|
{ |
|
jpc_dec_cp_setfromcox(cp, &cp->ccps[coc->compno], &coc->compparms, JPC_COC); |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_cp_setfromcox(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp, |
|
jpc_coxcp_t *compparms, int flags) |
|
{ |
|
int rlvlno; |
|
|
|
/* Eliminate compiler warnings about unused variables. */ |
|
cp = 0; |
|
|
|
if ((flags & JPC_COC) || !(ccp->flags & JPC_COC)) { |
|
ccp->numrlvls = compparms->numdlvls + 1; |
|
ccp->cblkwidthexpn = JPC_COX_GETCBLKSIZEEXPN( |
|
compparms->cblkwidthval); |
|
ccp->cblkheightexpn = JPC_COX_GETCBLKSIZEEXPN( |
|
compparms->cblkheightval); |
|
ccp->qmfbid = compparms->qmfbid; |
|
ccp->cblkctx = compparms->cblksty; |
|
ccp->csty = compparms->csty & JPC_COX_PRT; |
|
for (rlvlno = 0; rlvlno < compparms->numrlvls; ++rlvlno) { |
|
ccp->prcwidthexpns[rlvlno] = |
|
compparms->rlvls[rlvlno].parwidthval; |
|
ccp->prcheightexpns[rlvlno] = |
|
compparms->rlvls[rlvlno].parheightval; |
|
} |
|
ccp->flags |= flags | JPC_CSET; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_cp_setfromqcd(jpc_dec_cp_t *cp, jpc_qcd_t *qcd) |
|
{ |
|
int compno; |
|
jpc_dec_ccp_t *ccp; |
|
for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; |
|
++compno, ++ccp) { |
|
jpc_dec_cp_setfromqcx(cp, ccp, &qcd->compparms, 0); |
|
} |
|
cp->flags |= JPC_QSET; |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_cp_setfromqcc(jpc_dec_cp_t *cp, jpc_qcc_t *qcc) |
|
{ |
|
return jpc_dec_cp_setfromqcx(cp, &cp->ccps[qcc->compno], &qcc->compparms, JPC_QCC); |
|
} |
|
|
|
static int jpc_dec_cp_setfromqcx(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp, |
|
jpc_qcxcp_t *compparms, int flags) |
|
{ |
|
int bandno; |
|
|
|
/* Eliminate compiler warnings about unused variables. */ |
|
cp = 0; |
|
|
|
if ((flags & JPC_QCC) || !(ccp->flags & JPC_QCC)) { |
|
ccp->flags |= flags | JPC_QSET; |
|
for (bandno = 0; bandno < compparms->numstepsizes; ++bandno) { |
|
ccp->stepsizes[bandno] = compparms->stepsizes[bandno]; |
|
} |
|
ccp->numstepsizes = compparms->numstepsizes; |
|
ccp->numguardbits = compparms->numguard; |
|
ccp->qsty = compparms->qntsty; |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_cp_setfromrgn(jpc_dec_cp_t *cp, jpc_rgn_t *rgn) |
|
{ |
|
jpc_dec_ccp_t *ccp; |
|
ccp = &cp->ccps[rgn->compno]; |
|
ccp->roishift = rgn->roishift; |
|
return 0; |
|
} |
|
|
|
static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc) |
|
{ |
|
int pchgno; |
|
jpc_pchg_t *pchg; |
|
for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) { |
|
if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) { |
|
return -1; |
|
} |
|
if (jpc_pchglist_insert(pi->pchglist, -1, pchg)) { |
|
return -1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset) |
|
{ |
|
int pchgno; |
|
jpc_pchg_t *pchg; |
|
if (reset) { |
|
while (jpc_pchglist_numpchgs(cp->pchglist) > 0) { |
|
pchg = jpc_pchglist_remove(cp->pchglist, 0); |
|
jpc_pchg_destroy(pchg); |
|
} |
|
} |
|
for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) { |
|
if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) { |
|
return -1; |
|
} |
|
if (jpc_pchglist_insert(cp->pchglist, -1, pchg)) { |
|
return -1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits) |
|
{ |
|
jpc_fix_t absstepsize; |
|
int n; |
|
|
|
absstepsize = jpc_inttofix(1); |
|
n = JPC_FIX_FRACBITS - 11; |
|
absstepsize |= (n >= 0) ? (JPC_QCX_GETMANT(stepsize) << n) : |
|
(JPC_QCX_GETMANT(stepsize) >> (-n)); |
|
n = numbits - JPC_QCX_GETEXPN(stepsize); |
|
absstepsize = (n >= 0) ? (absstepsize << n) : (absstepsize >> (-n)); |
|
return absstepsize; |
|
} |
|
|
|
static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize) |
|
{ |
|
int i; |
|
int j; |
|
int t; |
|
|
|
assert(absstepsize >= 0); |
|
if (absstepsize == jpc_inttofix(1)) { |
|
return; |
|
} |
|
|
|
for (i = 0; i < jas_matrix_numrows(x); ++i) { |
|
for (j = 0; j < jas_matrix_numcols(x); ++j) { |
|
t = jas_matrix_get(x, i, j); |
|
if (t) { |
|
t = jpc_fix_mul(t, absstepsize); |
|
} else { |
|
t = 0; |
|
} |
|
jas_matrix_set(x, i, j, t); |
|
} |
|
} |
|
|
|
} |
|
|
|
static void jpc_undo_roi(jas_matrix_t *x, int roishift, int bgshift, int numbps) |
|
{ |
|
int i; |
|
int j; |
|
int thresh; |
|
jpc_fix_t val; |
|
jpc_fix_t mag; |
|
bool warn; |
|
uint_fast32_t mask; |
|
|
|
if (roishift == 0 && bgshift == 0) { |
|
return; |
|
} |
|
thresh = 1 << roishift; |
|
|
|
warn = false; |
|
for (i = 0; i < jas_matrix_numrows(x); ++i) { |
|
for (j = 0; j < jas_matrix_numcols(x); ++j) { |
|
val = jas_matrix_get(x, i, j); |
|
mag = JAS_ABS(val); |
|
if (mag >= thresh) { |
|
/* We are dealing with ROI data. */ |
|
mag >>= roishift; |
|
val = (val < 0) ? (-mag) : mag; |
|
jas_matrix_set(x, i, j, val); |
|
} else { |
|
/* We are dealing with non-ROI (i.e., background) data. */ |
|
mag <<= bgshift; |
|
mask = (1 << numbps) - 1; |
|
/* Perform a basic sanity check on the sample value. */ |
|
/* Some implementations write garbage in the unused |
|
most-significant bit planes introduced by ROI shifting. |
|
Here we ensure that any such bits are masked off. */ |
|
if (mag & (~mask)) { |
|
if (!warn) { |
|
jas_eprintf("warning: possibly corrupt code stream\n"); |
|
warn = true; |
|
} |
|
mag &= mask; |
|
} |
|
val = (val < 0) ? (-mag) : mag; |
|
jas_matrix_set(x, i, j, val); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in) |
|
{ |
|
jpc_dec_t *dec; |
|
|
|
if (!(dec = jas_malloc(sizeof(jpc_dec_t)))) { |
|
return 0; |
|
} |
|
|
|
dec->image = 0; |
|
dec->xstart = 0; |
|
dec->ystart = 0; |
|
dec->xend = 0; |
|
dec->yend = 0; |
|
dec->tilewidth = 0; |
|
dec->tileheight = 0; |
|
dec->tilexoff = 0; |
|
dec->tileyoff = 0; |
|
dec->numhtiles = 0; |
|
dec->numvtiles = 0; |
|
dec->numtiles = 0; |
|
dec->tiles = 0; |
|
dec->curtile = 0; |
|
dec->numcomps = 0; |
|
dec->in = in; |
|
dec->cp = 0; |
|
dec->maxlyrs = impopts->maxlyrs; |
|
dec->maxpkts = impopts->maxpkts; |
|
dec->numpkts = 0; |
|
dec->ppmseqno = 0; |
|
dec->state = 0; |
|
dec->cmpts = 0; |
|
dec->pkthdrstreams = 0; |
|
dec->ppmstab = 0; |
|
dec->curtileendoff = 0; |
|
|
|
return dec; |
|
} |
|
|
|
static void jpc_dec_destroy(jpc_dec_t *dec) |
|
{ |
|
if (dec->cstate) { |
|
jpc_cstate_destroy(dec->cstate); |
|
} |
|
if (dec->pkthdrstreams) { |
|
jpc_streamlist_destroy(dec->pkthdrstreams); |
|
} |
|
if (dec->image) { |
|
jas_image_destroy(dec->image); |
|
} |
|
|
|
if (dec->cp) { |
|
jpc_dec_cp_destroy(dec->cp); |
|
} |
|
|
|
if (dec->cmpts) { |
|
jas_free(dec->cmpts); |
|
} |
|
|
|
if (dec->tiles) { |
|
jas_free(dec->tiles); |
|
} |
|
|
|
jas_free(dec); |
|
} |
|
|
|
/******************************************************************************\ |
|
* |
|
\******************************************************************************/ |
|
|
|
void jpc_seglist_insert(jpc_dec_seglist_t *list, jpc_dec_seg_t *ins, jpc_dec_seg_t *node) |
|
{ |
|
jpc_dec_seg_t *prev; |
|
jpc_dec_seg_t *next; |
|
|
|
prev = ins; |
|
node->prev = prev; |
|
next = prev ? (prev->next) : 0; |
|
node->prev = prev; |
|
node->next = next; |
|
if (prev) { |
|
prev->next = node; |
|
} else { |
|
list->head = node; |
|
} |
|
if (next) { |
|
next->prev = node; |
|
} else { |
|
list->tail = node; |
|
} |
|
} |
|
|
|
void jpc_seglist_remove(jpc_dec_seglist_t *list, jpc_dec_seg_t *seg) |
|
{ |
|
jpc_dec_seg_t *prev; |
|
jpc_dec_seg_t *next; |
|
|
|
prev = seg->prev; |
|
next = seg->next; |
|
if (prev) { |
|
prev->next = next; |
|
} else { |
|
list->head = next; |
|
} |
|
if (next) { |
|
next->prev = prev; |
|
} else { |
|
list->tail = prev; |
|
} |
|
seg->prev = 0; |
|
seg->next = 0; |
|
} |
|
|
|
jpc_dec_seg_t *jpc_seg_alloc() |
|
{ |
|
jpc_dec_seg_t *seg; |
|
|
|
if (!(seg = jas_malloc(sizeof(jpc_dec_seg_t)))) { |
|
return 0; |
|
} |
|
seg->prev = 0; |
|
seg->next = 0; |
|
seg->passno = -1; |
|
seg->numpasses = 0; |
|
seg->maxpasses = 0; |
|
seg->type = JPC_SEG_INVALID; |
|
seg->stream = 0; |
|
seg->cnt = 0; |
|
seg->complete = 0; |
|
seg->lyrno = -1; |
|
return seg; |
|
} |
|
|
|
void jpc_seg_destroy(jpc_dec_seg_t *seg) |
|
{ |
|
if (seg->stream) { |
|
jas_stream_close(seg->stream); |
|
} |
|
jas_free(seg); |
|
} |
|
|
|
static int jpc_dec_dump(jpc_dec_t *dec, FILE *out) |
|
{ |
|
jpc_dec_tile_t *tile; |
|
int tileno; |
|
jpc_dec_tcomp_t *tcomp; |
|
int compno; |
|
jpc_dec_rlvl_t *rlvl; |
|
int rlvlno; |
|
jpc_dec_band_t *band; |
|
int bandno; |
|
jpc_dec_prc_t *prc; |
|
int prcno; |
|
jpc_dec_cblk_t *cblk; |
|
int cblkno; |
|
|
|
for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; |
|
++tileno, ++tile) { |
|
for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; |
|
++compno, ++tcomp) { |
|
for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < |
|
tcomp->numrlvls; ++rlvlno, ++rlvl) { |
|
fprintf(out, "RESOLUTION LEVEL %d\n", rlvlno); |
|
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", |
|
(int)rlvl->xstart, (int)rlvl->ystart, (int)rlvl->xend, (int)rlvl->yend, (int)(rlvl->xend - |
|
rlvl->xstart), (int)(rlvl->yend - rlvl->ystart)); |
|
for (bandno = 0, band = rlvl->bands; |
|
bandno < rlvl->numbands; ++bandno, ++band) { |
|
fprintf(out, "BAND %d\n", bandno); |
|
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", |
|
(int)jas_seq2d_xstart(band->data), (int)jas_seq2d_ystart(band->data), (int)jas_seq2d_xend(band->data), |
|
(int)jas_seq2d_yend(band->data), (int)(jas_seq2d_xend(band->data) - jas_seq2d_xstart(band->data)), |
|
(int)(jas_seq2d_yend(band->data) - jas_seq2d_ystart(band->data))); |
|
for (prcno = 0, prc = band->prcs; |
|
prcno < rlvl->numprcs; ++prcno, |
|
++prc) { |
|
fprintf(out, "CODE BLOCK GROUP %d\n", prcno); |
|
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", |
|
(int)prc->xstart, (int)prc->ystart, (int)prc->xend, (int)prc->yend, (int)(prc->xend - |
|
prc->xstart), (int)(prc->yend - prc->ystart)); |
|
for (cblkno = 0, cblk = |
|
prc->cblks; cblkno < |
|
prc->numcblks; ++cblkno, |
|
++cblk) { |
|
fprintf(out, "CODE BLOCK %d\n", cblkno); |
|
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", |
|
(int)jas_seq2d_xstart(cblk->data), (int)jas_seq2d_ystart(cblk->data), (int)jas_seq2d_xend(cblk->data), |
|
(int)jas_seq2d_yend(cblk->data), (int)(jas_seq2d_xend(cblk->data) - jas_seq2d_xstart(cblk->data)), |
|
(int)(jas_seq2d_yend(cblk->data) - jas_seq2d_ystart(cblk->data))); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
jpc_streamlist_t *jpc_streamlist_create() |
|
{ |
|
jpc_streamlist_t *streamlist; |
|
int i; |
|
|
|
if (!(streamlist = jas_malloc(sizeof(jpc_streamlist_t)))) { |
|
return 0; |
|
} |
|
streamlist->numstreams = 0; |
|
streamlist->maxstreams = 100; |
|
if (!(streamlist->streams = jas_malloc(streamlist->maxstreams * |
|
sizeof(jas_stream_t *)))) { |
|
jas_free(streamlist); |
|
return 0; |
|
} |
|
for (i = 0; i < streamlist->maxstreams; ++i) { |
|
streamlist->streams[i] = 0; |
|
} |
|
return streamlist; |
|
} |
|
|
|
int jpc_streamlist_insert(jpc_streamlist_t *streamlist, int streamno, |
|
jas_stream_t *stream) |
|
{ |
|
jas_stream_t **newstreams; |
|
int newmaxstreams; |
|
int i; |
|
/* Grow the array of streams if necessary. */ |
|
if (streamlist->numstreams >= streamlist->maxstreams) { |
|
newmaxstreams = streamlist->maxstreams + 1024; |
|
if (!(newstreams = jas_realloc(streamlist->streams, |
|
(newmaxstreams + 1024) * sizeof(jas_stream_t *)))) { |
|
return -1; |
|
} |
|
for (i = streamlist->numstreams; i < streamlist->maxstreams; ++i) { |
|
streamlist->streams[i] = 0; |
|
} |
|
streamlist->maxstreams = newmaxstreams; |
|
streamlist->streams = newstreams; |
|
} |
|
if (streamno != streamlist->numstreams) { |
|
/* Can only handle insertion at start of list. */ |
|
return -1; |
|
} |
|
streamlist->streams[streamno] = stream; |
|
++streamlist->numstreams; |
|
return 0; |
|
} |
|
|
|
jas_stream_t *jpc_streamlist_remove(jpc_streamlist_t *streamlist, int streamno) |
|
{ |
|
jas_stream_t *stream; |
|
int i; |
|
if (streamno >= streamlist->numstreams) { |
|
abort(); |
|
} |
|
stream = streamlist->streams[streamno]; |
|
for (i = streamno + 1; i < streamlist->numstreams; ++i) { |
|
streamlist->streams[i - 1] = streamlist->streams[i]; |
|
} |
|
--streamlist->numstreams; |
|
return stream; |
|
} |
|
|
|
void jpc_streamlist_destroy(jpc_streamlist_t *streamlist) |
|
{ |
|
int streamno; |
|
if (streamlist->streams) { |
|
for (streamno = 0; streamno < streamlist->numstreams; |
|
++streamno) { |
|
jas_stream_close(streamlist->streams[streamno]); |
|
} |
|
jas_free(streamlist->streams); |
|
} |
|
jas_free(streamlist); |
|
} |
|
|
|
jas_stream_t *jpc_streamlist_get(jpc_streamlist_t *streamlist, int streamno) |
|
{ |
|
assert(streamno < streamlist->numstreams); |
|
return streamlist->streams[streamno]; |
|
} |
|
|
|
int jpc_streamlist_numstreams(jpc_streamlist_t *streamlist) |
|
{ |
|
return streamlist->numstreams; |
|
} |
|
|
|
jpc_ppxstab_t *jpc_ppxstab_create() |
|
{ |
|
jpc_ppxstab_t *tab; |
|
|
|
if (!(tab = jas_malloc(sizeof(jpc_ppxstab_t)))) { |
|
return 0; |
|
} |
|
tab->numents = 0; |
|
tab->maxents = 0; |
|
tab->ents = 0; |
|
return tab; |
|
} |
|
|
|
void jpc_ppxstab_destroy(jpc_ppxstab_t *tab) |
|
{ |
|
int i; |
|
for (i = 0; i < tab->numents; ++i) { |
|
jpc_ppxstabent_destroy(tab->ents[i]); |
|
} |
|
if (tab->ents) { |
|
jas_free(tab->ents); |
|
} |
|
jas_free(tab); |
|
} |
|
|
|
int jpc_ppxstab_grow(jpc_ppxstab_t *tab, int maxents) |
|
{ |
|
jpc_ppxstabent_t **newents; |
|
if (tab->maxents < maxents) { |
|
newents = (tab->ents) ? jas_realloc(tab->ents, maxents * |
|
sizeof(jpc_ppxstabent_t *)) : jas_malloc(maxents * sizeof(jpc_ppxstabent_t *)); |
|
if (!newents) { |
|
return -1; |
|
} |
|
tab->ents = newents; |
|
tab->maxents = maxents; |
|
} |
|
return 0; |
|
} |
|
|
|
int jpc_ppxstab_insert(jpc_ppxstab_t *tab, jpc_ppxstabent_t *ent) |
|
{ |
|
int inspt; |
|
int i; |
|
|
|
for (i = 0; i < tab->numents; ++i) { |
|
if (tab->ents[i]->ind > ent->ind) { |
|
break; |
|
} |
|
} |
|
inspt = i; |
|
|
|
if (tab->numents >= tab->maxents) { |
|
if (jpc_ppxstab_grow(tab, tab->maxents + 128)) { |
|
return -1; |
|
} |
|
} |
|
|
|
for (i = tab->numents; i > inspt; --i) { |
|
tab->ents[i] = tab->ents[i - 1]; |
|
} |
|
tab->ents[i] = ent; |
|
++tab->numents; |
|
|
|
return 0; |
|
} |
|
|
|
jpc_streamlist_t *jpc_ppmstabtostreams(jpc_ppxstab_t *tab) |
|
{ |
|
jpc_streamlist_t *streams; |
|
uchar *dataptr; |
|
uint_fast32_t datacnt; |
|
uint_fast32_t tpcnt; |
|
jpc_ppxstabent_t *ent; |
|
int entno; |
|
jas_stream_t *stream; |
|
int n; |
|
|
|
if (!(streams = jpc_streamlist_create())) { |
|
goto error; |
|
} |
|
|
|
if (!tab->numents) { |
|
return streams; |
|
} |
|
|
|
entno = 0; |
|
ent = tab->ents[entno]; |
|
dataptr = ent->data; |
|
datacnt = ent->len; |
|
for (;;) { |
|
|
|
/* Get the length of the packet header data for the current |
|
tile-part. */ |
|
if (datacnt < 4) { |
|
goto error; |
|
} |
|
if (!(stream = jas_stream_memopen(0, 0))) { |
|
goto error; |
|
} |
|
if (jpc_streamlist_insert(streams, jpc_streamlist_numstreams(streams), |
|
stream)) { |
|
goto error; |
|
} |
|
tpcnt = (dataptr[0] << 24) | (dataptr[1] << 16) | (dataptr[2] << 8) |
|
| dataptr[3]; |
|
datacnt -= 4; |
|
dataptr += 4; |
|
|
|
/* Get the packet header data for the current tile-part. */ |
|
while (tpcnt) { |
|
if (!datacnt) { |
|
if (++entno >= tab->numents) { |
|
goto error; |
|
} |
|
ent = tab->ents[entno]; |
|
dataptr = ent->data; |
|
datacnt = ent->len; |
|
} |
|
n = JAS_MIN(tpcnt, datacnt); |
|
if (jas_stream_write(stream, dataptr, n) != n) { |
|
goto error; |
|
} |
|
tpcnt -= n; |
|
dataptr += n; |
|
datacnt -= n; |
|
} |
|
jas_stream_rewind(stream); |
|
if (!datacnt) { |
|
if (++entno >= tab->numents) { |
|
break; |
|
} |
|
ent = tab->ents[entno]; |
|
dataptr = ent->data; |
|
datacnt = ent->len; |
|
} |
|
} |
|
|
|
return streams; |
|
|
|
error: |
|
jpc_streamlist_destroy(streams); |
|
return 0; |
|
} |
|
|
|
int jpc_pptstabwrite(jas_stream_t *out, jpc_ppxstab_t *tab) |
|
{ |
|
int i; |
|
jpc_ppxstabent_t *ent; |
|
for (i = 0; i < tab->numents; ++i) { |
|
ent = tab->ents[i]; |
|
if (jas_stream_write(out, ent->data, ent->len) != JAS_CAST(int, ent->len)) { |
|
return -1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
jpc_ppxstabent_t *jpc_ppxstabent_create() |
|
{ |
|
jpc_ppxstabent_t *ent; |
|
if (!(ent = jas_malloc(sizeof(jpc_ppxstabent_t)))) { |
|
return 0; |
|
} |
|
ent->data = 0; |
|
ent->len = 0; |
|
ent->ind = 0; |
|
return ent; |
|
} |
|
|
|
void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent) |
|
{ |
|
if (ent->data) { |
|
jas_free(ent->data); |
|
} |
|
jas_free(ent); |
|
}
|
|
|