corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * CVS identifier: |
||
3 | * |
||
4 | * $Id: EBCOTRateAllocator.java,v 1.97 2002/05/22 14:59:44 grosbois Exp $ |
||
5 | * |
||
6 | * Class: EBCOTRateAllocator |
||
7 | * |
||
8 | * Description: Generic interface for post-compression |
||
9 | * rate allocator. |
||
10 | * |
||
11 | * |
||
12 | * |
||
13 | * COPYRIGHT: |
||
14 | * |
||
15 | * This software module was originally developed by Raphaël Grosbois and |
||
16 | * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel |
||
17 | * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David |
||
18 | * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research |
||
19 | * Centre France S.A) in the course of development of the JPEG2000 |
||
20 | * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This |
||
21 | * software module is an implementation of a part of the JPEG 2000 |
||
22 | * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio |
||
23 | * Systems AB and Canon Research Centre France S.A (collectively JJ2000 |
||
24 | * Partners) agree not to assert against ISO/IEC and users of the JPEG |
||
25 | * 2000 Standard (Users) any of their rights under the copyright, not |
||
26 | * including other intellectual property rights, for this software module |
||
27 | * with respect to the usage by ISO/IEC and Users of this software module |
||
28 | * or modifications thereof for use in hardware or software products |
||
29 | * claiming conformance to the JPEG 2000 Standard. Those intending to use |
||
30 | * this software module in hardware or software products are advised that |
||
31 | * their use may infringe existing patents. The original developers of |
||
32 | * this software module, JJ2000 Partners and ISO/IEC assume no liability |
||
33 | * for use of this software module or modifications thereof. No license |
||
34 | * or right to this software module is granted for non JPEG 2000 Standard |
||
35 | * conforming products. JJ2000 Partners have full right to use this |
||
36 | * software module for his/her own purpose, assign or donate this |
||
37 | * software module to any third party and to inhibit third parties from |
||
38 | * using this software module for non JPEG 2000 Standard conforming |
||
39 | * products. This copyright notice must be included in all copies or |
||
40 | * derivative works of this software module. |
||
41 | * |
||
42 | * Copyright (c) 1999/2000 JJ2000 Partners. |
||
43 | * */ |
||
44 | using System; |
||
45 | using CSJ2K.j2k.codestream.writer; |
||
46 | using CSJ2K.j2k.wavelet.analysis; |
||
47 | using CSJ2K.j2k.entropy.encoder; |
||
48 | using CSJ2K.j2k.codestream; |
||
49 | using CSJ2K.j2k.entropy; |
||
50 | using CSJ2K.j2k.encoder; |
||
51 | using CSJ2K.j2k.image; |
||
52 | using CSJ2K.j2k.util; |
||
53 | namespace CSJ2K.j2k.entropy.encoder |
||
54 | { |
||
55 | |||
56 | /// <summary> This implements the EBCOT post compression rate allocation algorithm. This |
||
57 | /// algorithm finds the most suitable truncation points for the set of |
||
58 | /// code-blocks, for each layer target bitrate. It works by first collecting |
||
59 | /// the rate distortion info from all code-blocks, in all tiles and all |
||
60 | /// components, and then running the rate-allocation on the whole image at |
||
61 | /// once, for each layer. |
||
62 | /// |
||
63 | /// <p>This implementation also provides some timing features. They can be |
||
64 | /// enabled by setting the 'DO_TIMING' constant of this class to true and |
||
65 | /// recompiling. The timing uses the 'System.currentTimeMillis()' Java API |
||
66 | /// call, which returns wall clock time, not the actual CPU time used. The |
||
67 | /// timing results will be printed on the message output. Since the times |
||
68 | /// reported are wall clock times and not CPU usage times they can not be added |
||
69 | /// to find the total used time (i.e. some time might be counted in several |
||
70 | /// places). When timing is disabled ('DO_TIMING' is false) there is no penalty |
||
71 | /// if the compiler performs some basic optimizations. Even if not the penalty |
||
72 | /// should be negligeable.</p> |
||
73 | /// |
||
74 | /// </summary> |
||
75 | /// <seealso cref="PostCompRateAllocator"> |
||
76 | /// </seealso> |
||
77 | /// <seealso cref="CodedCBlkDataSrcEnc"> |
||
78 | /// </seealso> |
||
79 | /// <seealso cref="jj2000.j2k.codestream.writer.CodestreamWriter"> |
||
80 | /// |
||
81 | /// </seealso> |
||
82 | public class EBCOTRateAllocator:PostCompRateAllocator |
||
83 | { |
||
84 | |||
85 | /// <summary>Whether to collect timing information or not: false. Used as a compile |
||
86 | /// time directive. |
||
87 | /// </summary> |
||
88 | |||
89 | #if DO_TIMING |
||
90 | /// <summary>The wall time for the initialization. </summary> |
||
91 | //private long initTime; |
||
92 | |||
93 | /// <summary>The wall time for the building of layers. </summary> |
||
94 | //private long buildTime; |
||
95 | |||
96 | /// <summary>The wall time for the writing of layers. </summary> |
||
97 | //private long writeTime; |
||
98 | #endif |
||
99 | |||
100 | /// <summary> 5D Array containing all the coded code-blocks: |
||
101 | /// |
||
102 | /// <ul> |
||
103 | /// <li>1st index: tile index</li> |
||
104 | /// <li>2nd index: component index</li> |
||
105 | /// <li>3rd index: resolution level index</li> |
||
106 | /// <li>4th index: subband index</li> |
||
107 | /// <li>5th index: code-block index</li> |
||
108 | /// </ul> |
||
109 | /// |
||
110 | /// </summary> |
||
111 | private CBlkRateDistStats[][][][][] cblks; |
||
112 | |||
113 | /// <summary> 6D Array containing the indices of the truncation points. It actually |
||
114 | /// contains the index of the element in CBlkRateDistStats.truncIdxs that |
||
115 | /// gives the real truncation point index. |
||
116 | /// |
||
117 | /// <ul> |
||
118 | /// <li>1st index: tile index</li> |
||
119 | /// <li>2nd index: layer index</li> |
||
120 | /// <li>3rd index: component index</li> |
||
121 | /// <li>4th index: resolution level index</li> |
||
122 | /// <li>5th index: subband index</li> |
||
123 | /// <li>6th index: code-block index</li> |
||
124 | /// </ul> |
||
125 | /// |
||
126 | /// </summary> |
||
127 | private int[][][][][][] truncIdxs; |
||
128 | |||
129 | /// <summary> Number of precincts in each resolution level: |
||
130 | /// |
||
131 | /// <ul> |
||
132 | /// <li>1st dim: tile index.</li> |
||
133 | /// <li>2nd dim: component index.</li> |
||
134 | /// <li>3nd dim: resolution level index.</li> |
||
135 | /// </ul> |
||
136 | /// |
||
137 | /// </summary> |
||
138 | private Coord[][][] numPrec; |
||
139 | |||
140 | /// <summary>Array containing the layers information. </summary> |
||
141 | private EBCOTLayer[] layers; |
||
142 | |||
143 | /// <summary>The log of 2, natural base </summary> |
||
144 | //UPGRADE_NOTE: Final was removed from the declaration of 'LOG2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" |
||
145 | private static readonly double LOG2 = System.Math.Log(2); |
||
146 | |||
147 | /// <summary>The normalization offset for the R-D summary table </summary> |
||
148 | private const int RD_SUMMARY_OFF = 24; |
||
149 | |||
150 | /// <summary>The size of the summary table </summary> |
||
151 | private const int RD_SUMMARY_SIZE = 64; |
||
152 | |||
153 | /// <summary>The relative precision for float data. This is the relative tolerance |
||
154 | /// up to which the layer slope thresholds are calculated. |
||
155 | /// </summary> |
||
156 | private const float FLOAT_REL_PRECISION = 1e-4f; |
||
157 | |||
158 | /// <summary>The precision for float data type, in an absolute sense. Two float |
||
159 | /// numbers are considered "equal" if they are within this precision. |
||
160 | /// </summary> |
||
161 | private const float FLOAT_ABS_PRECISION = 1e-10f; |
||
162 | |||
163 | /// <summary>Minimum average size of a packet. If layer has less bytes than the |
||
164 | /// this constant multiplied by number of packets in the layer, then the |
||
165 | /// layer is skipped. |
||
166 | /// </summary> |
||
167 | private const int MIN_AVG_PACKET_SZ = 32; |
||
168 | |||
169 | /// <summary>The R-D summary information collected from the coding of all |
||
170 | /// code-blocks. For each entry it contains the accumulated length of all |
||
171 | /// truncation points that have a slope not less than |
||
172 | /// '2*(k-RD_SUMMARY_OFF)', where 'k' is the entry index. |
||
173 | /// |
||
174 | /// <p>Therefore, the length at entry 'k' is the total number of bytes of |
||
175 | /// code-block data that would be obtained if the truncation slope was |
||
176 | /// chosen as '2*(k-RD_SUMMARY_OFF)', without counting the overhead |
||
177 | /// associated with the packet heads.</p> |
||
178 | /// |
||
179 | /// <p>This summary is used to estimate the relation of the R-D slope to |
||
180 | /// coded length, and to obtain absolute minimums on the slope given a |
||
181 | /// length. </p> |
||
182 | /// </summary> |
||
183 | private int[] RDSlopesRates; |
||
184 | |||
185 | /// <summary>Packet encoder. </summary> |
||
186 | private PktEncoder pktEnc; |
||
187 | |||
188 | /// <summary>The layer specifications </summary> |
||
189 | private LayersInfo lyrSpec; |
||
190 | |||
191 | /// <summary>The maximum slope accross all code-blocks and truncation points. </summary> |
||
192 | private float maxSlope; |
||
193 | |||
194 | /// <summary>The minimum slope accross all code-blocks and truncation points. </summary> |
||
195 | private float minSlope; |
||
196 | |||
197 | /// <summary> Initializes the EBCOT rate allocator of entropy coded data. The layout |
||
198 | /// of layers, and their bitrate constraints, is specified by the 'lyrs' |
||
199 | /// parameter. |
||
200 | /// |
||
201 | /// </summary> |
||
202 | /// <param name="src">The source of entropy coded data. |
||
203 | /// |
||
204 | /// </param> |
||
205 | /// <param name="lyrs">The layers layout specification. |
||
206 | /// |
||
207 | /// </param> |
||
208 | /// <param name="writer">The bit stream writer. |
||
209 | /// |
||
210 | /// </param> |
||
211 | /// <seealso cref="ProgressionType"> |
||
212 | /// |
||
213 | /// </seealso> |
||
214 | public EBCOTRateAllocator(CodedCBlkDataSrcEnc src, LayersInfo lyrs, CodestreamWriter writer, EncoderSpecs encSpec, ParameterList pl):base(src, lyrs.TotNumLayers, writer, encSpec) |
||
215 | { |
||
216 | |||
217 | int minsbi, maxsbi; |
||
218 | int i; |
||
219 | SubbandAn sb, sb2; |
||
220 | Coord ncblks = null; |
||
221 | |||
222 | // If we do timing create necessary structures |
||
223 | #if DO_TIMING |
||
224 | // If we are timing make sure that 'finalize' gets called. |
||
225 | //UPGRADE_ISSUE: Method 'java.lang.System.runFinalizersOnExit' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangSystem'" |
||
226 | // CONVERSION PROBLEM? |
||
227 | //System_Renamed.runFinalizersOnExit(true); |
||
228 | // The System.runFinalizersOnExit() method is deprecated in Java |
||
229 | // 1.2 since it can cause a deadlock in some cases. However, here |
||
230 | // we use it only for profiling purposes and is disabled in |
||
231 | // production code. |
||
232 | initTime = 0L; |
||
233 | buildTime = 0L; |
||
234 | writeTime = 0L; |
||
235 | #endif |
||
236 | |||
237 | // Save the layer specs |
||
238 | lyrSpec = lyrs; |
||
239 | |||
240 | //Initialize the size of the RD slope rates array |
||
241 | RDSlopesRates = new int[RD_SUMMARY_SIZE]; |
||
242 | |||
243 | //Get number of tiles, components |
||
244 | int nt = src.getNumTiles(); |
||
245 | int nc = NumComps; |
||
246 | |||
247 | //Allocate the coded code-blocks and truncation points indexes arrays |
||
248 | cblks = new CBlkRateDistStats[nt][][][][]; |
||
249 | for (int i2 = 0; i2 < nt; i2++) |
||
250 | { |
||
251 | cblks[i2] = new CBlkRateDistStats[nc][][][]; |
||
252 | } |
||
253 | truncIdxs = new int[nt][][][][][]; |
||
254 | for (int i3 = 0; i3 < nt; i3++) |
||
255 | { |
||
256 | truncIdxs[i3] = new int[num_Layers][][][][]; |
||
257 | for (int i4 = 0; i4 < num_Layers; i4++) |
||
258 | { |
||
259 | truncIdxs[i3][i4] = new int[nc][][][]; |
||
260 | } |
||
261 | } |
||
262 | |||
263 | int cblkPerSubband; // Number of code-blocks per subband |
||
264 | int mrl; // Number of resolution levels |
||
265 | int l; // layer index |
||
266 | int s; //subband index |
||
267 | |||
268 | // Used to compute the maximum number of precincts for each resolution |
||
269 | // level |
||
270 | int tx0, ty0, tx1, ty1; // Current tile position in the reference grid |
||
271 | int tcx0, tcy0, tcx1, tcy1; // Current tile position in the domain of |
||
272 | // the image component |
||
273 | int trx0, try0, trx1, try1; // Current tile position in the reduced |
||
274 | // resolution image domain |
||
275 | int xrsiz, yrsiz; // Component sub-sampling factors |
||
276 | Coord tileI = null; |
||
277 | Coord nTiles = null; |
||
278 | int xsiz, ysiz, x0siz, y0siz; |
||
279 | int xt0siz, yt0siz; |
||
280 | int xtsiz, ytsiz; |
||
281 | |||
282 | int cb0x = src.CbULX; |
||
283 | int cb0y = src.CbULY; |
||
284 | |||
285 | src.setTile(0, 0); |
||
286 | for (int t = 0; t < nt; t++) |
||
287 | { |
||
288 | // Loop on tiles |
||
289 | nTiles = src.getNumTiles(nTiles); |
||
290 | tileI = src.getTile(tileI); |
||
291 | x0siz = ImgULX; |
||
292 | y0siz = ImgULY; |
||
293 | xsiz = x0siz + ImgWidth; |
||
294 | ysiz = y0siz + ImgHeight; |
||
295 | xt0siz = src.TilePartULX; |
||
296 | yt0siz = src.TilePartULY; |
||
297 | xtsiz = src.NomTileWidth; |
||
298 | ytsiz = src.NomTileHeight; |
||
299 | |||
300 | // Tile's coordinates on the reference grid |
||
301 | tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; |
||
302 | ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; |
||
303 | tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; |
||
304 | ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; |
||
305 | |||
306 | for (int c = 0; c < nc; c++) |
||
307 | { |
||
308 | // loop on components |
||
309 | |||
310 | //Get the number of resolution levels |
||
311 | sb = src.getAnSubbandTree(t, c); |
||
312 | mrl = sb.resLvl + 1; |
||
313 | |||
314 | // Initialize maximum number of precincts per resolution array |
||
315 | if (numPrec == null) |
||
316 | { |
||
317 | Coord[][][] tmpArray = new Coord[nt][][]; |
||
318 | for (int i5 = 0; i5 < nt; i5++) |
||
319 | { |
||
320 | tmpArray[i5] = new Coord[nc][]; |
||
321 | } |
||
322 | numPrec = tmpArray; |
||
323 | } |
||
324 | if (numPrec[t][c] == null) |
||
325 | { |
||
326 | numPrec[t][c] = new Coord[mrl]; |
||
327 | } |
||
328 | |||
329 | // Subsampling factors |
||
330 | xrsiz = src.getCompSubsX(c); |
||
331 | yrsiz = src.getCompSubsY(c); |
||
332 | |||
333 | // Tile's coordinates in the image component domain |
||
334 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
335 | tcx0 = (int) System.Math.Ceiling(tx0 / (double) (xrsiz)); |
||
336 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
337 | tcy0 = (int) System.Math.Ceiling(ty0 / (double) (yrsiz)); |
||
338 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
339 | tcx1 = (int) System.Math.Ceiling(tx1 / (double) (xrsiz)); |
||
340 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
341 | tcy1 = (int) System.Math.Ceiling(ty1 / (double) (yrsiz)); |
||
342 | |||
343 | cblks[t][c] = new CBlkRateDistStats[mrl][][]; |
||
344 | |||
345 | for (l = 0; l < num_Layers; l++) |
||
346 | { |
||
347 | truncIdxs[t][l][c] = new int[mrl][][]; |
||
348 | } |
||
349 | |||
350 | for (int r = 0; r < mrl; r++) |
||
351 | { |
||
352 | // loop on resolution levels |
||
353 | |||
354 | // Tile's coordinates in the reduced resolution image |
||
355 | // domain |
||
356 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
357 | trx0 = (int) System.Math.Ceiling(tcx0 / (double) (1 << (mrl - 1 - r))); |
||
358 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
359 | try0 = (int) System.Math.Ceiling(tcy0 / (double) (1 << (mrl - 1 - r))); |
||
360 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
361 | trx1 = (int) System.Math.Ceiling(tcx1 / (double) (1 << (mrl - 1 - r))); |
||
362 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
363 | try1 = (int) System.Math.Ceiling(tcy1 / (double) (1 << (mrl - 1 - r))); |
||
364 | |||
365 | // Calculate the maximum number of precincts for each |
||
366 | // resolution level taking into account tile specific |
||
367 | // options. |
||
368 | double twoppx = (double) encSpec.pss.getPPX(t, c, r); |
||
369 | double twoppy = (double) encSpec.pss.getPPY(t, c, r); |
||
370 | numPrec[t][c][r] = new Coord(); |
||
371 | if (trx1 > trx0) |
||
372 | { |
||
373 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
374 | numPrec[t][c][r].x = (int) System.Math.Ceiling((trx1 - cb0x) / twoppx) - (int) System.Math.Floor((trx0 - cb0x) / twoppx); |
||
375 | } |
||
376 | else |
||
377 | { |
||
378 | numPrec[t][c][r].x = 0; |
||
379 | } |
||
380 | if (try1 > try0) |
||
381 | { |
||
382 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
383 | numPrec[t][c][r].y = (int) System.Math.Ceiling((try1 - cb0y) / twoppy) - (int) System.Math.Floor((try0 - cb0y) / (double) twoppy); |
||
384 | } |
||
385 | else |
||
386 | { |
||
387 | numPrec[t][c][r].y = 0; |
||
388 | } |
||
389 | |||
390 | minsbi = (r == 0)?0:1; |
||
391 | maxsbi = (r == 0)?1:4; |
||
392 | |||
393 | cblks[t][c][r] = new CBlkRateDistStats[maxsbi][]; |
||
394 | for (l = 0; l < num_Layers; l++) |
||
395 | { |
||
396 | truncIdxs[t][l][c][r] = new int[maxsbi][]; |
||
397 | } |
||
398 | |||
399 | for (s = minsbi; s < maxsbi; s++) |
||
400 | { |
||
401 | // loop on subbands |
||
402 | //Get the number of blocks in the current subband |
||
403 | sb2 = (SubbandAn) sb.getSubbandByIdx(r, s); |
||
404 | ncblks = sb2.numCb; |
||
405 | cblkPerSubband = ncblks.x * ncblks.y; |
||
406 | cblks[t][c][r][s] = new CBlkRateDistStats[cblkPerSubband]; |
||
407 | |||
408 | for (l = 0; l < num_Layers; l++) |
||
409 | { |
||
410 | truncIdxs[t][l][c][r][s] = new int[cblkPerSubband]; |
||
411 | for (i = 0; i < cblkPerSubband; i++) |
||
412 | { |
||
413 | truncIdxs[t][l][c][r][s][i] = - 1; |
||
414 | } |
||
415 | } |
||
416 | } // End loop on subbands |
||
417 | } // End lopp on resolution levels |
||
418 | } // End loop on components |
||
419 | if (t != nt - 1) |
||
420 | { |
||
421 | src.nextTile(); |
||
422 | } |
||
423 | } // End loop on tiles |
||
424 | |||
425 | //Initialize the packet encoder |
||
426 | pktEnc = new PktEncoder(src, encSpec, numPrec, pl); |
||
427 | |||
428 | // The layers array has to be initialized after the constructor since |
||
429 | // it is needed that the bit stream header has been entirely written |
||
430 | } |
||
431 | |||
432 | #if DO_TIMING |
||
433 | /// <summary> Prints the timing information, if collected, and calls 'finalize' on |
||
434 | /// the super class. |
||
435 | /// |
||
436 | /// </summary> |
||
437 | ~EBCOTRateAllocator() |
||
438 | { |
||
439 | |||
440 | System.Text.StringBuilder sb; |
||
441 | |||
442 | sb = new System.Text.StringBuilder("EBCOTRateAllocator wall clock times:\n"); |
||
443 | sb.Append(" initialization: "); |
||
444 | sb.Append(initTime); |
||
445 | sb.Append(" ms\n"); |
||
446 | sb.Append(" layer building: "); |
||
447 | sb.Append(buildTime); |
||
448 | sb.Append(" ms\n"); |
||
449 | sb.Append(" final writing: "); |
||
450 | sb.Append(writeTime); |
||
451 | sb.Append(" ms"); |
||
452 | FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.INFO, sb.ToString()); |
||
453 | //UPGRADE_NOTE: Call to 'super.finalize()' was removed. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1124'" |
||
454 | } |
||
455 | #endif |
||
456 | /// <summary> Runs the rate allocation algorithm and writes the data to the bit |
||
457 | /// stream writer object provided to the constructor. |
||
458 | /// |
||
459 | /// </summary> |
||
460 | public override void runAndWrite() |
||
461 | { |
||
462 | //Now, run the rate allocation |
||
463 | buildAndWriteLayers(); |
||
464 | } |
||
465 | |||
466 | /// <summary> Initializes the layers array. This must be called after the main header |
||
467 | /// has been entirely written or simulated, so as to take its overhead into |
||
468 | /// account. This method will get all the code-blocks and then initialize |
||
469 | /// the target bitrates for each layer, according to the specifications. |
||
470 | /// |
||
471 | /// </summary> |
||
472 | public override void initialize() |
||
473 | { |
||
474 | int n, i, l; |
||
475 | int ho; // The header overhead (in bytes) |
||
476 | float np; // The number of pixels divided by the number of bits per byte |
||
477 | double ls; // Step for log-scale |
||
478 | double basebytes; |
||
479 | int lastbytes, newbytes, nextbytes; |
||
480 | int loopnlyrs; |
||
481 | int minlsz; // The minimum allowable number of bytes in a layer |
||
482 | int totenclength; |
||
483 | int maxpkt; |
||
484 | int numTiles = src.getNumTiles(); |
||
485 | int numComps = src.NumComps; |
||
486 | int numLvls; |
||
487 | int avgPktLen; |
||
488 | #if DO_TIMING |
||
489 | long stime = 0L; |
||
490 | #endif |
||
491 | // Start by getting all the code-blocks, we need this in order to have |
||
492 | // an idea of the total encoded bitrate. |
||
493 | getAllCodeBlocks(); |
||
494 | |||
495 | #if DO_TIMING |
||
496 | stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; |
||
497 | #endif |
||
498 | |||
499 | // Now get the total encoded length |
||
500 | totenclength = RDSlopesRates[0]; // all the encoded data |
||
501 | // Make a rough estimation of the packet head overhead, as 2 bytes per |
||
502 | // packet in average (plus EPH / SOP) , and add that to the total |
||
503 | // encoded length |
||
504 | for (int t = 0; t < numTiles; t++) |
||
505 | { |
||
506 | avgPktLen = 2; |
||
507 | // Add SOP length if set |
||
508 | if (((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper())) |
||
509 | { |
||
510 | avgPktLen += CSJ2K.j2k.codestream.Markers.SOP_LENGTH; |
||
511 | } |
||
512 | // Add EPH length if set |
||
513 | if (((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper())) |
||
514 | { |
||
515 | avgPktLen += CSJ2K.j2k.codestream.Markers.EPH_LENGTH; |
||
516 | } |
||
517 | |||
518 | for (int c = 0; c < numComps; c++) |
||
519 | { |
||
520 | numLvls = src.getAnSubbandTree(t, c).resLvl + 1; |
||
521 | if (!src.precinctPartitionUsed(c, t)) |
||
522 | { |
||
523 | // Precinct partition is not used so there is only |
||
524 | // one packet per resolution level/layer |
||
525 | totenclength += num_Layers * avgPktLen * numLvls; |
||
526 | } |
||
527 | else |
||
528 | { |
||
529 | // Precinct partition is used so for each |
||
530 | // component/tile/resolution level, we get the maximum |
||
531 | // number of packets |
||
532 | for (int rl = 0; rl < numLvls; rl++) |
||
533 | { |
||
534 | maxpkt = numPrec[t][c][rl].x * numPrec[t][c][rl].y; |
||
535 | totenclength += num_Layers * avgPktLen * maxpkt; |
||
536 | } |
||
537 | } |
||
538 | } // End loop on components |
||
539 | } // End loop on tiles |
||
540 | |||
541 | // If any layer specifies more than 'totenclength' as its target |
||
542 | // length then 'totenclength' is used. This is to prevent that |
||
543 | // estimated layers get excessively large target lengths due to an |
||
544 | // excessively large target bitrate. At the end the last layer is set |
||
545 | // to the target length corresponding to the overall target |
||
546 | // bitrate. Thus, 'totenclength' can not limit the total amount of |
||
547 | // encoded data, as intended. |
||
548 | |||
549 | ho = headEnc.Length; |
||
550 | np = src.ImgWidth * src.ImgHeight / 8f; |
||
551 | |||
552 | // SOT marker must be taken into account |
||
553 | for (int t = 0; t < numTiles; t++) |
||
554 | { |
||
555 | headEnc.reset(); |
||
556 | headEnc.encodeTilePartHeader(0, t); |
||
557 | ho += headEnc.Length; |
||
558 | } |
||
559 | |||
560 | layers = new EBCOTLayer[num_Layers]; |
||
561 | for (n = num_Layers - 1; n >= 0; n--) |
||
562 | { |
||
563 | layers[n] = new EBCOTLayer(); |
||
564 | } |
||
565 | |||
566 | minlsz = 0; // To keep compiler happy |
||
567 | for (int t = 0; t < numTiles; t++) |
||
568 | { |
||
569 | for (int c = 0; c < numComps; c++) |
||
570 | { |
||
571 | numLvls = src.getAnSubbandTree(t, c).resLvl + 1; |
||
572 | |||
573 | if (!src.precinctPartitionUsed(c, t)) |
||
574 | { |
||
575 | // Precinct partition is not used |
||
576 | minlsz += MIN_AVG_PACKET_SZ * numLvls; |
||
577 | } |
||
578 | else |
||
579 | { |
||
580 | // Precinct partition is used |
||
581 | for (int rl = 0; rl < numLvls; rl++) |
||
582 | { |
||
583 | maxpkt = numPrec[t][c][rl].x * numPrec[t][c][rl].y; |
||
584 | minlsz += MIN_AVG_PACKET_SZ * maxpkt; |
||
585 | } |
||
586 | } |
||
587 | } // End loop on components |
||
588 | } // End loop on tiles |
||
589 | |||
590 | // Initialize layers |
||
591 | n = 0; |
||
592 | i = 0; |
||
593 | lastbytes = 0; |
||
594 | |||
595 | while (n < num_Layers - 1) |
||
596 | { |
||
597 | // At an optimized layer |
||
598 | basebytes = System.Math.Floor(lyrSpec.getTargetBitrate(i) * np); |
||
599 | if (i < lyrSpec.NOptPoints - 1) |
||
600 | { |
||
601 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
602 | nextbytes = (int) (lyrSpec.getTargetBitrate(i + 1) * np); |
||
603 | // Limit target length to 'totenclength' |
||
604 | if (nextbytes > totenclength) |
||
605 | nextbytes = totenclength; |
||
606 | } |
||
607 | else |
||
608 | { |
||
609 | nextbytes = 1; |
||
610 | } |
||
611 | loopnlyrs = lyrSpec.getExtraLayers(i) + 1; |
||
612 | ls = System.Math.Exp(System.Math.Log((double) nextbytes / basebytes) / loopnlyrs); |
||
613 | layers[n].optimize = true; |
||
614 | for (l = 0; l < loopnlyrs; l++) |
||
615 | { |
||
616 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
617 | newbytes = (int) basebytes - lastbytes - ho; |
||
618 | if (newbytes < minlsz) |
||
619 | { |
||
620 | // Skip layer (too small) |
||
621 | basebytes *= ls; |
||
622 | num_Layers--; |
||
623 | continue; |
||
624 | } |
||
625 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
626 | lastbytes = (int) basebytes - ho; |
||
627 | layers[n].maxBytes = lastbytes; |
||
628 | basebytes *= ls; |
||
629 | n++; |
||
630 | } |
||
631 | i++; // Goto next optimization point |
||
632 | } |
||
633 | |||
634 | // Ensure minimum size of last layer (this one determines overall |
||
635 | // bitrate) |
||
636 | n = num_Layers - 2; |
||
637 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
638 | nextbytes = (int) (lyrSpec.TotBitrate * np) - ho; |
||
639 | newbytes = nextbytes - ((n >= 0)?layers[n].maxBytes:0); |
||
640 | while (newbytes < minlsz) |
||
641 | { |
||
642 | if (num_Layers == 1) |
||
643 | { |
||
644 | if (newbytes <= 0) |
||
645 | { |
||
646 | throw new System.ArgumentException("Overall target bitrate too " + "low, given the current " + "bit stream header overhead"); |
||
647 | } |
||
648 | break; |
||
649 | } |
||
650 | // Delete last layer |
||
651 | num_Layers--; |
||
652 | n--; |
||
653 | newbytes = nextbytes - ((n >= 0)?layers[n].maxBytes:0); |
||
654 | } |
||
655 | // Set last layer to the overall target bitrate |
||
656 | n++; |
||
657 | layers[n].maxBytes = nextbytes; |
||
658 | layers[n].optimize = true; |
||
659 | |||
660 | // Re-initialize progression order changes if needed Default values |
||
661 | Progression[] prog1; // prog2 removed |
||
662 | prog1 = (Progression[]) encSpec.pocs.getDefault(); |
||
663 | int nValidProg = prog1.Length; |
||
664 | for (int prg = 0; prg < prog1.Length; prg++) |
||
665 | { |
||
666 | if (prog1[prg].lye > num_Layers) |
||
667 | { |
||
668 | prog1[prg].lye = num_Layers; |
||
669 | } |
||
670 | } |
||
671 | if (nValidProg == 0) |
||
672 | { |
||
673 | throw new System.ApplicationException("Unable to initialize rate allocator: No " + "default progression type has been defined."); |
||
674 | } |
||
675 | |||
676 | // Tile specific values |
||
677 | for (int t = 0; t < numTiles; t++) |
||
678 | { |
||
679 | if (encSpec.pocs.isTileSpecified(t)) |
||
680 | { |
||
681 | prog1 = (Progression[]) encSpec.pocs.getTileDef(t); |
||
682 | nValidProg = prog1.Length; |
||
683 | for (int prg = 0; prg < prog1.Length; prg++) |
||
684 | { |
||
685 | if (prog1[prg].lye > num_Layers) |
||
686 | { |
||
687 | prog1[prg].lye = num_Layers; |
||
688 | } |
||
689 | } |
||
690 | if (nValidProg == 0) |
||
691 | { |
||
692 | throw new System.ApplicationException("Unable to initialize rate allocator:" + " No default progression type has been " + "defined for tile " + t); |
||
693 | } |
||
694 | } |
||
695 | } // End loop on tiles |
||
696 | |||
697 | #if DO_TIMING |
||
698 | initTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; |
||
699 | #endif |
||
700 | } |
||
701 | |||
702 | /// <summary> This method gets all the coded code-blocks from the EBCOT entropy coder |
||
703 | /// for every component and every tile. Each coded code-block is stored in |
||
704 | /// a 5D array according to the component, the resolution level, the tile, |
||
705 | /// the subband it belongs and its position in the subband. |
||
706 | /// |
||
707 | /// <P> For each code-block, the valid slopes are computed and converted |
||
708 | /// into the mantissa-exponent representation. |
||
709 | /// |
||
710 | /// </summary> |
||
711 | private void getAllCodeBlocks() |
||
712 | { |
||
713 | |||
714 | int numComps, numTiles; // numBytes removed |
||
715 | int c, r, t, s, sidx, k; |
||
716 | //int slope; |
||
717 | SubbandAn subb; |
||
718 | CBlkRateDistStats ccb = null; |
||
719 | Coord ncblks = null; |
||
720 | int last_sidx; |
||
721 | float fslope; |
||
722 | #if DO_TIMING |
||
723 | long stime = 0L; |
||
724 | #endif |
||
725 | maxSlope = 0f; |
||
726 | minSlope = System.Single.MaxValue; |
||
727 | |||
728 | //Get the number of components and tiles |
||
729 | numComps = src.NumComps; |
||
730 | numTiles = src.getNumTiles(); |
||
731 | |||
732 | SubbandAn root, sb; |
||
733 | int cblkToEncode = 0; |
||
734 | int nEncCblk = 0; |
||
735 | ProgressWatch pw = FacilityManager.ProgressWatch; |
||
736 | |||
737 | //Get all coded code-blocks Goto first tile |
||
738 | src.setTile(0, 0); |
||
739 | for (t = 0; t < numTiles; t++) |
||
740 | { |
||
741 | //loop on tiles |
||
742 | nEncCblk = 0; |
||
743 | cblkToEncode = 0; |
||
744 | for (c = 0; c < numComps; c++) |
||
745 | { |
||
746 | root = src.getAnSubbandTree(t, c); |
||
747 | for (r = 0; r <= root.resLvl; r++) |
||
748 | { |
||
749 | if (r == 0) |
||
750 | { |
||
751 | sb = (SubbandAn) root.getSubbandByIdx(0, 0); |
||
752 | if (sb != null) |
||
753 | cblkToEncode += sb.numCb.x * sb.numCb.y; |
||
754 | } |
||
755 | else |
||
756 | { |
||
757 | sb = (SubbandAn) root.getSubbandByIdx(r, 1); |
||
758 | if (sb != null) |
||
759 | cblkToEncode += sb.numCb.x * sb.numCb.y; |
||
760 | sb = (SubbandAn) root.getSubbandByIdx(r, 2); |
||
761 | if (sb != null) |
||
762 | cblkToEncode += sb.numCb.x * sb.numCb.y; |
||
763 | sb = (SubbandAn) root.getSubbandByIdx(r, 3); |
||
764 | if (sb != null) |
||
765 | cblkToEncode += sb.numCb.x * sb.numCb.y; |
||
766 | } |
||
767 | } |
||
768 | } |
||
769 | if (pw != null) |
||
770 | { |
||
771 | pw.initProgressWatch(0, cblkToEncode, "Encoding tile " + t + "..."); |
||
772 | } |
||
773 | |||
774 | for (c = 0; c < numComps; c++) |
||
775 | { |
||
776 | //loop on components |
||
777 | |||
778 | //Get next coded code-block coordinates |
||
779 | while ((ccb = src.getNextCodeBlock(c, ccb)) != null) |
||
780 | { |
||
781 | #if DO_TIMING |
||
782 | stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; |
||
783 | #endif |
||
784 | |||
785 | if (pw != null) |
||
786 | { |
||
787 | nEncCblk++; |
||
788 | pw.updateProgressWatch(nEncCblk, null); |
||
789 | } |
||
790 | |||
791 | subb = ccb.sb; |
||
792 | |||
793 | //Get the coded code-block resolution level index |
||
794 | r = subb.resLvl; |
||
795 | |||
796 | //Get the coded code-block subband index |
||
797 | s = subb.sbandIdx; |
||
798 | |||
799 | //Get the number of blocks in the current subband |
||
800 | ncblks = subb.numCb; |
||
801 | |||
802 | // Add code-block contribution to summary R-D table |
||
803 | // RDSlopesRates |
||
804 | last_sidx = - 1; |
||
805 | for (k = ccb.nVldTrunc - 1; k >= 0; k--) |
||
806 | { |
||
807 | fslope = ccb.truncSlopes[k]; |
||
808 | if (fslope > maxSlope) |
||
809 | maxSlope = fslope; |
||
810 | if (fslope < minSlope) |
||
811 | minSlope = fslope; |
||
812 | sidx = getLimitedSIndexFromSlope(fslope); |
||
813 | for (; sidx > last_sidx; sidx--) |
||
814 | { |
||
815 | RDSlopesRates[sidx] += ccb.truncRates[ccb.truncIdxs[k]]; |
||
816 | } |
||
817 | last_sidx = getLimitedSIndexFromSlope(fslope); |
||
818 | } |
||
819 | |||
820 | //Fills code-blocks array |
||
821 | cblks[t][c][r][s][(ccb.m * ncblks.x) + ccb.n] = ccb; |
||
822 | ccb = null; |
||
823 | |||
824 | #if DO_TIMING |
||
825 | initTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; |
||
826 | #endif |
||
827 | } |
||
828 | } |
||
829 | |||
830 | if (pw != null) |
||
831 | { |
||
832 | pw.terminateProgressWatch(); |
||
833 | } |
||
834 | |||
835 | //Goto next tile |
||
836 | if (t < numTiles - 1) |
||
837 | //not at last tile |
||
838 | src.nextTile(); |
||
839 | } |
||
840 | } |
||
841 | |||
842 | /// <summary> This method builds all the bit stream layers and then writes them to |
||
843 | /// the output bit stream. Firstly it builds all the layers by computing |
||
844 | /// the threshold according to the layer target bit-rate, and then it |
||
845 | /// writes the layer bit streams according to the progressive type. |
||
846 | /// |
||
847 | /// </summary> |
||
848 | private void buildAndWriteLayers() |
||
849 | { |
||
850 | int nPrec = 0; |
||
851 | int maxBytes, actualBytes; |
||
852 | float rdThreshold; |
||
853 | SubbandAn sb; |
||
854 | //float threshold; |
||
855 | BitOutputBuffer hBuff = null; |
||
856 | byte[] bBuff = null; |
||
857 | int[] tileLengths; // Length of each tile |
||
858 | int tmp; |
||
859 | bool sopUsed; // Should SOP markers be used ? |
||
860 | bool ephUsed; // Should EPH markers be used ? |
||
861 | int nc = src.NumComps; |
||
862 | int nt = src.getNumTiles(); |
||
863 | int mrl; |
||
864 | #if DO_TIMING |
||
865 | long stime = 0L; |
||
866 | stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; |
||
867 | #endif |
||
868 | |||
869 | // Start with the maximum slope |
||
870 | rdThreshold = maxSlope; |
||
871 | |||
872 | tileLengths = new int[nt]; |
||
873 | actualBytes = 0; |
||
874 | |||
875 | // +------------------------------+ |
||
876 | // | First we build the layers | |
||
877 | // +------------------------------+ |
||
878 | // Bitstream is simulated to know tile length |
||
879 | for (int l = 0; l < num_Layers; l++) |
||
880 | { |
||
881 | //loop on layers |
||
882 | |||
883 | maxBytes = layers[l].maxBytes; |
||
884 | if (layers[l].optimize) |
||
885 | { |
||
886 | rdThreshold = optimizeBitstreamLayer(l, rdThreshold, maxBytes, actualBytes); |
||
887 | } |
||
888 | else |
||
889 | { |
||
890 | if (l <= 0 || l >= num_Layers - 1) |
||
891 | { |
||
892 | throw new System.ArgumentException("The first and the" + " last layer " + "thresholds" + " must be optimized"); |
||
893 | } |
||
894 | rdThreshold = estimateLayerThreshold(maxBytes, layers[l - 1]); |
||
895 | } |
||
896 | |||
897 | for (int t = 0; t < nt; t++) |
||
898 | { |
||
899 | //loop on tiles |
||
900 | if (l == 0) |
||
901 | { |
||
902 | // Tile header |
||
903 | headEnc.reset(); |
||
904 | headEnc.encodeTilePartHeader(0, t); |
||
905 | tileLengths[t] += headEnc.Length; |
||
906 | } |
||
907 | |||
908 | for (int c = 0; c < nc; c++) |
||
909 | { |
||
910 | //loop on components |
||
911 | |||
912 | // set boolean sopUsed here (SOP markers) |
||
913 | sopUsed = ((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper()); |
||
914 | // set boolean ephUsed here (EPH markers) |
||
915 | ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper()); |
||
916 | |||
917 | // Go to LL band |
||
918 | sb = src.getAnSubbandTree(t, c); |
||
919 | mrl = sb.resLvl + 1; |
||
920 | |||
921 | while (sb.subb_LL != null) |
||
922 | { |
||
923 | sb = sb.subb_LL; |
||
924 | } |
||
925 | |||
926 | for (int r = 0; r < mrl; r++) |
||
927 | { |
||
928 | // loop on resolution levels |
||
929 | |||
930 | nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; |
||
931 | for (int p = 0; p < nPrec; p++) |
||
932 | { |
||
933 | // loop on precincts |
||
934 | |||
935 | findTruncIndices(l, c, r, t, sb, rdThreshold, p); |
||
936 | |||
937 | hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p); |
||
938 | if (pktEnc.PacketWritable) |
||
939 | { |
||
940 | tmp = bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, true, sopUsed, ephUsed); |
||
941 | tmp += bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, true, pktEnc.ROIinPkt, pktEnc.ROILen); |
||
942 | actualBytes += tmp; |
||
943 | tileLengths[t] += tmp; |
||
944 | } |
||
945 | } // End loop on precincts |
||
946 | sb = sb.parentband; |
||
947 | } // End loop on resolution levels |
||
948 | } // End loop on components |
||
949 | } // end loop on tiles |
||
950 | layers[l].rdThreshold = rdThreshold; |
||
951 | layers[l].actualBytes = actualBytes; |
||
952 | } // end loop on layers |
||
953 | |||
954 | #if DO_TIMING |
||
955 | buildTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; |
||
956 | stime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; |
||
957 | #endif |
||
958 | // +--------------------------------------------------+ |
||
959 | // | Write tiles according to their Progression order | |
||
960 | // +--------------------------------------------------+ |
||
961 | // Reset the packet encoder before writing all packets |
||
962 | pktEnc.reset(); |
||
963 | Progression[] prog; // Progression(s) in each tile |
||
964 | int cs, ce, rs, re, lye; |
||
965 | |||
966 | int[] mrlc = new int[nc]; |
||
967 | for (int t = 0; t < nt; t++) |
||
968 | { |
||
969 | //loop on tiles |
||
970 | //int[][] lysA; // layer index start for each component and |
||
971 | // resolution level |
||
972 | int[][] lys = new int[nc][]; |
||
973 | for (int c = 0; c < nc; c++) |
||
974 | { |
||
975 | mrlc[c] = src.getAnSubbandTree(t, c).resLvl; |
||
976 | lys[c] = new int[mrlc[c] + 1]; |
||
977 | } |
||
978 | |||
979 | // Tile header |
||
980 | headEnc.reset(); |
||
981 | headEnc.encodeTilePartHeader(tileLengths[t], t); |
||
982 | bsWriter.commitBitstreamHeader(headEnc); |
||
983 | prog = (Progression[]) encSpec.pocs.getTileDef(t); |
||
984 | |||
985 | for (int prg = 0; prg < prog.Length; prg++) |
||
986 | { |
||
987 | // Loop on progression |
||
988 | lye = prog[prg].lye; |
||
989 | cs = prog[prg].cs; |
||
990 | ce = prog[prg].ce; |
||
991 | rs = prog[prg].rs; |
||
992 | re = prog[prg].re; |
||
993 | |||
994 | switch (prog[prg].type) |
||
995 | { |
||
996 | |||
997 | case CSJ2K.j2k.codestream.ProgressionType.RES_LY_COMP_POS_PROG: |
||
998 | writeResLyCompPos(t, rs, re, cs, ce, lys, lye); |
||
999 | break; |
||
1000 | |||
1001 | case CSJ2K.j2k.codestream.ProgressionType.LY_RES_COMP_POS_PROG: |
||
1002 | writeLyResCompPos(t, rs, re, cs, ce, lys, lye); |
||
1003 | break; |
||
1004 | |||
1005 | case CSJ2K.j2k.codestream.ProgressionType.POS_COMP_RES_LY_PROG: |
||
1006 | writePosCompResLy(t, rs, re, cs, ce, lys, lye); |
||
1007 | break; |
||
1008 | |||
1009 | case CSJ2K.j2k.codestream.ProgressionType.COMP_POS_RES_LY_PROG: |
||
1010 | writeCompPosResLy(t, rs, re, cs, ce, lys, lye); |
||
1011 | break; |
||
1012 | |||
1013 | case CSJ2K.j2k.codestream.ProgressionType.RES_POS_COMP_LY_PROG: |
||
1014 | writeResPosCompLy(t, rs, re, cs, ce, lys, lye); |
||
1015 | break; |
||
1016 | |||
1017 | default: |
||
1018 | throw new System.ApplicationException("Unsupported bit stream progression type"); |
||
1019 | |||
1020 | } // switch on progression |
||
1021 | |||
1022 | // Update next first layer index |
||
1023 | for (int c = cs; c < ce; c++) |
||
1024 | for (int r = rs; r < re; r++) |
||
1025 | { |
||
1026 | if (r > mrlc[c]) |
||
1027 | continue; |
||
1028 | lys[c][r] = lye; |
||
1029 | } |
||
1030 | } // End loop on progression |
||
1031 | } // End loop on tiles |
||
1032 | |||
1033 | #if DO_TIMING |
||
1034 | writeTime += (System.DateTime.Now.Ticks - 621355968000000000) / 10000 - stime; |
||
1035 | #endif |
||
1036 | } |
||
1037 | |||
1038 | /// <summary> Write a piece of bit stream according to the |
||
1039 | /// RES_LY_COMP_POS_PROG progression mode and between given bounds |
||
1040 | /// |
||
1041 | /// </summary> |
||
1042 | /// <param name="t">Tile index. |
||
1043 | /// |
||
1044 | /// </param> |
||
1045 | /// <param name="rs">First resolution level index. |
||
1046 | /// |
||
1047 | /// </param> |
||
1048 | /// <param name="re">Last resolution level index. |
||
1049 | /// |
||
1050 | /// </param> |
||
1051 | /// <param name="cs">First component index. |
||
1052 | /// |
||
1053 | /// </param> |
||
1054 | /// <param name="ce">Last component index. |
||
1055 | /// |
||
1056 | /// </param> |
||
1057 | /// <param name="lys">First layer index for each component and resolution. |
||
1058 | /// |
||
1059 | /// </param> |
||
1060 | /// <param name="lye">Index of the last layer. |
||
1061 | /// |
||
1062 | /// </param> |
||
1063 | public virtual void writeResLyCompPos(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) |
||
1064 | { |
||
1065 | |||
1066 | bool sopUsed; // Should SOP markers be used ? |
||
1067 | bool ephUsed; // Should EPH markers be used ? |
||
1068 | int nc = src.NumComps; |
||
1069 | int[] mrl = new int[nc]; |
||
1070 | SubbandAn sb; |
||
1071 | float threshold; |
||
1072 | BitOutputBuffer hBuff = null; |
||
1073 | byte[] bBuff = null; |
||
1074 | int nPrec = 0; |
||
1075 | |||
1076 | // Max number of resolution levels in the tile |
||
1077 | int maxResLvl = 0; |
||
1078 | for (int c = 0; c < nc; c++) |
||
1079 | { |
||
1080 | mrl[c] = src.getAnSubbandTree(t, c).resLvl; |
||
1081 | if (mrl[c] > maxResLvl) |
||
1082 | maxResLvl = mrl[c]; |
||
1083 | } |
||
1084 | |||
1085 | int minlys; // minimum layer start index of each component |
||
1086 | |||
1087 | for (int r = rs; r < re; r++) |
||
1088 | { |
||
1089 | //loop on resolution levels |
||
1090 | if (r > maxResLvl) |
||
1091 | continue; |
||
1092 | |||
1093 | minlys = 100000; |
||
1094 | for (int c = cs; c < ce; c++) |
||
1095 | { |
||
1096 | if (r < lys[c].Length && lys[c][r] < minlys) |
||
1097 | { |
||
1098 | minlys = lys[c][r]; |
||
1099 | } |
||
1100 | } |
||
1101 | |||
1102 | for (int l = minlys; l < lye; l++) |
||
1103 | { |
||
1104 | //loop on layers |
||
1105 | for (int c = cs; c < ce; c++) |
||
1106 | { |
||
1107 | //loop on components |
||
1108 | if (r >= lys[c].Length) |
||
1109 | continue; |
||
1110 | if (l < lys[c][r]) |
||
1111 | continue; |
||
1112 | |||
1113 | // If no more decomposition levels for this component |
||
1114 | if (r > mrl[c]) |
||
1115 | continue; |
||
1116 | |||
1117 | nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; |
||
1118 | for (int p = 0; p < nPrec; p++) |
||
1119 | { |
||
1120 | // loop on precincts |
||
1121 | |||
1122 | // set boolean sopUsed here (SOP markers) |
||
1123 | sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); |
||
1124 | // set boolean ephUsed here (EPH markers) |
||
1125 | ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); |
||
1126 | |||
1127 | sb = src.getAnSubbandTree(t, c); |
||
1128 | for (int i = mrl[c]; i > r; i--) |
||
1129 | { |
||
1130 | sb = sb.subb_LL; |
||
1131 | } |
||
1132 | |||
1133 | threshold = layers[l].rdThreshold; |
||
1134 | findTruncIndices(l, c, r, t, sb, threshold, p); |
||
1135 | |||
1136 | hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p); |
||
1137 | |||
1138 | if (pktEnc.PacketWritable) |
||
1139 | { |
||
1140 | bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); |
||
1141 | bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); |
||
1142 | } |
||
1143 | } // End loop on precincts |
||
1144 | } // End loop on components |
||
1145 | } // End loop on layers |
||
1146 | } // End loop on resolution levels |
||
1147 | } |
||
1148 | |||
1149 | /// <summary> Write a piece of bit stream according to the |
||
1150 | /// LY_RES_COMP_POS_PROG progression mode and between given bounds |
||
1151 | /// |
||
1152 | /// </summary> |
||
1153 | /// <param name="t">Tile index. |
||
1154 | /// |
||
1155 | /// </param> |
||
1156 | /// <param name="rs">First resolution level index. |
||
1157 | /// |
||
1158 | /// </param> |
||
1159 | /// <param name="re">Last resolution level index. |
||
1160 | /// |
||
1161 | /// </param> |
||
1162 | /// <param name="cs">First component index. |
||
1163 | /// |
||
1164 | /// </param> |
||
1165 | /// <param name="ce">Last component index. |
||
1166 | /// |
||
1167 | /// </param> |
||
1168 | /// <param name="lys">First layer index for each component and resolution. |
||
1169 | /// |
||
1170 | /// </param> |
||
1171 | /// <param name="lye">Index of the last layer. |
||
1172 | /// |
||
1173 | /// </param> |
||
1174 | public virtual void writeLyResCompPos(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) |
||
1175 | { |
||
1176 | |||
1177 | bool sopUsed; // Should SOP markers be used ? |
||
1178 | bool ephUsed; // Should EPH markers be used ? |
||
1179 | int nc = src.NumComps; |
||
1180 | int mrl; |
||
1181 | SubbandAn sb; |
||
1182 | float threshold; |
||
1183 | BitOutputBuffer hBuff = null; |
||
1184 | byte[] bBuff = null; |
||
1185 | int nPrec = 0; |
||
1186 | |||
1187 | int minlys = 100000; // minimum layer start index of each component |
||
1188 | for (int c = cs; c < ce; c++) |
||
1189 | { |
||
1190 | for (int r = 0; r < lys.Length; r++) |
||
1191 | { |
||
1192 | if (lys[c] != null && r < lys[c].Length && lys[c][r] < minlys) |
||
1193 | { |
||
1194 | minlys = lys[c][r]; |
||
1195 | } |
||
1196 | } |
||
1197 | } |
||
1198 | |||
1199 | for (int l = minlys; l < lye; l++) |
||
1200 | { |
||
1201 | // loop on layers |
||
1202 | for (int r = rs; r < re; r++) |
||
1203 | { |
||
1204 | // loop on resolution level |
||
1205 | for (int c = cs; c < ce; c++) |
||
1206 | { |
||
1207 | // loop on components |
||
1208 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1209 | if (r > mrl) |
||
1210 | continue; |
||
1211 | if (r >= lys[c].Length) |
||
1212 | continue; |
||
1213 | if (l < lys[c][r]) |
||
1214 | continue; |
||
1215 | |||
1216 | nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; |
||
1217 | for (int p = 0; p < nPrec; p++) |
||
1218 | { |
||
1219 | // loop on precincts |
||
1220 | |||
1221 | // set boolean sopUsed here (SOP markers) |
||
1222 | sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); |
||
1223 | // set boolean ephUsed here (EPH markers) |
||
1224 | ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); |
||
1225 | |||
1226 | sb = src.getAnSubbandTree(t, c); |
||
1227 | for (int i = mrl; i > r; i--) |
||
1228 | { |
||
1229 | sb = sb.subb_LL; |
||
1230 | } |
||
1231 | |||
1232 | threshold = layers[l].rdThreshold; |
||
1233 | findTruncIndices(l, c, r, t, sb, threshold, p); |
||
1234 | |||
1235 | hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, p); |
||
1236 | |||
1237 | if (pktEnc.PacketWritable) |
||
1238 | { |
||
1239 | bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); |
||
1240 | bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); |
||
1241 | } |
||
1242 | } // end loop on precincts |
||
1243 | } // end loop on components |
||
1244 | } // end loop on resolution levels |
||
1245 | } // end loop on layers |
||
1246 | } |
||
1247 | |||
1248 | /// <summary> Write a piece of bit stream according to the |
||
1249 | /// COMP_POS_RES_LY_PROG progression mode and between given bounds |
||
1250 | /// |
||
1251 | /// </summary> |
||
1252 | /// <param name="t">Tile index. |
||
1253 | /// |
||
1254 | /// </param> |
||
1255 | /// <param name="rs">First resolution level index. |
||
1256 | /// |
||
1257 | /// </param> |
||
1258 | /// <param name="re">Last resolution level index. |
||
1259 | /// |
||
1260 | /// </param> |
||
1261 | /// <param name="cs">First component index. |
||
1262 | /// |
||
1263 | /// </param> |
||
1264 | /// <param name="ce">Last component index. |
||
1265 | /// |
||
1266 | /// </param> |
||
1267 | /// <param name="lys">First layer index for each component and resolution. |
||
1268 | /// |
||
1269 | /// </param> |
||
1270 | /// <param name="lye">Index of the last layer. |
||
1271 | /// |
||
1272 | /// </param> |
||
1273 | public virtual void writePosCompResLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) |
||
1274 | { |
||
1275 | |||
1276 | bool sopUsed; // Should SOP markers be used ? |
||
1277 | bool ephUsed; // Should EPH markers be used ? |
||
1278 | int nc = src.NumComps; |
||
1279 | int mrl; |
||
1280 | SubbandAn sb; |
||
1281 | float threshold; |
||
1282 | BitOutputBuffer hBuff = null; |
||
1283 | byte[] bBuff = null; |
||
1284 | |||
1285 | // Computes current tile offset in the reference grid |
||
1286 | Coord nTiles = src.getNumTiles(null); |
||
1287 | Coord tileI = src.getTile(null); |
||
1288 | int x0siz = src.ImgULX; |
||
1289 | int y0siz = src.ImgULY; |
||
1290 | int xsiz = x0siz + src.ImgWidth; |
||
1291 | int ysiz = y0siz + src.ImgHeight; |
||
1292 | int xt0siz = src.TilePartULX; |
||
1293 | int yt0siz = src.TilePartULY; |
||
1294 | int xtsiz = src.NomTileWidth; |
||
1295 | int ytsiz = src.NomTileHeight; |
||
1296 | int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; |
||
1297 | int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; |
||
1298 | int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; |
||
1299 | int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; |
||
1300 | |||
1301 | // Get precinct information (number,distance between two consecutive |
||
1302 | // precincts in the reference grid) in each component and resolution |
||
1303 | // level |
||
1304 | PrecInfo prec; // temporary variable |
||
1305 | int p; // Current precinct index |
||
1306 | int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid |
||
1307 | int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid |
||
1308 | int nPrec = 0; // Total number of found precincts |
||
1309 | int[][] nextPrec = new int[ce][]; // Next precinct index in each |
||
1310 | // component and resolution level |
||
1311 | int minlys = 100000; // minimum layer start index of each component |
||
1312 | int minx = tx1; // Horiz. offset of the second precinct in the |
||
1313 | // reference grid |
||
1314 | int miny = ty1; // Vert. offset of the second precinct in the |
||
1315 | // reference grid. |
||
1316 | int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid |
||
1317 | int maxy = ty0; // Max. vert. offset of precincts in the ref. grid |
||
1318 | for (int c = cs; c < ce; c++) |
||
1319 | { |
||
1320 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1321 | nextPrec[c] = new int[mrl + 1]; |
||
1322 | for (int r = rs; r < re; r++) |
||
1323 | { |
||
1324 | if (r > mrl) |
||
1325 | continue; |
||
1326 | if (r < lys[c].Length && lys[c][r] < minlys) |
||
1327 | { |
||
1328 | minlys = lys[c][r]; |
||
1329 | } |
||
1330 | p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1; |
||
1331 | for (; p >= 0; p--) |
||
1332 | { |
||
1333 | prec = pktEnc.getPrecInfo(t, c, r, p); |
||
1334 | if (prec.rgulx != tx0) |
||
1335 | { |
||
1336 | if (prec.rgulx < minx) |
||
1337 | minx = prec.rgulx; |
||
1338 | if (prec.rgulx > maxx) |
||
1339 | maxx = prec.rgulx; |
||
1340 | } |
||
1341 | if (prec.rguly != ty0) |
||
1342 | { |
||
1343 | if (prec.rguly < miny) |
||
1344 | miny = prec.rguly; |
||
1345 | if (prec.rguly > maxy) |
||
1346 | maxy = prec.rguly; |
||
1347 | } |
||
1348 | |||
1349 | if (nPrec == 0) |
||
1350 | { |
||
1351 | gcd_x = prec.rgw; |
||
1352 | gcd_y = prec.rgh; |
||
1353 | } |
||
1354 | else |
||
1355 | { |
||
1356 | gcd_x = MathUtil.gcd(gcd_x, prec.rgw); |
||
1357 | gcd_y = MathUtil.gcd(gcd_y, prec.rgh); |
||
1358 | } |
||
1359 | nPrec++; |
||
1360 | } // precincts |
||
1361 | } // resolution levels |
||
1362 | } // components |
||
1363 | |||
1364 | if (nPrec == 0) |
||
1365 | { |
||
1366 | throw new System.ApplicationException("Image cannot have no precinct"); |
||
1367 | } |
||
1368 | |||
1369 | int pyend = (maxy - miny) / gcd_y + 1; |
||
1370 | int pxend = (maxx - minx) / gcd_x + 1; |
||
1371 | int y = ty0; |
||
1372 | int x = tx0; |
||
1373 | for (int py = 0; py <= pyend; py++) |
||
1374 | { |
||
1375 | // Vertical precincts |
||
1376 | for (int px = 0; px <= pxend; px++) |
||
1377 | { |
||
1378 | // Horiz. precincts |
||
1379 | for (int c = cs; c < ce; c++) |
||
1380 | { |
||
1381 | // Components |
||
1382 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1383 | for (int r = rs; r < re; r++) |
||
1384 | { |
||
1385 | // Resolution levels |
||
1386 | if (r > mrl) |
||
1387 | continue; |
||
1388 | if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y) |
||
1389 | { |
||
1390 | continue; |
||
1391 | } |
||
1392 | prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]); |
||
1393 | if ((prec.rgulx != x) || (prec.rguly != y)) |
||
1394 | { |
||
1395 | continue; |
||
1396 | } |
||
1397 | for (int l = minlys; l < lye; l++) |
||
1398 | { |
||
1399 | // Layers |
||
1400 | if (r >= lys[c].Length) |
||
1401 | continue; |
||
1402 | if (l < lys[c][r]) |
||
1403 | continue; |
||
1404 | |||
1405 | // set boolean sopUsed here (SOP markers) |
||
1406 | sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); |
||
1407 | // set boolean ephUsed here (EPH markers) |
||
1408 | ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); |
||
1409 | |||
1410 | sb = src.getAnSubbandTree(t, c); |
||
1411 | for (int i = mrl; i > r; i--) |
||
1412 | { |
||
1413 | sb = sb.subb_LL; |
||
1414 | } |
||
1415 | |||
1416 | threshold = layers[l].rdThreshold; |
||
1417 | findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]); |
||
1418 | |||
1419 | hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]); |
||
1420 | |||
1421 | if (pktEnc.PacketWritable) |
||
1422 | { |
||
1423 | bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); |
||
1424 | bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); |
||
1425 | } |
||
1426 | } // layers |
||
1427 | nextPrec[c][r]++; |
||
1428 | } // Resolution levels |
||
1429 | } // Components |
||
1430 | if (px != pxend) |
||
1431 | { |
||
1432 | x = minx + px * gcd_x; |
||
1433 | } |
||
1434 | else |
||
1435 | { |
||
1436 | x = tx0; |
||
1437 | } |
||
1438 | } // Horizontal precincts |
||
1439 | if (py != pyend) |
||
1440 | { |
||
1441 | y = miny + py * gcd_y; |
||
1442 | } |
||
1443 | else |
||
1444 | { |
||
1445 | y = ty0; |
||
1446 | } |
||
1447 | } // Vertical precincts |
||
1448 | |||
1449 | // Check that all precincts have been written |
||
1450 | for (int c = cs; c < ce; c++) |
||
1451 | { |
||
1452 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1453 | for (int r = rs; r < re; r++) |
||
1454 | { |
||
1455 | if (r > mrl) |
||
1456 | continue; |
||
1457 | if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1) |
||
1458 | { |
||
1459 | throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + "."); |
||
1460 | } |
||
1461 | } |
||
1462 | } |
||
1463 | } |
||
1464 | |||
1465 | /// <summary> Write a piece of bit stream according to the |
||
1466 | /// COMP_POS_RES_LY_PROG progression mode and between given bounds |
||
1467 | /// |
||
1468 | /// </summary> |
||
1469 | /// <param name="t">Tile index. |
||
1470 | /// |
||
1471 | /// </param> |
||
1472 | /// <param name="rs">First resolution level index. |
||
1473 | /// |
||
1474 | /// </param> |
||
1475 | /// <param name="re">Last resolution level index. |
||
1476 | /// |
||
1477 | /// </param> |
||
1478 | /// <param name="cs">First component index. |
||
1479 | /// |
||
1480 | /// </param> |
||
1481 | /// <param name="ce">Last component index. |
||
1482 | /// |
||
1483 | /// </param> |
||
1484 | /// <param name="lys">First layer index for each component and resolution. |
||
1485 | /// |
||
1486 | /// </param> |
||
1487 | /// <param name="lye">Index of the last layer. |
||
1488 | /// |
||
1489 | /// </param> |
||
1490 | public virtual void writeCompPosResLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) |
||
1491 | { |
||
1492 | |||
1493 | bool sopUsed; // Should SOP markers be used ? |
||
1494 | bool ephUsed; // Should EPH markers be used ? |
||
1495 | int nc = src.NumComps; |
||
1496 | int mrl; |
||
1497 | SubbandAn sb; |
||
1498 | float threshold; |
||
1499 | BitOutputBuffer hBuff = null; |
||
1500 | byte[] bBuff = null; |
||
1501 | |||
1502 | // Computes current tile offset in the reference grid |
||
1503 | Coord nTiles = src.getNumTiles(null); |
||
1504 | Coord tileI = src.getTile(null); |
||
1505 | int x0siz = src.ImgULX; |
||
1506 | int y0siz = src.ImgULY; |
||
1507 | int xsiz = x0siz + src.ImgWidth; |
||
1508 | int ysiz = y0siz + src.ImgHeight; |
||
1509 | int xt0siz = src.TilePartULX; |
||
1510 | int yt0siz = src.TilePartULY; |
||
1511 | int xtsiz = src.NomTileWidth; |
||
1512 | int ytsiz = src.NomTileHeight; |
||
1513 | int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; |
||
1514 | int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; |
||
1515 | int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; |
||
1516 | int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; |
||
1517 | |||
1518 | // Get precinct information (number,distance between two consecutive |
||
1519 | // precincts in the reference grid) in each component and resolution |
||
1520 | // level |
||
1521 | PrecInfo prec; // temporary variable |
||
1522 | int p; // Current precinct index |
||
1523 | int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid |
||
1524 | int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid |
||
1525 | int nPrec = 0; // Total number of found precincts |
||
1526 | int[][] nextPrec = new int[ce][]; // Next precinct index in each |
||
1527 | // component and resolution level |
||
1528 | int minlys = 100000; // minimum layer start index of each component |
||
1529 | int minx = tx1; // Horiz. offset of the second precinct in the |
||
1530 | // reference grid |
||
1531 | int miny = ty1; // Vert. offset of the second precinct in the |
||
1532 | // reference grid. |
||
1533 | int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid |
||
1534 | int maxy = ty0; // Max. vert. offset of precincts in the ref. grid |
||
1535 | for (int c = cs; c < ce; c++) |
||
1536 | { |
||
1537 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1538 | for (int r = rs; r < re; r++) |
||
1539 | { |
||
1540 | if (r > mrl) |
||
1541 | continue; |
||
1542 | nextPrec[c] = new int[mrl + 1]; |
||
1543 | if (r < lys[c].Length && lys[c][r] < minlys) |
||
1544 | { |
||
1545 | minlys = lys[c][r]; |
||
1546 | } |
||
1547 | p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1; |
||
1548 | for (; p >= 0; p--) |
||
1549 | { |
||
1550 | prec = pktEnc.getPrecInfo(t, c, r, p); |
||
1551 | if (prec.rgulx != tx0) |
||
1552 | { |
||
1553 | if (prec.rgulx < minx) |
||
1554 | minx = prec.rgulx; |
||
1555 | if (prec.rgulx > maxx) |
||
1556 | maxx = prec.rgulx; |
||
1557 | } |
||
1558 | if (prec.rguly != ty0) |
||
1559 | { |
||
1560 | if (prec.rguly < miny) |
||
1561 | miny = prec.rguly; |
||
1562 | if (prec.rguly > maxy) |
||
1563 | maxy = prec.rguly; |
||
1564 | } |
||
1565 | |||
1566 | if (nPrec == 0) |
||
1567 | { |
||
1568 | gcd_x = prec.rgw; |
||
1569 | gcd_y = prec.rgh; |
||
1570 | } |
||
1571 | else |
||
1572 | { |
||
1573 | gcd_x = MathUtil.gcd(gcd_x, prec.rgw); |
||
1574 | gcd_y = MathUtil.gcd(gcd_y, prec.rgh); |
||
1575 | } |
||
1576 | nPrec++; |
||
1577 | } // precincts |
||
1578 | } // resolution levels |
||
1579 | } // components |
||
1580 | |||
1581 | if (nPrec == 0) |
||
1582 | { |
||
1583 | throw new System.ApplicationException("Image cannot have no precinct"); |
||
1584 | } |
||
1585 | |||
1586 | int pyend = (maxy - miny) / gcd_y + 1; |
||
1587 | int pxend = (maxx - minx) / gcd_x + 1; |
||
1588 | int y; |
||
1589 | int x; |
||
1590 | for (int c = cs; c < ce; c++) |
||
1591 | { |
||
1592 | // Loop on components |
||
1593 | y = ty0; |
||
1594 | x = tx0; |
||
1595 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1596 | for (int py = 0; py <= pyend; py++) |
||
1597 | { |
||
1598 | // Vertical precincts |
||
1599 | for (int px = 0; px <= pxend; px++) |
||
1600 | { |
||
1601 | // Horiz. precincts |
||
1602 | for (int r = rs; r < re; r++) |
||
1603 | { |
||
1604 | // Resolution levels |
||
1605 | if (r > mrl) |
||
1606 | continue; |
||
1607 | if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y) |
||
1608 | { |
||
1609 | continue; |
||
1610 | } |
||
1611 | prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]); |
||
1612 | if ((prec.rgulx != x) || (prec.rguly != y)) |
||
1613 | { |
||
1614 | continue; |
||
1615 | } |
||
1616 | |||
1617 | for (int l = minlys; l < lye; l++) |
||
1618 | { |
||
1619 | // Layers |
||
1620 | if (r >= lys[c].Length) |
||
1621 | continue; |
||
1622 | if (l < lys[c][r]) |
||
1623 | continue; |
||
1624 | |||
1625 | // set boolean sopUsed here (SOP markers) |
||
1626 | sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); |
||
1627 | // set boolean ephUsed here (EPH markers) |
||
1628 | ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); |
||
1629 | |||
1630 | sb = src.getAnSubbandTree(t, c); |
||
1631 | for (int i = mrl; i > r; i--) |
||
1632 | { |
||
1633 | sb = sb.subb_LL; |
||
1634 | } |
||
1635 | |||
1636 | threshold = layers[l].rdThreshold; |
||
1637 | findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]); |
||
1638 | |||
1639 | hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]); |
||
1640 | |||
1641 | if (pktEnc.PacketWritable) |
||
1642 | { |
||
1643 | bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); |
||
1644 | bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); |
||
1645 | } |
||
1646 | } // Layers |
||
1647 | nextPrec[c][r]++; |
||
1648 | } // Resolution levels |
||
1649 | if (px != pxend) |
||
1650 | { |
||
1651 | x = minx + px * gcd_x; |
||
1652 | } |
||
1653 | else |
||
1654 | { |
||
1655 | x = tx0; |
||
1656 | } |
||
1657 | } // Horizontal precincts |
||
1658 | if (py != pyend) |
||
1659 | { |
||
1660 | y = miny + py * gcd_y; |
||
1661 | } |
||
1662 | else |
||
1663 | { |
||
1664 | y = ty0; |
||
1665 | } |
||
1666 | } // Vertical precincts |
||
1667 | } // components |
||
1668 | |||
1669 | // Check that all precincts have been written |
||
1670 | for (int c = cs; c < ce; c++) |
||
1671 | { |
||
1672 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1673 | for (int r = rs; r < re; r++) |
||
1674 | { |
||
1675 | if (r > mrl) |
||
1676 | continue; |
||
1677 | if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1) |
||
1678 | { |
||
1679 | throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + "."); |
||
1680 | } |
||
1681 | } |
||
1682 | } |
||
1683 | } |
||
1684 | |||
1685 | /// <summary> Write a piece of bit stream according to the |
||
1686 | /// RES_POS_COMP_LY_PROG progression mode and between given bounds |
||
1687 | /// |
||
1688 | /// </summary> |
||
1689 | /// <param name="t">Tile index. |
||
1690 | /// |
||
1691 | /// </param> |
||
1692 | /// <param name="rs">First resolution level index. |
||
1693 | /// |
||
1694 | /// </param> |
||
1695 | /// <param name="re">Last resolution level index. |
||
1696 | /// |
||
1697 | /// </param> |
||
1698 | /// <param name="cs">First component index. |
||
1699 | /// |
||
1700 | /// </param> |
||
1701 | /// <param name="ce">Last component index. |
||
1702 | /// |
||
1703 | /// </param> |
||
1704 | /// <param name="lys">First layer index for each component and resolution. |
||
1705 | /// |
||
1706 | /// </param> |
||
1707 | /// <param name="lye">Last layer index. |
||
1708 | /// |
||
1709 | /// </param> |
||
1710 | public virtual void writeResPosCompLy(int t, int rs, int re, int cs, int ce, int[][] lys, int lye) |
||
1711 | { |
||
1712 | |||
1713 | bool sopUsed; // Should SOP markers be used ? |
||
1714 | bool ephUsed; // Should EPH markers be used ? |
||
1715 | int nc = src.NumComps; |
||
1716 | int mrl; |
||
1717 | SubbandAn sb; |
||
1718 | float threshold; |
||
1719 | BitOutputBuffer hBuff = null; |
||
1720 | byte[] bBuff = null; |
||
1721 | |||
1722 | // Computes current tile offset in the reference grid |
||
1723 | Coord nTiles = src.getNumTiles(null); |
||
1724 | Coord tileI = src.getTile(null); |
||
1725 | int x0siz = src.ImgULX; |
||
1726 | int y0siz = src.ImgULY; |
||
1727 | int xsiz = x0siz + src.ImgWidth; |
||
1728 | int ysiz = y0siz + src.ImgHeight; |
||
1729 | int xt0siz = src.TilePartULX; |
||
1730 | int yt0siz = src.TilePartULY; |
||
1731 | int xtsiz = src.NomTileWidth; |
||
1732 | int ytsiz = src.NomTileHeight; |
||
1733 | int tx0 = (tileI.x == 0)?x0siz:xt0siz + tileI.x * xtsiz; |
||
1734 | int ty0 = (tileI.y == 0)?y0siz:yt0siz + tileI.y * ytsiz; |
||
1735 | int tx1 = (tileI.x != nTiles.x - 1)?xt0siz + (tileI.x + 1) * xtsiz:xsiz; |
||
1736 | int ty1 = (tileI.y != nTiles.y - 1)?yt0siz + (tileI.y + 1) * ytsiz:ysiz; |
||
1737 | |||
1738 | // Get precinct information (number,distance between two consecutive |
||
1739 | // precincts in the reference grid) in each component and resolution |
||
1740 | // level |
||
1741 | PrecInfo prec; // temporary variable |
||
1742 | int p; // Current precinct index |
||
1743 | int gcd_x = 0; // Horiz. distance between 2 precincts in the ref. grid |
||
1744 | int gcd_y = 0; // Vert. distance between 2 precincts in the ref. grid |
||
1745 | int nPrec = 0; // Total number of found precincts |
||
1746 | int[][] nextPrec = new int[ce][]; // Next precinct index in each |
||
1747 | // component and resolution level |
||
1748 | int minlys = 100000; // minimum layer start index of each component |
||
1749 | int minx = tx1; // Horiz. offset of the second precinct in the |
||
1750 | // reference grid |
||
1751 | int miny = ty1; // Vert. offset of the second precinct in the |
||
1752 | // reference grid. |
||
1753 | int maxx = tx0; // Max. horiz. offset of precincts in the ref. grid |
||
1754 | int maxy = ty0; // Max. vert. offset of precincts in the ref. grid |
||
1755 | for (int c = cs; c < ce; c++) |
||
1756 | { |
||
1757 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1758 | nextPrec[c] = new int[mrl + 1]; |
||
1759 | for (int r = rs; r < re; r++) |
||
1760 | { |
||
1761 | if (r > mrl) |
||
1762 | continue; |
||
1763 | if (r < lys[c].Length && lys[c][r] < minlys) |
||
1764 | { |
||
1765 | minlys = lys[c][r]; |
||
1766 | } |
||
1767 | p = numPrec[t][c][r].y * numPrec[t][c][r].x - 1; |
||
1768 | for (; p >= 0; p--) |
||
1769 | { |
||
1770 | prec = pktEnc.getPrecInfo(t, c, r, p); |
||
1771 | if (prec.rgulx != tx0) |
||
1772 | { |
||
1773 | if (prec.rgulx < minx) |
||
1774 | minx = prec.rgulx; |
||
1775 | if (prec.rgulx > maxx) |
||
1776 | maxx = prec.rgulx; |
||
1777 | } |
||
1778 | if (prec.rguly != ty0) |
||
1779 | { |
||
1780 | if (prec.rguly < miny) |
||
1781 | miny = prec.rguly; |
||
1782 | if (prec.rguly > maxy) |
||
1783 | maxy = prec.rguly; |
||
1784 | } |
||
1785 | |||
1786 | if (nPrec == 0) |
||
1787 | { |
||
1788 | gcd_x = prec.rgw; |
||
1789 | gcd_y = prec.rgh; |
||
1790 | } |
||
1791 | else |
||
1792 | { |
||
1793 | gcd_x = MathUtil.gcd(gcd_x, prec.rgw); |
||
1794 | gcd_y = MathUtil.gcd(gcd_y, prec.rgh); |
||
1795 | } |
||
1796 | nPrec++; |
||
1797 | } // precincts |
||
1798 | } // resolution levels |
||
1799 | } // components |
||
1800 | |||
1801 | if (nPrec == 0) |
||
1802 | { |
||
1803 | throw new System.ApplicationException("Image cannot have no precinct"); |
||
1804 | } |
||
1805 | |||
1806 | int pyend = (maxy - miny) / gcd_y + 1; |
||
1807 | int pxend = (maxx - minx) / gcd_x + 1; |
||
1808 | int x, y; |
||
1809 | for (int r = rs; r < re; r++) |
||
1810 | { |
||
1811 | // Resolution levels |
||
1812 | y = ty0; |
||
1813 | x = tx0; |
||
1814 | for (int py = 0; py <= pyend; py++) |
||
1815 | { |
||
1816 | // Vertical precincts |
||
1817 | for (int px = 0; px <= pxend; px++) |
||
1818 | { |
||
1819 | // Horiz. precincts |
||
1820 | for (int c = cs; c < ce; c++) |
||
1821 | { |
||
1822 | // Components |
||
1823 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1824 | if (r > mrl) |
||
1825 | continue; |
||
1826 | if (nextPrec[c][r] >= numPrec[t][c][r].x * numPrec[t][c][r].y) |
||
1827 | { |
||
1828 | continue; |
||
1829 | } |
||
1830 | prec = pktEnc.getPrecInfo(t, c, r, nextPrec[c][r]); |
||
1831 | if ((prec.rgulx != x) || (prec.rguly != y)) |
||
1832 | { |
||
1833 | continue; |
||
1834 | } |
||
1835 | for (int l = minlys; l < lye; l++) |
||
1836 | { |
||
1837 | if (r >= lys[c].Length) |
||
1838 | continue; |
||
1839 | if (l < lys[c][r]) |
||
1840 | continue; |
||
1841 | |||
1842 | // set boolean sopUsed here (SOP markers) |
||
1843 | sopUsed = ((System.String) encSpec.sops.getTileDef(t)).Equals("on"); |
||
1844 | // set boolean ephUsed here (EPH markers) |
||
1845 | ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).Equals("on"); |
||
1846 | |||
1847 | sb = src.getAnSubbandTree(t, c); |
||
1848 | for (int i = mrl; i > r; i--) |
||
1849 | { |
||
1850 | sb = sb.subb_LL; |
||
1851 | } |
||
1852 | |||
1853 | threshold = layers[l].rdThreshold; |
||
1854 | findTruncIndices(l, c, r, t, sb, threshold, nextPrec[c][r]); |
||
1855 | |||
1856 | hBuff = pktEnc.encodePacket(l + 1, c, r, t, cblks[t][c][r], truncIdxs[t][l][c][r], hBuff, bBuff, nextPrec[c][r]); |
||
1857 | |||
1858 | if (pktEnc.PacketWritable) |
||
1859 | { |
||
1860 | bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, false, sopUsed, ephUsed); |
||
1861 | bsWriter.writePacketBody(pktEnc.LastBodyBuf, pktEnc.LastBodyLen, false, pktEnc.ROIinPkt, pktEnc.ROILen); |
||
1862 | } |
||
1863 | } // layers |
||
1864 | nextPrec[c][r]++; |
||
1865 | } // Components |
||
1866 | if (px != pxend) |
||
1867 | { |
||
1868 | x = minx + px * gcd_x; |
||
1869 | } |
||
1870 | else |
||
1871 | { |
||
1872 | x = tx0; |
||
1873 | } |
||
1874 | } // Horizontal precincts |
||
1875 | if (py != pyend) |
||
1876 | { |
||
1877 | y = miny + py * gcd_y; |
||
1878 | } |
||
1879 | else |
||
1880 | { |
||
1881 | y = ty0; |
||
1882 | } |
||
1883 | } // Vertical precincts |
||
1884 | } // Resolution levels |
||
1885 | |||
1886 | // Check that all precincts have been written |
||
1887 | for (int c = cs; c < ce; c++) |
||
1888 | { |
||
1889 | mrl = src.getAnSubbandTree(t, c).resLvl; |
||
1890 | for (int r = rs; r < re; r++) |
||
1891 | { |
||
1892 | if (r > mrl) |
||
1893 | continue; |
||
1894 | if (nextPrec[c][r] < numPrec[t][c][r].x * numPrec[t][c][r].y - 1) |
||
1895 | { |
||
1896 | throw new System.ApplicationException("JJ2000 bug: One precinct at least has " + "not been written for resolution level " + r + " of component " + c + " in tile " + t + "."); |
||
1897 | } |
||
1898 | } |
||
1899 | } |
||
1900 | } |
||
1901 | |||
1902 | /// <summary> This function implements the rate-distortion optimization algorithm. |
||
1903 | /// It saves the state of any previously generated bit-stream layers and |
||
1904 | /// then simulate the formation of a new layer in the bit stream as often |
||
1905 | /// as necessary to find the smallest rate-distortion threshold such that |
||
1906 | /// the total number of bytes required to represent the layer does not |
||
1907 | /// exceed `maxBytes' minus `prevBytes'. It then restores the state of any |
||
1908 | /// previously generated bit-stream layers and returns the threshold. |
||
1909 | /// |
||
1910 | /// </summary> |
||
1911 | /// <param name="layerIdx">The index of the current layer |
||
1912 | /// |
||
1913 | /// </param> |
||
1914 | /// <param name="fmaxt">The maximum admissible slope value. Normally the threshold |
||
1915 | /// slope of the previous layer. |
||
1916 | /// |
||
1917 | /// </param> |
||
1918 | /// <param name="maxBytes">The maximum number of bytes that can be written. It |
||
1919 | /// includes the length of the current layer bistream length and all the |
||
1920 | /// previous layers bit streams. |
||
1921 | /// |
||
1922 | /// </param> |
||
1923 | /// <param name="prevBytes">The number of bytes of all the previous layers. |
||
1924 | /// |
||
1925 | /// </param> |
||
1926 | /// <returns> The value of the slope threshold. |
||
1927 | /// |
||
1928 | /// </returns> |
||
1929 | private float optimizeBitstreamLayer(int layerIdx, float fmaxt, int maxBytes, int prevBytes) |
||
1930 | { |
||
1931 | |||
1932 | int nt; // The total number of tiles |
||
1933 | int nc; // The total number of components |
||
1934 | int numLvls; // The total number of resolution levels |
||
1935 | int actualBytes; // Actual number of bytes for a layer |
||
1936 | float fmint; // Minimum of the current threshold interval |
||
1937 | float ft; // Current threshold |
||
1938 | SubbandAn sb; // Current subband |
||
1939 | BitOutputBuffer hBuff; // The packet head buffer |
||
1940 | byte[] bBuff; // The packet body buffer |
||
1941 | int sidx; // The index in the summary table |
||
1942 | bool sopUsed; // Should SOP markers be used ? |
||
1943 | bool ephUsed; // Should EPH markers be used ? |
||
1944 | //int precinctIdx; // Precinct index for current packet |
||
1945 | int nPrec; // Number of precincts in the current resolution level |
||
1946 | |||
1947 | // Save the packet encoder state |
||
1948 | pktEnc.save(); |
||
1949 | |||
1950 | nt = src.getNumTiles(); |
||
1951 | nc = src.NumComps; |
||
1952 | hBuff = null; |
||
1953 | bBuff = null; |
||
1954 | |||
1955 | // Estimate the minimum slope to start with from the summary |
||
1956 | // information in 'RDSlopesRates'. This is a real minimum since it |
||
1957 | // does not include the packet head overhead, which is always |
||
1958 | // non-zero. |
||
1959 | |||
1960 | // Look for the summary entry that gives 'maxBytes' or more data |
||
1961 | for (sidx = RD_SUMMARY_SIZE - 1; sidx > 0; sidx--) |
||
1962 | { |
||
1963 | if (RDSlopesRates[sidx] >= maxBytes) |
||
1964 | { |
||
1965 | break; |
||
1966 | } |
||
1967 | } |
||
1968 | // Get the corresponding minimum slope |
||
1969 | fmint = getSlopeFromSIndex(sidx); |
||
1970 | // Ensure that it is smaller the maximum slope |
||
1971 | if (fmint >= fmaxt) |
||
1972 | { |
||
1973 | sidx--; |
||
1974 | fmint = getSlopeFromSIndex(sidx); |
||
1975 | } |
||
1976 | // If we are using the last entry of the summary, then that |
||
1977 | // corresponds to all the data, Thus, set the minimum slope to 0. |
||
1978 | if (sidx <= 0) |
||
1979 | fmint = 0; |
||
1980 | |||
1981 | // We look for the best threshold 'ft', which is the lowest threshold |
||
1982 | // that generates no more than 'maxBytes' code bytes. |
||
1983 | |||
1984 | // The search is done iteratively using a binary split algorithm. We |
||
1985 | // start with 'fmaxt' as the maximum possible threshold, and 'fmint' |
||
1986 | // as the minimum threshold. The threshold 'ft' is calculated as the |
||
1987 | // middle point of 'fmaxt'-'fmint' interval. The 'fmaxt' or 'fmint' |
||
1988 | // bounds are moved according to the number of bytes obtained from a |
||
1989 | // simulation, where 'ft' is used as the threshold. |
||
1990 | |||
1991 | // We stop whenever the interval is sufficiently small, and thus |
||
1992 | // enough precision is achieved. |
||
1993 | |||
1994 | // Initialize threshold as the middle point of the interval. |
||
1995 | ft = (fmaxt + fmint) / 2f; |
||
1996 | // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are so |
||
1997 | // close that the average is 'fmint', due to rounding. Force it to |
||
1998 | // 'fmaxt' instead, since 'fmint' is normally an exclusive lower |
||
1999 | // bound. |
||
2000 | if (ft <= fmint) |
||
2001 | ft = fmaxt; |
||
2002 | |||
2003 | do |
||
2004 | { |
||
2005 | // Get the number of bytes used by this layer, if 'ft' is the |
||
2006 | // threshold, by simulation. |
||
2007 | actualBytes = prevBytes; |
||
2008 | src.setTile(0, 0); |
||
2009 | |||
2010 | for (int t = 0; t < nt; t++) |
||
2011 | { |
||
2012 | for (int c = 0; c < nc; c++) |
||
2013 | { |
||
2014 | // set boolean sopUsed here (SOP markers) |
||
2015 | sopUsed = ((System.String) encSpec.sops.getTileDef(t)).ToUpper().Equals("on".ToUpper()); |
||
2016 | // set boolean ephUsed here (EPH markers) |
||
2017 | ephUsed = ((System.String) encSpec.ephs.getTileDef(t)).ToUpper().Equals("on".ToUpper()); |
||
2018 | |||
2019 | // Get LL subband |
||
2020 | sb = (SubbandAn) src.getAnSubbandTree(t, c); |
||
2021 | numLvls = sb.resLvl + 1; |
||
2022 | sb = (SubbandAn) sb.getSubbandByIdx(0, 0); |
||
2023 | //loop on resolution levels |
||
2024 | for (int r = 0; r < numLvls; r++) |
||
2025 | { |
||
2026 | |||
2027 | nPrec = numPrec[t][c][r].x * numPrec[t][c][r].y; |
||
2028 | for (int p = 0; p < nPrec; p++) |
||
2029 | { |
||
2030 | |||
2031 | findTruncIndices(layerIdx, c, r, t, sb, ft, p); |
||
2032 | hBuff = pktEnc.encodePacket(layerIdx + 1, c, r, t, cblks[t][c][r], truncIdxs[t][layerIdx][c][r], hBuff, bBuff, p); |
||
2033 | |||
2034 | if (pktEnc.PacketWritable) |
||
2035 | { |
||
2036 | bBuff = pktEnc.LastBodyBuf; |
||
2037 | actualBytes += bsWriter.writePacketHead(hBuff.Buffer, hBuff.Length, true, sopUsed, ephUsed); |
||
2038 | actualBytes += bsWriter.writePacketBody(bBuff, pktEnc.LastBodyLen, true, pktEnc.ROIinPkt, pktEnc.ROILen); |
||
2039 | } |
||
2040 | } // end loop on precincts |
||
2041 | sb = sb.parentband; |
||
2042 | } // End loop on resolution levels |
||
2043 | } // End loop on components |
||
2044 | } // End loop on tiles |
||
2045 | |||
2046 | // Move the interval bounds according to simulation result |
||
2047 | if (actualBytes > maxBytes) |
||
2048 | { |
||
2049 | // 'ft' is too low and generates too many bytes, make it the |
||
2050 | // new minimum. |
||
2051 | fmint = ft; |
||
2052 | } |
||
2053 | else |
||
2054 | { |
||
2055 | // 'ft' is too high and does not generate as many bytes as we |
||
2056 | // are allowed too, make it the new maximum. |
||
2057 | fmaxt = ft; |
||
2058 | } |
||
2059 | |||
2060 | // Update 'ft' for the new iteration as the middle point of the |
||
2061 | // new interval. |
||
2062 | ft = (fmaxt + fmint) / 2f; |
||
2063 | // If 'ft' reaches 'fmint' it means that 'fmaxt' and 'fmint' are |
||
2064 | // so close that the average is 'fmint', due to rounding. Force it |
||
2065 | // to 'fmaxt' instead, since 'fmint' is normally an exclusive |
||
2066 | // lower bound. |
||
2067 | if (ft <= fmint) |
||
2068 | ft = fmaxt; |
||
2069 | |||
2070 | // Restore previous packet encoder state |
||
2071 | pktEnc.restore(); |
||
2072 | |||
2073 | // We continue to iterate, until the threshold reaches the upper |
||
2074 | // limit of the interval, within a FLOAT_REL_PRECISION relative |
||
2075 | // tolerance, or a FLOAT_ABS_PRECISION absolute tolerance. This is |
||
2076 | // the sign that the interval is sufficiently small. |
||
2077 | } |
||
2078 | while (ft < fmaxt * (1f - FLOAT_REL_PRECISION) && ft < (fmaxt - FLOAT_ABS_PRECISION)); |
||
2079 | |||
2080 | // If we have a threshold which is close to 0, set it to 0 so that |
||
2081 | // everything is taken into the layer. This is to avoid not sending |
||
2082 | // some least significant bit-planes in the lossless case. We use the |
||
2083 | // FLOAT_ABS_PRECISION value as a measure of "close" to 0. |
||
2084 | if (ft <= FLOAT_ABS_PRECISION) |
||
2085 | { |
||
2086 | ft = 0f; |
||
2087 | } |
||
2088 | else |
||
2089 | { |
||
2090 | // Otherwise make the threshold 'fmaxt', just to be sure that we |
||
2091 | // will not send more bytes than allowed. |
||
2092 | ft = fmaxt; |
||
2093 | } |
||
2094 | return ft; |
||
2095 | } |
||
2096 | |||
2097 | /// <summary> This function attempts to estimate a rate-distortion slope threshold |
||
2098 | /// which will achieve a target number of code bytes close the |
||
2099 | /// `targetBytes' value. |
||
2100 | /// |
||
2101 | /// </summary> |
||
2102 | /// <param name="targetBytes">The target number of bytes for the current layer |
||
2103 | /// |
||
2104 | /// </param> |
||
2105 | /// <param name="lastLayer">The previous layer information. |
||
2106 | /// |
||
2107 | /// </param> |
||
2108 | /// <returns> The value of the slope threshold for the estimated layer |
||
2109 | /// |
||
2110 | /// </returns> |
||
2111 | private float estimateLayerThreshold(int targetBytes, EBCOTLayer lastLayer) |
||
2112 | { |
||
2113 | float log_sl1; // The log of the first slope used for interpolation |
||
2114 | float log_sl2; // The log of the second slope used for interpolation |
||
2115 | float log_len1; // The log of the first length used for interpolation |
||
2116 | float log_len2; // The log of the second length used for interpolation |
||
2117 | float log_isl; // The log of the interpolated slope |
||
2118 | float log_ilen; // Log of the interpolated length |
||
2119 | float log_ab; // Log of actual bytes in last layer |
||
2120 | int sidx; // Index into the summary R-D info array |
||
2121 | float log_off; // The log of the offset proportion |
||
2122 | int tlen; // The corrected target layer length |
||
2123 | float lthresh; // The threshold of the last layer |
||
2124 | float eth; // The estimated threshold |
||
2125 | |||
2126 | // In order to estimate the threshold we base ourselves in the summary |
||
2127 | // R-D info in RDSlopesRates. In order to use it we must compensate |
||
2128 | // for the overhead of the packet heads. The proportion of overhead is |
||
2129 | // estimated using the last layer simulation results. |
||
2130 | |||
2131 | // NOTE: the model used in this method is that the slope varies |
||
2132 | // linearly with the log of the rate (i.e. length). |
||
2133 | |||
2134 | // NOTE: the model used in this method is that the distortion is |
||
2135 | // proprotional to a power of the rate. Thus, the slope is also |
||
2136 | // proportional to another power of the rate. This translates as the |
||
2137 | // log of the slope varies linearly with the log of the rate, which is |
||
2138 | // what we use. |
||
2139 | |||
2140 | // 1) Find the offset of the length predicted from the summary R-D |
||
2141 | // information, to the actual length by using the last layer. |
||
2142 | |||
2143 | // We ensure that the threshold we use for estimation actually |
||
2144 | // includes some data. |
||
2145 | lthresh = lastLayer.rdThreshold; |
||
2146 | if (lthresh > maxSlope) |
||
2147 | lthresh = maxSlope; |
||
2148 | // If the slope of the last layer is too small then we just include |
||
2149 | // all the rest (not possible to do better). |
||
2150 | if (lthresh < FLOAT_ABS_PRECISION) |
||
2151 | return 0f; |
||
2152 | sidx = getLimitedSIndexFromSlope(lthresh); |
||
2153 | // If the index is outside of the summary info array use the last two, |
||
2154 | // or first two, indexes, as appropriate |
||
2155 | if (sidx >= RD_SUMMARY_SIZE - 1) |
||
2156 | sidx = RD_SUMMARY_SIZE - 2; |
||
2157 | |||
2158 | // Get the logs of the lengths and the slopes |
||
2159 | |||
2160 | if (RDSlopesRates[sidx + 1] == 0) |
||
2161 | { |
||
2162 | // Pathological case, we can not use log of 0. Add |
||
2163 | // RDSlopesRates[sidx]+1 bytes to the rates (just a crude simple |
||
2164 | // solution to this rare case) |
||
2165 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2166 | log_len1 = (float) System.Math.Log((RDSlopesRates[sidx] << 1) + 1); |
||
2167 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2168 | log_len2 = (float) System.Math.Log(RDSlopesRates[sidx] + 1); |
||
2169 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2170 | log_ab = (float) System.Math.Log(lastLayer.actualBytes + RDSlopesRates[sidx] + 1); |
||
2171 | } |
||
2172 | else |
||
2173 | { |
||
2174 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2175 | log_len1 = (float) System.Math.Log(RDSlopesRates[sidx]); |
||
2176 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2177 | log_len2 = (float) System.Math.Log(RDSlopesRates[sidx + 1]); |
||
2178 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2179 | log_ab = (float) System.Math.Log(lastLayer.actualBytes); |
||
2180 | } |
||
2181 | |||
2182 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2183 | log_sl1 = (float) System.Math.Log(getSlopeFromSIndex(sidx)); |
||
2184 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2185 | log_sl2 = (float) System.Math.Log(getSlopeFromSIndex(sidx + 1)); |
||
2186 | |||
2187 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2188 | log_isl = (float) System.Math.Log(lthresh); |
||
2189 | |||
2190 | log_ilen = log_len1 + (log_isl - log_sl1) * (log_len1 - log_len2) / (log_sl1 - log_sl2); |
||
2191 | |||
2192 | log_off = log_ab - log_ilen; |
||
2193 | |||
2194 | // Do not use negative offsets (i.e. offset proportion larger than 1) |
||
2195 | // since that is probably a sign that our model is off. To be |
||
2196 | // conservative use an offset of 0 (i.e. offset proportiojn 1). |
||
2197 | if (log_off < 0) |
||
2198 | log_off = 0f; |
||
2199 | |||
2200 | // 2) Correct the target layer length by the offset. |
||
2201 | |||
2202 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2203 | tlen = (int) (targetBytes / (float) System.Math.Exp(log_off)); |
||
2204 | |||
2205 | // 3) Find, from the summary R-D info, the thresholds that generate |
||
2206 | // lengths just above and below our corrected target layer length. |
||
2207 | |||
2208 | // Look for the index in the summary info array that gives the largest |
||
2209 | // length smaller than the target length |
||
2210 | for (sidx = RD_SUMMARY_SIZE - 1; sidx >= 0; sidx--) |
||
2211 | { |
||
2212 | if (RDSlopesRates[sidx] >= tlen) |
||
2213 | break; |
||
2214 | } |
||
2215 | sidx++; |
||
2216 | // Correct if out of the array |
||
2217 | if (sidx >= RD_SUMMARY_SIZE) |
||
2218 | sidx = RD_SUMMARY_SIZE - 1; |
||
2219 | if (sidx <= 0) |
||
2220 | sidx = 1; |
||
2221 | |||
2222 | // Get the log of the lengths and the slopes that are just above and |
||
2223 | // below the target length. |
||
2224 | |||
2225 | if (RDSlopesRates[sidx] == 0) |
||
2226 | { |
||
2227 | // Pathological case, we can not use log of 0. Add |
||
2228 | // RDSlopesRates[sidx-1]+1 bytes to the rates (just a crude simple |
||
2229 | // solution to this rare case) |
||
2230 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2231 | log_len1 = (float) System.Math.Log(RDSlopesRates[sidx - 1] + 1); |
||
2232 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2233 | log_len2 = (float) System.Math.Log((RDSlopesRates[sidx - 1] << 1) + 1); |
||
2234 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2235 | log_ilen = (float) System.Math.Log(tlen + RDSlopesRates[sidx - 1] + 1); |
||
2236 | } |
||
2237 | else |
||
2238 | { |
||
2239 | // Normal case, we can safely take the logs. |
||
2240 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2241 | log_len1 = (float) System.Math.Log(RDSlopesRates[sidx]); |
||
2242 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2243 | log_len2 = (float) System.Math.Log(RDSlopesRates[sidx - 1]); |
||
2244 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2245 | log_ilen = (float) System.Math.Log(tlen); |
||
2246 | } |
||
2247 | |||
2248 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2249 | log_sl1 = (float) System.Math.Log(getSlopeFromSIndex(sidx)); |
||
2250 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2251 | log_sl2 = (float) System.Math.Log(getSlopeFromSIndex(sidx - 1)); |
||
2252 | |||
2253 | // 4) Interpolate the two thresholds to find the target threshold. |
||
2254 | |||
2255 | log_isl = log_sl1 + (log_ilen - log_len1) * (log_sl1 - log_sl2) / (log_len1 - log_len2); |
||
2256 | |||
2257 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2258 | eth = (float) System.Math.Exp(log_isl); |
||
2259 | |||
2260 | // Correct out of bounds results |
||
2261 | if (eth > lthresh) |
||
2262 | eth = lthresh; |
||
2263 | if (eth < FLOAT_ABS_PRECISION) |
||
2264 | eth = 0f; |
||
2265 | |||
2266 | // Return the estimated threshold |
||
2267 | return eth; |
||
2268 | } |
||
2269 | |||
2270 | /// <summary> This function finds the new truncation points indices for a packet. It |
||
2271 | /// does so by including the data from the code-blocks in the component, |
||
2272 | /// resolution level and tile, associated with a R-D slope which is larger |
||
2273 | /// than or equal to 'fthresh'. |
||
2274 | /// |
||
2275 | /// </summary> |
||
2276 | /// <param name="layerIdx">The index of the current layer |
||
2277 | /// |
||
2278 | /// </param> |
||
2279 | /// <param name="compIdx">The index of the current component |
||
2280 | /// |
||
2281 | /// </param> |
||
2282 | /// <param name="lvlIdx">The index of the current resolution level |
||
2283 | /// |
||
2284 | /// </param> |
||
2285 | /// <param name="tileIdx">The index of the current tile |
||
2286 | /// |
||
2287 | /// </param> |
||
2288 | /// <param name="subb">The LL subband in the resolution level lvlIdx, which is |
||
2289 | /// parent of all the subbands in the packet. Except for resolution level 0 |
||
2290 | /// this subband is always a node. |
||
2291 | /// |
||
2292 | /// </param> |
||
2293 | /// <param name="fthresh">The value of the rate-distortion threshold |
||
2294 | /// |
||
2295 | /// </param> |
||
2296 | private void findTruncIndices(int layerIdx, int compIdx, int lvlIdx, int tileIdx, SubbandAn subb, float fthresh, int precinctIdx) |
||
2297 | { |
||
2298 | int minsbi, maxsbi, b, n; // bIdx removed |
||
2299 | //Coord ncblks = null; |
||
2300 | SubbandAn sb; |
||
2301 | CBlkRateDistStats cur_cblk; |
||
2302 | PrecInfo prec = pktEnc.getPrecInfo(tileIdx, compIdx, lvlIdx, precinctIdx); |
||
2303 | Coord cbCoord; |
||
2304 | |||
2305 | sb = subb; |
||
2306 | while (sb.subb_HH != null) |
||
2307 | { |
||
2308 | sb = sb.subb_HH; |
||
2309 | } |
||
2310 | minsbi = (lvlIdx == 0)?0:1; |
||
2311 | maxsbi = (lvlIdx == 0)?1:4; |
||
2312 | |||
2313 | int yend, xend; |
||
2314 | |||
2315 | sb = (SubbandAn) subb.getSubbandByIdx(lvlIdx, minsbi); |
||
2316 | for (int s = minsbi; s < maxsbi; s++) |
||
2317 | { |
||
2318 | //loop on subbands |
||
2319 | yend = (prec.cblk[s] != null)?prec.cblk[s].Length:0; |
||
2320 | for (int y = 0; y < yend; y++) |
||
2321 | { |
||
2322 | xend = (prec.cblk[s][y] != null)?prec.cblk[s][y].Length:0; |
||
2323 | for (int x = 0; x < xend; x++) |
||
2324 | { |
||
2325 | cbCoord = prec.cblk[s][y][x].idx; |
||
2326 | b = cbCoord.x + cbCoord.y * sb.numCb.x; |
||
2327 | |||
2328 | //Get the current code-block |
||
2329 | cur_cblk = cblks[tileIdx][compIdx][lvlIdx][s][b]; |
||
2330 | for (n = 0; n < cur_cblk.nVldTrunc; n++) |
||
2331 | { |
||
2332 | if (cur_cblk.truncSlopes[n] < fthresh) |
||
2333 | { |
||
2334 | break; |
||
2335 | } |
||
2336 | else |
||
2337 | { |
||
2338 | continue; |
||
2339 | } |
||
2340 | } |
||
2341 | // Store the index in the code-block truncIdxs that gives |
||
2342 | // the real truncation index. |
||
2343 | truncIdxs[tileIdx][layerIdx][compIdx][lvlIdx][s][b] = n - 1; |
||
2344 | } // End loop on horizontal code-blocks |
||
2345 | } // End loop on vertical code-blocks |
||
2346 | sb = (SubbandAn) sb.nextSubband(); |
||
2347 | } // End loop on subbands |
||
2348 | } |
||
2349 | |||
2350 | /// <summary> Returns the index of a slope for the summary table, limiting to the |
||
2351 | /// admissible values. The index is calculated as RD_SUMMARY_OFF plus the |
||
2352 | /// maximum exponent, base 2, that yields a value not larger than the slope |
||
2353 | /// itself. |
||
2354 | /// |
||
2355 | /// <p>If the value to return is lower than 0, 0 is returned. If it is |
||
2356 | /// larger than the maximum table index, then the maximum is returned.</p> |
||
2357 | /// |
||
2358 | /// </summary> |
||
2359 | /// <param name="slope">The slope value |
||
2360 | /// |
||
2361 | /// </param> |
||
2362 | /// <returns> The index for the summary table of the slope. |
||
2363 | /// |
||
2364 | /// </returns> |
||
2365 | private static int getLimitedSIndexFromSlope(float slope) |
||
2366 | { |
||
2367 | int idx; |
||
2368 | |||
2369 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2370 | idx = (int) System.Math.Floor(System.Math.Log(slope) / LOG2) + RD_SUMMARY_OFF; |
||
2371 | |||
2372 | if (idx < 0) |
||
2373 | { |
||
2374 | return 0; |
||
2375 | } |
||
2376 | else if (idx >= RD_SUMMARY_SIZE) |
||
2377 | { |
||
2378 | return RD_SUMMARY_SIZE - 1; |
||
2379 | } |
||
2380 | else |
||
2381 | { |
||
2382 | return idx; |
||
2383 | } |
||
2384 | } |
||
2385 | |||
2386 | /// <summary> Returns the minimum slope value associated with a summary table |
||
2387 | /// index. This minimum slope is just 2^(index-RD_SUMMARY_OFF). |
||
2388 | /// |
||
2389 | /// </summary> |
||
2390 | /// <param name="index">The summary index value. |
||
2391 | /// |
||
2392 | /// </param> |
||
2393 | /// <returns> The minimum slope value associated with a summary table index. |
||
2394 | /// |
||
2395 | /// </returns> |
||
2396 | private static float getSlopeFromSIndex(int index) |
||
2397 | { |
||
2398 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
2399 | return (float) System.Math.Pow(2, (index - RD_SUMMARY_OFF)); |
||
2400 | } |
||
2401 | } |
||
2402 | } |