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