All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jj2000.j2k.codestream.reader.FileBitstreamReaderAgent Maven / Gradle / Ivy

Go to download

JPEG2000 support for Java Advanced Imaging Image I/O Tools API core. This module is licensed under the [JJ2000 license](LICENSE.txt) and is therefore NOT compatible with the GPL 3 license. It should be compatible with the LGPL 2.1 license.

There is a newer version: 1.4.0
Show newest version
/*
 * $RCSfile: FileBitstreamReaderAgent.java,v $
 * $Revision: 1.4 $
 * $Date: 2006/10/05 01:10:31 $
 * $State: Exp $
 *
 * Class:                   FileBitstreamReaderAgent
 *
 * Description:             Retrieve code-blocks codewords in the bit stream
 *
 *
 *
 * 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 java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;

import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;

import jj2000.j2k.JJ2KExceptionHandler;
import jj2000.j2k.NoNextElementException;
import jj2000.j2k.NotImplementedError;
import jj2000.j2k.codestream.CorruptedCodestreamException;
import jj2000.j2k.codestream.HeaderInfo;
import jj2000.j2k.codestream.Markers;
import jj2000.j2k.codestream.PrecInfo;
import jj2000.j2k.codestream.ProgressionType;
import jj2000.j2k.decoder.DecoderSpecs;
import jj2000.j2k.entropy.StdEntropyCoderOptions;
import jj2000.j2k.entropy.decoder.DecLyrdCBlk;
import jj2000.j2k.io.RandomAccessIO;
import jj2000.j2k.quantization.dequantizer.StdDequantizerParams;
import jj2000.j2k.util.ArrayUtil;
import jj2000.j2k.util.FacilityManager;
import jj2000.j2k.util.MathUtil;
import jj2000.j2k.util.MsgLogger;
import jj2000.j2k.wavelet.synthesis.SubbandSyn;

import com.github.jaiimageio.jpeg2000.impl.J2KImageReadParamJava;

/**
 * This class reads the bit stream (with the help of HeaderDecoder for tile
 * headers and PktDecoder for packets header and body) and retrives location
 * of all code-block's codewords.
 *
 * 

Note: All tile-parts headers are read by the constructor whereas packets * are processed when decoding related tile (when setTile method is called). * *

In parsing mode, the reader simulates a virtual layer-resolution * progressive bit stream with the same truncation points in each code-block, * whereas in truncation mode, only the first bytes are taken into account (it * behaves like if it is a real truncated codestream). * * @see HeaderDecoder * @see PktDecoder * */ public class FileBitstreamReaderAgent extends BitstreamReaderAgent implements Markers, ProgressionType, StdEntropyCoderOptions{ /** Whether or not the last read Psot value was zero. Only the Psot in the * last tile-part in the codestream can have such a value. */ private boolean isPsotEqualsZero = true; /** Reference to the PktDecoder instance */ public PktDecoder pktDec; /** Reference to the J2KImageReadParamJava instance */ private J2KImageReadParamJava j2krparam; /** The RandomAccessIO where to get data from */ private RandomAccessIO in; /** The number of tiles in the image */ private int nt; /** Offset of the first packet in each tile-part in each tile */ private int[][] firstPackOff; /** * Returns the number of tile-part found for a given tile * * @param t Tile index * * */ public int getNumTileParts(int t) { if(firstPackOff==null || firstPackOff[t]==null) { throw new Error("Tile "+t+" not found in input codestream."); } return firstPackOff[t].length; } /** Number of bytes allocated to each tile. In parsing mode, this number * is related to the tile length in the codestream whereas in truncation * mode all the rate is affected to the first tiles. */ private int[] nBytes; /** Whether or not to print information found in codestream */ private boolean printInfo = false; /** * Backup of the number of bytes allocated to each tile. This array is * used to restore the number of bytes to read in each tile when the * codestream is read several times (for instance when decoding an R,G,B * image to three output files) * */ private int[] baknBytes; /** Length of each tile-part (written in Psot) */ private int[][] tilePartLen; /** Total length of each tile */ private int[] totTileLen; /** Total length of tiles' header */ private int[] totTileHeadLen; /** First tile part header length*/ private int firstTilePartHeadLen; /** Total length of all tile parts in all tiles */ private double totAllTileLen; /** Length of main header */ private int mainHeadLen; /** Length of main and tile-parts headers */ private int headLen = 0; /** Length of all tile-part headers */ private int[][] tilePartHeadLen; /** Length of each packet head found in the tile */ private Vector pktHL; /** True if truncation mode is used. False if parsing mode */ private boolean isTruncMode; /** The number of tile-parts that remain to read */ private int remainingTileParts; /** The number of tile-parts read so far for each tile */ private int[] tilePartsRead; /** Thetotal number of tile-parts read so far */ private int totTilePartsRead=0; /** The number of tile-parts in each tile */ private int[] tileParts; /** The total number of tile-parts in each tile */ private int[] totTileParts; /** The current tile part being used */ private int curTilePart; /** The number of the tile-part in the codestream */ private int[][] tilePartNum; /** Whether or not a EOC marker has been found instead of a SOT */ private boolean isEOCFound = false; /** Reference to the HeaderInfo instance (used when reading SOT marker * segments) */ private HeaderInfo hi; /** Array containing info. for all the code-blocks:
* - 1st dim: component index.
* - 2nd dim: resolution level index.
* - 3rd dim: subband index.
* - 4th/5th dim: code-block index (vert. and horiz.).
*/ private CBlkInfo[][][][][] cbI; /** Gets the reference to the CBlkInfo array */ public CBlkInfo[][][][][] getCBlkInfo() { return cbI; } /** The maximum number of layers to decode for any code-block */ private int lQuit; /** Whether or not to use only first progression order */ private boolean usePOCQuit = false; /** * Reads all tiles headers and keep offset of their first * packet. Finally it calls the rate allocation method. * * @param hd HeaderDecoder of the codestream. * * @param ehs The input stream where to read bit-stream. * * @param decSpec The decoder specifications * * @param j2krparam The J2KImageReadParam instance created from the * command-line arguments. * * @param cdstrInfo Whether or not to print information found in * codestream. * * @see #allocateRate * */ public FileBitstreamReaderAgent(HeaderDecoder hd,RandomAccessIO ehs, DecoderSpecs decSpec, J2KImageReadParamJava j2krparam, boolean cdstrInfo,HeaderInfo hi) throws IOException { super(hd,decSpec); this.j2krparam = j2krparam; this.printInfo = cdstrInfo; this.hi = hi; String strInfo = printInfo ? "Codestream elements information in bytes "+ "(offset, total length, header length):\n\n" : null; // Check whether quit conditiosn used //usePOCQuit = j2krparam.getPOCQuit(); // Get decoding rate if (j2krparam.getDecodingRate() == Double.MAX_VALUE) tnbytes = Integer.MAX_VALUE; else tnbytes = (int)(j2krparam.getDecodingRate() * hd.getMaxCompImgWidth() * hd.getMaxCompImgHeight()) / 8; //isTruncMode = !j2krparam.getParsing(); isTruncMode = true; // Check if quit conditions are being used //int ncbQuit = j2krparam.getNCBQuit(); int ncbQuit = -1; if(ncbQuit != -1 && !isTruncMode){ throw new Error("Cannot use -parsing and -ncb_quit condition at "+ "the same time."); } // lQuit = j2krparam.getLQuit(); lQuit = -1; // initializations nt = ntX * ntY; in = ehs; pktDec = new PktDecoder(decSpec,hd,ehs,this,isTruncMode, ncbQuit); tileParts = new int[nt]; totTileParts = new int[nt]; totTileLen = new int[nt]; tilePartLen = new int[nt][]; tilePartNum = new int[nt][]; firstPackOff = new int[nt][]; tilePartsRead = new int[nt]; totTileHeadLen = new int[nt]; tilePartHeadLen = new int[nt][]; nBytes = new int[nt]; baknBytes = new int[nt]; hd.nTileParts = new int[nt]; this.isTruncMode = isTruncMode; // Keeps main header's length, takes file format overhead into account cdstreamStart = hd.mainHeadOff; // Codestream offset in the file mainHeadLen = in.getPos() - cdstreamStart; headLen = mainHeadLen; // If ncb and lbody quit conditions are used, headers are not counted if(ncbQuit == -1) { anbytes = mainHeadLen; } else { anbytes = 0; } if(printInfo) strInfo += "Main header length : "+cdstreamStart+", "+mainHeadLen+ ", "+mainHeadLen+"\n"; // If cannot even read the first tile-part if(anbytes>tnbytes) { throw new Error("Requested bitrate is too small."); } // Initialize variables used when reading tile-part headers. totAllTileLen = 0; remainingTileParts = nt; // at least as many tile-parts as tiles maxPos = lastPos = in.getPos(); // Update 'res' value according to the parameter and the main header. if(j2krparam.getResolution()== -1) { targetRes = decSpec.dls.getMin(); } else { targetRes = j2krparam.getResolution(); if(targetRes<0) { throw new IllegalArgumentException("Specified negative "+ "resolution level index: "+ targetRes); } } // Verify reduction in resolution level int mdl = decSpec.dls.getMin(); if(targetRes>mdl) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING, "Specified resolution level ("+targetRes+ ") is larger"+ " than the maximum possible. Setting it to "+ mdl +" (maximum possible)"); targetRes = mdl; } // Initialize tile part positions from TLM marker segment. initTLM(); } // An array of the positions of tile parts: // - length of tilePartPositions is nt. // - length of tilePartPositions[i] is totTileParts[i]. long[][] tilePartPositions = null; // // Initialize the tilePartPositions positions array if a TLM marker // segment is present in the main header. If no such marker segment // is present the array will remain null. This method rewinds to the // start of the codestream and scans until the first SOT marker is // encountered. Before return the stream is returned to its position // when the method was invoked. // private void initTLM() throws IOException { // Save the position to return to at the end of this method. int savePos = in.getPos(); // Array to store contents of TLM segments. The first index is // Ztlm. The contents of tlmSegments[i] is the bytes in the TLM // segment with Ztlm == i after the Ztlm byte. byte[][] tlmSegments = null; // Number of TLM segments. The first numTLM elements of tlmSegments // should be non-null if the segments are correct. int numTLM = 0; try { // Rewind to the start of the main header. in.seek(cdstreamStart + 2); // skip SOC // Loop over marker segments. short marker; while((marker = in.readShort()) != SOT) { // Get the length (which includes the 2-byte length parameter). int markerLength = in.readUnsignedShort(); // Process TLM segments. if(marker == TLM) { numTLM++; if(tlmSegments == null) { tlmSegments = new byte[256][]; // 0 <= Ztlm <= 255 } // Save contents after Ztlm in array. int Ztlm = in.read(); tlmSegments[Ztlm] = new byte[markerLength - 3]; in.readFully(tlmSegments[Ztlm], 0, markerLength - 3); } else { in.skipBytes(markerLength - 2); } } } catch(IOException e) { // Reset so that the TLM segments are not processed further. tlmSegments = null; } if(tlmSegments != null) { ArrayList[] tlmOffsets = null; // Tiles start after the main header. long tilePos = cdstreamStart + mainHeadLen; // Tile counter for when tile indexes are not included. int tileCounter = 0; for(int itlm = 0; itlm < numTLM; itlm++) { if(tlmSegments[itlm] == null) { // Null segment among first numTLM entries: error. tlmOffsets = null; break; } else if(tlmOffsets == null) { tlmOffsets = new ArrayList[nt]; } // Create a stream. ByteArrayInputStream bais = new ByteArrayInputStream(tlmSegments[itlm]); ImageInputStream iis = new MemoryCacheImageInputStream(bais); try { int Stlm = iis.read(); int ST = (Stlm >> 4) & 0x3; int SP = (Stlm >> 6) & 0x1; int tlmLength = tlmSegments[itlm].length; while(iis.getStreamPosition() < tlmLength) { int tileIndex = tileCounter; switch(ST) { case 1: tileIndex = iis.read(); break; case 2: tileIndex = iis.readUnsignedShort(); } if(tlmOffsets[tileIndex] == null) { tlmOffsets[tileIndex] = new ArrayList(); } tlmOffsets[tileIndex].add(new Long(tilePos)); long tileLength = 0L; switch(SP) { case 0: tileLength = iis.readUnsignedShort(); break; case 1: tileLength = iis.readUnsignedInt(); break; } tilePos += tileLength; if(ST == 0) tileCounter++; } } catch(IOException e) { // XXX? } } if(tlmOffsets != null) { tilePartPositions = new long[nt][]; for(int i = 0; i < nt; i++) { if(tlmOffsets[i] == null) { tilePartPositions = null; break; } else { ArrayList list = tlmOffsets[i]; int count = list.size(); tilePartPositions[i] = new long[count]; long[] tpPos = tilePartPositions[i]; for(int j = 0; j < count; j++) { tpPos[j] = ((Long)list.get(j)).longValue(); } } } } } in.seek(savePos); } int cdstreamStart = 0; int t=0, pos=-1, tp=0, tptot=0; int tilePartStart = 0; boolean rateReached = false; int numtp = 0; int maxTP = nt; // If maximum 1 tile part per tile specified int lastPos = 0, maxPos = 0; /** * Read all tile-part headers of the requested tile. All tile-part * headers prior to the last tile-part header of the current tile will * also be read. * * @param tileNum The index of the tile for which to read tile-part * headers. */ private void initTile(int tileNum) throws IOException { if(tilePartPositions == null) in.seek(lastPos); String strInfo = ""; int ncbQuit = -1; boolean isTilePartRead = false; boolean isEOFEncountered = false; try { int tpNum = 0; while(remainingTileParts!=0 && (totTileParts[tileNum] == 0 || tilePartsRead[tileNum] < totTileParts[tileNum])) { isTilePartRead = true; if(tilePartPositions != null) { in.seek((int)tilePartPositions[tileNum][tpNum++]); } tilePartStart = in.getPos(); // Read tile-part header try { t = readTilePartHeader(); if(isEOCFound) { // Some tiles are missing but the // codestream is OK break; } tp = tilePartsRead[t]; if(isPsotEqualsZero) { // Psot may equals zero for the // last tile-part: it is assumed that this tile-part // contain all data until EOC tilePartLen[t][tp] = in.length()-2-tilePartStart; } } catch(EOFException e) { firstPackOff[t][tp] = in.length(); throw e; } pos = in.getPos(); // In truncation mode, if target decoding rate is reached in // tile-part header, skips the tile-part and stop reading // unless the ncb and lbody quit condition is in use if(isTruncMode && ncbQuit == -1) { if((pos-cdstreamStart)>tnbytes) { firstPackOff[t][tp] = in.length(); rateReached = true; break; } } // Set tile part position and header length firstPackOff[t][tp] = pos; tilePartHeadLen[t][tp] = (pos-tilePartStart); if(printInfo) strInfo += "Tile-part "+tp+" of tile "+t+" : "+tilePartStart +", "+tilePartLen[t][tp]+", "+tilePartHeadLen[t][tp]+"\n"; // Update length counters totTileLen[t] += tilePartLen[t][tp]; totTileHeadLen[t] += tilePartHeadLen[t][tp]; totAllTileLen += tilePartLen[t][tp]; if(isTruncMode) { if(anbytes+tilePartLen[t][tp]>tnbytes) { anbytes += tilePartHeadLen[t][tp]; headLen += tilePartHeadLen[t][tp]; rateReached = true; nBytes[t] += (tnbytes-anbytes); break; } else { anbytes += tilePartHeadLen[t][tp]; headLen += tilePartHeadLen[t][tp]; nBytes[t] += (tilePartLen[t][tp]- tilePartHeadLen[t][tp]); } } else { if(anbytes+tilePartHeadLen[t][tp]>tnbytes) { break; } else { anbytes += tilePartHeadLen[t][tp]; headLen += tilePartHeadLen[t][tp]; } } // If this is first tile-part, remember header length if(tptot==0) firstTilePartHeadLen = tilePartHeadLen[t][tp]; // Go to the beginning of next tile part tilePartsRead[t]++; int nextMarkerPos = tilePartStart+tilePartLen[t][tp]; if(tilePartPositions == null) { in.seek(nextMarkerPos); } if(nextMarkerPos > maxPos) { maxPos = nextMarkerPos; } remainingTileParts--; maxTP--; tptot++; // If Psot of the current tile-part was equal to zero, it is // assumed that it contains all data until the EOC marker if(isPsotEqualsZero) { if(remainingTileParts!=0) { FacilityManager.getMsgLogger().printmsg (MsgLogger.WARNING,"Some tile-parts have not "+ "been found. The codestream may be corrupted."); } break; } } } catch(EOFException e) { isEOFEncountered = true; if(printInfo) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,strInfo); } FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Codestream truncated in tile "+t); // Set specified rate to end of file if valid int fileLen = in.length(); if(fileLenmdl) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING, "Specified resolution level ("+targetRes+ ") is larger"+ " than the maximum possible. Setting it to "+ mdl +" (maximum possible)"); targetRes = mdl; } XXX: END */ if(!isEOFEncountered) { if(printInfo) { FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); } if(remainingTileParts == 0) { // Check presence of EOC marker is decoding rate not reached or // if this marker has not been found yet if(!isEOCFound && !isPsotEqualsZero && !rateReached) { try { int savePos = in.getPos(); in.seek(maxPos); if(in.readShort()!=EOC) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"EOC marker not found. "+ "Codestream is corrupted."); } in.seek(savePos); } catch(EOFException e) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"EOC marker is missing"); } } } } // Bit-rate allocation if(!isTruncMode) { allocateRate(); } else if(remainingTileParts == 0 && !isEOFEncountered) { // Take EOC into account if rate is not reached if(in.getPos()>=tnbytes) anbytes += 2; } if(tilePartPositions == null) lastPos = in.getPos(); // Backup nBytes for (int tIdx=0; tIdx stopOff){ throw new Error("Requested bitrate is too small for parsing"); } // Calculate bitrate for each tile int rem = stopOff-anbytes; int totnByte = rem; for(int t=nt-1; t>0; t--){ rem -= nBytes[t]=(int)(totnByte*(totTileLen[t]/totAllTileLen)); } nBytes[0] = rem; } /** * Reads SOT marker segment of the tile-part header and calls related * methods of the HeaderDecoder to read other markers segments. The * tile-part header is entirely read when a SOD marker is encountered. * * @return The tile number of the tile part that was read * */ private int readTilePartHeader() throws IOException{ HeaderInfo.SOT ms = hi.getNewSOT(); // SOT marker short marker = in.readShort(); if(marker!=SOT) { if(marker==EOC) { isEOCFound = true; return -1; } else { throw new CorruptedCodestreamException("SOT tag not found "+ "in tile-part start"); } } isEOCFound = false; // Lsot (shall equals 10) int lsot = in.readUnsignedShort(); ms.lsot = lsot; if(lsot!=10) throw new CorruptedCodestreamException("Wrong length for "+ "SOT marker segment: "+ lsot); // Isot int tile = in.readUnsignedShort(); ms.isot = tile; if(tile>65534){ throw new CorruptedCodestreamException("Tile index too high in "+ "tile-part."); } // Psot int psot = in.readInt(); ms.psot = psot; isPsotEqualsZero = (psot!=0) ? false : true; if(psot<0) { throw new NotImplementedError("Tile length larger "+ "than maximum supported"); } // TPsot int tilePart = in.read(); ms.tpsot = tilePart; if( tilePart!=tilePartsRead[tile] || tilePart<0 || tilePart>254 ) { throw new CorruptedCodestreamException("Out of order tile-part"); } // TNsot int nrOfTileParts = in.read(); ms.tnsot = nrOfTileParts; hi.sot.put("t"+tile+"_tp"+tilePart,ms); if(nrOfTileParts==0) { // The number of tile-part is not specified in // this tile-part header. // Assumes that there will be another tile-part in the codestream // that will indicate the number of tile-parts for this tile) int nExtraTp; if(tileParts[tile]==0 || tileParts[tile]==tilePartLen.length ) { // Then there are two tile-parts (one is the current and the // other will indicate the number of tile-part for this tile) nExtraTp = 2; remainingTileParts += 1; } else { // There is already one scheduled extra tile-part. In this // case just add place for the current one nExtraTp = 1; } tileParts[tile] += nExtraTp; nrOfTileParts = tileParts[tile]; FacilityManager.getMsgLogger(). printmsg(MsgLogger.WARNING,"Header of tile-part "+tilePart+ " of tile "+tile+", does not indicate the total"+ " number of tile-parts. Assuming that there are "+ nrOfTileParts+" tile-parts for this tile."); // Increase and re-copy tilePartLen array int[] tmpA = tilePartLen[tile]; tilePartLen[tile] = new int[nrOfTileParts]; for(int i=0; i nrOfTileParts ) { // Already found more tile-parts than signaled here throw new CorruptedCodestreamException("Invalid number "+ "of tile-parts in"+ " tile "+tile+": "+ nrOfTileParts); } else { // Signaled number of tile-part fits with number of // previously found tile-parts remainingTileParts += nrOfTileParts-tileParts[tile]; if(tileParts[tile]!=nrOfTileParts) { // Increase and re-copy tilePartLen array int[] tmpA = tilePartLen[tile]; tilePartLen[tile] = new int[nrOfTileParts]; for(int i=0; i=mdl.length) continue; for(int r=ress; r=mdl.length) continue; // Checks if resolution level exists if(r>=lys[c].length) continue; if(r>mdl[c]) continue; // Checks if layer exists if(l=numLayers) continue; nPrec = pktDec.getNumPrecinct(c,r); for(int p=0; plastByte && curTilePart=mdl.length) continue; for(int r=ress; rmdl[c]) continue; if(lys[c]!=null && r=mdl.length) continue; // Checks if resolution level exists if(r>mdl[c]) continue; if(r>=lys[c].length) continue; // Checks if layer exists if(l=numLayers) continue; nPrec = pktDec.getNumPrecinct(c,r); for(int p=0; plastByte && curTilePart=mdl.length) continue; if(r>mdl[c]) continue; nextPrec[c] = new int[mdl[c]+1]; if (lys[c]!=null && r=0; p--) { prec = pktDec.getPrecInfo(c,r,p); if(prec.rgulx!=tx0) { if(prec.rgulxmaxx) maxx = prec.rgulx; } if(prec.rguly!=ty0) { if(prec.rgulymaxy) maxy = prec.rguly; } if(nPrec==0) { gcd_x = prec.rgw; gcd_y = prec.rgh; } else { gcd_x = MathUtil.gcd(gcd_x,prec.rgw); gcd_y = MathUtil.gcd(gcd_y,prec.rgh); } nPrec++; } // precincts } // resolution levels } // components if(nPrec==0) { throw new Error("Image cannot have no precinct"); } int pyend = (maxy-miny)/gcd_y+1; int pxend = (maxx-minx)/gcd_x+1; int x,y; int hlen,plen; int start; boolean status = false; int lastByte = firstPackOff[t][curTilePart]+ tilePartLen[t][curTilePart]-1- tilePartHeadLen[t][curTilePart]; int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); String strInfo = printInfo ? "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ "): offset, length, header length\n" : null; boolean pph = false; if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { pph = true; } for(int r=ress; r=mdl.length) continue; if(r>mdl[c]) continue; if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) { continue; } prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]); if((prec.rgulx!=x) || (prec.rguly!=y)) { continue; } for(int l=minlys; l=lys[c].length) continue; if(l=numLayers) continue; start = in.getPos(); // If packed packet headers are used, there is no // need to check that there are bytes enough to // read header if(pph) { pktDec.readPktHead(l,r,c,nextPrec[c][r], cbI[c][r],nBytes); } // If we are about to read outside of tile-part, // skip to next tile-part if(start>lastByte && curTilePart=mdl.length) continue; if(r>mdl[c]) continue; nextPrec[c] = new int[mdl[c]+1]; if (lys[c]!=null && r=0; p--) { prec = pktDec.getPrecInfo(c,r,p); if(prec.rgulx!=tx0) { if(prec.rgulxmaxx) maxx = prec.rgulx; } if(prec.rguly!=ty0) { if(prec.rgulymaxy) maxy = prec.rguly; } if(nPrec==0) { gcd_x = prec.rgw; gcd_y = prec.rgh; } else { gcd_x = MathUtil.gcd(gcd_x,prec.rgw); gcd_y = MathUtil.gcd(gcd_y,prec.rgh); } nPrec++; } // precincts } // resolution levels } // components if(nPrec==0) { throw new Error("Image cannot have no precinct"); } int pyend = (maxy-miny)/gcd_y+1; int pxend = (maxx-minx)/gcd_x+1; int hlen,plen; int start; boolean status = false; int lastByte = firstPackOff[t][curTilePart]+ tilePartLen[t][curTilePart]-1- tilePartHeadLen[t][curTilePart]; int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); String strInfo = printInfo ? "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ "): offset, length, header length\n" : null; boolean pph = false; if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { pph = true; } int y = ty0; int x = tx0; for(int py=0; py<=pyend; py++) { // Vertical precincts for(int px=0; px<=pxend; px++) { // Horiz. precincts for(int c=comps; c=mdl.length) continue; for(int r=ress; rmdl[c]) continue; if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) { continue; } prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]); if((prec.rgulx!=x) || (prec.rguly!=y)) { continue; } for(int l=minlys; l=lys[c].length) continue; if(l=numLayers) continue; start = in.getPos(); // If packed packet headers are used, there is no // need to check that there are bytes enough to // read header if(pph) { pktDec.readPktHead(l,r,c,nextPrec[c][r], cbI[c][r],nBytes); } // Read SOP marker segment if necessary status = pktDec.readSOPMarker(nBytes, nextPrec[c][r],c,r); if(status) { if(printInfo) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,strInfo); } return true; } if(!pph) { status = pktDec.readPktHead(l,r,c, nextPrec[c][r], cbI[c][r],nBytes); } if(status) { if(printInfo) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,strInfo); } return true; } // Store packet's head length hlen = in.getPos()-start; pktHL.addElement(new Integer(hlen)); // Reads packet's body status = pktDec.readPktBody(l,r,c,nextPrec[c][r], cbI[c][r],nBytes); plen = in.getPos()-start; if(printInfo) strInfo+= " Pkt l="+l+",r="+r+",c="+c+",p="+ nextPrec[c][r]+": "+ start+", "+plen+", "+hlen+"\n"; if(status) { if(printInfo) { FacilityManager.getMsgLogger(). printmsg(MsgLogger.INFO,strInfo); } return true; } } // layers nextPrec[c][r]++; } // Resolution levels } // Components if(px!=pxend) { x = minx+px*gcd_x; } else { x = tx0; } } // Horizontal precincts if(py!=pyend) { y = miny+py*gcd_y; } else { y = ty0; } } // Vertical precincts if(printInfo) { FacilityManager.getMsgLogger().printmsg(MsgLogger.INFO,strInfo); } return false; // Decoding rate was not reached } /** * Reads packets of the current tile according to the * component-position-resolution-layer progressiveness. * * @param lys Index of the first layer for each component and resolution. * * @param lye Index of the last layer. * * @param ress Index of the first resolution level. * * @param rese Index of the last resolution level. * * @param comps Index of the first component. * * @param compe Index of the last component. * * @return True if rate has been reached. * */ private boolean readCompPosResLy(int lys[][],int lye,int ress,int rese, int comps,int compe) throws IOException { Point nTiles = getNumTiles(null); Point tileI = getTile(null); int x0siz = hd.getImgULX(); int y0siz = hd.getImgULY(); int xsiz = x0siz + hd.getImgWidth(); int ysiz = y0siz + hd.getImgHeight(); int xt0siz = getTilePartULX(); int yt0siz = getTilePartULY(); int xtsiz = getNomTileWidth(); int ytsiz = getNomTileHeight(); 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; // Get precinct information (number,distance between two consecutive // precincts in the reference grid) in each component and resolution // level int t = getTileIdx(); // Current tile index PrecInfo prec; // temporary variable int p; // Current precinct index int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid int nPrec = 0; // Total number of found precincts int[][] nextPrec = new int [compe][]; // Next precinct index in each // component and resolution level int minlys = 100000; // minimum layer start index of each component int minx = tx1; // Horiz. offset of the second precinct in the // reference grid int miny = ty1; // Vert. offset of the second precinct in the // reference grid. int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid int maxy = ty0; // Max. vert. offset of precincts in the ref. grid Point numPrec; for(int c=comps; c=mdl.length) continue; if(r>mdl[c]) continue; nextPrec[c] = new int[mdl[c]+1]; if (lys[c]!=null && r=0; p--) { prec = pktDec.getPrecInfo(c,r,p); if(prec.rgulx!=tx0) { if(prec.rgulxmaxx) maxx = prec.rgulx; } if(prec.rguly!=ty0) { if(prec.rgulymaxy) maxy = prec.rguly; } if(nPrec==0) { gcd_x = prec.rgw; gcd_y = prec.rgh; } else { gcd_x = MathUtil.gcd(gcd_x,prec.rgw); gcd_y = MathUtil.gcd(gcd_y,prec.rgh); } nPrec++; } // precincts } // resolution levels } // components if(nPrec==0) { throw new Error("Image cannot have no precinct"); } int pyend = (maxy-miny)/gcd_y+1; int pxend = (maxx-minx)/gcd_x+1; int hlen,plen; int start; boolean status = false; int lastByte = firstPackOff[t][curTilePart]+ tilePartLen[t][curTilePart]-1- tilePartHeadLen[t][curTilePart]; int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); String strInfo = printInfo ? "Tile "+getTileIdx()+" (tile-part:"+curTilePart+ "): offset, length, header length\n" : null; boolean pph = false; if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { pph = true; } int x,y; for(int c=comps; c=mdl.length) continue; y = ty0; x = tx0; for(int py=0; py<=pyend; py++) { // Vertical precincts for(int px=0; px<=pxend; px++) { // Horiz. precincts for(int r=ress; rmdl[c]) continue; if(nextPrec[c][r]>=pktDec.getNumPrecinct(c,r)) { continue; } prec = pktDec.getPrecInfo(c,r,nextPrec[c][r]); if((prec.rgulx!=x) || (prec.rguly!=y)) { continue; } for(int l=minlys; l=lys[c].length) continue; if(llastByte && curTilePartThen, if a parsing output rate is defined, it keeps information of * first layers only. This operation simulates a creation of a * layer-resolution-component progressive bit-stream which will be next * truncated and decoded.

* * @param t Tile index * * @see PktDecoder * */ private void readTilePkts(int t) throws IOException { pktHL = new Vector(); int oldNBytes = nBytes[t]; // Number of layers int nl = ((Integer)decSpec.nls.getTileDef(t)).intValue(); // If packed packet headers was used, get the packet headers for this // tile if(((Boolean)decSpec.pphs.getTileDef(t)).booleanValue()) { // Gets packed headers as separate input stream ByteArrayInputStream pphbais = hd.getPackedPktHead(t); // Restarts PktDecoder instance cbI = pktDec.restart(nc,mdl,nl,cbI,true,pphbais); } else { // Restarts PktDecoder instance cbI = pktDec.restart(nc,mdl,nl,cbI,false,null); } // Reads packets of the tile according to the progression order int[][] pocSpec = ((int[][])decSpec.pcs.getTileDef(t)); int nChg = (pocSpec==null) ? 1 : pocSpec.length; // Create an array containing information about changes (progression // order type, layers index start, layer index end, resolution level // start, resolution level end, component index start, component index // end). There is one row per progresion order int[][] change = new int[nChg][6]; int idx = 0; // Index of the current progression order change[0][1] = 0; // layer start if(pocSpec==null) { change[idx][0] = ((Integer)decSpec.pos.getTileDef(t)).intValue(); // Progression type found in COx marker segments change[idx][1] = nl; // Layer index end change[idx][2] = 0; // resolution level start change[idx][3] = decSpec.dls.getMaxInTile(t)+1; // res. level end change[idx][4] = 0; // Component index start change[idx][5] = nc; // Component index end } else { for(idx=0; idx=lys.length) continue; for(int r=ress; r=lys[c].length) continue; lys[c][r] = lye; } } if(status || usePOCQuit) { break; } } } catch(EOFException e) { // Should never happen. Truncated codestream are normally found by // the class constructor throw e; } // In truncation mode, update the number of read bytes if(isTruncMode) { anbytes += nb-nBytes[t]; // If truncation rate is reached if(status) { nBytes[t] = 0; } } else if(nBytes[t]<(totTileLen[t]-totTileHeadLen[t])) { // In parsing mode, if there is not enough rate to entirely read the // tile. Then, parses the bit stream so as to create a virtual // layer-resolution-component progressive bit stream that will be // truncated and decoded afterwards. CBlkInfo cb; // Systematicaly reject all remaining code-blocks if one // code-block, at least, is refused. boolean reject; // Stop reading any data from the bit stream boolean stopCount = false; // Length of each packet's head (in an array) int[] pktHeadLen = new int[pktHL.size()]; for(int i=pktHL.size()-1;i>=0;i--) { pktHeadLen[i] = ((Integer)pktHL.elementAt(i)).intValue(); } // Parse each code-block, layer per layer until nBytes[t] is // reached reject = false; for(int l=0; lmres) mres = cbI[c].length; } for(int r=0; rmsub) msub = cbI[c][r].length; } for(int s=0; s 0 continue; } int mnby=0; for(int c=0; cmnby) mnby = cbI[c][r][s].length; } for(int m=0; mmnbx) mnbx = cbI[c][r][s][m].length; } for(int n=0; n=ntX || y>=ntY) { throw new IllegalArgumentException(); } int t = (y*ntX+x); try { initTile(t); } catch(IOException ioe) { // XXX Do something! } // Reset number of read bytes if needed if(t==0) { anbytes = headLen; if(!isTruncMode) { anbytes += 2; } // Restore values of nBytes for(int tIdx=0; tIdx=0; i--) { culx[i] = (ctox+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i); culy[i] = (ctoy+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i); offX[i] = (px+x*ntW+hd.getCompSubsX(i)-1)/hd.getCompSubsX(i); offY[i] = (py+y*ntH+hd.getCompSubsY(i)-1)/hd.getCompSubsY(i); } // Initialize subband tree and number of resolution levels subbTrees = new SubbandSyn[nc]; mdl = new int[nc]; derived = new boolean[nc]; params = new StdDequantizerParams[nc]; gb = new int[nc]; for(int c=0; cThe argument 'fl' is to be used by subsequent calls to this method * for the same code-block. In this way supplemental data can be retrieved * at a later time. The fact that data from more than one layer can be * returned means that several packets from the same code-block, of the * same component, and the same tile, have been concatenated.

* *

The returned compressed code-block can have its progressive * attribute set. If this attribute is set it means that more data can be * obtained by subsequent calls to this method (subject to transmission * delays, etc). If the progressive attribute is not set it means that the * returned data is all the data that can be obtained for the specified * code-block.

* *

The compressed code-block is uniquely specified by the current tile, * the component (identified by 'c'), the subband (indentified by 'sb') * and the code-block vertical and horizontal indexes 'n' and 'm'.

* *

The 'ulx' and 'uly' members of the returned 'DecLyrdCBlk' object * contain the coordinates of the top-left corner of the block, with * respect to the tile, not the subband.

* * @param c The index of the component, from 0 to N-1. * * @param m The vertical index of the code-block to return, in the * specified subband. * * @param n The horizontal index of the code-block to return, in the * specified subband. * * @param sb The subband in whic the requested code-block is. * * @param fl The first layer to return. * * @param nl The number of layers to return, if negative all available * layers are returned, starting at 'fl'. * * @param ccb If not null this object is used to return the compressed * code-block. If null a new object is created and returned. If the data * array in ccb is not null then it can be reused to return the compressed * data. * @return The compressed code-block, with a certain number of layers * determined by the available data and 'nl'. * */ public DecLyrdCBlk getCodeBlock(int c,int m,int n,SubbandSyn sb,int fl, int nl,DecLyrdCBlk ccb) { int t = getTileIdx(); CBlkInfo rcb; // requested code-block int r = sb.resLvl; // Resolution level int s = sb.sbandIdx; // Subband index int tpidx; int passtype; // Number of layers int numLayers = ((Integer)decSpec.nls.getTileDef(t)).intValue(); int options = ((Integer)decSpec.ecopts.getTileCompVal(t,c)).intValue(); if(nl<0) { nl = numLayers-fl+1; } // If the l quit condition is used, Make sure that no layer // after lquit is returned if(lQuit != -1 && fl+nl>lQuit){ nl = lQuit - fl; } // Check validity of resquested resolution level (according to the // "-res" option). int maxdl = getSynSubbandTree(t,c).resLvl; /* XXX Suppress error check for speed performance reasons. if(r>targetRes+maxdl-decSpec.dls.getMin()) { throw new Error("JJ2000 error: requesting a code-block "+ "disallowed by the '-res' option."); } */ // Check validity of all the arguments try { rcb = cbI[c][r][s][m][n]; if(fl<1 || fl>numLayers || fl+nl-1>numLayers) { throw new IllegalArgumentException(); } } catch(ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("Code-block (t:"+t+", c:"+ c+", r:"+r+", s:"+s+", "+m+"x"+ +n+") not found in codestream"); } catch(NullPointerException e) { throw new IllegalArgumentException("Code-block (t:"+t+", c:"+ c+", r:"+r+", s:"+s+", "+m+"x" +n+") not found in bit stream"); } // Create DecLyrdCBlk object if necessary if(ccb==null) { ccb = new DecLyrdCBlk(); } ccb.m = m; ccb.n = n; ccb.nl = 0; ccb.dl = 0; ccb.nTrunc = 0; if(rcb==null) { // This code-block was skipped when reading. Returns no data ccb.skipMSBP = 0; ccb.prog = false; ccb.w = ccb.h = ccb.ulx = ccb.uly = 0; return ccb; } // ccb initialization ccb.skipMSBP = rcb.msbSkipped; ccb.ulx = rcb.ulx; ccb.uly = rcb.uly; ccb.w = rcb.w; ccb.h = rcb.h; ccb.ftpIdx = 0; // Search for index of first truncation point (first layer where // length of data is not zero) int l=0; while( (l= FIRST_BYPASS_PASS_IDX-1) { passtype = (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES; if (passtype == 1 || passtype == 2) { // lazy pass just before MQ pass or MQ pass just // before lazy pass => terminated nts++; } } } } } else { // Nothing special in use, just one terminated segment nts = 1; } // ccb.data creation if(ccb.data==null || ccb.data.length1 && (ccb.tsLengths==null || ccb.tsLengths.length1 && (options & (OPT_BYPASS|OPT_TERM_PASS)) == OPT_BYPASS) { ArrayUtil.intArraySet(ccb.tsLengths,0); } // Fill ccb with compressed data int dataIdx = -1; tpidx = ccb.ftpIdx; int ctp = ccb.ftpIdx; // Cumulative number of truncation // point for the current layer layer int tsidx=0; int j; for(l=fl-1; l each pass is terminated for(j=0; tpidx=FIRST_BYPASS_PASS_IDX-1) { passtype = (tpidx+NUM_EMPTY_PASSES_IN_MS_BP)%NUM_PASSES; if(passtype!=0) { // lazy pass just before MQ pass or MQ // pass just before lazy pass => // terminated if(rcb.segLen[l]!=null) { ccb.tsLengths[tsidx++] += rcb.segLen[l][j++]; rcb.len[l] -= rcb.segLen[l][j-1]; } else { // Only one terminated segment in packet ccb.tsLengths[tsidx++] += rcb.len[l]; rcb.len[l] = 0; } } } } // Last length in packet always in (either terminated segment // or contribution to terminated segment) if(rcb.segLen[l]!=null && j




© 2015 - 2024 Weber Informatics LLC | Privacy Policy