001/* 002 * $RCSfile: PostCompRateAllocator.java,v $ 003 * $Revision: 1.1 $ 004 * $Date: 2005/02/11 05:02:09 $ 005 * $State: Exp $ 006 * 007 * Class: PostCompRateAllocator 008 * 009 * Description: Generic interface for post-compression 010 * rate allocator. 011 * 012 * 013 * 014 * COPYRIGHT: 015 * 016 * This software module was originally developed by Raphaël Grosbois and 017 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel 018 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David 019 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research 020 * Centre France S.A) in the course of development of the JPEG2000 021 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This 022 * software module is an implementation of a part of the JPEG 2000 023 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio 024 * Systems AB and Canon Research Centre France S.A (collectively JJ2000 025 * Partners) agree not to assert against ISO/IEC and users of the JPEG 026 * 2000 Standard (Users) any of their rights under the copyright, not 027 * including other intellectual property rights, for this software module 028 * with respect to the usage by ISO/IEC and Users of this software module 029 * or modifications thereof for use in hardware or software products 030 * claiming conformance to the JPEG 2000 Standard. Those intending to use 031 * this software module in hardware or software products are advised that 032 * their use may infringe existing patents. The original developers of 033 * this software module, JJ2000 Partners and ISO/IEC assume no liability 034 * for use of this software module or modifications thereof. No license 035 * or right to this software module is granted for non JPEG 2000 Standard 036 * conforming products. JJ2000 Partners have full right to use this 037 * software module for his/her own purpose, assign or donate this 038 * software module to any third party and to inhibit third parties from 039 * using this software module for non JPEG 2000 Standard conforming 040 * products. This copyright notice must be included in all copies or 041 * derivative works of this software module. 042 * 043 * Copyright (c) 1999/2000 JJ2000 Partners. 044 * */ 045package jj2000.j2k.entropy.encoder; 046 047import jj2000.j2k.codestream.writer.*; 048import jj2000.j2k.wavelet.analysis.*; 049import jj2000.j2k.codestream.*; 050import jj2000.j2k.entropy.*; 051import jj2000.j2k.image.*; 052import jj2000.j2k.util.*; 053import jj2000.j2k.*; 054 055import java.io.*; 056 057import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava; 058/** 059 * This is the abstract class from which post-compression rate allocators 060 * which generate layers should inherit. The source of data is a 061 * 'CodedCBlkDataSrcEnc' which delivers entropy coded blocks with 062 * rate-distortion statistics. 063 * 064 * <P>The post compression rate allocator implementation should create the 065 * layers, according to a rate allocation policy, and send the packets to a 066 * CodestreamWriter. Since the rate allocator sends the packets to the bit 067 * stream then it should output the packets to the bit stream in the order 068 * imposed by the bit stream profiles. 069 * 070 * @see CodedCBlkDataSrcEnc 071 * 072 * @see jj2000.j2k.codestream.writer.CodestreamWriter 073 * */ 074public abstract class PostCompRateAllocator extends ImgDataAdapter { 075 076 /** The prefix for rate allocation options: 'A' */ 077 public final static char OPT_PREFIX = 'A'; 078 079 /** The list of parameters that is accepted for entropy coding. Options 080 * for entropy coding start with 'R'. */ 081 private final static String [][] pinfo = { 082 { "Aptype", "[<tile idx>] res|layer|res-pos|"+ 083 "pos-comp|comp-pos [res_start comp_start layer_end res_end "+ 084 "comp_end "+ 085 "prog] [[res_start comp_start ly_end res_end comp_end prog] ...] ["+ 086 "[<tile-component idx>] ...]", 087 "Specifies which type of progression should be used when "+ 088 "generating "+ 089 "the codestream. The 'res' value generates a resolution "+ 090 "progressive codestream with the number of layers specified by "+ 091 "'Alayers' option. The 'layer' value generates a layer progressive "+ 092 "codestream with multiple layers. In any case the rate-allocation "+ 093 "algorithm optimizes for best quality in each layer. The quality "+ 094 "measure is mean squared error (MSE) or a weighted version of it "+ 095 "(WMSE). If no progression type is specified or imposed by other "+ 096 "modules, the default value is 'layer'.\n"+ 097 "It is also possible to describe progression order changes. In "+ 098 "this case, 'res_start' is the index (from 0) of the first "+ 099 "resolution "+ 100 "level, 'comp_start' is the index (from 0) of the first component, "+ 101 "'ly_end' is the index (from 0) of the first layer not included, "+ 102 "'res_end' is the index (from 0) of the first resolution level not "+ 103 "included, 'comp_end' is index (from 0) of the first component not "+ 104 "included and 'prog' is the progression type to be used "+ 105 "for the rest of the tile/image. Several progression order changes "+ 106 "can be specified, one after the other." 107 , null}, 108 { "Alayers", "<rate> [+<layers>] [<rate [+<layers>] [...]]", 109 "Explicitly specifies the codestream layer formation parameters. "+ 110 "The <rate> parameter specifies the bitrate to which the first "+ 111 "layer should be optimized. The <layers> parameter, if present, "+ 112 "specifies the number of extra layers that should be added for "+ 113 "scalability. These extra layers are not optimized. "+ 114 "Any extra <rate> and <layers> parameters add more layers, in the "+ 115 "same way. An additional layer is always added at the end, which"+ 116 " is "+ 117 "optimized to the overall target bitrate of the bit stream. Any "+ 118 "layers (optimized or not) whose target bitrate is higher that the "+ 119 "overall target bitrate are silently ignored. The bitrates of the "+ 120 "extra layers that are added through the <layers> parameter are "+ 121 "approximately log-spaced between the other target bitrates. If "+ 122 "several <rate> [+<layers>] constructs appear the <rate>"+ 123 " parameters "+ 124 "must appear in increasing order. The rate allocation algorithm "+ 125 "ensures that all coded layers have a minimal reasonable size, if "+ 126 "not these layers are silently ignored.","0.015 +20 2.0 +10"} 127 }; 128 129 /** The source of entropy coded data */ 130 protected CodedCBlkDataSrcEnc src; 131 132 /** The source of entropy coded data */ 133 protected J2KImageWriteParamJava wp; 134 135 /** The number of layers. */ 136 protected int numLayers; 137 138 /** The bit-stream writer */ 139 CodestreamWriter bsWriter; 140 141 /** The header encoder */ 142 HeaderEncoder headEnc; 143 144 /** 145 * Initializes the source of entropy coded data. 146 * 147 * @param src The source of entropy coded data. 148 * 149 * @param ln The number of layers to create 150 * 151 * @param pt The Progression type, as defined in 'ProgressionType'. 152 * 153 * @param bw The packet bit stream writer. 154 * 155 * @see ProgressionType 156 * */ 157 public PostCompRateAllocator(CodedCBlkDataSrcEnc src, int nl, 158 CodestreamWriter bw, J2KImageWriteParamJava wp) { 159 super(src); 160 this.src = src; 161 this.wp = wp; 162 numLayers = nl; 163 bsWriter = bw; 164 } 165 166 /** 167 * Keep a reference to the header encoder. 168 * 169 * @param headEnc The header encoder 170 * */ 171 public void setHeaderEncoder(HeaderEncoder headEnc){ 172 this.headEnc = headEnc; 173 } 174 175 /** 176 * Initializes the rate allocation points, taking into account header 177 * overhead and such. This method must be called after the header has been 178 * simulated but before calling the runAndWrite() one. The header must be 179 * rewritten after a call to this method since the number of layers may 180 * change. 181 * 182 * @param oldSyntax Whether or not the old syntax is used. 183 * 184 * @see #runAndWrite 185 * */ 186 public abstract void initialize() throws IOException; 187 188 /** 189 * Runs the rate allocation algorithm and writes the data to the 190 * bit stream. This must be called after the initialize() method. 191 * 192 * @see #initialize 193 * */ 194 public abstract void runAndWrite() throws IOException; 195 196 /** 197 * Returns the number of layers that are actually generated. 198 * 199 * @return The number of layers generated. 200 * */ 201 public int getNumLayers() { 202 return numLayers; 203 } 204 205 /** 206 * Returns the parameters that are used in this class and implementing 207 * classes. It returns a 2D String array. Each of the 1D arrays is for a 208 * different option, and they have 3 elements. The first element is the 209 * option name, the second one is the synopsis, the third one is a long 210 * description of what the parameter is and the fourth is its default 211 * value. The synopsis or description may be 'null', in which case it is 212 * assumed that there is no synopsis or description of the option, 213 * respectively. Null may be returned if no options are supported. 214 * 215 * @return the options name, their synopsis and their explanation, 216 * or null if no options are supported. 217 * */ 218 public static String[][] getParameterInfo() { 219 return pinfo; 220 } 221 222 /** 223 * Creates a PostCompRateAllocator object for the appropriate rate 224 * allocation parameters in the parameter list 'pl', having 'src' as the 225 * source of entropy coded data, 'rate' as the target bitrate and 'bw' as 226 * the bit stream writer object. 227 * 228 * @param src The source of entropy coded data. 229 * 230 * @param pl The parameter lis (or options). 231 * 232 * @param rate The target bitrate for the rate allocation 233 * 234 * @param bw The bit stream writer object, where the bit stream data will 235 * be written. 236 * */ 237 public static PostCompRateAllocator createInstance(CodedCBlkDataSrcEnc src, 238 float rate, 239 CodestreamWriter bw, 240 J2KImageWriteParamJava wp){ 241 String lyropt = wp.getLayers(); 242 if (lyropt == null) { 243 if(wp.getROIs().getSpecified() == null) { 244 lyropt = "res"; 245 } 246 else { 247 lyropt = "layer"; 248 } 249 } 250 251 // Construct the layer specification from the Alayers option 252 LayersInfo lyrs = parseAlayers(lyropt,rate); 253 254 int nTiles = wp.getNumTiles(); 255 int nComp = wp.getNumComponents(); 256 int numLayers = lyrs.getTotNumLayers(); 257 258 // Parse the Progression type 259 wp.setProgressionType(lyrs, wp.getProgressionName()); 260 261 return new EBCOTRateAllocator(src,lyrs,bw,wp); 262 } 263 264 /** 265 * Convenience method that parses the 'Alayers' option. 266 * 267 * @param params The parameters of the 'Alayers' option 268 * 269 * @param rate The overall target bitrate 270 * 271 * @return The layer specification. 272 * */ 273 private static LayersInfo parseAlayers(String params, float rate) { 274 LayersInfo lyrs; 275 StreamTokenizer stok; 276 boolean islayer,ratepending; 277 float r; 278 279 lyrs = new LayersInfo(rate); 280 stok = new StreamTokenizer(new StringReader(params)); 281 stok.eolIsSignificant(false); 282 283 try { 284 stok.nextToken(); 285 } 286 catch (IOException e) { 287 throw new Error("An IOException has ocurred where it "+ 288 "should never occur"); 289 } 290 ratepending = false; 291 islayer = false; 292 r = 0; // to keep compiler happy 293 while (stok.ttype != stok.TT_EOF) { 294 switch(stok.ttype) { 295 case StreamTokenizer.TT_NUMBER: 296 if (islayer) { // layer parameter 297 try { 298 lyrs.addOptPoint(r,(int)stok.nval); 299 } 300 catch (IllegalArgumentException e) { 301 throw new 302 IllegalArgumentException("Error in 'Alayers' "+ 303 "option: "+e.getMessage()); 304 } 305 ratepending = false; 306 islayer = false; 307 } 308 else { // rate parameter 309 if (ratepending) { // Add pending rate parameter 310 try { 311 lyrs.addOptPoint(r,0); 312 } 313 catch (IllegalArgumentException e) { 314 throw new 315 IllegalArgumentException("Error in 'Alayers' "+ 316 "option: "+ 317 e.getMessage()); 318 } 319 } 320 // Now store new rate parameter 321 r = (float) stok.nval; 322 ratepending = true; 323 } 324 break; 325 case '+': 326 if (!ratepending || islayer) { 327 throw new 328 IllegalArgumentException("Layer parameter without "+ 329 "previous rate parameter "+ 330 "in 'Alayers' option"); 331 } 332 islayer = true; // Next number is layer parameter 333 break; 334 case StreamTokenizer.TT_WORD: 335 try { 336 stok.nextToken(); 337 } catch(IOException e) { 338 throw new Error("An IOException has ocurred where it "+ 339 "should never occur"); 340 } 341 if (stok.ttype != stok.TT_EOF) { 342 throw new 343 IllegalArgumentException("'sl' argument of "+ 344 "'-Alayers' option must be "+ 345 "used alone."); 346 } 347 break; 348 default: 349 throw new IllegalArgumentException("Error parsing 'Alayers' "+ 350 "option"); 351 } 352 try { 353 stok.nextToken(); 354 } 355 catch (IOException e) { 356 throw new Error("An IOException has ocurred where it "+ 357 "should never occur"); 358 } 359 } 360 if (islayer) { 361 throw new IllegalArgumentException("Error parsing 'Alayers' "+ 362 "option"); 363 } 364 if (ratepending) { 365 try { 366 lyrs.addOptPoint(r,0); 367 } 368 catch (IllegalArgumentException e) { 369 throw new 370 IllegalArgumentException("Error in 'Alayers' "+ 371 "option: "+ 372 e.getMessage()); 373 } 374 } 375 return lyrs; 376 } 377 378}