/* * #%L * Fork of JAI Image I/O Tools. * %% * Copyright (C) 2008 - 2014 Open Microscopy Environment: * - Board of Regents of the University of Wisconsin-Madison * - Glencoe Software, Inc. * - University of Dundee * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of any organization. * #L% */ /* * $RCSfile: PktDecoder.java,v $ * $Revision: 1.1 $ * $Date: 2005/02/11 05:02:01 $ * $State: Exp $ * * Class: PktDecoder * * Description: Reads packets heads and keeps location of * code-blocks' codewords * * * * COPYRIGHT: * * This software module was originally developed by Raphaël Grosbois and * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research * Centre France S.A) in the course of development of the JPEG2000 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This * software module is an implementation of a part of the JPEG 2000 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio * Systems AB and Canon Research Centre France S.A (collectively JJ2000 * Partners) agree not to assert against ISO/IEC and users of the JPEG * 2000 Standard (Users) any of their rights under the copyright, not * including other intellectual property rights, for this software module * with respect to the usage by ISO/IEC and Users of this software module * or modifications thereof for use in hardware or software products * claiming conformance to the JPEG 2000 Standard. Those intending to use * this software module in hardware or software products are advised that * their use may infringe existing patents. The original developers of * this software module, JJ2000 Partners and ISO/IEC assume no liability * for use of this software module or modifications thereof. No license * or right to this software module is granted for non JPEG 2000 Standard * conforming products. JJ2000 Partners have full right to use this * software module for his/her own purpose, assign or donate this * software module to any third party and to inhibit third parties from * using this software module for non JPEG 2000 Standard conforming * products. This copyright notice must be included in all copies or * derivative works of this software module. * * Copyright (c) 1999/2000 JJ2000 Partners. * */ package jj2000.j2k.codestream.reader; import java.awt.Point; import jj2000.j2k.wavelet.synthesis.*; import jj2000.j2k.codestream.*; import jj2000.j2k.entropy.*; import jj2000.j2k.wavelet.*; import jj2000.j2k.decoder.*; import jj2000.j2k.image.*; import jj2000.j2k.util.*; import jj2000.j2k.io.*; import java.util.*; import java.io.*; /** * This class is used to read packet's head and body. All the members must be * re-initialized at the beginning of each tile thanks to the restart() * method. * */ public class PktDecoder implements StdEntropyCoderOptions{ /** Reference to the codestream reader agent */ private BitstreamReaderAgent src; /** Flag indicating whether packed packet header was used for this tile*/ private boolean pph=false; /** The packed packet header if it was used */ private ByteArrayInputStream pphbais; /** Reference to decoder specifications */ private DecoderSpecs decSpec; /** Reference to the HeaderDecoder */ private HeaderDecoder hd; /** Initial value of the state variable associated with code-block * length. */ private final int INIT_LBLOCK = 3; /** The wrapper to read bits for the packet heads */ private PktHeaderBitReader bin; /** Reference to the stream where to read from */ private RandomAccessIO ehs; /** * Maximum number of precincts : * * <ul> * <li> 1st dim: component index.</li> * <li> 2nd dim: resolution level index.</li> * </ul> * */ private Point[][] numPrec; /** Index of the current tile */ private int tIdx; /** * Array containing the coordinates, width, height, indexes, ... of the * precincts in the current tile: * * <ul> * <li> 1st dim: component index.</li> * <li> 2nd dim: resolution level index.</li> * <li> 3rd dim: precinct index.</li> * </ul> * */ private PrecInfo[][][] ppinfo; /** * Lblock value used to read code size information in each packet head: * * <ul> * <li> 1st dim: component index.</li> * <li> 2nd dim: resolution level index.</li> * <li> 3rd dim: subband index.</li> * <li> 4th/5th dim: code-block index (vert. and horiz.).</li> * </ul> * */ private int[][][][][] lblock; /** * Tag tree used to read inclusion informations in packet's head: * * <ul> * <li> 1st dim: component index.</li> * <li> 2nd dim: resolution level index.</li> * <li> 3rd dim: precinct index.</li> * <li> 4th dim: subband index.</li> * */ private TagTreeDecoder[][][][] ttIncl; /** * Tag tree used to read bit-depth information in packet's head: * * <ul> * <li> 1st dim: component index.</li> * <li> 2nd dim: resolution level index.</li> * <li> 3rd dim: precinct index.</li> * <li> 4th dim: subband index.</li> * </ul> * */ private TagTreeDecoder[][][][] ttMaxBP; /** Number of layers in t he current tile */ private int nl = 0; /** The number of components */ private int nc; /** Whether or not SOP marker segment are used */ private boolean sopUsed = false; /** Whether or not EPH marker are used */ private boolean ephUsed = false; /** Index of the current packet in the tile. Used with SOP marker segment*/ private int pktIdx; /** List of code-blocks found in last read packet head (one list * per subband) */ private Vector[] cblks; /** Number of codeblocks encountered. used for ncb quit condition*/ private int ncb; /** Maximum number of codeblocks to read before ncb quit condition is * reached */ private int maxCB; /** Flag indicating whether ncb quit condition has been reached */ private boolean ncbQuit; /** The tile in which the ncb quit condition was reached */ private int tQuit; /** The component in which the ncb quit condition was reached */ private int cQuit; /** The subband in which the ncb quit condition was reached */ private int sQuit; /** The resolution in which the ncb quit condition was reached */ private int rQuit; /** The x position of the last code block before ncb quit reached */ private int xQuit; /** The y position of the last code block before ncb quit reached */ private int yQuit; /** True if truncation mode is used. False if it is parsing mode */ private boolean isTruncMode; /** * Creates an empty PktDecoder object associated with given decoder * specifications and HeaderDecoder. This object must be initialized * thanks to the restart method before being used. * * @param decSpec The decoder specifications. * * @param hd The HeaderDecoder instance. * * @param ehs The stream where to read data from. * * @param src The bit stream reader agent. * * @param isTruncMode Whether or not truncation mode is required. * * @param maxCB The maximum number of code-blocks to read before ncbquit * * */ public PktDecoder(DecoderSpecs decSpec,HeaderDecoder hd, RandomAccessIO ehs,BitstreamReaderAgent src, boolean isTruncMode, int maxCB) { this.decSpec = decSpec; this.hd = hd; this.ehs = ehs; this.isTruncMode = isTruncMode; bin = new PktHeaderBitReader(ehs); this.src = src; ncb = 0; ncbQuit = false; this.maxCB = maxCB; } /** * Re-initialize the PktDecoder instance at the beginning of a new tile. * * @param nc The number of components in this tile * * @param mdl The maximum number of decomposition level in each component * of this tile * * @param nl The number of layers in this tile * * @param cbI The code-blocks array * * @param pph Flag indicating whether packed packet headers was used * * @param pphbais Stream containing the packed packet headers * */ public CBlkInfo[][][][][] restart(int nc,int[] mdl,int nl, CBlkInfo[][][][][] cbI, boolean pph, ByteArrayInputStream pphbais) { this.nc = nc; this.nl = nl; this.tIdx = src.getTileIdx(); this.pph = pph; this.pphbais = pphbais; sopUsed = ((Boolean)decSpec.sops.getTileDef(tIdx)).booleanValue(); pktIdx = 0; ephUsed = ((Boolean)decSpec.ephs.getTileDef(tIdx)).booleanValue(); cbI = new CBlkInfo[nc][][][][]; lblock = new int[nc][][][][]; ttIncl = new TagTreeDecoder[nc][][][]; ttMaxBP = new TagTreeDecoder[nc][][][]; numPrec = new Point[nc][]; ppinfo = new PrecInfo[nc][][]; // Used to compute the maximum number of precincts for each resolution // level int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of // the image component int trx0, try0, trx1, try1; // Current tile position in the reduced // resolution image domain int xrsiz, yrsiz; // Component sub-sampling factors SubbandSyn root,sb; int mins,maxs; Point nBlk = null; int cb0x = src.getCbULX(); int cb0y = src.getCbULY(); for(int c=0; c<nc; c++) { cbI[c] = new CBlkInfo[mdl[c]+1][][][]; lblock[c] = new int[mdl[c]+1][][][]; ttIncl[c] = new TagTreeDecoder[mdl[c]+1][][]; ttMaxBP[c] = new TagTreeDecoder[mdl[c]+1][][]; numPrec[c] = new Point[mdl[c]+1]; ppinfo[c] = new PrecInfo[mdl[c]+1][]; // Get the tile-component coordinates on the reference grid tcx0 = src.getResULX(c,mdl[c]); tcy0 = src.getResULY(c,mdl[c]); tcx1 = tcx0 + src.getTileCompWidth(tIdx,c,mdl[c]); tcy1 = tcy0 + src.getTileCompHeight(tIdx,c,mdl[c]); for(int r=0; r<=mdl[c]; r++) { // Tile's coordinates in the reduced resolution image domain trx0 = (int)Math.ceil(tcx0/(double)(1<<(mdl[c]-r))); try0 = (int)Math.ceil(tcy0/(double)(1<<(mdl[c]-r))); trx1 = (int)Math.ceil(tcx1/(double)(1<<(mdl[c]-r))); try1 = (int)Math.ceil(tcy1/(double)(1<<(mdl[c]-r))); // Calculate the maximum number of precincts for each // resolution level taking into account tile specific options. double twoppx = (double)getPPX(tIdx,c,r); double twoppy = (double)getPPY(tIdx,c,r); numPrec[c][r] = new Point(); if (trx1>trx0) { numPrec[c][r].x = (int)Math.ceil((trx1-cb0x)/twoppx) - (int)Math.floor((trx0-cb0x)/twoppx); } else { numPrec[c][r].x = 0; } if (try1>try0) { numPrec[c][r].y = (int)Math.ceil((try1-cb0y)/twoppy) - (int)Math.floor((try0-cb0y)/twoppy); } else { numPrec[c][r].y = 0; } // First and last subbands indexes mins = (r==0) ? 0 : 1; maxs = (r==0) ? 1 : 4; int maxPrec = numPrec[c][r].x * numPrec[c][r].y; ttIncl[c][r] = new TagTreeDecoder[maxPrec][maxs+1]; ttMaxBP[c][r] = new TagTreeDecoder[maxPrec][maxs+1]; cbI[c][r] = new CBlkInfo[maxs+1][][]; lblock[c][r] = new int[maxs+1][][]; ppinfo[c][r] = new PrecInfo[maxPrec]; fillPrecInfo(c,r,mdl[c]); root = (SubbandSyn)src.getSynSubbandTree(tIdx,c); for(int s=mins; s<maxs; s++){ sb = (SubbandSyn)root.getSubbandByIdx(r,s); nBlk = sb.numCb; cbI[c][r][s] = new CBlkInfo[nBlk.y][nBlk.x]; lblock[c][r][s] = new int[nBlk.y][nBlk.x]; for(int i=nBlk.y-1;i>=0;i--) { ArrayUtil.intArraySet(lblock[c][r][s][i],INIT_LBLOCK); } } // loop on subbands } // End loop on resolution levels } // End loop on components return cbI; } /** * Retrives precincts and code-blocks coordinates in the given resolution, * level and component. Finishes TagTreeEncoder initialization as well. * * @param c Component index. * * @param r Resolution level index. * * @param mdl Number of decomposition level in component <tt>c</tt>. * */ private void fillPrecInfo(int c,int r,int mdl) { if(ppinfo[c][r].length==0) return; // No precinct in this // resolution level Point tileI = src.getTile(null); Point nTiles = src.getNumTiles(null); int xsiz,ysiz,x0siz,y0siz; int xt0siz,yt0siz; int xtsiz,ytsiz; xt0siz = src.getTilePartULX(); yt0siz = src.getTilePartULY(); xtsiz = src.getNomTileWidth(); ytsiz = src.getNomTileHeight(); x0siz = hd.getImgULX(); y0siz = hd.getImgULY(); xsiz = hd.getImgWidth(); ysiz = hd.getImgHeight(); int tx0 = (tileI.x==0) ? x0siz : xt0siz+tileI.x*xtsiz; int ty0 = (tileI.y==0) ? y0siz : yt0siz+tileI.y*ytsiz; int tx1 = (tileI.x!=nTiles.x-1) ? xt0siz+(tileI.x+1)*xtsiz : xsiz; int ty1 = (tileI.y!=nTiles.y-1) ? yt0siz+(tileI.y+1)*ytsiz : ysiz; int xrsiz = hd.getCompSubsX(c); int yrsiz = hd.getCompSubsY(c); int tcx0 = src.getResULX(c,mdl); int tcy0 = src.getResULY(c,mdl); int tcx1 = tcx0 + src.getTileCompWidth(tIdx,c,mdl); int tcy1 = tcy0 + src.getTileCompHeight(tIdx,c,mdl); int ndl = mdl-r; int trx0 = (int)Math.ceil(tcx0/(double)(1<<ndl)); int try0 = (int)Math.ceil(tcy0/(double)(1<<ndl)); int trx1 = (int)Math.ceil(tcx1/(double)(1<<ndl)); int try1 = (int)Math.ceil(tcy1/(double)(1<<ndl)); int cb0x = src.getCbULX(); int cb0y = src.getCbULY(); double twoppx = (double)getPPX(tIdx,c,r); double twoppy = (double)getPPY(tIdx,c,r); int twoppx2 = (int)(twoppx/2); int twoppy2 = (int)(twoppy/2); // Precincts are located at (cb0x+i*twoppx,cb0y+j*twoppy) // Valid precincts are those which intersect with the current // resolution level int maxPrec = ppinfo[c][r].length; int nPrec = 0; int istart = (int)Math.floor((try0-cb0y)/twoppy); int iend = (int)Math.floor((try1-1-cb0y)/twoppy); int jstart = (int)Math.floor((trx0-cb0x)/twoppx); int jend = (int)Math.floor((trx1-1-cb0x)/twoppx); int acb0x,acb0y; SubbandSyn root = src.getSynSubbandTree(tIdx,c); SubbandSyn sb = null; int p0x,p0y,p1x,p1y; // Precinct projection in subband int s0x,s0y,s1x,s1y; // Active subband portion int cw,ch; int kstart,kend,lstart,lend,k0,l0; int prg_ulx,prg_uly; int prg_w = (int)twoppx<<ndl; int prg_h = (int)twoppy<<ndl; int tmp1,tmp2; CBlkCoordInfo cb; for(int i=istart; i<=iend; i++) { // Vertical precincts for(int j=jstart; j<=jend; j++,nPrec++) { // Horizontal precincts if(j==jstart && (trx0-cb0x)%(xrsiz*((int)twoppx))!=0) { prg_ulx = tx0; } else { prg_ulx = cb0x+j*xrsiz*((int)twoppx<<ndl); } if(i==istart && (try0-cb0y)%(yrsiz*((int)twoppy))!=0) { prg_uly = ty0; } else { prg_uly = cb0y+i*yrsiz*((int)twoppy<<ndl); } ppinfo[c][r][nPrec] = new PrecInfo(r,(int)(cb0x+j*twoppx),(int)(cb0y+i*twoppy), (int)twoppx,(int)twoppy, prg_ulx,prg_uly,prg_w,prg_h); if(r==0) { // LL subband acb0x = cb0x; acb0y = cb0y; p0x = acb0x+j*(int)twoppx; p1x = p0x + (int)twoppx; p0y = acb0y+i*(int)twoppy; p1y = p0y + (int)twoppy; sb = (SubbandSyn)root.getSubbandByIdx(0,0); s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x; s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x; s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y; s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y; // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch) cw = sb.nomCBlkW; ch = sb.nomCBlkH; k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch); kstart = (int)Math.floor((s0y-acb0y)/(double)ch); kend = (int)Math.floor((s1y-1-acb0y)/(double)ch); l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw); lstart = (int)Math.floor((s0x-acb0x)/(double)cw); lend = (int)Math.floor((s1x-1-acb0x)/(double)cw); if(s1x-s0x<=0 || s1y-s0y<=0) { ppinfo[c][r][nPrec].nblk[0] = 0; ttIncl[c][r][nPrec][0] = new TagTreeDecoder(0,0); ttMaxBP[c][r][nPrec][0] = new TagTreeDecoder(0,0); } else { ttIncl[c][r][nPrec][0] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ttMaxBP[c][r][nPrec][0] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ppinfo[c][r][nPrec].cblk[0] = new CBlkCoordInfo[kend-kstart+1][lend-lstart+1]; ppinfo[c][r][nPrec]. nblk[0] = (kend-kstart+1)*(lend-lstart+1); for(int k=kstart; k<=kend; k++) { // Vertical cblks for(int l=lstart; l<=lend; l++) { // Horiz. cblks cb = new CBlkCoordInfo(k-k0,l-l0); if(l==l0) { cb.ulx = sb.ulx; } else { cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x); } if(k==k0) { cb.uly = sb.uly; } else { cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y); } tmp1 = acb0x+l*cw; tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx; tmp2 = acb0x+(l+1)*cw; tmp2 = (tmp2>sb.ulcx+sb.w) ? sb.ulcx+sb.w : tmp2; cb.w = tmp2-tmp1; tmp1 = acb0y+k*ch; tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy; tmp2 = acb0y+(k+1)*ch; tmp2 = (tmp2>sb.ulcy+sb.h) ? sb.ulcy+sb.h : tmp2; cb.h = tmp2-tmp1; ppinfo[c][r][nPrec]. cblk[0][k-kstart][l-lstart] = cb; } // Horizontal code-blocks } // Vertical code-blocks } } else { // HL, LH and HH subbands // HL subband acb0x = 0; acb0y = cb0y; p0x = acb0x+j*twoppx2; p1x = p0x + twoppx2; p0y = acb0y+i*twoppy2; p1y = p0y + twoppy2; sb = (SubbandSyn)root.getSubbandByIdx(r,1); s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x; s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x; s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y; s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y; // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch) cw = sb.nomCBlkW; ch = sb.nomCBlkH; k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch); kstart = (int)Math.floor((s0y-acb0y)/(double)ch); kend = (int)Math.floor((s1y-1-acb0y)/(double)ch); l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw); lstart = (int)Math.floor((s0x-acb0x)/(double)cw); lend = (int)Math.floor((s1x-1-acb0x)/(double)cw); if(s1x-s0x<=0 || s1y-s0y<=0) { ppinfo[c][r][nPrec].nblk[1] = 0; ttIncl[c][r][nPrec][1] = new TagTreeDecoder(0,0); ttMaxBP[c][r][nPrec][1] = new TagTreeDecoder(0,0); } else { ttIncl[c][r][nPrec][1] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ttMaxBP[c][r][nPrec][1] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ppinfo[c][r][nPrec].cblk[1] = new CBlkCoordInfo[kend-kstart+1][lend-lstart+1]; ppinfo[c][r][nPrec]. nblk[1] = (kend-kstart+1)*(lend-lstart+1); for(int k=kstart; k<=kend; k++) { // Vertical cblks for(int l=lstart; l<=lend; l++) { // Horiz. cblks cb = new CBlkCoordInfo(k-k0,l-l0); if(l==l0) { cb.ulx = sb.ulx; } else { cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x); } if(k==k0) { cb.uly = sb.uly; } else { cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y); } tmp1 = acb0x+l*cw; tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx; tmp2 = acb0x+(l+1)*cw; tmp2 = (tmp2>sb.ulcx+sb.w) ? sb.ulcx+sb.w : tmp2; cb.w = tmp2-tmp1; tmp1 = acb0y+k*ch; tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy; tmp2 = acb0y+(k+1)*ch; tmp2 = (tmp2>sb.ulcy+sb.h) ? sb.ulcy+sb.h : tmp2; cb.h = tmp2-tmp1; ppinfo[c][r][nPrec]. cblk[1][k-kstart][l-lstart] = cb; } // Horizontal code-blocks } // Vertical code-blocks } // LH subband acb0x = cb0x; acb0y = 0; p0x = acb0x+j*twoppx2; p1x = p0x + twoppx2; p0y = acb0y+i*twoppy2; p1y = p0y + twoppy2; sb = (SubbandSyn)root.getSubbandByIdx(r,2); s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x; s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x; s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y; s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y; // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch) cw = sb.nomCBlkW; ch = sb.nomCBlkH; k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch); kstart = (int)Math.floor((s0y-acb0y)/(double)ch); kend = (int)Math.floor((s1y-1-acb0y)/(double)ch); l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw); lstart = (int)Math.floor((s0x-acb0x)/(double)cw); lend = (int)Math.floor((s1x-1-acb0x)/(double)cw); if(s1x-s0x<=0 || s1y-s0y<=0) { ppinfo[c][r][nPrec].nblk[2] = 0; ttIncl[c][r][nPrec][2] = new TagTreeDecoder(0,0); ttMaxBP[c][r][nPrec][2] = new TagTreeDecoder(0,0); } else { ttIncl[c][r][nPrec][2] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ttMaxBP[c][r][nPrec][2] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ppinfo[c][r][nPrec].cblk[2] = new CBlkCoordInfo[kend-kstart+1][lend-lstart+1]; ppinfo[c][r][nPrec]. nblk[2] = (kend-kstart+1)*(lend-lstart+1); for(int k=kstart; k<=kend; k++) { // Vertical cblks for(int l=lstart; l<=lend; l++) { // Horiz cblks cb = new CBlkCoordInfo(k-k0,l-l0); if(l==l0) { cb.ulx = sb.ulx; } else { cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x); } if(k==k0) { cb.uly = sb.uly; } else { cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y); } tmp1 = acb0x+l*cw; tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx; tmp2 = acb0x+(l+1)*cw; tmp2 = (tmp2>sb.ulcx+sb.w) ? sb.ulcx+sb.w : tmp2; cb.w = tmp2-tmp1; tmp1 = acb0y+k*ch; tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy; tmp2 = acb0y+(k+1)*ch; tmp2 = (tmp2>sb.ulcy+sb.h) ? sb.ulcy+sb.h : tmp2; cb.h = tmp2-tmp1; ppinfo[c][r][nPrec]. cblk[2][k-kstart][l-lstart] = cb; } // Horizontal code-blocks } // Vertical code-blocks } // HH subband acb0x = 0; acb0y = 0; p0x = acb0x+j*twoppx2; p1x = p0x + twoppx2; p0y = acb0y+i*twoppy2; p1y = p0y + twoppy2; sb = (SubbandSyn)root.getSubbandByIdx(r,3); s0x = (p0x<sb.ulcx) ? sb.ulcx : p0x; s1x = (p1x>sb.ulcx+sb.w) ? sb.ulcx+sb.w : p1x; s0y = (p0y<sb.ulcy) ? sb.ulcy : p0y; s1y = (p1y>sb.ulcy+sb.h) ? sb.ulcy+sb.h : p1y; // Code-blocks are located at (acb0x+k*cw,acb0y+l*ch) cw = sb.nomCBlkW; ch = sb.nomCBlkH; k0 = (int)Math.floor((sb.ulcy-acb0y)/(double)ch); kstart = (int)Math.floor((s0y-acb0y)/(double)ch); kend = (int)Math.floor((s1y-1-acb0y)/(double)ch); l0 = (int)Math.floor((sb.ulcx-acb0x)/(double)cw); lstart = (int)Math.floor((s0x-acb0x)/(double)cw); lend = (int)Math.floor((s1x-1-acb0x)/(double)cw); if(s1x-s0x<=0 || s1y-s0y<=0) { ppinfo[c][r][nPrec].nblk[3] = 0; ttIncl[c][r][nPrec][3] = new TagTreeDecoder(0,0); ttMaxBP[c][r][nPrec][3] = new TagTreeDecoder(0,0); } else { ttIncl[c][r][nPrec][3] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ttMaxBP[c][r][nPrec][3] = new TagTreeDecoder(kend-kstart+1,lend-lstart+1); ppinfo[c][r][nPrec].cblk[3] = new CBlkCoordInfo[kend-kstart+1][lend-lstart+1]; ppinfo[c][r][nPrec]. nblk[3] = (kend-kstart+1)*(lend-lstart+1); for(int k=kstart; k<=kend; k++) { // Vertical cblks for(int l=lstart; l<=lend; l++) { // Horiz cblks cb = new CBlkCoordInfo(k-k0,l-l0); if(l==l0) { cb.ulx = sb.ulx; } else { cb.ulx = sb.ulx+l*cw-(sb.ulcx-acb0x); } if(k==k0) { cb.uly = sb.uly; } else { cb.uly = sb.uly+k*ch-(sb.ulcy-acb0y); } tmp1 = acb0x+l*cw; tmp1 = (tmp1>sb.ulcx) ? tmp1 : sb.ulcx; tmp2 = acb0x+(l+1)*cw; tmp2 = (tmp2>sb.ulcx+sb.w) ? sb.ulcx+sb.w : tmp2; cb.w = tmp2-tmp1; tmp1 = acb0y+k*ch; tmp1 = (tmp1>sb.ulcy) ? tmp1 : sb.ulcy; tmp2 = acb0y+(k+1)*ch; tmp2 = (tmp2>sb.ulcy+sb.h) ? sb.ulcy+sb.h : tmp2; cb.h = tmp2-tmp1; ppinfo[c][r][nPrec]. cblk[3][k-kstart][l-lstart] = cb; } // Horizontal code-blocks } // Vertical code-blocks } } } // Horizontal precincts } // Vertical precincts } /** * Gets the number of precincts in a given component and resolution level. * * @param c Component index * * @param r Resolution index * */ public int getNumPrecinct(int c,int r) { return numPrec[c][r].x*numPrec[c][r].y; } /** * Read specified packet head and found length of each code-block's piece * of codewords as well as number of skipped most significant bit-planes. * * @param l layer index * * @param r Resolution level index * * @param c Component index * * @param p Precinct index * * @param cbI CBlkInfo array of relevant component and resolution * level. * * @param nb The number of bytes to read in each tile before reaching * output rate (used by truncation mode) * * @return True if specified output rate or EOF is reached. * */ public boolean readPktHead(int l,int r,int c,int p,CBlkInfo[][][] cbI, int[] nb) throws IOException { CBlkInfo ccb; int nSeg; // number of segment to read int cbLen; // Length of cblk's code-words int ltp; // last truncation point index int passtype; // coding pass type TagTreeDecoder tdIncl,tdBD; int tmp,tmp2,totnewtp,lblockCur,tpidx; int sumtotnewtp = 0; Point cbc; int startPktHead = ehs.getPos(); if(startPktHead>=ehs.length()) { // EOF reached at the beginning of this packet head return true; } int tIdx = src.getTileIdx(); PktHeaderBitReader bin; int mend,nend; int b; SubbandSyn sb; SubbandSyn root = src.getSynSubbandTree(tIdx,c); // If packed packet headers was used, use separate stream for reading // of packet headers if(pph) { bin = new PktHeaderBitReader(pphbais); } else { bin = this.bin; } int mins = (r==0) ? 0 : 1; int maxs = (r==0) ? 1 : 4; boolean precFound = false; for(int s=mins; s<maxs; s++) { if(p<ppinfo[c][r].length) { precFound = true; } } if(!precFound) { return false; } PrecInfo prec = ppinfo[c][r][p]; // Synchronize for bit reading bin.sync(); // If packet is empty there is no info in it (i.e. no code-blocks) if(bin.readBit()==0) { // No code-block is included cblks = new Vector[maxs+1]; for(int s=mins; s<maxs; s++){ cblks[s] = new Vector(); } pktIdx++; // If truncation mode, checks if output rate is reached // unless ncb quit condition is used in which case headers // are not counted if(isTruncMode && maxCB == -1) { tmp = ehs.getPos()-startPktHead; if(tmp>nb[tIdx]) { nb[tIdx] = 0; return true; } else { nb[tIdx] -= tmp; } } // Read EPH marker if needed if(ephUsed) { readEPHMarker(bin); } return false; } // Packet is not empty => decode info // Loop on each subband in this resolution level if(cblks==null || cblks.length<maxs+1) { cblks = new Vector[maxs+1]; } for(int s=mins; s<maxs; s++) { if(cblks[s]==null) { cblks[s] = new Vector(); } else { cblks[s].removeAllElements(); } sb = (SubbandSyn)root.getSubbandByIdx(r,s); // No code-block in this precinct if(prec.nblk[s]==0) { // Go to next subband continue; } tdIncl = ttIncl[c][r][p][s]; tdBD = ttMaxBP[c][r][p][s]; mend = (prec.cblk[s]==null) ? 0 : prec.cblk[s].length; for(int m=0; m<mend; m++) { // Vertical code-blocks nend = (prec.cblk[s][m]==null) ? 0 : prec.cblk[s][m].length; for (int n=0; n<nend; n++) { // Horizontal code-blocks cbc = prec.cblk[s][m][n].idx; b = cbc.x+cbc.y*sb.numCb.x; ccb = cbI[s][cbc.y][cbc.x]; try { // If code-block not included in previous layer(s) if(ccb==null || ccb.ctp==0) { if(ccb==null) { ccb = cbI[s][cbc.y][cbc.x] = new CBlkInfo(prec.cblk[s][m][n].ulx, prec.cblk[s][m][n].uly, prec.cblk[s][m][n].w, prec.cblk[s][m][n].h,nl); } ccb.pktIdx[l] = pktIdx; // Read inclusion using tag-tree tmp = tdIncl.update(m,n,l+1,bin); if(tmp>l) { // Not included continue; } // Read bitdepth using tag-tree tmp = 1;// initialization for(tmp2=1; tmp>=tmp2; tmp2++) { tmp = tdBD.update(m,n,tmp2,bin); } ccb.msbSkipped = tmp2-2; // New code-block => at least one truncation point totnewtp = 1; ccb.addNTP(l,0); // Check whether ncb quit condition is reached ncb++; if(maxCB != -1 && !ncbQuit && ncb == maxCB){ // ncb quit contidion reached ncbQuit = true; tQuit = tIdx; cQuit = c; sQuit = s; rQuit = r; xQuit = cbc.x; yQuit = cbc.y; } } else { // If code-block already included in one of // the previous layers. ccb.pktIdx[l] = pktIdx; // If not inclused if(bin.readBit()!=1) { continue; } // At least 1 more truncation point than // prev. packet totnewtp = 1; } // Read new truncation points if(bin.readBit()==1) {// if bit is 1 totnewtp++; // if next bit is 0 do nothing if(bin.readBit()==1) {//if is 1 totnewtp++; tmp = bin.readBits(2); totnewtp += tmp; // If next 2 bits are not 11 do nothing if(tmp==0x3) { //if 11 tmp = bin.readBits(5); totnewtp += tmp; // If next 5 bits are not 11111 do nothing if(tmp==0x1F) { //if 11111 totnewtp += bin.readBits(7); } } } } ccb.addNTP(l,totnewtp); sumtotnewtp += totnewtp; cblks[s].addElement(prec.cblk[s][m][n]); // Code-block length // -- Compute the number of bit to read to obtain // code-block length. // numBits = betaLamda + log2(totnewtp); // The length is signalled for each segment in // addition to the final one. The total length is the // sum of all segment lengths. // If regular termination in use, then there is one // segment per truncation point present. Otherwise, if // selective arithmetic bypass coding mode is present, // then there is one termination per bypass/MQ and // MQ/bypass transition. Otherwise the only // termination is at the end of the code-block. int options = ((Integer)decSpec.ecopts.getTileCompVal(tIdx,c)). intValue(); if( (options&OPT_TERM_PASS) != 0) { // Regular termination in use, one segment per new // pass (i.e. truncation point) nSeg = totnewtp; } else if( (options&OPT_BYPASS) != 0) { // Selective arithmetic coding bypass coding mode // in use, but no regular termination 1 segment up // to the end of the last pass of the 4th most // significant bit-plane, and, in each following // bit-plane, one segment upto the end of the 2nd // pass and one upto the end of the 3rd pass. if(ccb.ctp<=FIRST_BYPASS_PASS_IDX) { nSeg = 1; } else { nSeg = 1; // One at least for last pass // And one for each other terminated pass for(tpidx = ccb.ctp-totnewtp; tpidx < ccb.ctp-1; tpidx++) { if(tpidx >= FIRST_BYPASS_PASS_IDX-1) { passtype = (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)% NUM_PASSES; if (passtype==1 || passtype==2) { // bypass coding just before MQ // pass or MQ pass just before // bypass coding => terminated nSeg++; } } } } } else { // Nothing special in use, just one segment nSeg = 1; } // Reads lblock increment (common to all segments) while(bin.readBit()!=0) { lblock[c][r][s][cbc.y][cbc.x]++; } if(nSeg==1) { // Only one segment in packet cbLen = bin.readBits(lblock[c][r][s][cbc.y][cbc.x]+ MathUtil.log2(totnewtp)); } else { // We must read one length per segment ccb.segLen[l] = new int[nSeg]; cbLen = 0; int j; if((options&OPT_TERM_PASS) != 0) { // Regular termination: each pass is terminated for(tpidx=ccb.ctp-totnewtp,j=0; tpidx<ccb.ctp;tpidx++,j++) { lblockCur = lblock[c][r][s][cbc.y][cbc.x]; tmp = bin.readBits(lblockCur); ccb.segLen[l][j] = tmp; cbLen += tmp; } } else { // Bypass coding: only some passes are // terminated ltp = ccb.ctp-totnewtp-1; for(tpidx = ccb.ctp-totnewtp, j=0; tpidx<ccb.ctp-1;tpidx++) { if(tpidx >= FIRST_BYPASS_PASS_IDX-1) { passtype = (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)% NUM_PASSES; if (passtype==0) continue; lblockCur = lblock[c][r][s][cbc.y][cbc.x]; tmp = bin. readBits(lblockCur+ MathUtil.log2(tpidx-ltp)); ccb.segLen[l][j] = tmp; cbLen += tmp; ltp = tpidx; j++; } } // Last pass has always the length sent lblockCur = lblock[c][r][s][cbc.y][cbc.x]; tmp = bin.readBits(lblockCur+ MathUtil.log2(tpidx-ltp)); cbLen += tmp; ccb.segLen[l][j] = tmp; } } ccb.len[l] = cbLen; // If truncation mode, checks if output rate is reached // unless ncb and lbody quit contitions used. if(isTruncMode && maxCB==-1) { tmp = ehs.getPos()-startPktHead; if(tmp>nb[tIdx]) { nb[tIdx] = 0; // Remove found information in this code-block if(l==0) { cbI[s][cbc.y][cbc.x] = null; } else { ccb.off[l]=ccb.len[l]=0; ccb.ctp -= ccb.ntp[l]; ccb.ntp[l] = 0; ccb.pktIdx[l] = -1; } return true; } } } catch(EOFException e) { // Remove found information in this code-block if(l==0) { cbI[s][cbc.y][cbc.x] = null; } else { ccb.off[l]=ccb.len[l]=0; ccb.ctp -= ccb.ntp[l]; ccb.ntp[l] = 0; ccb.pktIdx[l] = -1; } // throw new EOFException(); return true; } } // End loop on horizontal code-blocks } // End loop on vertical code-blocks } // End loop on subbands // Read EPH marker if needed if(ephUsed) { readEPHMarker(bin); } pktIdx++; // If truncation mode, checks if output rate is reached if(isTruncMode && maxCB == -1) { tmp = ehs.getPos()-startPktHead; if(tmp>nb[tIdx]) { nb[tIdx] = 0; return true; } else { nb[tIdx] -= tmp; } } return false; } /** * Reads specificied packet body in order to find offset of each * code-block's piece of codeword. This use the list of found code-blocks * in previous red packet head. * * @param l layer index * * @param r Resolution level index * * @param c Component index * * @param p Precinct index * * @param cbI CBlkInfo array of relevant component and resolution * level. * * @param nb The remainding number of bytes to read from the bit stream in * each tile before reaching the decoding rate (in truncation mode) * * @return True if decoding rate is reached * */ public boolean readPktBody(int l,int r,int c,int p,CBlkInfo[][][] cbI, int[] nb) throws IOException { int curOff = ehs.getPos(); Point curCB; CBlkInfo ccb; boolean stopRead = false; int tIdx = src.getTileIdx(); Point cbc; boolean precFound = false; int mins = (r==0) ? 0 : 1; int maxs = (r==0) ? 1 : 4; for(int s=mins; s<maxs; s++) { if(p<ppinfo[c][r].length) { precFound = true; } } if(!precFound) { return false; } for(int s=mins; s<maxs; s++) { for(int numCB=0; numCB<cblks[s].size(); numCB++) { cbc = ((CBlkCoordInfo)cblks[s].elementAt(numCB)).idx; ccb = cbI[s][cbc.y][cbc.x]; ccb.off[l] = curOff; curOff += ccb.len[l]; try { ehs.seek(curOff); } catch(EOFException e) { if(l==0) { cbI[s][cbc.y][cbc.x] = null; } else { ccb.off[l] = ccb.len[l]=0; ccb.ctp -= ccb.ntp[l]; ccb.ntp[l] = 0; ccb.pktIdx[l] = -1; } throw new EOFException(); } // If truncation mode if(isTruncMode) { if(stopRead || ccb.len[l]>nb[tIdx]) { // Remove found information in this code-block if(l==0) { cbI[s][cbc.y][cbc.x] = null; } else { ccb.off[l] = ccb.len[l] = 0; ccb.ctp -= ccb.ntp[l]; ccb.ntp[l] = 0; ccb.pktIdx[l] = -1; } stopRead = true; } if(!stopRead) { nb[tIdx] -= ccb.len[l]; } } // If ncb quit condition reached if(ncbQuit && r == rQuit && s == sQuit && cbc.x == xQuit && cbc.y == yQuit && tIdx == tQuit && c == cQuit) { cbI[s][cbc.y][cbc.x] = null; stopRead = true; } } // Loop on code-blocks } // End loop on subbands // Seek to the end of the packet ehs.seek(curOff); if(stopRead) { return true; } else { return false; } } /** * Returns the precinct partition width for the specified component, * resolution level and tile. * * @param t the tile index * * @param c The index of the component (between 0 and C-1) * * @param r The resolution level, from 0 to L. * * @return the precinct partition width for the specified component, * resolution level and tile. * */ public final int getPPX(int t,int c,int r){ return decSpec.pss.getPPX(t,c,r); } /** * Returns the precinct partition height for the specified component, * resolution level and tile. * * @param t the tile index * * @param c The index of the component (between 0 and C-1) * * @param rl The resolution level, from 0 to L. * * @return the precinct partition height in the specified component, for * the specified resolution level, for the current tile. * */ public final int getPPY(int t,int c,int rl) { return decSpec.pss.getPPY(t,c,rl); } /** * Try to read a SOP marker and check that its sequence number if not out * of sequence. If so, an error is thrown. * * @param nBytes The number of bytes left to read from each tile * * @param p Precinct index * * @param r Resolution level index * * @param c Component index * */ public boolean readSOPMarker(int[] nBytes,int p,int c,int r) throws IOException { int val; byte sopArray[] = new byte[6]; int tIdx = src.getTileIdx(); int mins = (r==0) ? 0 : 1; int maxs = (r==0) ? 1 : 4; boolean precFound = false; for(int s=mins; s<maxs; s++) { if(p<ppinfo[c][r].length) { precFound = true; } } if(!precFound) { return false; } // If SOP markers are not used, return if(!sopUsed) { return false; } // Check if SOP is used for this packet int pos = ehs.getPos(); if( (short)((ehs.read()<<8) | ehs.read()) != Markers.SOP ) { ehs.seek(pos); return false; } ehs.seek(pos); // If length of SOP marker greater than remaining bytes to read for // this tile return true if(nBytes[tIdx]<6) { return true; } nBytes[tIdx] -= 6; // Read marker into array 'sopArray' ehs.readFully(sopArray,0,Markers.SOP_LENGTH); // Check if this is the correct marker val = sopArray[0]; val <<= 8; val |= sopArray[1]; if(val!=Markers.SOP) { throw new Error("Corrupted Bitstream: Could not parse SOP "+ "marker !"); } // Check if length is correct val = (sopArray[2]&0xff); val <<= 8; val |= (sopArray[3]&0xff); if(val!=4) { throw new Error("Corrupted Bitstream: Corrupted SOP marker !"); } // Check if sequence number if ok val = (sopArray[4]&0xff); val <<= 8; val |= (sopArray[5]&0xff); if(!pph && val!=pktIdx) { throw new Error("Corrupted Bitstream: SOP marker out of " +"sequence !"); } if(pph && val!=pktIdx-1) { // if packed packet headers are used, packet header was read // before SOP marker segment throw new Error("Corrupted Bitstream: SOP marker out of " +"sequence !"); } return false; } /** * Try to read an EPH marker. If it is not possible then an Error is * thrown. * * @param bin The packet header reader to read the EPH marker from * */ public void readEPHMarker(PktHeaderBitReader bin) throws IOException { int val; byte ephArray[] = new byte[2]; if(bin.usebais) { bin.bais.read(ephArray,0,Markers.EPH_LENGTH); } else { bin.in.readFully(ephArray,0,Markers.EPH_LENGTH); } // Check if this is the correct marker val = ephArray[0]; val <<= 8; val |= ephArray[1]; if (val!=Markers.EPH) { throw new Error("Corrupted Bitstream: Could not parse EPH " +"marker ! "); } } /** * Get PrecInfo instance of the specified resolution level, component and * precinct. * * @param c Component index. * * @param r Resolution level index. * * @param p Precinct index. * */ public PrecInfo getPrecInfo(int c,int r,int p) { return ppinfo[c][r][p]; } }