OpenJPH
Open-source implementation of JPEG2000 Part-15
ojph_codestream.cpp
Go to the documentation of this file.
1 //***************************************************************************/
2 // This software is released under the 2-Clause BSD license, included
3 // below.
4 //
5 // Copyright (c) 2019, Aous Naman
6 // Copyright (c) 2019, Kakadu Software Pty Ltd, Australia
7 // Copyright (c) 2019, The University of New South Wales, Australia
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are
11 // met:
12 //
13 // 1. Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright
17 // notice, this list of conditions and the following disclaimer in the
18 // documentation and/or other materials provided with the distribution.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 //***************************************************************************/
32 // This file is part of the OpenJPH software implementation.
33 // File: ojph_codestream.cpp
34 // Author: Aous Naman
35 // Date: 28 August 2019
36 //***************************************************************************/
37 
38 
39 #include <climits>
40 #include <cmath>
41 
42 #include "ojph_file.h"
43 #include "ojph_mem.h"
44 #include "ojph_params.h"
45 #include "ojph_codestream.h"
46 #include "ojph_codestream_local.h"
47 
48 #include "../transform/ojph_colour.h"
49 #include "../transform/ojph_transform.h"
50 #include "../coding/ojph_block_decoder.h"
51 #include "../coding/ojph_block_encoder.h"
52 
53 namespace ojph {
54 
56  //
57  //
58  //
59  //
60  //
62 
65  {
66  if (state) delete state;
67  }
68 
71  {
73  }
74 
77  {
78  return param_siz(&state->siz);
79  }
80 
83  {
84  return param_cod(&state->cod);
85  }
86 
89  {
90  return param_qcd(&state->qcd);
91  }
92 
94  void codestream::set_planar(bool planar)
95  {
96  state->set_planar(planar ? 1 : 0);
97  }
98 
100  void codestream::set_profile(const char *s)
101  {
102  state->set_profile(s);
103  }
104 
107  {
108  return state->is_planar();
109  }
110 
113  {
114  state->write_headers(file);
115  }
116 
119  {
121  }
122 
125  {
126  state->read_headers(file);
127  }
128 
130  void codestream::restrict_input_resolution(ui32 skipped_res_for_read,
131  ui32 skipped_res_for_recon)
132  {
133  state->restrict_input_resolution(skipped_res_for_read,
134  skipped_res_for_recon);
135  }
136 
139  {
140  state->read();
141  }
142 
145  {
146  return state->pull(comp_num);
147  }
148 
149 
152  {
153  state->flush();
154  }
155 
158  {
159  state->close();
160  }
161 
163  line_buf* codestream::exchange(line_buf* line, ui32& next_component)
164  {
165  return state->exchange(line, next_component);
166  }
167 
168 
169 
171  //
172  //
173  // LOCAL
174  //
175  //
177 
178  namespace local
179  {
180 
182  static inline
184  {
185  return (ui16)((t << 8) | (t >> 8));
186  }
187 
189  //
190  //
191  //
192  //
193  //
195 
198  : precinct_scratch(NULL), allocator(NULL), elastic_alloc(NULL)
199  {
200  tiles = NULL;
201  line = NULL;
202  comp_size = NULL;
203  recon_comp_size = NULL;
204  allocator = NULL;
205  outfile = NULL;
206  infile = NULL;
207 
208  num_comps = 0;
209  employ_color_transform = false;
210  planar = -1;
212 
213  cur_comp = 0;
214  cur_line = 0;
215  cur_tile_row = 0;
216  resilient = false;
218 
220 
221  used_qcc_fields = 0;
222  qcc = qcc_store;
223 
225  elastic_alloc = new mem_elastic_allocator(1048576); //1 megabyte
226 
229  }
230 
233  {
234  if (qcc_store != qcc)
235  delete[] qcc;
236  if (allocator)
237  delete allocator;
238  if (elastic_alloc)
239  delete elastic_alloc;
240  }
241 
244  {
250  if (num_tiles.area() > 65535)
251  OJPH_ERROR(0x00030011, "number of tiles cannot exceed 65535");
252 
253  //allocate tiles
255 
256  point index;
257  rect tile_rect, recon_tile_rect;
258  ui32 ds = 1 << skipped_res_for_recon;
259  for (index.y = 0; index.y < num_tiles.h; ++index.y)
260  {
261  ui32 y0 = sz.get_tile_offset().y
262  + index.y * sz.get_tile_size().h;
263  ui32 y1 = y0 + sz.get_tile_size().h; //end of tile
264 
265  tile_rect.org.y = ojph_max(y0, sz.get_image_offset().y);
266  tile_rect.siz.h =
267  ojph_min(y1, sz.get_image_extent().y) - tile_rect.org.y;
268 
269  recon_tile_rect.org.y = ojph_max(ojph_div_ceil(y0, ds),
270  ojph_div_ceil(sz.get_image_offset().y, ds));
271  recon_tile_rect.siz.h = ojph_min(ojph_div_ceil(y1, ds),
272  ojph_div_ceil(sz.get_image_extent().y, ds))
273  - recon_tile_rect.org.y;
274 
275  for (index.x = 0; index.x < num_tiles.w; ++index.x)
276  {
277  ui32 x0 = sz.get_tile_offset().x
278  + index.x * sz.get_tile_size().w;
279  ui32 x1 = x0 + sz.get_tile_size().w;
280 
281  tile_rect.org.x = ojph_max(x0, sz.get_image_offset().x);
282  tile_rect.siz.w =
283  ojph_min(x1, sz.get_image_extent().x) - tile_rect.org.x;
284 
285  recon_tile_rect.org.x = ojph_max(ojph_div_ceil(x0, ds),
286  ojph_div_ceil(sz.get_image_offset().x, ds));
287  recon_tile_rect.siz.w = ojph_min(ojph_div_ceil(x1, ds),
288  ojph_div_ceil(sz.get_image_extent().x, ds))
289  - recon_tile_rect.org.x;
290 
291  tile::pre_alloc(this, tile_rect, recon_tile_rect);
292  }
293  }
294 
295  //allocate lines
296  //These lines are used by codestream to exchange data with external
297  // world
300  allocator->pre_alloc_obj<size>(num_comps); //for *comp_size
301  allocator->pre_alloc_obj<size>(num_comps); //for *recon_comp_size
302  ui32 width = 0;
303  for (ui32 i = 0; i < num_comps; ++i)
304  width = ojph_max(width, siz.get_recon_width(i));
305 
306  allocator->pre_alloc_data<si32>(width, 0);
307 
308  //allocate tlm
309  if (outfile != NULL)
310  {
312  {
313  ui32 num_pairs = (ui32)num_tiles.area() * num_comps;
315  }
316  else
317  {
318  ui32 num_pairs = (ui32)num_tiles.area();
320  }
321  }
322 
323  //precinct scratch buffer
324  ui32 num_decomps = cod.get_num_decompositions();
325  size log_cb = cod.get_log_block_dims();
326 
327  size ratio;
328  for (ui32 r = 0; r <= num_decomps; ++r)
329  {
330  size log_PP = cod.get_log_precinct_size(r);
331  log_PP.w -= (r ? 1 : 0);
332  log_PP.h -= (r ? 1 : 0);
333  ratio.w = ojph_max(ratio.w, log_PP.w - ojph_min(log_cb.w, log_PP.w));
334  ratio.h = ojph_max(ratio.h, log_PP.h - ojph_min(log_cb.h, log_PP.h));
335  }
336  ui32 max_ratio = ojph_max(ratio.w, ratio.h);
337  max_ratio = 1 << max_ratio;
338  // assuming that we have a hierarchy of n levels.
339  // This needs 4/3 times the area, rounded up
340  // (rounding up leaves one extra entry).
341  // This exta entry is necessary
342  // We need 4 such tables. These tables store
343  // 1. missing msbs and 2. their flags,
344  // 3. number of layers and 4. their flags
346  4 * ((max_ratio * max_ratio * 4 + 2) / 3);
347 
349  }
350 
353  {
354  allocator->alloc();
355 
356  //precinct scratch buffer
359 
360  //get tiles
362 
363  point index;
364  rect tile_rect, recon_tile_rect;
366  ui32 ds = 1 << skipped_res_for_recon;
367  for (index.y = 0; index.y < num_tiles.h; ++index.y)
368  {
369  ui32 y0 = sz.get_tile_offset().y
370  + index.y * sz.get_tile_size().h;
371  ui32 y1 = y0 + sz.get_tile_size().h; //end of tile
372 
373  tile_rect.org.y = ojph_max(y0, sz.get_image_offset().y);
374  tile_rect.siz.h =
375  ojph_min(y1, sz.get_image_extent().y) - tile_rect.org.y;
376 
377  recon_tile_rect.org.y = ojph_max(ojph_div_ceil(y0, ds),
378  ojph_div_ceil(sz.get_image_offset().y, ds));
379  recon_tile_rect.siz.h = ojph_min(ojph_div_ceil(y1, ds),
380  ojph_div_ceil(sz.get_image_extent().y, ds))
381  - recon_tile_rect.org.y;
382 
383  ui32 offset = 0;
384  for (index.x = 0; index.x < num_tiles.w; ++index.x)
385  {
386  ui32 x0 = sz.get_tile_offset().x
387  + index.x * sz.get_tile_size().w;
388  ui32 x1 = x0 + sz.get_tile_size().w;
389 
390  tile_rect.org.x = ojph_max(x0, sz.get_image_offset().x);
391  tile_rect.siz.w =
392  ojph_min(x1, sz.get_image_extent().x) - tile_rect.org.x;
393 
394  recon_tile_rect.org.x = ojph_max(ojph_div_ceil(x0, ds),
395  ojph_div_ceil(sz.get_image_offset().x, ds));
396  recon_tile_rect.siz.w = ojph_min(ojph_div_ceil(x1, ds),
397  ojph_div_ceil(sz.get_image_extent().x, ds))
398  - recon_tile_rect.org.x;
399 
400  ui32 idx = index.y * num_tiles.w + index.x;
401  tiles[idx].finalize_alloc(this, tile_rect, recon_tile_rect,
402  idx, offset);
403  offset += recon_tile_rect.siz.w;
404  }
405  }
406 
407  //allocate lines
408  //These lines are used by codestream to exchange data with external
409  // world
415  ui32 width = 0;
416  for (ui32 i = 0; i < num_comps; ++i)
417  {
418  comp_size[i].w = siz.get_width(i);
419  comp_size[i].h = siz.get_height(i);
420  ui32 cw = siz.get_recon_width(i);
421  recon_comp_size[i].w = cw;
423  width = ojph_max(width, cw);
424  }
425 
426  line->wrap(allocator->post_alloc_data<si32>(width, 0), width, 0);
427 
428  cur_comp = 0;
429  cur_line = 0;
430 
431  //allocate tlm
432  if (outfile != NULL)
433  {
435  {
436  ui32 num_pairs = (ui32)num_tiles.area() * num_comps;
437  tlm.init(num_pairs,
439  }
440  else
441  {
442  ui32 num_pairs = (ui32)num_tiles.area();
443  tlm.init(num_pairs,
445  }
446  }
447  }
448 
449 
452  {
453  //two possibilities lossy single tile or lossless
454  //For the following code, we use the least strict profile
455  ojph::param_siz sz(&siz);
456  ojph::param_cod cd(&cod);
457  bool reversible = cd.is_reversible();
458  bool imf2k = !reversible, imf4k = !reversible, imf8k = !reversible;
459  bool imf2kls = reversible, imf4kls = reversible, imf8kls = reversible;
460 
461  if (reversible)
462  {
463  point ext = sz.get_image_extent();
464  if (ext.x <= 2048 && ext.y <= 1556)
465  imf2kls &= true;
466  if (ext.x <= 4096 && ext.y <= 3112)
467  imf4kls &= true;
468  if (ext.x <= 8192 && ext.y <= 6224)
469  imf8kls &= true;
470 
471  if (!imf2kls && !imf4kls && !imf8kls)
472  OJPH_ERROR(0x000300C1,
473  "Image dimensions do not meet any of the lossless IMF profiles");
474  }
475  else
476  {
477  point ext = sz.get_image_extent();
478  if (ext.x <= 2048 && ext.y <= 1556)
479  imf2k &= true;
480  if (ext.x <= 4096 && ext.y <= 3112)
481  imf4k &= true;
482  if (ext.x <= 8192 && ext.y <= 6224)
483  imf8k &= true;
484 
485  if (!imf2k && !imf4k && !imf8k)
486  OJPH_ERROR(0x000300C2,
487  "Image dimensions do not meet any of the lossy IMF profiles");
488  }
489 
490 
491  if (sz.get_image_offset().x != 0 || sz.get_image_offset().y != 0)
492  OJPH_ERROR(0x000300C3,
493  "For IMF profile, image offset (XOsiz, YOsiz) has to be 0.");
494  if (sz.get_tile_offset().x != 0 || sz.get_tile_offset().y != 0)
495  OJPH_ERROR(0x000300C4,
496  "For IMF profile, tile offset (XTOsiz, YTOsiz) has to be 0.");
497  if (sz.get_num_components() > 3)
498  OJPH_ERROR(0x000300C5,
499  "For IMF profile, the number of components has to be less "
500  " or equal to 3");
501  bool test_ds1 = true, test_ds2 = true;
502  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
503  {
504  point downsamping = sz.get_downsampling(i);
505  test_ds1 &= downsamping.y == 1;
506  test_ds2 &= downsamping.y == 1;
507 
508  test_ds1 &= downsamping.x == 1;
509  if (i == 1 || i == 2)
510  test_ds2 &= downsamping.x == 2;
511  else
512  test_ds2 &= downsamping.x == 1;
513  }
514  if (!test_ds1 && !test_ds2)
515  OJPH_ERROR(0x000300C6,
516  "For IMF profile, either no component downsampling is used,"
517  " or the x-dimension of the 2nd and 3rd components is downsampled"
518  " by 2.");
519 
520  bool test_bd = true;
521  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
522  {
523  ui32 bit_depth = sz.get_bit_depth(i);
524  bool is_signed = sz.is_signed(i);
525  test_bd &= bit_depth >= 8 && bit_depth <= 16 && is_signed == false;
526  }
527  if (!test_bd)
528  OJPH_ERROR(0x000300C7,
529  "For IMF profile, compnent bit_depth has to be between"
530  " 8 and 16 bits inclusively, and the samples must be unsigned");
531 
532  if (cd.get_log_block_dims().w != 5 || cd.get_log_block_dims().h != 5)
533  OJPH_ERROR(0x000300C8,
534  "For IMF profile, codeblock dimensions are restricted."
535  " Use \"-block_size {32,32}\" at the commandline");
536 
537  ui32 num_decomps = cd.get_num_decompositions();
538  bool test_pz = cd.get_log_precinct_size(0).w == 7
539  && cd.get_log_precinct_size(0).h == 7;
540  for (ui32 i = 1; i <= num_decomps; ++i)
541  test_pz = cd.get_log_precinct_size(i).w == 8
542  && cd.get_log_precinct_size(i).h == 8;
543  if (!test_pz)
544  OJPH_ERROR(0x000300C9,
545  "For IMF profile, precinct sizes are restricted."
546  " Use \"-precincts {128,128},{256,256}\" at the commandline");
547 
549  OJPH_ERROR(0x000300CA,
550  "For IMF profile, the CPRL progression order must be used."
551  " Use \"-prog_order CPRL\".");
552 
553  imf2k &= num_decomps <= 5;
554  imf2kls &= num_decomps <= 5;
555  imf4k &= num_decomps <= 6;
556  imf4kls &= num_decomps <= 6;
557  imf8k &= num_decomps <= 7;
558  imf8kls &= num_decomps <= 7;
559 
560  if (num_decomps == 0 ||
561  (!imf2k && !imf4k && !imf8k && !imf2kls && !imf4kls && !imf8kls))
562  OJPH_ERROR(0x000300CB,
563  "Number of decompositions does not match the IMF profile"
564  " dictated by wavelet reversibility and image dimensions.");
565 
566  ui32 tiles_w = sz.get_image_extent().x;
567  tiles_w = ojph_div_ceil(tiles_w, sz.get_tile_size().w);
568  ui32 tiles_h = sz.get_image_extent().y;
569  tiles_h = ojph_div_ceil(tiles_h, sz.get_tile_size().h);
570  ui32 total_tiles = tiles_w * tiles_h;
571 
572  if (total_tiles > 1)
573  {
574  if (!reversible)
575  OJPH_ERROR(0x000300CC,
576  "Lossy IMF profile must have one tile.");
577 
578  size tt = sz.get_tile_size();
579  imf2kls &= (tt.w == 1024 && tt.h == 1024);
580  imf2kls &= (tt.w >= 1024 && num_decomps <= 4)
581  || (tt.w >= 2048 && num_decomps <= 5);
582  imf4kls &= (tt.w == 1024 && tt.h == 1024)
583  || (tt.w == 2048 && tt.h == 2048);
584  imf4kls &= (tt.w >= 1024 && num_decomps <= 4)
585  || (tt.w >= 2048 && num_decomps <= 5)
586  || (tt.w >= 4096 && num_decomps <= 6);
587  imf8kls &= (tt.w == 1024 && tt.h == 1024)
588  || (tt.w == 2048 && tt.h == 2048)
589  || (tt.w == 4096 && tt.h == 4096);
590  imf8kls &= (tt.w >= 1024 && num_decomps <= 4)
591  || (tt.w >= 2048 && num_decomps <= 5)
592  || (tt.w >= 4096 && num_decomps <= 6)
593  || (tt.w >= 8192 && num_decomps <= 7);
594  if (!imf2kls && !imf4kls && !imf8kls)
595  OJPH_ERROR(0x000300CD,
596  "Number of decompositions does not match the IMF profile"
597  " dictated by wavelet reversibility and image dimensions and"
598  " tiles.");
599  }
600 
601  }
602 
605  {
606  ojph::param_siz sz(&siz);
607  ojph::param_cod cd(&cod);
608 
609  if (sz.get_image_offset().x != 0 || sz.get_image_offset().y != 0)
610  OJPH_ERROR(0x000300B1,
611  "For broadcast profile, image offset (XOsiz, YOsiz) has to be 0.");
612  if (sz.get_tile_offset().x != 0 || sz.get_tile_offset().y != 0)
613  OJPH_ERROR(0x000300B2,
614  "For broadcast profile, tile offset (XTOsiz, YTOsiz) has to be 0.");
615  if (sz.get_num_components() > 4)
616  OJPH_ERROR(0x000300B3,
617  "For broadcast profile, the number of components has to be less "
618  " or equal to 4");
619  bool test_ds1 = true, test_ds2 = true;
620  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
621  {
622  point downsamping = sz.get_downsampling(i);
623  test_ds1 &= downsamping.y == 1;
624  test_ds2 &= downsamping.y == 1;
625 
626  test_ds1 &= downsamping.x == 1;
627  if (i == 1 || i == 2)
628  test_ds2 &= downsamping.x == 2;
629  else
630  test_ds2 &= downsamping.x == 1;
631  }
632  if (!test_ds1 && !test_ds2)
633  OJPH_ERROR(0x000300B4,
634  "For broadcast profile, either no component downsampling is used,"
635  " or the x-dimension of the 2nd and 3rd components is downsampled"
636  " by 2.");
637 
638  bool test_bd = true;
639  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
640  {
641  ui32 bit_depth = sz.get_bit_depth(i);
642  bool is_signed = sz.is_signed(i);
643  test_bd &= bit_depth >= 8 && bit_depth <= 12 && is_signed == false;
644  }
645  if (!test_bd)
646  OJPH_ERROR(0x000300B5,
647  "For broadcast profile, compnent bit_depth has to be between"
648  " 8 and 12 bits inclusively, and the samples must be unsigned");
649 
650  ui32 num_decomps = cd.get_num_decompositions();
651  if (num_decomps == 0 || num_decomps > 5)
652  OJPH_ERROR(0x000300B6,
653  "For broadcast profile, number of decompositions has to be between"
654  "1 and 5 inclusively.");
655 
656  if (cd.get_log_block_dims().w < 5 || cd.get_log_block_dims().w > 7)
657  OJPH_ERROR(0x000300B7,
658  "For broadcast profile, codeblock dimensions are restricted such"
659  " that codeblock width has to be either 32, 64, or 128.");
660 
661  if (cd.get_log_block_dims().h < 5 || cd.get_log_block_dims().h > 7)
662  OJPH_ERROR(0x000300B8,
663  "For broadcast profile, codeblock dimensions are restricted such"
664  " that codeblock height has to be either 32, 64, or 128.");
665 
666  bool test_pz = cd.get_log_precinct_size(0).w == 7
667  && cd.get_log_precinct_size(0).h == 7;
668  for (ui32 i = 1; i <= num_decomps; ++i)
669  test_pz = cd.get_log_precinct_size(i).w == 8
670  && cd.get_log_precinct_size(i).h == 8;
671  if (!test_pz)
672  OJPH_ERROR(0x000300B9,
673  "For broadcast profile, precinct sizes are restricted."
674  " Use \"-precincts {128,128},{256,256}\" at the commandline");
675 
677  OJPH_ERROR(0x000300BA,
678  "For broadcast profile, the CPRL progression order must be used."
679  " Use \"-prog_order CPRL\".");
680 
681  ui32 tiles_w = sz.get_image_extent().x;
682  tiles_w = ojph_div_ceil(tiles_w, sz.get_tile_size().w);
683  ui32 tiles_h = sz.get_image_extent().y;
684  tiles_h = ojph_div_ceil(tiles_h, sz.get_tile_size().h);
685  ui32 total_tiles = tiles_w * tiles_h;
686 
687  if (total_tiles != 1 && total_tiles != 4)
688  OJPH_ERROR(0x000300BB,
689  "The broadcast profile can only have 1 or 4 tiles");
690  }
691 
694  {
695  //finalize
700  if (profile == OJPH_PN_IMF)
702  else if (profile == OJPH_PN_BROADCAST)
704 
705  if (planar == -1) //not initialized
707  else if (planar == 0) //interleaved is chosen
708  {
709  }
710  else if (planar == 1) //plannar is chosen
711  {
712  if (cod.is_employing_color_transform() == true)
713  OJPH_ERROR(0x00030021,
714  "the planar interface option cannot be used when colour "
715  "transform is employed");
716  }
717  else
718  assert(0);
719 
720  assert(this->outfile == NULL);
721  this->outfile = file;
722  this->pre_alloc();
723  this->finalize_alloc();
724 
726  if (file->write(&t, 2) != 2)
727  OJPH_ERROR(0x00030022, "Error writing to file");
728 
729  if (!siz.write(file))
730  OJPH_ERROR(0x00030023, "Error writing to file");
731 
732  if (!cap.write(file))
733  OJPH_ERROR(0x00030024, "Error writing to file");
734 
735  if (!cod.write(file))
736  OJPH_ERROR(0x00030025, "Error writing to file");
737 
738  if (!qcd.write(file))
739  OJPH_ERROR(0x00030026, "Error writing to file");
740 
741  char buf[] = " OpenJPH Ver "
745  size_t len = strlen(buf);
746  *(ui16*)buf = swap_byte(JP2K_MARKER::COM);
747  *(ui16*)(buf + 2) = swap_byte((ui16)(len - 2));
748  //1 for General use (IS 8859-15:1999 (Latin) values)
749  *(ui16*)(buf + 4) = swap_byte((ui16)(1));
750  if (file->write(buf, len) != len)
751  OJPH_ERROR(0x00030027, "Error writing to file");
752  }
753 
755  static
756  int find_marker(infile_base *f, const ui16* char_list, int list_len)
757  {
758  //returns the marker index in char_list, or -1
759  while (!f->eof())
760  {
761  ui8 new_char;
762  size_t num_bytes = f->read(&new_char, 1);
763  if (num_bytes != 1)
764  return -1;
765  if (new_char == 0xFF)
766  {
767  size_t num_bytes = f->read(&new_char, 1);
768 
769  if (num_bytes != 1)
770  return -1;
771 
772  for (int i = 0; i < list_len; ++i)
773  if (new_char == (char_list[i] & 0xFF))
774  return i;
775  }
776  }
777  return -1;
778  }
779 
781  static
782  int skip_marker(infile_base *file, const char *marker,
783  const char *msg, int msg_level, bool resilient)
784  {
785  ojph_unused(marker);
786  ui16 com_len;
787  if (file->read(&com_len, 2) != 2)
788  {
789  if (resilient)
790  return -1;
791  else
792  OJPH_ERROR(0x00030041, "error reading marker");
793  }
794  com_len = swap_byte(com_len);
795  file->seek(com_len - 2, infile_base::OJPH_SEEK_CUR);
796  if (msg != NULL && msg_level != OJPH_MSG_LEVEL::NO_MSG)
797  {
798  if (msg_level == OJPH_MSG_LEVEL::INFO)
799  {
800  OJPH_INFO(0x00030001, "%s\n", msg);
801  }
802  else if (msg_level == OJPH_MSG_LEVEL::WARN)
803  {
804  OJPH_WARN(0x00030001, "%s\n", msg);
805  }
806  else if (msg_level == OJPH_MSG_LEVEL::ERROR)
807  {
808  OJPH_ERROR(0x00030001, "%s\n", msg);
809  }
810  else
811  assert(0);
812  }
813  return 0;
814  }
815 
818  {
819  ui16 marker_list[17] = { SOC, SIZ, CAP, PRF, CPF, COD, COC, QCD, QCC,
820  RGN, POC, PPM, TLM, PLM, CRG, COM, SOT };
821  find_marker(file, marker_list, 1); //find SOC
822  find_marker(file, marker_list + 1, 1); //find SIZ
823  siz.read(file);
824  int marker_idx = 0;
825  int received_markers = 0; //check that COD, & QCD received
826  while (true)
827  {
828  marker_idx = find_marker(file, marker_list + 2, 15);
829  if (marker_idx == 0)
830  cap.read(file);
831  else if (marker_idx == 1)
832  //Skipping PRF marker segment; this should not cause any issues
833  skip_marker(file, "PRF", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
834  else if (marker_idx == 2)
835  //Skipping CPF marker segment; this should not cause any issues
836  skip_marker(file, "CPF", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
837  else if (marker_idx == 3)
838  { cod.read(file); received_markers |= 1; }
839  else if (marker_idx == 4)
840  skip_marker(file, "COC", "COC is not supported yet",
841  OJPH_MSG_LEVEL::WARN, false);
842  else if (marker_idx == 5)
843  { qcd.read(file); received_markers |= 2; }
844  else if (marker_idx == 6)
845  {
847  if (qcc == qcc_store &&
848  num_comps * sizeof(param_qcc) > sizeof(qcc_store))
849  {
850  qcc = new param_qcc[num_comps];
851  }
852  qcc[used_qcc_fields++].read(file, num_comps);
853  }
854  else if (marker_idx == 7)
855  skip_marker(file, "RGN", "RGN is not supported yet",
856  OJPH_MSG_LEVEL::WARN, false);
857  else if (marker_idx == 8)
858  skip_marker(file, "POC", "POC is not supported yet",
859  OJPH_MSG_LEVEL::WARN, false);
860  else if (marker_idx == 9)
861  skip_marker(file, "PPM", "PPM is not supported yet",
862  OJPH_MSG_LEVEL::WARN, false);
863  else if (marker_idx == 10)
864  //Skipping TLM marker segment; this should not cause any issues
865  skip_marker(file, "TLM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
866  else if (marker_idx == 11)
867  //Skipping PLM marker segment; this should not cause any issues
868  skip_marker(file, "PLM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
869  else if (marker_idx == 12)
870  //Skipping CRG marker segment;
871  skip_marker(file, "CRG", "CRG has been ignored; CRG is related to"
872  " where the Cb and Cr colour components are co-sited or located"
873  " with respect to the Y' luma component. Perhaps, it is better"
874  " to get the indivdual components and assemble the samples"
875  " according to your needs",
876  OJPH_MSG_LEVEL::INFO, false);
877  else if (marker_idx == 13)
878  skip_marker(file, "COM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
879  else if (marker_idx == 14)
880  break;
881  else
882  OJPH_ERROR(0x00030051, "File ended before finding a tile segment");
883  }
884 
885  if (received_markers != 3)
886  OJPH_ERROR(0x00030052, "markers error, COD and QCD are required");
887 
888  this->infile = file;
890  }
891 
893  void codestream::restrict_input_resolution(ui32 skipped_res_for_read,
894  ui32 skipped_res_for_recon)
895  {
897  OJPH_ERROR(0x000300A1,
898  "skipped_resolution for data %d must be equal or smaller than "
899  " skipped_resolution for reconstruction %d\n",
902  OJPH_ERROR(0x000300A2,
903  "skipped_resolution for data %d must be smaller than "
904  " the number of decomposition levels %d\n",
906 
907  this->skipped_res_for_read = skipped_res_for_read;
908  this->skipped_res_for_recon = skipped_res_for_recon;
910  }
911 
914  {
915  if (infile != NULL)
916  OJPH_ERROR(0x000300A3, "Codestream resilience must be enabled before"
917  " reading file headers.\n");
918  this->resilient = true;
919  }
920 
923  {
924  this->pre_alloc();
925  this->finalize_alloc();
926 
927  while (true)
928  {
929  param_sot sot;
930  if (sot.read(infile, resilient))
931  {
932  ui64 tile_start_location = (ui64)infile->tell();
933 
934  if (sot.get_tile_index() > (int)num_tiles.area())
935  {
936  if (resilient)
937  OJPH_INFO(0x00030061, "wrong tile index")
938  else
939  OJPH_ERROR(0x00030061, "wrong tile index")
940  }
941 
942  if (sot.get_tile_part_index())
943  { //tile part
944  if (sot.get_num_tile_parts() &&
946  {
947  if (resilient)
948  OJPH_INFO(0x00030062,
949  "error in tile part number, should be smaller than total"
950  " number of tile parts")
951  else
952  OJPH_ERROR(0x00030062,
953  "error in tile part number, should be smaller than total"
954  " number of tile parts")
955  }
956 
957  bool sod_found = false;
958  ui16 other_tile_part_markers[6] = { SOT, POC, PPT, PLT, COM, SOD };
959  while (true)
960  {
961  int marker_idx = 0;
962  int result = 0;
963  marker_idx = find_marker(infile, other_tile_part_markers + 1, 5);
964  if (marker_idx == 0)
965  result = skip_marker(infile, "POC",
966  "POC in a tile is not supported yet",
968  else if (marker_idx == 1)
969  result = skip_marker(infile, "PPT",
970  "PPT in a tile is not supported yet",
972  else if (marker_idx == 2)
973  //Skipping PLT marker segment;this should not cause any issues
974  result = skip_marker(infile, "PLT", NULL,
976  else if (marker_idx == 3)
977  result = skip_marker(infile, "COM", NULL,
979  else if (marker_idx == 4)
980  {
981  sod_found = true;
982  break;
983  }
984 
985  if (marker_idx == -1) //marker not found
986  {
987  if (resilient)
988  OJPH_INFO(0x00030063,
989  "File terminated early before start of data is found"
990  " for tile indexed %d and tile part %d",
991  sot.get_tile_index(), sot.get_tile_part_index())
992  else
993  OJPH_ERROR(0x00030063,
994  "File terminated early before start of data is found"
995  " for tile indexed %d and tile part %d",
996  sot.get_tile_index(), sot.get_tile_part_index())
997  break;
998  }
999  if (result == -1) //file terminated during marker seg. skipping
1000  {
1001  if (resilient)
1002  OJPH_INFO(0x00030064,
1003  "File terminated during marker segment skipping")
1004  else
1005  OJPH_ERROR(0x00030064,
1006  "File terminated during marker segment skipping")
1007  break;
1008  }
1009  }
1010  if (sod_found)
1012  tile_start_location);
1013  }
1014  else
1015  { //first tile part
1016  bool sod_found = false;
1017  ui16 first_tile_part_markers[11] = { SOT, COD, COC, QCD, QCC, RGN,
1018  POC, PPT, PLT, COM, SOD };
1019  while (true)
1020  {
1021  int marker_idx = 0;
1022  int result = 0;
1023  marker_idx = find_marker(infile, first_tile_part_markers+1, 10);
1024  if (marker_idx == 0)
1025  result = skip_marker(infile, "COD",
1026  "COD in a tile is not supported yet",
1028  else if (marker_idx == 1)
1029  result = skip_marker(infile, "COC",
1030  "COC in a tile is not supported yet",
1032  else if (marker_idx == 2)
1033  result = skip_marker(infile, "QCD",
1034  "QCD in a tile is not supported yet",
1036  else if (marker_idx == 3)
1037  result = skip_marker(infile, "QCC",
1038  "QCC in a tile is not supported yet",
1040  else if (marker_idx == 4)
1041  result = skip_marker(infile, "RGN",
1042  "RGN in a tile is not supported yet",
1044  else if (marker_idx == 5)
1045  result = skip_marker(infile, "POC",
1046  "POC in a tile is not supported yet",
1048  else if (marker_idx == 6)
1049  result = skip_marker(infile, "PPT",
1050  "PPT in a tile is not supported yet",
1052  else if (marker_idx == 7)
1053  //Skipping PLT marker segment;this should not cause any issues
1054  result = skip_marker(infile, "PLT", NULL,
1056  else if (marker_idx == 8)
1057  result = skip_marker(infile, "COM", NULL,
1059  else if (marker_idx == 9)
1060  {
1061  sod_found = true;
1062  break;
1063  }
1064 
1065  if (marker_idx == -1) //marker not found
1066  {
1067  if (resilient)
1068  OJPH_INFO(0x00030065,
1069  "File terminated early before start of data is found"
1070  " for tile indexed %d and tile part %d",
1071  sot.get_tile_index(), sot.get_tile_part_index())
1072  else
1073  OJPH_ERROR(0x00030065,
1074  "File terminated early before start of data is found"
1075  " for tile indexed %d and tile part %d",
1076  sot.get_tile_index(), sot.get_tile_part_index())
1077  break;
1078  }
1079  if (result == -1) //file terminated during marker seg. skipping
1080  {
1081  if (resilient)
1082  OJPH_INFO(0x00030066,
1083  "File terminated during marker segment skipping")
1084  else
1085  OJPH_ERROR(0x00030066,
1086  "File terminated during marker segment skipping")
1087  break;
1088  }
1089  }
1090  if (sod_found)
1092  tile_start_location);
1093  }
1094  }
1095 
1096  // check the next marker; either SOT or EOC,
1097  // if something is broken, just an end of file
1098  ui16 next_markers[2] = { SOT, EOC };
1099  int marker_idx = find_marker(infile, next_markers, 2);
1100  if (marker_idx == -1)
1101  {
1102  OJPH_INFO(0x00030067, "File terminated early");
1103  break;
1104  }
1105  else if (marker_idx == 0)
1106  ;
1107  else if (marker_idx == 1)
1108  break;
1109  }
1110  }
1111 
1113  void codestream::set_planar(int planar)
1114  {
1115  this->planar = planar;
1116  }
1117 
1119  void codestream::set_profile(const char *s)
1120  {
1121  size_t len = strlen(s);
1122  if (len == 9 && strncmp(s, OJPH_PN_STRING_BROADCAST, 9) == 0)
1124  else if (len == 3 && strncmp(s, OJPH_PN_STRING_IMF, 3) == 0)
1125  profile = OJPH_PN_IMF;
1126  else
1127  OJPH_ERROR(0x000300A1, "unkownn or unsupported profile");
1128  }
1129 
1132  {
1133  si32 repeat = (si32)num_tiles.area();
1134  for (si32 i = 0; i < repeat; ++i)
1135  tiles[i].prepare_for_flush();
1137  { //write tlm
1138  for (si32 i = 0; i < repeat; ++i)
1139  tiles[i].fill_tlm(&tlm);
1140  tlm.write(outfile);
1141  }
1142  for (si32 i = 0; i < repeat; ++i)
1143  tiles[i].flush(outfile);
1145  if (!outfile->write(&t, 2))
1146  OJPH_ERROR(0x00030071, "Error writing to file");
1147  }
1148 
1151  {
1152  if (infile)
1153  infile->close();
1154  if (outfile)
1155  outfile->close();
1156  }
1157 
1159  line_buf* codestream::exchange(line_buf *line, ui32 &next_component)
1160  {
1161  if (line)
1162  {
1163  bool success = false;
1164  while (!success)
1165  {
1166  success = true;
1167  for (ui32 i = 0; i < num_tiles.w; ++i)
1168  {
1169  ui32 idx = i + cur_tile_row * num_tiles.w;
1170  if ((success &= tiles[idx].push(line, cur_comp)) == false)
1171  break;
1172  }
1173  cur_tile_row += success == false ? 1 : 0;
1174  if (cur_tile_row >= num_tiles.h)
1175  cur_tile_row = 0;
1176  }
1177 
1178  if (planar) //process one component at a time
1179  {
1180  if (++cur_line >= comp_size[cur_comp].h)
1181  {
1182  cur_line = 0;
1183  cur_tile_row = 0;
1184  if (++cur_comp >= num_comps)
1185  {
1186  next_component = 0;
1187  return NULL;
1188  }
1189  }
1190  }
1191  else //process all component for a line
1192  {
1193  if (++cur_comp >= num_comps)
1194  {
1195  cur_comp = 0;
1196  if (++cur_line >= comp_size[cur_comp].h)
1197  {
1198  next_component = 0;
1199  return NULL;
1200  }
1201  }
1202  }
1203  }
1204 
1205  next_component = cur_comp;
1206  return this->line;
1207  }
1208 
1211  {
1212  bool success = false;
1213  while (!success)
1214  {
1215  success = true;
1216  for (ui32 i = 0; i < num_tiles.w; ++i)
1217  {
1218  ui32 idx = i + cur_tile_row * num_tiles.w;
1219  if ((success &= tiles[idx].pull(line, cur_comp)) == false)
1220  break;
1221  }
1222  cur_tile_row += success == false ? 1 : 0;
1223  if (cur_tile_row >= num_tiles.h)
1224  cur_tile_row = 0;
1225  }
1226  comp_num = cur_comp;
1227 
1228  if (planar) //process one component at a time
1229  {
1230  if (++cur_line >= recon_comp_size[cur_comp].h)
1231  {
1232  cur_line = 0;
1233  cur_tile_row = 0;
1234  if (cur_comp++ >= num_comps)
1235  {
1236  comp_num = 0;
1237  return NULL;
1238  }
1239  }
1240  }
1241  else //process all component for a line
1242  {
1243  if (++cur_comp >= num_comps)
1244  {
1245  cur_comp = 0;
1246  if (cur_line++ >= recon_comp_size[cur_comp].h)
1247  {
1248  comp_num = 0;
1249  return NULL;
1250  }
1251  }
1252  }
1253 
1254  return line;
1255  }
1256 
1258  //
1259  //
1260  //
1261  //
1262  //
1264 
1266  void tile::pre_alloc(codestream *codestream, const rect& tile_rect,
1267  const rect& recon_tile_rect)
1268  {
1270 
1271  //allocate tiles_comp
1272  const param_siz *szp = codestream->get_siz();
1274  allocator->pre_alloc_obj<tile_comp>(num_comps);
1275  allocator->pre_alloc_obj<rect>(num_comps); //for comp_rects
1276  allocator->pre_alloc_obj<rect>(num_comps); //for recon_comp_rects
1277  allocator->pre_alloc_obj<ui32>(num_comps); //for line_offsets
1278  allocator->pre_alloc_obj<ui32>(num_comps); //for num_bits
1279  allocator->pre_alloc_obj<bool>(num_comps); //for is_signed
1280  allocator->pre_alloc_obj<ui32>(num_comps); //for cur_line
1281 
1282  int profile = codestream->get_profile();
1284  allocator->pre_alloc_obj<ui32>(num_comps); //for num_comp_bytes
1285  else
1286  allocator->pre_alloc_obj<ui32>(1);
1287 
1288  ui32 tx0 = tile_rect.org.x;
1289  ui32 ty0 = tile_rect.org.y;
1290  ui32 tx1 = tile_rect.org.x + tile_rect.siz.w;
1291  ui32 ty1 = tile_rect.org.y + tile_rect.siz.h;
1292  ui32 recon_tx0 = recon_tile_rect.org.x;
1293  ui32 recon_ty0 = recon_tile_rect.org.y;
1294  ui32 recon_tx1 = recon_tile_rect.org.x + recon_tile_rect.siz.w;
1295  ui32 recon_ty1 = recon_tile_rect.org.y + recon_tile_rect.siz.h;
1296 
1297  ui32 width = 0;
1298  for (ui32 i = 0; i < num_comps; ++i)
1299  {
1300  point downsamp = szp->get_downsampling(i);
1301 
1302  ui32 tcx0 = ojph_div_ceil(tx0, downsamp.x);
1303  ui32 tcy0 = ojph_div_ceil(ty0, downsamp.y);
1304  ui32 tcx1 = ojph_div_ceil(tx1, downsamp.x);
1305  ui32 tcy1 = ojph_div_ceil(ty1, downsamp.y);
1306  ui32 recon_tcx0 = ojph_div_ceil(recon_tx0, downsamp.x);
1307  ui32 recon_tcy0 = ojph_div_ceil(recon_ty0, downsamp.y);
1308  ui32 recon_tcx1 = ojph_div_ceil(recon_tx1, downsamp.x);
1309  ui32 recon_tcy1 = ojph_div_ceil(recon_ty1, downsamp.y);
1310 
1311  rect comp_rect;
1312  comp_rect.org.x = tcx0;
1313  comp_rect.org.y = tcy0;
1314  comp_rect.siz.w = tcx1 - tcx0;
1315  comp_rect.siz.h = tcy1 - tcy0;
1316 
1317  rect recon_comp_rect;
1318  recon_comp_rect.org.x = recon_tcx0;
1319  recon_comp_rect.org.y = recon_tcy0;
1320  recon_comp_rect.siz.w = recon_tcx1 - recon_tcx0;
1321  recon_comp_rect.siz.h = recon_tcy1 - recon_tcy0;
1322 
1323  tile_comp::pre_alloc(codestream, comp_rect, recon_comp_rect);
1324  width = ojph_max(width, recon_comp_rect.siz.w);
1325  }
1326 
1327  //allocate lines
1329  {
1330  allocator->pre_alloc_obj<line_buf>(3);
1331  for (int i = 0; i < 3; ++i)
1332  allocator->pre_alloc_data<si32>(width, 0);
1333  }
1334  }
1335 
1338  const rect& recon_tile_rect,
1339  ui32 tile_idx, ui32 offset)
1340  {
1341  //this->parent = codestream;
1343 
1344  sot.init(0, (ui16)tile_idx, 0, 1);
1346 
1347  //allocate tiles_comp
1348  const param_siz *szp = codestream->get_siz();
1349 
1350  num_comps = szp->get_num_components();
1352  comps = allocator->post_alloc_obj<tile_comp>(num_comps);
1353  comp_rects = allocator->post_alloc_obj<rect>(num_comps);
1355  line_offsets = allocator->post_alloc_obj<ui32>(num_comps);
1356  num_bits = allocator->post_alloc_obj<ui32>(num_comps);
1357  is_signed = allocator->post_alloc_obj<bool>(num_comps);
1358  cur_line = allocator->post_alloc_obj<ui32>(num_comps);
1359 
1363  else
1364  num_comp_bytes = allocator->post_alloc_obj<ui32>(1);
1365 
1366  this->resilient = codestream->is_resilient();
1367  this->tile_rect = tile_rect;
1368  this->recon_tile_rect = recon_tile_rect;
1369 
1370  ui32 tx0 = tile_rect.org.x;
1371  ui32 ty0 = tile_rect.org.y;
1372  ui32 tx1 = tile_rect.org.x + tile_rect.siz.w;
1373  ui32 ty1 = tile_rect.org.y + tile_rect.siz.h;
1374  ui32 recon_tx0 = recon_tile_rect.org.x;
1375  ui32 recon_ty0 = recon_tile_rect.org.y;
1376  ui32 recon_tx1 = recon_tile_rect.org.x + recon_tile_rect.siz.w;
1377  ui32 recon_ty1 = recon_tile_rect.org.y + recon_tile_rect.siz.h;
1378 
1379  ui32 width = 0;
1380  for (ui32 i = 0; i < num_comps; ++i)
1381  {
1382  point downsamp = szp->get_downsampling(i);
1383 
1384  ui32 tcx0 = ojph_div_ceil(tx0, downsamp.x);
1385  ui32 tcy0 = ojph_div_ceil(ty0, downsamp.y);
1386  ui32 tcx1 = ojph_div_ceil(tx1, downsamp.x);
1387  ui32 tcy1 = ojph_div_ceil(ty1, downsamp.y);
1388  ui32 recon_tcx0 = ojph_div_ceil(recon_tx0, downsamp.x);
1389  ui32 recon_tcy0 = ojph_div_ceil(recon_ty0, downsamp.y);
1390  ui32 recon_tcx1 = ojph_div_ceil(recon_tx1, downsamp.x);
1391  ui32 recon_tcy1 = ojph_div_ceil(recon_ty1, downsamp.y);
1392 
1393  line_offsets[i] =
1394  recon_tcx0 - ojph_div_ceil(recon_tx0 - offset, downsamp.x);
1395  comp_rects[i].org.x = tcx0;
1396  comp_rects[i].org.y = tcy0;
1397  comp_rects[i].siz.w = tcx1 - tcx0;
1398  comp_rects[i].siz.h = tcy1 - tcy0;
1399  recon_comp_rects[i].org.x = recon_tcx0;
1400  recon_comp_rects[i].org.y = recon_tcy0;
1401  recon_comp_rects[i].siz.w = recon_tcx1 - recon_tcx0;
1402  recon_comp_rects[i].siz.h = recon_tcy1 - recon_tcy0;
1403 
1404  comps[i].finalize_alloc(codestream, this, i, comp_rects[i],
1405  recon_comp_rects[i]);
1406  width = ojph_max(width, recon_comp_rects[i].siz.w);
1407 
1408  num_bits[i] = szp->get_bit_depth(i);
1409  is_signed[i] = szp->is_signed(i);
1410  cur_line[i] = 0;
1411  }
1412 
1413  //allocate lines
1414  const param_cod* cdp = codestream->get_cod();
1415  this->reversible = cdp->is_reversible();
1417  if (this->employ_color_transform)
1418  {
1419  num_lines = 3;
1420  lines = allocator->post_alloc_obj<line_buf>(num_lines);
1421  for (int i = 0; i < 3; ++i)
1422  lines[i].wrap(
1423  allocator->post_alloc_data<si32>(width,0),width,0);
1424  }
1425  else
1426  {
1427  lines = NULL;
1428  num_lines = 0;
1429  }
1430  next_tile_part = 0;
1431  }
1432 
1434  bool tile::push(line_buf *line, ui32 comp_num)
1435  {
1436  assert(comp_num < num_comps);
1437  if (cur_line[comp_num] >= comp_rects[comp_num].siz.h)
1438  return false;
1439  cur_line[comp_num]++;
1440 
1441  //converts to signed representation
1442  //employs color transform if there is a need
1443  if (!employ_color_transform || comp_num >= 3)
1444  {
1445  assert(comp_num < num_comps);
1446  ui32 comp_width = comp_rects[comp_num].siz.w;
1447  line_buf *tc = comps[comp_num].get_line();
1448  if (reversible)
1449  {
1450  int shift = 1 << (num_bits[comp_num] - 1);
1451  const si32 *sp = line->i32 + line_offsets[comp_num];
1452  si32* dp = tc->i32;
1453  if (is_signed[comp_num])
1454  memcpy(dp, sp, comp_width * sizeof(si32));
1455  else
1456  cnvrt_si32_to_si32_shftd(sp, dp, -shift, comp_width);
1457  }
1458  else
1459  {
1460  float mul = 1.0f / (float)(1<<num_bits[comp_num]);
1461  const si32 *sp = line->i32 + line_offsets[comp_num];
1462  float *dp = tc->f32;
1463  if (is_signed[comp_num])
1464  cnvrt_si32_to_float(sp, dp, mul, comp_width);
1465  else
1466  cnvrt_si32_to_float_shftd(sp, dp, mul, comp_width);
1467  }
1468  comps[comp_num].push_line();
1469  }
1470  else
1471  {
1472  ui32 comp_width = comp_rects[comp_num].siz.w;
1473  if (reversible)
1474  {
1475  int shift = 1 << (num_bits[comp_num] - 1);
1476  const si32 *sp = line->i32 + line_offsets[comp_num];
1477  si32 *dp = lines[comp_num].i32;
1478  if (is_signed[comp_num])
1479  memcpy(dp, sp, comp_width * sizeof(si32));
1480  else
1481  cnvrt_si32_to_si32_shftd(sp, dp, -shift, comp_width);
1482  if (comp_num == 2)
1483  { // reversible color transform
1484  rct_forward(lines[0].i32, lines[1].i32, lines[2].i32,
1485  comps[0].get_line()->i32,
1486  comps[1].get_line()->i32,
1487  comps[2].get_line()->i32, comp_width);
1488  comps[0].push_line();
1489  comps[1].push_line();
1490  comps[2].push_line();
1491  }
1492  }
1493  else
1494  {
1495  float mul = 1.0f / (float)(1<<num_bits[comp_num]);
1496  const si32 *sp = line->i32 + line_offsets[comp_num];
1497  float *dp = lines[comp_num].f32;
1498  if (is_signed[comp_num])
1499  cnvrt_si32_to_float(sp, dp, mul, comp_width);
1500  else
1501  cnvrt_si32_to_float_shftd(sp, dp, mul, comp_width);
1502  if (comp_num == 2)
1503  { // irreversible color transform
1504  ict_forward(lines[0].f32, lines[1].f32, lines[2].f32,
1505  comps[0].get_line()->f32,
1506  comps[1].get_line()->f32,
1507  comps[2].get_line()->f32, comp_width);
1508  comps[0].push_line();
1509  comps[1].push_line();
1510  comps[2].push_line();
1511  }
1512  }
1513  }
1514 
1515  return true;
1516  }
1517 
1519  bool tile::pull(line_buf* tgt_line, ui32 comp_num)
1520  {
1521  assert(comp_num < num_comps);
1522  if (cur_line[comp_num] >= recon_comp_rects[comp_num].siz.h)
1523  return false;
1524 
1525  cur_line[comp_num]++;
1526 
1527  if (!employ_color_transform || num_comps == 1)
1528  {
1529  line_buf *src_line = comps[comp_num].pull_line();
1530  ui32 comp_width = recon_comp_rects[comp_num].siz.w;
1531  if (reversible)
1532  {
1533  int shift = 1 << (num_bits[comp_num] - 1);
1534  const si32 *sp = src_line->i32;
1535  si32* dp = tgt_line->i32 + line_offsets[comp_num];
1536  if (is_signed[comp_num])
1537  memcpy(dp, sp, comp_width * sizeof(si32));
1538  else
1539  cnvrt_si32_to_si32_shftd(sp, dp, +shift, comp_width);
1540  }
1541  else
1542  {
1543  float mul = (float)(1 << num_bits[comp_num]);
1544  const float *sp = src_line->f32;
1545  si32 *dp = tgt_line->i32 + line_offsets[comp_num];
1546  if (is_signed[comp_num])
1547  cnvrt_float_to_si32(sp, dp, mul, comp_width);
1548  else
1549  cnvrt_float_to_si32_shftd(sp, dp, mul, comp_width);
1550  }
1551  }
1552  else
1553  {
1554  assert(num_comps >= 3);
1555  ui32 comp_width = recon_comp_rects[comp_num].siz.w;
1556  if (comp_num == 0)
1557  {
1558  if (reversible)
1559  rct_backward(comps[0].pull_line()->i32, comps[1].pull_line()->i32,
1560  comps[2].pull_line()->i32, lines[0].i32, lines[1].i32,
1561  lines[2].i32, comp_width);
1562  else
1563  ict_backward(comps[0].pull_line()->f32, comps[1].pull_line()->f32,
1564  comps[2].pull_line()->f32, lines[0].f32, lines[1].f32,
1565  lines[2].f32, comp_width);
1566  }
1567  if (reversible)
1568  {
1569  int shift = 1 << (num_bits[comp_num] - 1);
1570  const si32 *sp;
1571  if (comp_num < 3)
1572  sp = lines[comp_num].i32;
1573  else
1574  sp = comps[comp_num].pull_line()->i32;
1575  si32* dp = tgt_line->i32 + line_offsets[comp_num];
1576  if (is_signed[comp_num])
1577  memcpy(dp, sp, comp_width * sizeof(si32));
1578  else
1579  cnvrt_si32_to_si32_shftd(sp, dp, +shift, comp_width);
1580  }
1581  else
1582  {
1583  float mul = (float)(1 << num_bits[comp_num]);
1584  const float *sp;
1585  if (comp_num < 3)
1586  sp = lines[comp_num].f32;
1587  else
1588  sp = comps[comp_num].pull_line()->f32;
1589  si32 *dp = tgt_line->i32 + line_offsets[comp_num];
1590  if (is_signed[comp_num])
1591  cnvrt_float_to_si32(sp, dp, mul, comp_width);
1592  else
1593  cnvrt_float_to_si32_shftd(sp, dp, mul, comp_width);
1594  }
1595  }
1596 
1597  return true;
1598  }
1599 
1600 
1603  {
1604  //prepare precinct headers
1606  for (ui32 c = 0; c < num_comps; ++c)
1607  num_comp_bytes[c] = comps[c].prepare_precincts();
1608  else
1609  {
1610  num_comp_bytes[0] = 0;
1611  for (ui32 c = 0; c < num_comps; ++c)
1612  num_comp_bytes[0] += comps[c].prepare_precincts();
1613  }
1614  }
1615 
1618  {
1620  {
1621  for (ui32 c = 0; c < num_comps; ++c)
1623  }
1624  else
1626  }
1627 
1628 
1631  {
1632  ui32 max_decompositions = 0;
1633  for (ui32 c = 0; c < num_comps; ++c)
1634  max_decompositions = ojph_max(max_decompositions,
1635  comps[c].get_num_decompositions());
1636 
1638  {
1639  //write tile header
1640  if (!sot.write(file, num_comp_bytes[0]))
1641  OJPH_ERROR(0x00030081, "Error writing to file");
1642 
1643  //write start of data
1645  if (!file->write(&t, 2))
1646  OJPH_ERROR(0x00030082, "Error writing to file");
1647  }
1648 
1649 
1650  //sequence the writing of precincts according to progression order
1652  {
1653  for (ui32 r = 0; r <= max_decompositions; ++r)
1654  for (ui32 c = 0; c < num_comps; ++c)
1655  comps[c].write_precincts(r, file);
1656  }
1657  else if (prog_order == OJPH_PO_RPCL)
1658  {
1659  for (ui32 r = 0; r <= max_decompositions; ++r)
1660  {
1661  while (true)
1662  {
1663  bool found = false;
1664  ui32 comp_num = 0;
1665  point smallest(INT_MAX, INT_MAX), cur;
1666  for (ui32 c = 0; c < num_comps; ++c)
1667  {
1668  if (!comps[c].get_top_left_precinct(r, cur))
1669  continue;
1670  else
1671  found = true;
1672 
1673  if (cur.y < smallest.y)
1674  { smallest = cur; comp_num = c; }
1675  else if (cur.y == smallest.y && cur.x < smallest.x)
1676  { smallest = cur; comp_num = c; }
1677  }
1678  if (found == true)
1679  comps[comp_num].write_one_precinct(r, file);
1680  else
1681  break;
1682  }
1683  }
1684  }
1685  else if (prog_order == OJPH_PO_PCRL)
1686  {
1687  while (true)
1688  {
1689  bool found = false;
1690  ui32 comp_num = 0;
1691  ui32 res_num = 0;
1692  point smallest(INT_MAX, INT_MAX), cur;
1693  for (ui32 c = 0; c < num_comps; ++c)
1694  {
1695  for (ui32 r = 0; r <= comps[c].get_num_decompositions(); ++r)
1696  {
1697  if (!comps[c].get_top_left_precinct(r, cur))
1698  continue;
1699  else
1700  found = true;
1701 
1702  if (cur.y < smallest.y)
1703  { smallest = cur; comp_num = c; res_num = r; }
1704  else if (cur.y == smallest.y && cur.x < smallest.x)
1705  { smallest = cur; comp_num = c; res_num = r; }
1706  else if (cur.y == smallest.y && cur.x == smallest.x &&
1707  c < comp_num)
1708  { smallest = cur; comp_num = c; res_num = r; }
1709  else if (cur.y == smallest.y && cur.x == smallest.x &&
1710  c == comp_num && r < res_num)
1711  { smallest = cur; comp_num = c; res_num = r; }
1712  }
1713  }
1714  if (found == true)
1715  comps[comp_num].write_one_precinct(res_num, file);
1716  else
1717  break;
1718  }
1719  }
1720  else if (prog_order == OJPH_PO_CPRL)
1721  {
1722  for (ui32 c = 0; c < num_comps; ++c)
1723  {
1725  {
1726  //write tile header
1727  if (!sot.write(file, num_comp_bytes[c], (ui8)c, (ui8)num_comps))
1728  OJPH_ERROR(0x00030083, "Error writing to file");
1729 
1730  //write start of data
1732  if (!file->write(&t, 2))
1733  OJPH_ERROR(0x00030084, "Error writing to file");
1734  }
1735 
1736  while (true)
1737  {
1738  bool found = false;
1739  ui32 res_num = 0;
1740  point smallest(INT_MAX, INT_MAX), cur;
1741  for (ui32 r = 0; r <= max_decompositions; ++r)
1742  {
1743  if (!comps[c].get_top_left_precinct(r, cur)) //res exist?
1744  continue;
1745  else
1746  found = true;
1747 
1748  if (cur.y < smallest.y)
1749  { smallest = cur; res_num = r; }
1750  else if (cur.y == smallest.y && cur.x < smallest.x)
1751  { smallest = cur; res_num = r; }
1752  }
1753  if (found == true)
1754  comps[c].write_one_precinct(res_num, file);
1755  else
1756  break;
1757  }
1758  }
1759  }
1760  else
1761  assert(0);
1762 
1763  }
1764 
1767  const ui64& tile_start_location)
1768  {
1770  {
1771  if (resilient)
1772  OJPH_INFO(0x00030091, "wrong tile part index")
1773  else
1774  OJPH_ERROR(0x00030091, "wrong tile part index")
1775  }
1776  ++next_tile_part;
1777 
1778  //tile_end_location used on failure
1779  ui64 tile_end_location = tile_start_location + sot.get_payload_length();
1780 
1781  ui32 data_left = sot.get_payload_length(); //bytes left to parse
1782  data_left -= (ui32)((ui64)file->tell() - tile_start_location);
1783 
1784  if (data_left == 0)
1785  return;
1786 
1787  ui32 max_decompositions = 0;
1788  for (ui32 c = 0; c < num_comps; ++c)
1789  max_decompositions = ojph_max(max_decompositions,
1790  comps[c].get_num_decompositions());
1791 
1792  try
1793  {
1794  //sequence the reading of precincts according to progression order
1796  {
1797  max_decompositions -= skipped_res_for_read;
1798  for (ui32 r = 0; r <= max_decompositions; ++r)
1799  for (ui32 c = 0; c < num_comps; ++c)
1800  if (data_left > 0)
1801  comps[c].parse_precincts(r, data_left, file);
1802  }
1803  else if (prog_order == OJPH_PO_RPCL)
1804  {
1805  max_decompositions -= skipped_res_for_read;
1806  for (ui32 r = 0; r <= max_decompositions; ++r)
1807  {
1808  while (true)
1809  {
1810  bool found = false;
1811  ui32 comp_num = 0;
1812  point smallest(INT_MAX, INT_MAX), cur;
1813  for (ui32 c = 0; c < num_comps; ++c)
1814  {
1815  if (!comps[c].get_top_left_precinct(r, cur))
1816  continue;
1817  else
1818  found = true;
1819 
1820  if (cur.y < smallest.y)
1821  { smallest = cur; comp_num = c; }
1822  else if (cur.y == smallest.y && cur.x < smallest.x)
1823  { smallest = cur; comp_num = c; }
1824  }
1825  if (found == true && data_left > 0)
1826  comps[comp_num].parse_one_precinct(r, data_left, file);
1827  else
1828  break;
1829  }
1830  }
1831  }
1832  else if (prog_order == OJPH_PO_PCRL)
1833  {
1834  while (true)
1835  {
1836  bool found = false;
1837  ui32 comp_num = 0;
1838  ui32 res_num = 0;
1839  point smallest(INT_MAX, INT_MAX), cur;
1840  for (ui32 c = 0; c < num_comps; ++c)
1841  {
1842  for (ui32 r = 0; r <= comps[c].get_num_decompositions(); ++r)
1843  {
1844  if (!comps[c].get_top_left_precinct(r, cur))
1845  continue;
1846  else
1847  found = true;
1848 
1849  if (cur.y < smallest.y)
1850  { smallest = cur; comp_num = c; res_num = r; }
1851  else if (cur.y == smallest.y && cur.x < smallest.x)
1852  { smallest = cur; comp_num = c; res_num = r; }
1853  else if (cur.y == smallest.y && cur.x == smallest.x &&
1854  c < comp_num)
1855  { smallest = cur; comp_num = c; res_num = r; }
1856  else if (cur.y == smallest.y && cur.x == smallest.x &&
1857  c == comp_num && r < res_num)
1858  { smallest = cur; comp_num = c; res_num = r; }
1859  }
1860  }
1861  if (found == true && data_left > 0)
1862  comps[comp_num].parse_one_precinct(res_num, data_left, file);
1863  else
1864  break;
1865  }
1866  }
1867  else if (prog_order == OJPH_PO_CPRL)
1868  {
1869  for (ui32 c = 0; c < num_comps; ++c)
1870  {
1871  while (true)
1872  {
1873  bool found = false;
1874  ui32 res_num = 0;
1875  point smallest(INT_MAX, INT_MAX), cur;
1876  for (ui32 r = 0; r <= max_decompositions; ++r)
1877  {
1878  if (!comps[c].get_top_left_precinct(r, cur)) //res exist?
1879  continue;
1880  else
1881  found = true;
1882 
1883  if (cur.y < smallest.y)
1884  { smallest = cur; res_num = r; }
1885  else if (cur.y == smallest.y && cur.x < smallest.x)
1886  { smallest = cur; res_num = r; }
1887  }
1888  if (found == true && data_left > 0)
1889  comps[c].parse_one_precinct(res_num, data_left, file);
1890  else
1891  break;
1892  }
1893  }
1894  }
1895  else
1896  assert(0);
1897 
1898  }
1899  catch (const char *error)
1900  {
1901  if (resilient)
1902  OJPH_INFO(0x00030092, "%s", error)
1903  else
1904  OJPH_ERROR(0x00030092, "%s", error)
1905  }
1906  file->seek((si64)tile_end_location, infile_base::OJPH_SEEK_SET);
1907  }
1908 
1910  //
1911  //
1912  //
1913  //
1914  //
1916 
1919  const rect& recon_comp_rect)
1920  {
1922 
1923  //allocate a resolution
1925  allocator->pre_alloc_obj<resolution>(1);
1926 
1927  resolution::pre_alloc(codestream, comp_rect, recon_comp_rect,
1928  num_decomps);
1929  }
1930 
1933  ui32 comp_num, const rect& comp_rect,
1934  const rect& recon_comp_rect)
1935  {
1937 
1938  //allocate a resolution
1940 
1942  this->comp_rect = comp_rect;
1943  this->parent_tile = parent;
1944 
1945  this->comp_num = comp_num;
1946  res = allocator->post_alloc_obj<resolution>(1);
1947  res->finalize_alloc(codestream, comp_rect, recon_comp_rect, comp_num,
1948  num_decomps, comp_downsamp, this, NULL);
1949  }
1950 
1953  {
1954  return res->get_line();
1955  }
1956 
1959  {
1960  res->push_line();
1961  }
1962 
1965  {
1966  return res->pull_line();
1967  }
1968 
1971  {
1972  return res->prepare_precinct();
1973  }
1974 
1977  {
1978  assert(res_num <= num_decomps);
1979  res_num = num_decomps - res_num; //how many levels to go down
1980  resolution *r = res;
1981  while (res_num > 0 && r != NULL)
1982  {
1983  r = r->next_resolution();
1984  --res_num;
1985  }
1986  if (r) //resolution does not exist if r is NULL
1987  r->write_precincts(file);
1988  }
1989 
1992  {
1993  assert(res_num <= num_decomps);
1994  res_num = num_decomps - res_num;
1995  resolution *r = res;
1996  while (res_num > 0 && r != NULL)
1997  {
1998  r = r->next_resolution();
1999  --res_num;
2000  }
2001  if (r) //resolution does not exist if r is NULL
2002  return r->get_top_left_precinct(top_left);
2003  else
2004  return false;
2005  }
2006 
2009  {
2010  assert(res_num <= num_decomps);
2011  res_num = num_decomps - res_num;
2012  resolution *r = res;
2013  while (res_num > 0 && r != NULL)
2014  {
2015  r = r->next_resolution();
2016  --res_num;
2017  }
2018  if (r) //resolution does not exist if r is NULL
2019  r->write_one_precinct(file);
2020  }
2021 
2023  void tile_comp::parse_precincts(ui32 res_num, ui32& data_left,
2024  infile_base *file)
2025  {
2026  assert(res_num <= num_decomps);
2027  res_num = num_decomps - res_num; //how many levels to go down
2028  resolution *r = res;
2029  while (res_num > 0 && r != NULL)
2030  {
2031  r = r->next_resolution();
2032  --res_num;
2033  }
2034  if (r) //resolution does not exist if r is NULL
2035  r->parse_all_precincts(data_left, file);
2036  }
2037 
2038 
2040  void tile_comp::parse_one_precinct(ui32 res_num, ui32& data_left,
2041  infile_base *file)
2042  {
2043  assert(res_num <= num_decomps);
2044  res_num = num_decomps - res_num;
2045  resolution *r = res;
2046  while (res_num > 0 && r != NULL)
2047  {
2048  r = r->next_resolution();
2049  --res_num;
2050  }
2051  if (r) //resolution does not exist if r is NULL
2052  r->parse_one_precinct(data_left, file);
2053  }
2054 
2055 
2056 
2058  //
2059  //
2060  //
2061  //
2062  //
2064 
2066  static void rotate_buffers(line_buf *line1, line_buf* line2,
2067  line_buf *line3, line_buf* line4)
2068  {
2069  assert(line1->size == line2->size &&
2070  line1->pre_size == line2->pre_size &&
2071  line1->size == line3->size &&
2072  line1->pre_size == line3->pre_size &&
2073  line1->size == line4->size &&
2074  line1->pre_size == line4->pre_size);
2075  si32* p = line4->i32;
2076  line4->i32 = line3->i32;
2077  line3->i32 = line2->i32;
2078  line2->i32 = line1->i32;
2079  line1->i32 = p;
2080  }
2081 
2083  static void rotate_buffers(line_buf *line1, line_buf* line2,
2084  line_buf *line3, line_buf* line4,
2085  line_buf *line5, line_buf* line6)
2086  {
2087  assert(line1->size == line2->size &&
2088  line1->pre_size == line2->pre_size &&
2089  line1->size == line3->size &&
2090  line1->pre_size == line3->pre_size &&
2091  line1->size == line4->size &&
2092  line1->pre_size == line4->pre_size &&
2093  line1->size == line5->size &&
2094  line1->pre_size == line5->pre_size &&
2095  line1->size == line6->size &&
2096  line1->pre_size == line6->pre_size);
2097  si32* p = line6->i32;
2098  line6->i32 = line5->i32;
2099  line5->i32 = line4->i32;
2100  line4->i32 = line3->i32;
2101  line3->i32 = line2->i32;
2102  line2->i32 = line1->i32;
2103  line1->i32 = p;
2104  }
2105 
2108  const rect& recon_res_rect, ui32 res_num)
2109  {
2111  const param_cod* cdp = codestream->get_cod();
2114  bool skipped_res_for_recon = res_num > t;
2115 
2116  //create next resolution
2117  if (res_num > 0)
2118  {
2119  //allocate a resolution
2120  allocator->pre_alloc_obj<resolution>(1);
2121  ui32 trx0 = ojph_div_ceil(res_rect.org.x, 2);
2122  ui32 try0 = ojph_div_ceil(res_rect.org.y, 2);
2123  ui32 trx1 = ojph_div_ceil(res_rect.org.x + res_rect.siz.w, 2);
2124  ui32 try1 = ojph_div_ceil(res_rect.org.y + res_rect.siz.h, 2);
2125  rect next_res_rect;
2126  next_res_rect.org.x = trx0;
2127  next_res_rect.org.y = try0;
2128  next_res_rect.siz.w = trx1 - trx0;
2129  next_res_rect.siz.h = try1 - try0;
2130 
2131  resolution::pre_alloc(codestream, next_res_rect,
2132  skipped_res_for_recon ? recon_res_rect : next_res_rect, res_num - 1);
2133  }
2134 
2135  //allocate subbands
2136  ui32 trx0 = res_rect.org.x;
2137  ui32 try0 = res_rect.org.y;
2138  ui32 trx1 = res_rect.org.x + res_rect.siz.w;
2139  ui32 try1 = res_rect.org.y + res_rect.siz.h;
2140  allocator->pre_alloc_obj<subband>(4);
2141  if (res_num > 0)
2142  {
2143  for (ui32 i = 1; i < 4; ++i)
2144  {
2145  ui32 tbx0 = (trx0 - (i&1) + 1) >> 1;
2146  ui32 tbx1 = (trx1 - (i&1) + 1) >> 1;
2147  ui32 tby0 = (try0 - (i>>1) + 1) >> 1;
2148  ui32 tby1 = (try1 - (i>>1) + 1) >> 1;
2149 
2150  rect band_rect;
2151  band_rect.org.x = tbx0;
2152  band_rect.org.y = tby0;
2153  band_rect.siz.w = tbx1 - tbx0;
2154  band_rect.siz.h = tby1 - tby0;
2155  subband::pre_alloc(codestream, band_rect, res_num);
2156  }
2157  }
2158  else
2160 
2161  //prealloc precincts
2164  if (trx0 != trx1 && try0 != try1)
2165  {
2166  num_precincts.w = (trx1 + (1<<log_PP.w) - 1) >> log_PP.w;
2167  num_precincts.w -= trx0 >> log_PP.w;
2168  num_precincts.h = (try1 + (1<<log_PP.h) - 1) >> log_PP.h;
2169  num_precincts.h -= try0 >> log_PP.h;
2170  allocator->pre_alloc_obj<precinct>(num_precincts.area());
2171  }
2172 
2173  //allocate lines
2174  if (skipped_res_for_recon == false)
2175  {
2176  bool reversible = cdp->is_reversible();
2177  ui32 num_lines = reversible ? 4 : 6;
2178  allocator->pre_alloc_obj<line_buf>(num_lines);
2179 
2180  ui32 width = res_rect.siz.w + 1;
2181  for (ui32 i = 0; i < num_lines; ++i)
2182  allocator->pre_alloc_data<si32>(width, 1);
2183  }
2184  }
2185 
2188  const rect& res_rect,
2189  const rect& recon_res_rect,
2190  ui32 comp_num, ui32 res_num,
2191  point comp_downsamp,
2192  tile_comp *parent_tile_comp,
2193  resolution *parent_res)
2194  {
2197  ui32 t, num_decomps = codestream->get_cod()->get_num_decompositions();
2198  t = num_decomps - codestream->get_skipped_res_for_recon();
2200  t = num_decomps - codestream->get_skipped_res_for_read();
2202  const param_cod* cdp = codestream->get_cod();
2203 
2204  this->comp_downsamp = comp_downsamp;
2205  this->parent_comp = parent_tile_comp;
2206  this->parent_res = parent_res;
2207  this->res_rect = res_rect;
2208  this->comp_num = comp_num;
2209  this->res_num = res_num;
2210  //finalize next resolution
2211  if (res_num > 0)
2212  {
2213  //allocate a resolution
2214  child_res = allocator->post_alloc_obj<resolution>(1);
2215  ui32 trx0 = ojph_div_ceil(res_rect.org.x, 2);
2216  ui32 try0 = ojph_div_ceil(res_rect.org.y, 2);
2217  ui32 trx1 = ojph_div_ceil(res_rect.org.x + res_rect.siz.w, 2);
2218  ui32 try1 = ojph_div_ceil(res_rect.org.y + res_rect.siz.h, 2);
2219  rect next_res_rect;
2220  next_res_rect.org.x = trx0;
2221  next_res_rect.org.y = try0;
2222  next_res_rect.siz.w = trx1 - trx0;
2223  next_res_rect.siz.h = try1 - try0;
2224 
2225  child_res->finalize_alloc(codestream, next_res_rect,
2226  skipped_res_for_recon ? recon_res_rect : next_res_rect, comp_num,
2227  res_num - 1, comp_downsamp, parent_tile_comp, this);
2228  }
2229  else
2230  child_res = NULL;
2231 
2232  //allocate subbands
2233  ui32 trx0 = res_rect.org.x;
2234  ui32 try0 = res_rect.org.y;
2235  ui32 trx1 = res_rect.org.x + res_rect.siz.w;
2236  ui32 try1 = res_rect.org.y + res_rect.siz.h;
2237  bands = allocator->post_alloc_obj<subband>(4);
2238  if (res_num > 0)
2239  {
2240  this->num_bands = 3;
2241  for (ui32 i = 1; i < 4; ++i)
2242  {
2243  ui32 tbx0 = (trx0 - (i&1) + 1) >> 1;
2244  ui32 tbx1 = (trx1 - (i&1) + 1) >> 1;
2245  ui32 tby0 = (try0 - (i>>1) + 1) >> 1;
2246  ui32 tby1 = (try1 - (i>>1) + 1) >> 1;
2247 
2248  rect band_rect;
2249  band_rect.org.x = tbx0;
2250  band_rect.org.y = tby0;
2251  band_rect.siz.w = tbx1 - tbx0;
2252  band_rect.siz.h = tby1 - tby0;
2253  bands[i].finalize_alloc(codestream, band_rect, this, res_num, i);
2254  }
2255  }
2256  else {
2257  this->num_bands = 1;
2258  bands[0].finalize_alloc(codestream, res_rect, this, res_num, 0);
2259  }
2260 
2261  //finalize precincts
2263  num_precincts = size();
2264  precincts = NULL;
2265  if (trx0 != trx1 && try0 != try1)
2266  {
2267  num_precincts.w = (trx1 + (1<<log_PP.w) - 1) >> log_PP.w;
2268  num_precincts.w -= trx0 >> log_PP.w;
2269  num_precincts.h = (try1 + (1<<log_PP.h) - 1) >> log_PP.h;
2270  num_precincts.h -= try0 >> log_PP.h;
2272  memset(precincts, 0, sizeof(precinct) * num_precincts.area());
2273  }
2274  // precincts will be initialized in full shortly
2275 
2276  ui32 x_lower_bound = (trx0 >> log_PP.w) << log_PP.w;
2277  ui32 y_lower_bound = (try0 >> log_PP.h) << log_PP.h;
2278 
2279  point proj_factor;
2280  proj_factor.x = comp_downsamp.x * (1<<(num_decomps - res_num));
2281  proj_factor.y = comp_downsamp.y * (1<<(num_decomps - res_num));
2282  precinct *pp = precincts;
2283 
2284  point tile_top_left = parent_tile_comp->get_tile()->get_tile_rect().org;
2285  for (ui32 y = 0; y < num_precincts.h; ++y)
2286  {
2287  ui32 ppy0 = y_lower_bound + (y << log_PP.h);
2288  for (ui32 x = 0; x < num_precincts.w; ++x, ++pp)
2289  {
2290  ui32 ppx0 = x_lower_bound + (x << log_PP.w);
2291  point t(proj_factor.x * ppx0, proj_factor.y * ppy0);
2292  t.x = t.x > tile_top_left.x ? t.x : tile_top_left.x;
2293  t.y = t.y > tile_top_left.y ? t.y : tile_top_left.y;
2294  pp->img_point = t;
2295  pp->num_bands = num_bands;
2296  pp->bands = bands;
2297  pp->may_use_sop = cdp->packets_may_use_sop();
2298  pp->uses_eph = cdp->packets_use_eph();
2300  pp->coded = NULL;
2301  }
2302  }
2303  if (num_bands == 1)
2305  else
2306  for (int i = 1; i < 4; ++i)
2307  bands[i].get_cb_indices(num_precincts, precincts);
2308 
2309  size log_cb = cdp->get_log_block_dims();
2310  log_PP.w -= (res_num?1:0);
2311  log_PP.h -= (res_num?1:0);
2312  size ratio;
2313  ratio.w = log_PP.w - ojph_min(log_cb.w, log_PP.w);
2314  ratio.h = log_PP.h - ojph_min(log_cb.h, log_PP.h);
2315  max_num_levels = ojph_max(ratio.w, ratio.h);
2316  ui32 val = 1u << (max_num_levels << 1);
2317  tag_tree_size = (int)((val * 4 + 2) / 3);
2318  ++max_num_levels;
2319  level_index[0] = 0;
2320  for (ui32 i = 1; i <= max_num_levels; ++i, val >>= 2)
2321  level_index[i] = level_index[i - 1] + val;
2322  cur_precinct_loc = point(0, 0);
2323 
2324  //allocate lines
2325  if (skipped_res_for_recon == false)
2326  {
2327  this->reversible = cdp->is_reversible();
2328  this->num_lines = this->reversible ? 4 : 6;
2329  lines = allocator->post_alloc_obj<line_buf>(num_lines);
2330 
2331  ui32 width = res_rect.siz.w + 1;
2332  for (ui32 i = 0; i < num_lines; ++i)
2333  lines[i].wrap(allocator->post_alloc_data<si32>(width, 1), width, 1);
2334  cur_line = 0;
2335  vert_even = (res_rect.org.y & 1) == 0;
2336  horz_even = (res_rect.org.x & 1) == 0;
2337  }
2338  }
2339 
2342  {
2343  if (res_num == 0)
2344  {
2345  assert(num_bands == 1 && child_res == NULL);
2346  bands[0].exchange_buf(lines + 0);//line at location 0
2347  bands[0].push_line();
2348  return;
2349  }
2350 
2351  ui32 width = res_rect.siz.w;
2352  if (width == 0)
2353  return;
2354  if (reversible)
2355  {
2356  //vertical transform
2357  assert(num_lines >= 4);
2358  if (vert_even)
2359  {
2361  cur_line > 1 ? lines + 2 : lines,
2362  lines + 1, width);
2364  cur_line > 2 ? lines + 3 : lines + 1,
2365  lines + 2, width);
2366 
2367  // push to horizontal transform lines[2](L) and lines[1] (H)
2368  if (cur_line >= 1)
2369  {
2371  bands[3].get_line(), width, horz_even);
2372  bands[2].push_line();
2373  bands[3].push_line();
2374  }
2375  if (cur_line >= 2)
2376  {
2378  bands[1].get_line(), width, horz_even);
2379  bands[1].push_line();
2380  child_res->push_line();
2381  }
2382  }
2383 
2384  if (cur_line >= res_rect.siz.h - 1)
2385  { //finished, so we need to process any lines left
2386  if (cur_line)
2387  {
2388  if (vert_even)
2389  {
2391  lines, width);
2392  //push lines[0] to L
2394  bands[1].get_line(), width, horz_even);
2395  bands[1].push_line();
2396  child_res->push_line();
2397  }
2398  else
2399  {
2401  lines, width);
2403  cur_line > 1 ? lines + 2:lines,
2404  lines + 1, width);
2405 
2406  // push to horizontal transform lines[1](L) and line[0] (H)
2407  //line[0] to H
2409  bands[3].get_line(), width, horz_even);
2410  bands[2].push_line();
2411  bands[3].push_line();
2412  //line[1] to L
2414  bands[1].get_line(), width, horz_even);
2415  bands[1].push_line();
2416  child_res->push_line();
2417  }
2418  }
2419  else
2420  { //only one line
2421  if (vert_even)
2422  {
2423  //push to L
2425  bands[1].get_line(), width, horz_even);
2426  bands[1].push_line();
2427  child_res->push_line();
2428  }
2429  else
2430  {
2431  si32 *sp = lines[0].i32;
2432  for (ui32 i = width; i > 0; --i)
2433  *sp++ <<= 1;
2434  //push to H
2436  bands[3].get_line(), width, horz_even);
2437  bands[2].push_line();
2438  bands[3].push_line();
2439  }
2440  }
2441  }
2442 
2443  rotate_buffers(lines, lines+1, lines+2, lines+3);
2444 
2445  ++cur_line;
2446  vert_even = !vert_even;
2447  }
2448  else
2449  {
2450  //vertical transform
2451  assert(num_lines >= 6);
2452  if (vert_even)
2453  {
2455  cur_line > 1 ? lines + 2 : lines,
2456  lines + 1, 0, width);
2458  cur_line > 2 ? lines + 3 : lines + 1,
2459  lines + 2, 1, width);
2461  cur_line > 3 ? lines + 4 : lines + 2,
2462  lines + 3, 2, width);
2464  cur_line > 4 ? lines + 5 : lines + 3,
2465  lines + 4, 3, width);
2466 
2467  // push to horizontal transform lines[4](L) and lines[3] (H)
2468  if (cur_line >= 3)
2469  {
2470  irrev_vert_wvlt_K(lines + 3, lines + 5,
2471  false, width);
2473  bands[3].get_line(), width, horz_even);
2474  bands[2].push_line();
2475  bands[3].push_line();
2476  }
2477  if (cur_line >= 4)
2478  {
2479  irrev_vert_wvlt_K(lines + 4, lines + 5,
2480  true, width);
2482  bands[1].get_line(), width, horz_even);
2483  bands[1].push_line();
2484  child_res->push_line();
2485  }
2486  }
2487 
2488  if (cur_line >= res_rect.siz.h - 1)
2489  { //finished, so we need to process any left line
2490  if (cur_line)
2491  {
2492  if (vert_even)
2493  {
2494  irrev_vert_wvlt_step(lines + 1, lines + 1,
2495  lines, 1, width);
2497  cur_line > 1 ? lines + 2 : lines,
2498  lines + 1, 2, width);
2500  cur_line > 2 ? lines + 3 : lines + 1,
2501  lines + 2, 3, width);
2502  irrev_vert_wvlt_step(lines + 1, lines + 1,
2503  lines, 3, width);
2504  //push lines[2] to L, lines[1] to H, and lines[0] to L
2505  if (cur_line >= 2)
2506  {
2507  irrev_vert_wvlt_K(lines + 2, lines + 5,
2508  true, width);
2510  child_res->get_line(), bands[1].get_line(),
2511  width, horz_even);
2512  bands[1].push_line();
2513  child_res->push_line();
2514  }
2515  irrev_vert_wvlt_K(lines + 1, lines + 5,
2516  false, width);
2518  bands[3].get_line(), width, horz_even);
2519  bands[2].push_line();
2520  bands[3].push_line();
2522  true, width);
2524  bands[1].get_line(), width, horz_even);
2525  bands[1].push_line();
2526  child_res->push_line();
2527  }
2528  else
2529  {
2530  irrev_vert_wvlt_step(lines + 1, lines + 1,
2531  lines, 0, width);
2533  cur_line > 1 ? lines + 2 : lines,
2534  lines + 1, 1, width);
2536  cur_line > 2 ? lines + 3 : lines + 1,
2537  lines + 2, 2, width);
2539  cur_line > 3 ? lines + 4 : lines + 2,
2540  lines + 3, 3, width);
2541 
2542  irrev_vert_wvlt_step(lines + 1, lines + 1,
2543  lines, 2, width);
2545  cur_line > 1 ? lines + 2 : lines,
2546  lines + 1, 3, width);
2547 
2548  //push lines[3] L, lines[2] H, lines[1] L, and lines[0] H
2549  if (cur_line >= 3)
2550  {
2551  irrev_vert_wvlt_K(lines + 3, lines + 5,
2552  true, width);
2554  child_res->get_line(), bands[1].get_line(),
2555  width, horz_even);
2556  bands[1].push_line();
2557  child_res->push_line();
2558  }
2559  irrev_vert_wvlt_K(lines + 2, lines + 5,
2560  false, width);
2562  bands[3].get_line(), width, horz_even);
2563  bands[2].push_line();
2564  bands[3].push_line();
2565  irrev_vert_wvlt_K(lines + 1, lines + 5,
2566  true, width);
2568  bands[1].get_line(), width, horz_even);
2569  bands[1].push_line();
2570  child_res->push_line();
2572  false, width);
2574  bands[3].get_line(), width, horz_even);
2575  bands[2].push_line();
2576  bands[3].push_line();
2577  }
2578  }
2579  else
2580  { //only one line
2581  if (vert_even)
2582  {
2583  //push to L
2585  bands[1].get_line(), width, horz_even);
2586  bands[1].push_line();
2587  child_res->push_line();
2588  }
2589  else
2590  {
2591  //push to H
2593  bands[3].get_line(), width, horz_even);
2594  bands[2].push_line();
2595  bands[3].push_line();
2596  }
2597  }
2598  }
2599 
2600  rotate_buffers(lines, lines+1, lines+2, lines+3, lines+4, lines+5);
2601 
2602  ++cur_line;
2603  vert_even = !vert_even;
2604  }
2605  }
2606 
2609  {
2610  if (res_num == 0)
2611  {
2612  assert(num_bands == 1 && child_res == NULL);
2613  return bands[0].pull_line();
2614  }
2615 
2616  if (skipped_res_for_recon == true)
2617  return child_res->pull_line();
2618 
2619  ui32 width = res_rect.siz.w;
2620  if (width == 0)
2621  return lines;
2622  if (reversible)
2623  {
2624  assert(num_lines >= 4);
2625  if (res_rect.siz.h > 1)
2626  {
2627  do
2628  {
2629  //horizontal transform
2630  if (cur_line < res_rect.siz.h)
2631  {
2632  if (vert_even)
2635  width, horz_even);
2636  else
2638  bands[2].pull_line(), bands[3].pull_line(),
2639  width, horz_even);
2640  }
2641 
2642  //vertical transform
2643  if (!vert_even)
2644  {
2646  cur_line > 1 ? lines + 2 : lines,
2647  cur_line < res_rect.siz.h ? lines : lines + 2,
2648  lines + 1, width);
2650  cur_line > 2 ? lines + 3 : lines + 1,
2651  cur_line < res_rect.siz.h + 1 ? lines + 1 : lines + 3,
2652  lines + 2, width);
2653  }
2654 
2655  vert_even = !vert_even;
2656  rotate_buffers(lines, lines+1, lines+2, lines+3);
2657  ++cur_line;
2658  }
2659  while (cur_line < 3);
2660  memcpy(lines[0].i32, lines[3].i32, res_rect.siz.w * sizeof(si32));
2661  return lines;
2662  }
2663  else if (res_rect.siz.h == 1)
2664  {
2665  if (vert_even)
2666  {
2668  bands[1].pull_line(), width, horz_even);
2669  }
2670  else
2671  {
2673  bands[3].pull_line(), width, horz_even);
2674  if (width)
2675  {
2676  si32 *sp = lines[0].i32;
2677  for (ui32 i = width; i > 0; --i)
2678  *sp++ >>= 1;
2679  }
2680  }
2681  return lines;
2682  }
2683  else
2684  return lines;
2685  }
2686  else
2687  {
2688  assert(num_lines >= 6);
2689  if (res_rect.siz.h > 1)
2690  {
2691  do
2692  {
2693  //horizontal transform
2694  if (cur_line < res_rect.siz.h)
2695  {
2696  if (vert_even)
2697  {
2700  width, horz_even);
2701  irrev_vert_wvlt_K(lines, lines, false, width);
2702  }
2703  else
2704  {
2706  bands[2].pull_line(), bands[3].pull_line(),
2707  width, horz_even);
2708  irrev_vert_wvlt_K(lines, lines, true, width);
2709  }
2710  }
2711 
2712  //vertical transform
2713  if (!vert_even)
2714  {
2716  cur_line > 1 ? lines + 2 : lines,
2717  cur_line < res_rect.siz.h ? lines : lines + 2,
2718  lines + 1, 7, width);
2720  cur_line > 2 ? lines + 3 : lines + 1,
2721  cur_line < res_rect.siz.h + 1 ? lines + 1 : lines + 3,
2722  lines + 2, 6, width);
2724  cur_line > 3 ? lines + 4 : lines + 2,
2725  cur_line < res_rect.siz.h + 2 ? lines + 2 : lines + 4,
2726  lines + 3, 5, width);
2728  cur_line > 4 ? lines + 5 : lines + 3,
2729  cur_line < res_rect.siz.h + 3 ? lines + 3 : lines + 5,
2730  lines + 4, 4, width);
2731  }
2732 
2733  vert_even = !vert_even;
2735  ++cur_line;
2736  }
2737  while (cur_line < 5);
2738  memcpy(lines[0].f32, lines[5].f32, res_rect.siz.w * sizeof(float));
2739  return lines;
2740  }
2741  else if (res_rect.siz.h == 1)
2742  {
2743  if (vert_even)
2744  {
2746  bands[1].pull_line(), width, horz_even);
2747  }
2748  else
2749  {
2751  bands[3].pull_line(), width, horz_even);
2752  if (width)
2753  {
2754  float *sp = lines[0].f32;
2755  for (ui32 i = width; i > 0; --i)
2756  *sp++ *= 0.5f;
2757  }
2758  }
2759  return lines;
2760  }
2761  else
2762  return lines;
2763  }
2764  }
2765 
2768  {
2769  ui32 used_bytes = 0;
2770  if (res_num != 0)
2771  used_bytes = child_res->prepare_precinct();
2772 
2773  si32 repeat = (si32)num_precincts.area();
2774  for (si32 i = 0; i < repeat; ++i)
2775  used_bytes += precincts[i].prepare_precinct(tag_tree_size,
2776  level_index, elastic);
2777 
2778  return used_bytes;
2779  }
2780 
2783  {
2784  precinct *p = precincts;
2785  for (si32 i = 0; i < (si32)num_precincts.area(); ++i)
2786  p[i].write(file);
2787  }
2788 
2791  {
2793  if (idx < num_precincts.area())
2794  {
2795  top_left = precincts[idx].img_point;
2796  return true;
2797  }
2798  return false;
2799  }
2800 
2803  {
2805  assert(idx < num_precincts.area());
2806  precincts[idx].write(file);
2807 
2808  if (++cur_precinct_loc.x >= num_precincts.w)
2809  {
2810  cur_precinct_loc.x = 0;
2811  ++cur_precinct_loc.y;
2812  }
2813  }
2814 
2817  {
2818  precinct *p = precincts;
2820  for (ui32 i = idx; i < num_precincts.area(); ++i)
2821  {
2822  if (data_left == 0)
2823  break;
2824  p[i].parse(tag_tree_size, level_index, elastic, data_left, file,
2826  if (++cur_precinct_loc.x >= num_precincts.w)
2827  {
2828  cur_precinct_loc.x = 0;
2829  ++cur_precinct_loc.y;
2830  }
2831  }
2832  }
2833 
2836  {
2838  assert(idx < num_precincts.area());
2839 
2840  if (data_left == 0)
2841  return;
2842  precinct *p = precincts + idx;
2843  p->parse(tag_tree_size, level_index, elastic, data_left, file,
2845  if (++cur_precinct_loc.x >= num_precincts.w)
2846  {
2847  cur_precinct_loc.x = 0;
2848  ++cur_precinct_loc.y;
2849  }
2850  }
2851 
2853  //
2854  //
2855  //
2856  //
2857  //
2859 
2862  {
2863  static const int needed;
2864 
2865  bit_write_buf() { ccl = NULL; avail_bits = 0; tmp = 0; }
2869  };
2870 
2872  const int bit_write_buf::needed = 512;
2873 
2875  static inline
2877  coded_lists*& cur_coded_list)
2878  {
2879  assert(cur_coded_list == NULL);
2880  elastic->get_buffer(bit_write_buf::needed, cur_coded_list);
2881  bbp->ccl = cur_coded_list;
2882  bbp->tmp = 0;
2883  }
2884 
2886  static inline
2888  coded_lists*& cur_coded_list)
2889  {
2890  bb_expand_buf(bbp, elastic, cur_coded_list);
2891  bbp->avail_bits = 8;
2892  }
2893 
2895  static inline
2897  mem_elastic_allocator *elastic,
2898  coded_lists*& cur_coded_list, ui32& ph_bytes)
2899  {
2900  --bbp->avail_bits;
2901  bbp->tmp |= (bit & 1) << bbp->avail_bits;
2902  if (bbp->avail_bits <= 0)
2903  {
2904  bbp->avail_bits = 8 - (bbp->tmp != 0xFF ? 0 : 1);
2905  bbp->ccl->buf[bbp->ccl->buf_size - bbp->ccl->avail_size] =
2906  (ui8)(bbp->tmp & 0xFF);
2907  bbp->tmp = 0;
2908  --bbp->ccl->avail_size;
2909  if (bbp->ccl->avail_size == 0)
2910  {
2911  bb_expand_buf(bbp, elastic, cur_coded_list->next_list);
2912  cur_coded_list = cur_coded_list->next_list;
2913  ph_bytes += bit_write_buf::needed;
2914  }
2915  }
2916  }
2917 
2919  static inline
2920  void bb_put_bits(bit_write_buf *bbp, ui32 data, int num_bits,
2921  mem_elastic_allocator *elastic,
2922  coded_lists*& cur_coded_list, ui32& ph_bytes)
2923  {
2924 // assert(num_bits <= 32);
2925  for (int i = num_bits - 1; i >= 0; --i)
2926  bb_put_bit(bbp, data >> i, elastic, cur_coded_list, ph_bytes);
2927 // while (num_bits) {
2928 // int tx_bits = num_bits < bbp->avail_bits ? num_bits : bbp->avail_bits;
2929 // bbp->tmp |= (data >> (num_bits - tx_bits)) & ((1 << tx_bits) - 1);
2930 // bbp->avail_bits -= tx_bits;
2931 // if (bbp->avail_bits <= 0)
2932 // {
2933 // bbp->avail_bits = 8 - (bbp->tmp != 0xFF ? 0 : 1);
2934 // bbp->buf[bbp->buf_size - bbp->avail_size] = (ui8)(bbp->tmp & 0xFF);
2935 // bbp->tmp = 0;
2936 // --bbp->avail_size;
2937 // if (bbp->avail_size == 0)
2938 // {
2939 // bb_expand_buf(bbp, elastic, cur_coded_list->next_list);
2940 // cur_coded_list = cur_coded_list->next_list;
2941 // ph_bytes += bit_buffer::needed;
2942 // }
2943 // }
2944 // }
2945  }
2946 
2948  static inline
2950  {
2951  if (bbp->avail_bits < 8) //bits have been written
2952  {
2953  ui8 val = (ui8)(bbp->tmp & 0xFF);
2954  bbp->ccl->buf[bbp->ccl->buf_size - bbp->ccl->avail_size] = val;
2955  --bbp->ccl->avail_size;
2956  }
2957  }
2958 
2960  struct tag_tree
2961  {
2962  void init(ui8* buf, ui32 *lev_idx, ui32 num_levels, size s, int init_val)
2963  {
2964  for (ui32 i = 0; i <= num_levels; ++i) //on extra level
2965  levs[i] = buf + lev_idx[i];
2966  for (ui32 i = num_levels + 1; i < 16; ++i)
2967  levs[i] = (ui8*)INT_MAX; //make it crash on error
2968  width = s.w;
2969  height = s.h;
2970  for (ui32 i = 0; i < num_levels; ++i)
2971  {
2972  ui32 size = 1u << ((num_levels - 1 - i) << 1);
2973  memset(levs[i], init_val, size);
2974  }
2975  *levs[num_levels] = 0;
2976  this->num_levels = num_levels;
2977  }
2978 
2979  ui8* get(ui32 x, ui32 y, ui32 lev)
2980  {
2981  return levs[lev] + (x + y * ((width + (1 << lev) - 1) >> lev));
2982  }
2983 
2985  ui8* levs[16]; // you cannot have this high number of levels
2986  };
2987 
2989  static inline ui32 log2ceil(ui32 x)
2990  {
2991  ui32 t = 31 - count_leading_zeros(x);
2992  return t + (x & (x - 1) ? 1 : 0);
2993  }
2994 
2996  ui32 precinct::prepare_precinct(int tag_tree_size, ui32* lev_idx,
2997  mem_elastic_allocator* elastic)
2998  {
2999  bit_write_buf bb;
3000  coded_lists *cur_coded_list = NULL;
3001  ui32 cb_bytes = 0; //cb_bytes;
3002  ui32 ph_bytes = 0; //precinct header size
3003  int sst = num_bands == 3 ? 1 : 0;
3004  int send = num_bands == 3 ? 4 : 1;
3005  int num_skipped_subbands = 0;
3006  for (int s = sst; s < send; ++s)
3007  {
3008  if (cb_idxs[s].siz.w == 0 || cb_idxs[s].siz.h == 0)
3009  continue;
3010 
3011  ui32 num_levels = 1 +
3012  ojph_max(log2ceil(cb_idxs[s].siz.w), log2ceil(cb_idxs[s].siz.h));
3013 
3014  //create quad trees for inclusion and missing msbs
3015  tag_tree inc_tag, inc_tag_flags, mmsb_tag, mmsb_tag_flags;
3016  inc_tag.init(scratch, lev_idx, num_levels, cb_idxs[s].siz, 255);
3017  inc_tag_flags.init(scratch + tag_tree_size,
3018  lev_idx, num_levels, cb_idxs[s].siz, 0);
3019  mmsb_tag.init(scratch + (tag_tree_size<<1),
3020  lev_idx, num_levels, cb_idxs[s].siz, 255);
3021  mmsb_tag_flags.init(scratch + (tag_tree_size<<1) + tag_tree_size,
3022  lev_idx, num_levels, cb_idxs[s].siz, 0);
3023  ui32 band_width = bands[s].num_blocks.w;
3024  coded_cb_header *cp = bands[s].coded_cbs;
3025  cp += cb_idxs[s].org.x + cb_idxs[s].org.y * band_width;
3026  for (ui32 y = 0; y < cb_idxs[s].siz.h; ++y)
3027  {
3028  for (ui32 x = 0; x < cb_idxs[s].siz.w; ++x)
3029  {
3030  coded_cb_header *p = cp + x;
3031  *inc_tag.get(x, y, 0) = (p->next_coded == NULL); //1 if true
3032  *mmsb_tag.get(x, y, 0) = (ui8)p->missing_msbs;
3033  }
3034  cp += band_width;
3035  }
3036  for (ui32 lev = 1; lev < num_levels; ++lev)
3037  {
3038  ui32 height = (cb_idxs[s].siz.h + (1<<lev) - 1) >> lev;
3039  ui32 width = (cb_idxs[s].siz.w + (1<<lev) - 1) >> lev;
3040  for (ui32 y = 0; y < height; ++y)
3041  {
3042  for (ui32 x = 0; x < width; ++x)
3043  {
3044  ui8 t1, t2;
3045  t1 = ojph_min(*inc_tag.get(x<<1, y<<1, lev-1),
3046  *inc_tag.get((x<<1) + 1, y<<1, lev-1));
3047  t2 = ojph_min(*inc_tag.get(x<<1, (y<<1) + 1, lev-1),
3048  *inc_tag.get((x<<1) + 1, (y<<1) + 1, lev-1));
3049  *inc_tag.get(x, y, lev) = ojph_min(t1, t2);
3050  *inc_tag_flags.get(x, y, lev) = 0;
3051  t1 = ojph_min(*mmsb_tag.get(x<<1, y<<1, lev-1),
3052  *mmsb_tag.get((x<<1) + 1, y<<1, lev-1));
3053  t2 = ojph_min(*mmsb_tag.get(x<<1, (y<<1) + 1, lev-1),
3054  *mmsb_tag.get((x<<1) + 1, (y<<1) + 1, lev-1));
3055  *mmsb_tag.get(x, y, lev) = ojph_min(t1, t2);
3056  *mmsb_tag_flags.get(x, y, lev) = 0;
3057  }
3058  }
3059  }
3060  *inc_tag.get(0,0,num_levels) = 0;
3061  *inc_tag_flags.get(0,0,num_levels) = 0;
3062  *mmsb_tag.get(0,0,num_levels) = 0;
3063  *mmsb_tag_flags.get(0,0,num_levels) = 0;
3064  if (*inc_tag.get(0, 0, num_levels-1) != 0) //empty subband
3065  {
3066  if (coded) //non empty precinct, tag tree top is 0
3067  bb_put_bits(&bb, 0, 1, elastic, cur_coded_list, ph_bytes);
3068  else
3069  ++num_skipped_subbands;
3070  continue;
3071  }
3072  //now we are in a position to code
3073  if (coded == NULL)
3074  {
3075  bb_init(&bb, elastic, cur_coded_list);
3076  coded = cur_coded_list;
3077  //store non empty packet
3078  bb_put_bit(&bb, 1, elastic, cur_coded_list, ph_bytes);
3079 
3080  // if the first one or two subbands are empty (has codeblocks but
3081  // no data in them), we need to code them here.
3082  bb_put_bits(&bb, 0, num_skipped_subbands, elastic, cur_coded_list,
3083  ph_bytes);
3084  num_skipped_subbands = 0; //this line is not needed
3085  }
3086 
3087  ui32 width = cb_idxs[s].siz.w;
3088  ui32 height = cb_idxs[s].siz.h;
3089  for (ui32 y = 0; y < height; ++y)
3090  {
3091  cp = bands[s].coded_cbs;
3092  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3093  for (ui32 x = 0; x < width; ++x, ++cp)
3094  {
3095  //inclusion bits
3096  for (ui32 cur_lev = num_levels; cur_lev > 0; --cur_lev)
3097  {
3098  ui32 levm1 = cur_lev - 1;
3099  //check sent
3100  if (*inc_tag_flags.get(x>>levm1, y>>levm1, levm1) == 0)
3101  {
3102  ui32 skipped = *inc_tag.get(x>>levm1, y>>levm1, levm1);
3103  skipped -= *inc_tag.get(x>>cur_lev, y>>cur_lev, cur_lev);
3104  assert(skipped <= 1); // for HTJ2K, this should 0 or 1
3105  bb_put_bits(&bb, 1 - skipped, 1,
3106  elastic, cur_coded_list, ph_bytes);
3107  *inc_tag_flags.get(x>>levm1, y>>levm1, levm1) = 1;
3108  }
3109  if (*inc_tag.get(x>>levm1, y>>levm1, levm1) > 0)
3110  break;
3111  }
3112 
3113  if (cp->num_passes == 0) //empty codeblock
3114  continue;
3115 
3116  //missing msbs
3117  for (ui32 cur_lev = num_levels; cur_lev > 0; --cur_lev)
3118  {
3119  ui32 levm1 = cur_lev - 1;
3120  //check sent
3121  if (*mmsb_tag_flags.get(x>>levm1, y>>levm1, levm1) == 0)
3122  {
3123  int num_zeros = *mmsb_tag.get(x>>levm1, y>>levm1, levm1);
3124  num_zeros -= *mmsb_tag.get(x>>cur_lev, y>>cur_lev, cur_lev);
3125  bb_put_bits(&bb, 1, num_zeros + 1,
3126  elastic, cur_coded_list, ph_bytes);
3127  *mmsb_tag_flags.get(x>>levm1, y>>levm1, levm1) = 1;
3128  }
3129  }
3130 
3131  //number of coding passes
3132  switch (cp->num_passes)
3133  {
3134  case 3:
3135  bb_put_bits(&bb, 12, 4, elastic, cur_coded_list, ph_bytes);
3136  break;
3137  case 2:
3138  bb_put_bits(&bb, 2, 2, elastic, cur_coded_list, ph_bytes);
3139  break;
3140  case 1:
3141  bb_put_bits(&bb, 0, 1, elastic, cur_coded_list, ph_bytes);
3142  break;
3143  default:
3144  assert(0);
3145  }
3146 
3147  //pass lengths
3148  //either one, two, or three passes, but only one or two lengths
3149  int bits1 = 32 - (int)count_leading_zeros(cp->pass_length[0]);
3150  int extra_bit = cp->num_passes > 2 ? 1 : 0; //for 2nd length
3151  int bits2 = 0;
3152  if (cp->num_passes > 1)
3153  bits2 = 32 - (int)count_leading_zeros(cp->pass_length[1]);
3154  int bits = ojph_max(bits1, bits2 - extra_bit) - 3;
3155  bits = ojph_max(bits, 0);
3156  bb_put_bits(&bb, 0xFFFFFFFEu, bits+1,
3157  elastic, cur_coded_list, ph_bytes);
3158 
3159  bb_put_bits(&bb, cp->pass_length[0], bits+3,
3160  elastic, cur_coded_list, ph_bytes);
3161  if (cp->num_passes > 1)
3162  bb_put_bits(&bb, cp->pass_length[1], bits+3+extra_bit,
3163  elastic, cur_coded_list, ph_bytes);
3164 
3165  cb_bytes += cp->pass_length[0] + cp->pass_length[1];
3166  }
3167  }
3168  }
3169 
3170  if (coded)
3171  {
3172  bb_terminate(&bb);
3173  ph_bytes += cur_coded_list->buf_size - cur_coded_list->avail_size;
3174  }
3175 
3176  return coded ? cb_bytes + ph_bytes : 1;
3177  }
3178 
3181  {
3182  if (coded)
3183  {
3184  //write packet header
3185  coded_lists *ccl = coded;
3186  while (ccl)
3187  {
3188  file->write(ccl->buf, ccl->buf_size - ccl->avail_size);
3189  ccl = ccl->next_list;
3190  }
3191 
3192  //write codeblocks
3193  int sst = num_bands == 3 ? 1 : 0;
3194  int send = num_bands == 3 ? 4 : 1;
3195  for (int s = sst; s < send; ++s)
3196  {
3197  ui32 band_width = bands[s].num_blocks.w;
3198  ui32 width = cb_idxs[s].siz.w;
3199  ui32 height = cb_idxs[s].siz.h;
3200  for (ui32 y = 0; y < height; ++y)
3201  {
3202  coded_cb_header *cp = bands[s].coded_cbs;
3203  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3204  for (ui32 x = 0; x < width; ++x, ++cp)
3205  {
3206  coded_lists *ccl = cp->next_coded;
3207  while (ccl)
3208  {
3209  file->write(ccl->buf, ccl->buf_size - ccl->avail_size);
3210  ccl = ccl->next_list;
3211  }
3212  }
3213  }
3214  }
3215  }
3216  else
3217  {
3218  //empty packet
3219  char buf = 0x00;
3220  file->write(&buf, 1);
3221  }
3222  }
3223 
3226  {
3230  bool unstuff;
3232  };
3233 
3235  static inline
3236  void bb_init(bit_read_buf *bbp, ui32 bytes_left, infile_base* file)
3237  {
3238  bbp->avail_bits = 0;
3239  bbp->file = file;
3240  bbp->bytes_left = bytes_left;
3241  bbp->tmp = 0;
3242  bbp->unstuff = false;
3243  }
3244 
3246  static inline
3248  {
3249  if (bbp->bytes_left > 0)
3250  {
3251  ui32 t = 0;
3252  if (bbp->file->read(&t, 1) != 1)
3253  throw "error reading from file";
3254  bbp->tmp = t;
3255  bbp->avail_bits = 8 - bbp->unstuff;
3256  bbp->unstuff = (t == 0xFF);
3257  --bbp->bytes_left;
3258  return true;
3259  }
3260  else
3261  {
3262  bbp->tmp = 0;
3263  bbp->avail_bits = 8 - bbp->unstuff;
3264  bbp->unstuff = false;
3265  return false;
3266  }
3267  }
3268 
3270  static inline
3271  bool bb_read_bit(bit_read_buf *bbp, ui32& bit)
3272  {
3273  bool result = true;
3274  if (bbp->avail_bits == 0)
3275  result = bb_read(bbp);
3276  bit = (bbp->tmp >> --bbp->avail_bits) & 1;
3277  return result;
3278  }
3279 
3281  static inline
3282  bool bb_read_bits(bit_read_buf *bbp, int num_bits, ui32& bits)
3283  {
3284  assert(num_bits <= 32);
3285 
3286  bits = 0;
3287  bool result = true;
3288  while (num_bits) {
3289  if (bbp->avail_bits == 0)
3290  result = bb_read(bbp);
3291  int tx_bits = ojph_min(bbp->avail_bits, num_bits);
3292  bits <<= tx_bits;
3293  bbp->avail_bits -= tx_bits;
3294  num_bits -= tx_bits;
3295  bits |= (bbp->tmp >> bbp->avail_bits) & ((1 << tx_bits) - 1);
3296  }
3297  return result;
3298  }
3299 
3301  static inline
3302  bool bb_read_chunk(bit_read_buf *bbp, ui32 num_bytes,
3303  coded_lists*& cur_coded_list,
3304  mem_elastic_allocator *elastic)
3305  {
3306  assert(bbp->avail_bits == 0 && bbp->unstuff == false);
3307  ui32 bytes = ojph_min(num_bytes, bbp->bytes_left);
3309  + coded_cb_header::suffix_buf_size, cur_coded_list);
3310  ui32 bytes_read = (ui32)bbp->file->read(
3311  cur_coded_list->buf + coded_cb_header::prefix_buf_size, bytes);
3312  if (num_bytes > bytes_read)
3313  memset(cur_coded_list->buf + coded_cb_header::prefix_buf_size + bytes,
3314  0, num_bytes - bytes_read);
3315  bbp->bytes_left -= bytes_read;
3316  return bytes_read == bytes;
3317  }
3318 
3320  static inline
3322  {
3323  if (bbp->bytes_left >= 2)
3324  {
3325  ui8 marker[2];
3326  if (bbp->file->read(marker, 2) != 2)
3327  throw "error reading from file";
3328  bbp->bytes_left -= 2;
3329  if ((int)marker[0] != (EPH >> 8) || (int)marker[1] != (EPH & 0xFF))
3330  throw "should find EPH, but found something else";
3331  }
3332  }
3333 
3335  static inline
3336  bool bb_terminate(bit_read_buf *bbp, bool uses_eph)
3337  {
3338  bool result = true;
3339  if (bbp->unstuff)
3340  result = bb_read(bbp);
3341  assert(bbp->unstuff == false);
3342  if (uses_eph)
3343  bb_skip_eph(bbp);
3344  bbp->tmp = 0;
3345  bbp->avail_bits = 0;
3346  return result;
3347  }
3348 
3350  static inline
3352  {
3353  if (bbp->bytes_left >= 2)
3354  {
3355  ui8 marker[2];
3356  if (bbp->file->read(marker, 2) != 2)
3357  throw "error reading from file";
3358  if ((int)marker[0] == (SOP >> 8) && (int)marker[1] == (SOP & 0xFF))
3359  {
3360  bbp->bytes_left -= 2;
3361  if (bbp->bytes_left >= 4)
3362  {
3363  ui16 com_len;
3364  if (bbp->file->read(&com_len, 2) != 2)
3365  throw "error reading from file";
3366  com_len = swap_byte(com_len);
3367  if (com_len != 4)
3368  throw "something is wrong with SOP length";
3369  int result =
3370  bbp->file->seek(com_len - 2, infile_base::OJPH_SEEK_CUR);
3371  if (result != 0)
3372  throw "error seeking file";
3373  bbp->bytes_left -= com_len;
3374  }
3375  else
3376  throw "precinct truncated early";
3377  return true;
3378  }
3379  else
3380  {
3381  //put the bytes back
3382  if (bbp->file->seek(-2, infile_base::OJPH_SEEK_CUR) != 0)
3383  throw "error seeking file";
3384  return false;
3385  }
3386  }
3387 
3388  return false;
3389  }
3390 
3392  void precinct::parse(int tag_tree_size, ui32* lev_idx,
3393  mem_elastic_allocator *elastic,
3394  ui32 &data_left, infile_base *file,
3395  bool skipped)
3396  {
3397  assert(data_left > 0);
3398  bit_read_buf bb;
3399  bb_init(&bb, data_left, file);
3400  if (may_use_sop)
3401  bb_skip_sop(&bb);
3402 
3403  int sst = num_bands == 3 ? 1 : 0;
3404  int send = num_bands == 3 ? 4 : 1;
3405  bool empty_packet = true;
3406  for (int s = sst; s < send; ++s)
3407  {
3408  if (cb_idxs[s].siz.w == 0 || cb_idxs[s].siz.h == 0)
3409  continue;
3410 
3411  if (empty_packet) //one bit to check if the packet is empty
3412  {
3413  ui32 bit;
3414  bb_read_bit(&bb, bit);
3415  if (bit == 0) //empty packet
3416  { bb_terminate(&bb, uses_eph); data_left = bb.bytes_left; return; }
3417  empty_packet = false;
3418  }
3419 
3420  ui32 num_levels = 1 +
3421  ojph_max(log2ceil(cb_idxs[s].siz.w), log2ceil(cb_idxs[s].siz.h));
3422 
3423  //create quad trees for inclusion and missing msbs
3424  tag_tree inc_tag, inc_tag_flags, mmsb_tag, mmsb_tag_flags;
3425  inc_tag.init(scratch, lev_idx, num_levels, cb_idxs[s].siz, 0);
3426  *inc_tag.get(0, 0, num_levels) = 0;
3427  inc_tag_flags.init(scratch + tag_tree_size, lev_idx, num_levels,
3428  cb_idxs[s].siz, 0);
3429  *inc_tag_flags.get(0, 0, num_levels) = 0;
3430  mmsb_tag.init(scratch + (tag_tree_size<<1), lev_idx, num_levels,
3431  cb_idxs[s].siz, 0);
3432  *mmsb_tag.get(0, 0, num_levels) = 0;
3433  mmsb_tag_flags.init(scratch + (tag_tree_size<<1) + tag_tree_size,
3434  lev_idx, num_levels, cb_idxs[s].siz, 0);
3435  *mmsb_tag_flags.get(0, 0, num_levels) = 0;
3436 
3437  //
3438  ui32 band_width = bands[s].num_blocks.w;
3439  ui32 width = cb_idxs[s].siz.w;
3440  ui32 height = cb_idxs[s].siz.h;
3441  for (ui32 y = 0; y < height; ++y)
3442  {
3443  coded_cb_header *cp = bands[s].coded_cbs;
3444  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3445  for (ui32 x = 0; x < width; ++x, ++cp)
3446  {
3447  //process inclusion
3448  bool empty_cb = false;
3449  for (ui32 cl = num_levels; cl > 0; --cl)
3450  {
3451  ui32 cur_lev = cl - 1;
3452  empty_cb = *inc_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) == 1;
3453  if (empty_cb)
3454  break;
3455  //check received
3456  if (*inc_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) == 0)
3457  {
3458  ui32 bit;
3459  if (bb_read_bit(&bb, bit) == false)
3460  { data_left = 0; throw "error reading from file p1"; }
3461  empty_cb = (bit == 0);
3462  *inc_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) = (ui8)(1 - bit);
3463  *inc_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) = 1;
3464  }
3465  if (empty_cb)
3466  break;
3467  }
3468 
3469  if (empty_cb)
3470  continue;
3471 
3472  //process missing msbs
3473  ui32 mmsbs = 0;
3474  for (ui32 levp1 = num_levels; levp1 > 0; --levp1)
3475  {
3476  ui32 cur_lev = levp1 - 1;
3477  mmsbs = *mmsb_tag.get(x>>levp1, y>>levp1, levp1);
3478  //check received
3479  if (*mmsb_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) == 0)
3480  {
3481  ui32 bit = 0;
3482  while (bit == 0)
3483  {
3484  if (bb_read_bit(&bb, bit) == false)
3485  { data_left = 0; throw "error reading from file p2"; }
3486  mmsbs += 1 - bit;
3487  }
3488  *mmsb_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) = (ui8)mmsbs;
3489  *mmsb_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) = 1;
3490  }
3491  }
3492 
3493  if (mmsbs > cp->Kmax)
3494  throw "error in parsing a tile header; "
3495  "missing msbs are larger or equal to Kmax. The most likely "
3496  "cause is a corruption in the bitstream.";
3497  cp->missing_msbs = mmsbs;
3498 
3499  //get number of passes
3500  ui32 bit, num_passes = 1;
3501  if (bb_read_bit(&bb, bit) == false)
3502  { data_left = 0; throw "error reading from file p3"; }
3503  if (bit)
3504  {
3505  num_passes = 2;
3506  if (bb_read_bit(&bb, bit) == false)
3507  { data_left = 0; throw "error reading from file p4"; }
3508  if (bit)
3509  {
3510  if (bb_read_bits(&bb, 2, bit) == false)
3511  { data_left = 0; throw "error reading from file p5"; }
3512  num_passes = 3 + bit;
3513  if (bit == 3)
3514  {
3515  if (bb_read_bits(&bb, 5, bit) == false)
3516  { data_left = 0; throw "error reading from file p6"; }
3517  num_passes = 6 + bit;
3518  if (bit == 31)
3519  {
3520  if (bb_read_bits(&bb, 7, bit) == false)
3521  { data_left = 0; throw "error reading from file p7"; }
3522  num_passes = 37 + bit;
3523  }
3524  }
3525  }
3526  }
3527  cp->num_passes = num_passes;
3528 
3529  //parse pass lengths
3530  //for one pass, one length, but for 2 or 3 passes, two lengths
3531  int extra_bit = cp->num_passes > 2 ? 1 : 0;
3532  int bits1 = 3;
3533  bit = 1;
3534  while (bit)
3535  {
3536  if (bb_read_bit(&bb, bit) == false)
3537  { data_left = 0; throw "error reading from file p8"; }
3538  bits1 += bit;
3539  }
3540 
3541  if (bb_read_bits(&bb, bits1, bit) == false)
3542  { data_left = 0; throw "error reading from file p9"; }
3543  cp->pass_length[0] = bit;
3544  if (num_passes > 1)
3545  {
3546  if (bb_read_bits(&bb, bits1 + extra_bit, bit) == false)
3547  { data_left = 0; throw "error reading from file p10"; }
3548  cp->pass_length[1] = bit;
3549  }
3550  }
3551  }
3552  }
3553  bb_terminate(&bb, uses_eph);
3554  //read codeblock data
3555  for (int s = sst; s < send; ++s)
3556  {
3557  ui32 band_width = bands[s].num_blocks.w;
3558  ui32 width = cb_idxs[s].siz.w;
3559  ui32 height = cb_idxs[s].siz.h;
3560  for (ui32 y = 0; y < height; ++y)
3561  {
3562  coded_cb_header *cp = bands[s].coded_cbs;
3563  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3564  for (ui32 x = 0; x < width; ++x, ++cp)
3565  {
3566  ui32 num_bytes = cp->pass_length[0] + cp->pass_length[1];
3567  if (data_left)
3568  {
3569  if (num_bytes)
3570  {
3571  if (skipped)
3572  { //no need to read
3573  si64 cur_loc = file->tell();
3574  ui32 t = ojph_min(num_bytes, bb.bytes_left);
3575  file->seek(t, infile_base::OJPH_SEEK_CUR);
3576  ui32 bytes_read = (ui32)(file->tell() - cur_loc);
3577  cp->pass_length[0] = cp->pass_length[1] = 0;
3578  bb.bytes_left -= bytes_read;
3579  assert(bytes_read == t || bb.bytes_left == 0);
3580  }
3581  else
3582  {
3583  if (!bb_read_chunk(&bb, num_bytes, cp->next_coded, elastic))
3584  {
3585  //no need to decode a broken codeblock
3586  cp->pass_length[0] = cp->pass_length[1] = 0;
3587  data_left = 0;
3588  }
3589  }
3590  }
3591  }
3592  else
3593  cp->pass_length[0] = cp->pass_length[1] = 0;
3594  }
3595  }
3596  }
3597  data_left = bb.bytes_left;
3598  }
3599 
3601  //
3602  //
3603  //
3604  //
3605  //
3607 
3610  ui32 res_num)
3611  {
3613 
3614  const param_cod* cdp = codestream->get_cod();
3615  size log_cb = cdp->get_log_block_dims();
3617 
3618  ui32 xcb_prime = ojph_min(log_cb.w, log_PP.w - (res_num?1:0));
3619  ui32 ycb_prime = ojph_min(log_cb.h, log_PP.h - (res_num?1:0));
3620 
3621  size nominal(1 << xcb_prime, 1 << ycb_prime);
3622 
3623  ui32 tbx0 = band_rect.org.x;
3624  ui32 tby0 = band_rect.org.y;
3625  ui32 tbx1 = band_rect.org.x + band_rect.siz.w;
3626  ui32 tby1 = band_rect.org.y + band_rect.siz.h;
3627 
3628  size num_blocks;
3629  if (tbx0 != tbx1 && tby0 != tby1)
3630  {
3631  num_blocks.w = (tbx1 + (1 << xcb_prime) - 1) >> xcb_prime;
3632  num_blocks.w -= tbx0 >> xcb_prime;
3633  num_blocks.h = (tby1 + (1 << ycb_prime) - 1) >> ycb_prime;
3634  num_blocks.h -= tby0 >> ycb_prime;
3635  }
3636 
3637  if (num_blocks.area())
3638  {
3639  allocator->pre_alloc_obj<codeblock>(num_blocks.w);
3640  //allocate codeblock headers
3642 
3643  for (ui32 i = 0; i < num_blocks.w; ++i)
3644  codeblock::pre_alloc(codestream, nominal);
3645 
3646  //allocate lines
3647  allocator->pre_alloc_obj<line_buf>(1);
3648  //allocate line_buf
3649  ui32 width = band_rect.siz.w + 1;
3650  allocator->pre_alloc_data<si32>(width, 1);
3651  }
3652  }
3653 
3656  const rect &band_rect,
3657  resolution* res, ui32 res_num,
3658  ui32 subband_num)
3659  {
3662 
3663  this->res_num = res_num;
3664  this->band_num = subband_num;
3665  this->band_rect = band_rect;
3666  this->parent = res;
3667 
3668  const param_cod* cdp = codestream->get_cod();
3669  this->reversible = cdp->is_reversible();
3670  size log_cb = cdp->get_log_block_dims();
3672 
3673  xcb_prime = ojph_min(log_cb.w, log_PP.w - (res_num?1:0));
3674  ycb_prime = ojph_min(log_cb.h, log_PP.h - (res_num?1:0));
3675 
3676  size nominal(1 << xcb_prime, 1 << ycb_prime);
3677 
3678  cur_cb_row = 0;
3679  cur_line = 0;
3680  cur_cb_height = 0;
3682  this->K_max = qcd->get_Kmax(this->res_num, band_num);
3683  if (!reversible)
3684  {
3685  float d = qcd->irrev_get_delta(res_num, subband_num);
3686  d /= (float)(1u << (31 - this->K_max));
3687  delta = d;
3688  delta_inv = (1.0f/d);
3689  }
3690 
3691  ui32 tbx0 = band_rect.org.x;
3692  ui32 tby0 = band_rect.org.y;
3693  ui32 tbx1 = band_rect.org.x + band_rect.siz.w;
3694  ui32 tby1 = band_rect.org.y + band_rect.siz.h;
3695 
3696  num_blocks = size();
3697  if (tbx0 != tbx1 && tby0 != tby1)
3698  {
3699  num_blocks.w = (tbx1 + (1 << xcb_prime) - 1) >> xcb_prime;
3700  num_blocks.w -= tbx0 >> xcb_prime;
3701  num_blocks.h = (tby1 + (1 << ycb_prime) - 1) >> ycb_prime;
3702  num_blocks.h -= tby0 >> ycb_prime;
3703  }
3704 
3705  if (num_blocks.area())
3706  {
3707  blocks = allocator->post_alloc_obj<codeblock>(num_blocks.w);
3708  //allocate codeblock headers
3709  coded_cb_header *cp = coded_cbs =
3711  memset(coded_cbs, 0, sizeof(coded_cb_header) * num_blocks.area());
3712  for (int i = (int)num_blocks.area(); i > 0; --i, ++cp)
3713  cp->Kmax = K_max;
3714 
3715  ui32 x_lower_bound = (tbx0 >> xcb_prime) << xcb_prime;
3716  ui32 y_lower_bound = (tby0 >> ycb_prime) << ycb_prime;
3717 
3718  size cb_size;
3719  cb_size.h = ojph_min(tby1, y_lower_bound + nominal.h) - tby0;
3720  cur_cb_height = (si32)cb_size.h;
3721  int line_offset = 0;
3722  for (ui32 i = 0; i < num_blocks.w; ++i)
3723  {
3724  ui32 cbx0 = ojph_max(tbx0, x_lower_bound + i * nominal.w);
3725  ui32 cbx1 = ojph_min(tbx1, x_lower_bound + (i + 1) * nominal.w);
3726  cb_size.w = cbx1 - cbx0;
3727  blocks[i].finalize_alloc(codestream, this, nominal, cb_size,
3728  coded_cbs + i, K_max, line_offset);
3729  line_offset += cb_size.w;
3730  }
3731 
3732  //allocate lines
3733  lines = allocator->post_alloc_obj<line_buf>(1);
3734  //allocate line_buf
3735  ui32 width = band_rect.siz.w + 1;
3736  lines->wrap(allocator->post_alloc_data<si32>(width,1),width,1);
3737  }
3738  }
3739 
3741  void subband::get_cb_indices(const size& num_precincts,
3742  precinct *precincts)
3743  {
3744  if (band_rect.siz.w == 0 || band_rect.siz.h == 0)
3745  return;
3746 
3747  rect res_rect = parent->get_rect();
3748  ui32 trx0 = res_rect.org.x;
3749  ui32 try0 = res_rect.org.y;
3750  ui32 trx1 = res_rect.org.x + res_rect.siz.w;
3751  ui32 try1 = res_rect.org.y + res_rect.siz.h;
3752 
3753  ui32 pc_lft = (res_rect.org.x >> log_PP.w) << log_PP.w;
3754  ui32 pc_top = (res_rect.org.y >> log_PP.h) << log_PP.h;
3755 
3756  ui32 pcx0, pcx1, pcy0, pcy1, shift = (band_num != 0 ? 1 : 0);
3757  ui32 yb, xb, coly = 0, colx = 0;
3758  for (ui32 y = 0; y < num_precincts.h; ++y)
3759  {
3760  pcy0 = ojph_max(try0, pc_top + (y << log_PP.h));
3761  pcy1 = ojph_min(try1, pc_top + ((y + 1) << log_PP.h));
3762  pcy0 = (pcy0 - (band_num >> 1) + (1<<shift) - 1) >> shift;
3763  pcy1 = (pcy1 - (band_num >> 1) + (1<<shift) - 1) >> shift;
3764 
3765  precinct *p = precincts + y * num_precincts.w;
3766  yb = ((pcy1 + (1<<ycb_prime) - 1) >> ycb_prime);
3767  yb -= (pcy0 >> ycb_prime);
3768  colx = 0;
3769 
3770  for (ui32 x = 0; x < num_precincts.w; ++x, ++p)
3771  {
3772  pcx0 = ojph_max(trx0, pc_lft + (x << log_PP.w));
3773  pcx1 = ojph_min(trx1, pc_lft + ((x + 1) << log_PP.w));
3774  pcx0 = (pcx0 - (band_num & 1) + (1<<shift) - 1) >> shift;
3775  pcx1 = (pcx1 - (band_num & 1) + (1<<shift) - 1) >> shift;
3776 
3777  rect *bp = p->cb_idxs + band_num;
3778  xb = ((pcx1 + (1<<xcb_prime) - 1) >> xcb_prime);
3779  xb -= (pcx0 >> xcb_prime);
3780 
3781  bp->org.x = colx;
3782  bp->org.y = coly;
3783  bp->siz.w = xb;
3784  bp->siz.h = yb;
3785 
3786  colx += xb;
3787  }
3788  coly += yb;
3789  }
3790  assert(colx == num_blocks.w && coly == num_blocks.h);
3791  }
3792 
3795  {
3796  assert(l->pre_size == lines[0].pre_size && l->size == lines[0].size);
3797  si32* t = lines[0].i32;
3798  lines[0].i32 = l->i32;
3799  l->i32 = t;
3800  }
3801 
3804  {
3805  if (reversible)
3806  {
3807  ui32 shift = 31 - K_max;
3808  //convert to sign and magnitude
3809  si32 *sp = lines->i32;
3810  for (ui32 i = band_rect.siz.w; i > 0; --i)
3811  {
3812  si32 val = *sp >= 0 ? *sp : -*sp;
3813  si32 sign = *sp >= 0 ? 0 : (int)0x80000000;
3814  *sp++ = sign | (val << shift);
3815  }
3816  }
3817  else
3818  {
3819  //quantize and convert to sign and magnitude
3820  const float *sp = lines->f32;
3821  si32 *dp = lines->i32;
3822  for (ui32 i = band_rect.siz.w; i > 0; --i)
3823  {
3824  si32 t = ojph_trunc(*sp++ * delta_inv);
3825  si32 val = t >= 0 ? t : -t;
3826  si32 sign = t >= 0 ? 0 : (int)0x80000000;
3827  *dp++ = sign | val;
3828  }
3829  }
3830 
3831  //push to codeblocks
3832  for (ui32 i = 0; i < num_blocks.w; ++i)
3833  blocks[i].push(lines + 0);
3834  if (++cur_line >= cur_cb_height)
3835  {
3836  for (ui32 i = 0; i < num_blocks.w; ++i)
3837  blocks[i].encode(elastic);
3838 
3839  if (++cur_cb_row < num_blocks.h)
3840  {
3841  cur_line = 0;
3842 
3843  ui32 tbx0 = band_rect.org.x;
3844  ui32 tby0 = band_rect.org.y;
3845  ui32 tbx1 = band_rect.org.x + band_rect.siz.w;
3846  ui32 tby1 = band_rect.org.y + band_rect.siz.h;
3847  size nominal(1 << xcb_prime, 1 << ycb_prime);
3848 
3849  ui32 x_lower_bound = (tbx0 >> xcb_prime) << xcb_prime;
3850  ui32 y_lower_bound = (tby0 >> ycb_prime) << ycb_prime;
3851  ui32 cby0 = y_lower_bound + cur_cb_row * nominal.h;
3852  ui32 cby1 = ojph_min(tby1, cby0 + nominal.h);
3853 
3854  size cb_size;
3855  cb_size.h = cby1 - ojph_max(tby0, cby0);
3856  cur_cb_height = (int)cb_size.h;
3857  for (ui32 i = 0; i < num_blocks.w; ++i)
3858  {
3859  ui32 cbx0 = ojph_max(tbx0, x_lower_bound + i * nominal.w);
3860  ui32 cbx1 = ojph_min(tbx1, x_lower_bound + (i + 1) * nominal.w);
3861  cb_size.w = cbx1 - cbx0;
3862  blocks[i].recreate(cb_size,
3863  coded_cbs + i + cur_cb_row * num_blocks.w);
3864  }
3865  }
3866  }
3867  }
3868 
3871  {
3872  if (band_rect.siz.w == 0 || band_rect.siz.h == 0)
3873  return lines;
3874 
3875  //pull from codeblocks
3876  if (--cur_line <= 0)
3877  {
3878  if (cur_cb_row < num_blocks.h)
3879  {
3880  ui32 tbx0 = band_rect.org.x;
3881  ui32 tby0 = band_rect.org.y;
3882  ui32 tbx1 = band_rect.org.x + band_rect.siz.w;
3883  ui32 tby1 = band_rect.org.y + band_rect.siz.h;
3884  size nominal(1 << xcb_prime, 1 << ycb_prime);
3885 
3886  ui32 x_lower_bound = (tbx0 >> xcb_prime) << xcb_prime;
3887  ui32 y_lower_bound = (tby0 >> ycb_prime) << ycb_prime;
3888  ui32 cby0 = ojph_max(tby0, y_lower_bound + cur_cb_row * nominal.h);
3889  ui32 cby1 = ojph_min(tby1, y_lower_bound+(cur_cb_row+1)*nominal.h);
3890 
3891  size cb_size;
3892  cb_size.h = cby1 - cby0;
3893  cur_line = cur_cb_height = (int)cb_size.h;
3894  for (ui32 i = 0; i < num_blocks.w; ++i)
3895  {
3896  ui32 cbx0 = ojph_max(tbx0, x_lower_bound + i * nominal.w);
3897  ui32 cbx1 = ojph_min(tbx1, x_lower_bound + (i + 1) * nominal.w);
3898  cb_size.w = cbx1 - cbx0;
3899  blocks[i].recreate(cb_size,
3900  coded_cbs + i + cur_cb_row * num_blocks.w);
3901  blocks[i].decode();
3902  }
3903  ++cur_cb_row;
3904  }
3905  }
3906 
3907  assert(cur_line >= 0);
3908 
3909  //pull from codeblocks
3910  for (ui32 i = 0; i < num_blocks.w; ++i)
3911  blocks[i].pull_line(lines + 0);
3912 
3913  if (reversible)
3914  {
3915  ui32 shift = 31 - K_max;
3916  //convert to sign and magnitude
3917  si32 *sp = lines->i32;
3918  for (ui32 i = band_rect.siz.w; i > 0; --i, ++sp)
3919  {
3920  si32 val = (*sp & 0x7FFFFFFF) >> shift;
3921  *sp = ((ui32)*sp & 0x80000000) ? -val : val;
3922  }
3923  }
3924  else
3925  {
3926  //quantize and convert to sign and magnitude
3927  const si32 *sp = lines->i32;
3928  float *dp = lines->f32;
3929  for (ui32 i = band_rect.siz.w; i > 0; --i, ++sp)
3930  {
3931  float val = (float)(*sp & 0x7FFFFFFF) * delta;
3932  *dp++ = ((ui32)*sp & 0x80000000) ? -val : val;
3933  }
3934  }
3935 
3936  return lines;
3937  }
3938 
3939 
3941  //
3942  //
3943  //
3944  //
3945  //
3947 
3950  const size& nominal)
3951  {
3953 
3954  ui32 stride = (nominal.w + 3) & 0xFFFFFFFCU; // a multiple of 4
3955  allocator->pre_alloc_data<ui32>(nominal.h * stride, 0);
3956  }
3957 
3960  subband *parent, const size& nominal,
3961  const size& cb_size,
3962  coded_cb_header* coded_cb,
3963  ui32 K_max, int line_offset)
3964  {
3966 
3967  this->stride = (nominal.w + 3) & 0xFFFFFFFC; // a multiple of 4
3968  this->buf_size = this->stride * nominal.h;
3969  this->buf = allocator->post_alloc_data<ui32>(this->buf_size, 0);
3970 
3971  this->nominal_size = nominal;
3972  this->cb_size = cb_size;
3973  this->parent = parent;
3974  this->line_offset = line_offset;
3975  this->cur_line = 0;
3976  this->K_max = K_max;
3977  this->max_val = 0;
3978  this->resilient = codestream->is_resilient();
3981  this->coded_cb = coded_cb;
3982  }
3983 
3986  {
3987  const si32 *sp = line->i32 + line_offset;
3988  ui32 *dp = buf + cur_line * stride;
3989  int tmax = max_val; //this improves speed considerably
3990  for (ui32 i = cb_size.w; i > 0; --i)
3991  {
3992  si32 t = *sp++;
3993  tmax = ojph_max(tmax, 0x7FFFFFFF & t);
3994  *dp++ = (ui32)t;
3995  }
3996  //for (ui32 i = stride - cb_size.w; i > 0; --i)
3997  // *dp++ = 0;
3998  max_val = tmax;
3999  ++cur_line;
4000  }
4001 
4004  {
4005  if (max_val >= 1<<(31 - K_max))
4006  {
4007  coded_cb->missing_msbs = K_max - 1;
4008  assert(coded_cb->missing_msbs > 0);
4009  assert(coded_cb->missing_msbs < K_max);
4010  coded_cb->num_passes = 1;
4011 
4014  elastic, coded_cb->next_coded);
4015  }
4016  }
4017 
4019  void codeblock::recreate(const size &cb_size, coded_cb_header* coded_cb)
4020  {
4021  assert(cb_size.h * stride <= buf_size && cb_size.w <= stride);
4022  this->cb_size = cb_size;
4023  this->coded_cb = coded_cb;
4024  this->cur_line = 0;
4025  this->max_val = 0;
4026  }
4027 
4030  {
4031  if (coded_cb->pass_length[0] > 0 && coded_cb->num_passes > 0 &&
4032  coded_cb->next_coded != NULL)
4033  {
4034  bool result =
4040 
4041  if (result == false)
4042  {
4043  if (resilient == true)
4044  memset(buf, 0, cb_size.h * stride * sizeof(si32));
4045  else
4046  OJPH_ERROR(0x000300A1, "Error decoding a codeblock\n");
4047  }
4048  }
4049  else
4050  memset(buf, 0, cb_size.h * stride * sizeof(si32));
4051  }
4052 
4055  {
4056  const ui32 *sp = buf + cur_line * stride;
4057  si32 *dp = line->i32 + line_offset;
4058  memcpy(dp, sp, cb_size.w * sizeof(si32));
4059  ++cur_line;
4060  assert(cur_line <= cb_size.h);
4061  }
4062 
4063  }
4064 }
OJPH_EXPORT param_siz access_siz()
OJPH_EXPORT param_cod access_cod()
OJPH_EXPORT void restrict_input_resolution(ui32 skipped_res_for_data, ui32 skipped_res_for_recon)
local::codestream * state
OJPH_EXPORT void close()
OJPH_EXPORT void set_planar(bool planar)
OJPH_EXPORT ~codestream()
OJPH_EXPORT void enable_resilience()
OJPH_EXPORT line_buf * exchange(line_buf *line, ui32 &next_component)
OJPH_EXPORT codestream()
OJPH_EXPORT void set_profile(const char *s)
OJPH_EXPORT void write_headers(outfile_base *file)
OJPH_EXPORT param_qcd access_qcd()
OJPH_EXPORT void read_headers(infile_base *file)
OJPH_EXPORT void create()
OJPH_EXPORT bool is_planar() const
OJPH_EXPORT void flush()
OJPH_EXPORT line_buf * pull(ui32 &comp_num)
virtual bool eof()=0
virtual void close()
Definition: ojph_file.h:215
virtual si64 tell()=0
virtual size_t read(void *ptr, size_t size)=0
static void pre_alloc(codestream *codestream, const size &nominal)
void push(line_buf *line)
void encode(mem_elastic_allocator *elastic)
void recreate(const size &cb_size, coded_cb_header *coded_cb)
void finalize_alloc(codestream *codestream, subband *parent, const size &nominal, const size &cb_size, coded_cb_header *coded_cb, ui32 K_max, int tbx0)
void pull_line(line_buf *line)
mem_elastic_allocator * get_elastic_alloc()
line_buf * exchange(line_buf *line, ui32 &next_component)
const param_siz * get_siz()
void restrict_input_resolution(ui32 skipped_res_for_data, ui32 skipped_res_for_recon)
mem_elastic_allocator * elastic_alloc
mem_fixed_allocator * allocator
mem_fixed_allocator * get_allocator()
param_qcd * access_qcd(ui32 comp_num)
void read_headers(infile_base *file)
const param_cod * get_cod()
void set_profile(const char *s)
void write_headers(outfile_base *file)
line_buf * pull(ui32 &comp_num)
bool get_top_left_precinct(point &top_left)
void parse_one_precinct(ui32 &data_left, infile_base *file)
mem_elastic_allocator * elastic
void write_precincts(outfile_base *file)
void finalize_alloc(codestream *codestream, const rect &res_rect, const rect &recon_res_rect, ui32 comp_num, ui32 res_num, point comp_downsamp, tile_comp *parent_tile_comp, resolution *parent_res)
void parse_all_precincts(ui32 &data_left, infile_base *file)
static void pre_alloc(codestream *codestream, const rect &res_rect, const rect &recon_res_rect, ui32 res_num)
void write_one_precinct(outfile_base *file)
void exchange_buf(line_buf *l)
coded_cb_header * coded_cbs
void get_cb_indices(const size &num_precincts, precinct *precincts)
mem_elastic_allocator * elastic
static void pre_alloc(codestream *codestream, const rect &band_rect, ui32 res_num)
void finalize_alloc(codestream *codestream, const rect &band_rect, resolution *res, ui32 res_num, ui32 subband_num)
static void pre_alloc(codestream *codestream, const rect &comp_rect, const rect &recon_comp_rect)
bool get_top_left_precinct(ui32 res_num, point &top_left)
void write_one_precinct(ui32 res_num, outfile_base *file)
void finalize_alloc(codestream *codestream, tile *parent, ui32 comp_num, const rect &comp_rect, const rect &recon_comp_rect)
void parse_one_precinct(ui32 res_num, ui32 &data_left, infile_base *file)
void write_precincts(ui32 res_num, outfile_base *file)
void parse_precincts(ui32 res_num, ui32 &data_left, infile_base *file)
bool pull(line_buf *, ui32 comp_num)
void finalize_alloc(codestream *codestream, const rect &tile_rect, const rect &recon_tile_rect, ui32 tile_idx, ui32 offset)
void fill_tlm(param_tlm *tlm)
static void pre_alloc(codestream *codestream, const rect &tile_rect, const rect &recon_tile_rect)
void flush(outfile_base *file)
bool push(line_buf *line, ui32 comp_num)
void parse_tile_header(const param_sot &sot, infile_base *file, const ui64 &tile_start_location)
void get_buffer(ui32 needed_bytes, coded_lists *&p)
Definition: ojph_mem.cpp:95
void pre_alloc_data(size_t num_ele, ui32 pre_size)
Definition: ojph_mem.h:66
void pre_alloc_obj(size_t num_ele)
Definition: ojph_mem.h:72
T * post_alloc_obj(size_t num_ele)
Definition: ojph_mem.h:96
T * post_alloc_data(size_t num_ele, ui32 pre_size)
Definition: ojph_mem.h:89
virtual void close()
Definition: ojph_file.h:83
virtual size_t write(const void *ptr, size_t size)=0
OJPH_EXPORT int get_progression_order() const
OJPH_EXPORT ui32 get_num_decompositions() const
OJPH_EXPORT size get_log_block_dims() const
OJPH_EXPORT bool is_reversible() const
OJPH_EXPORT bool get_block_vertical_causality() const
OJPH_EXPORT size get_log_precinct_size(ui32 level_num) const
OJPH_EXPORT point get_image_extent() const
OJPH_EXPORT ui32 get_bit_depth(ui32 comp_num) const
OJPH_EXPORT point get_image_offset() const
OJPH_EXPORT size get_tile_size() const
OJPH_EXPORT point get_downsampling(ui32 comp_num) const
OJPH_EXPORT point get_tile_offset() const
OJPH_EXPORT bool is_signed(ui32 comp_num) const
OJPH_EXPORT ui32 get_num_components() const
static bool bb_read_chunk(bit_read_buf *bbp, ui32 num_bytes, coded_lists *&cur_coded_list, mem_elastic_allocator *elastic)
void(* cnvrt_float_to_si32)(const float *sp, si32 *dp, float mul, ui32 width)
Definition: ojph_colour.cpp:70
static int find_marker(infile_base *f, const ui16 *char_list, int list_len)
static bool bb_read_bit(bit_read_buf *bbp, ui32 &bit)
static int skip_marker(infile_base *file, const char *marker, const char *msg, int msg_level, bool resilient)
static void bb_terminate(bit_write_buf *bbp)
void(* irrev_horz_wvlt_fwd_tx)(line_buf *src, line_buf *ldst, line_buf *hdst, ui32 width, bool even)
static void bb_init(bit_write_buf *bbp, mem_elastic_allocator *elastic, coded_lists *&cur_coded_list)
void(* cnvrt_si32_to_float_shftd)(const si32 *sp, float *dp, float mul, ui32 width)
Definition: ojph_colour.cpp:55
void(* ict_forward)(const float *r, const float *g, const float *b, float *y, float *cb, float *cr, ui32 repeat)
Definition: ojph_colour.cpp:87
void(* rev_horz_wvlt_bwd_tx)(line_buf *dst, line_buf *lsrc, line_buf *hsrc, ui32 width, bool even)
void(* cnvrt_si32_to_si32_shftd)(const si32 *sp, si32 *dp, int shift, ui32 width)
Definition: ojph_colour.cpp:50
static bool bb_read_bits(bit_read_buf *bbp, int num_bits, ui32 &bits)
static bool bb_skip_sop(bit_read_buf *bbp)
void(* ict_backward)(const float *y, const float *cb, const float *cr, float *r, float *g, float *b, ui32 repeat)
Definition: ojph_colour.cpp:93
static void rotate_buffers(line_buf *line1, line_buf *line2, line_buf *line3, line_buf *line4)
void(* rct_backward)(const si32 *y, const si32 *cb, const si32 *cr, si32 *r, si32 *g, si32 *b, ui32 repeat)
Definition: ojph_colour.cpp:81
void init_wavelet_transform_functions()
void init_colour_transform_functions()
void(* rev_vert_wvlt_fwd_update)(const line_buf *src1, const line_buf *src2, line_buf *dst, ui32 repeat)
static bool bb_read(bit_read_buf *bbp)
void(* cnvrt_float_to_si32_shftd)(const float *sp, si32 *dp, float mul, ui32 width)
Definition: ojph_colour.cpp:65
static ui32 log2ceil(ui32 x)
static void bb_put_bits(bit_write_buf *bbp, ui32 data, int num_bits, mem_elastic_allocator *elastic, coded_lists *&cur_coded_list, ui32 &ph_bytes)
void(* cnvrt_si32_to_float)(const si32 *sp, float *dp, float mul, ui32 width)
Definition: ojph_colour.cpp:60
void(* rev_horz_wvlt_fwd_tx)(line_buf *src, line_buf *ldst, line_buf *hdst, ui32 width, bool even)
void(* irrev_vert_wvlt_step)(const line_buf *src1, const line_buf *src2, line_buf *dst, int step_num, ui32 repeat)
void(* rct_forward)(const si32 *r, const si32 *g, const si32 *b, si32 *y, si32 *cb, si32 *cr, ui32 repeat)
Definition: ojph_colour.cpp:75
static ui16 swap_byte(ui16 t)
void(* rev_vert_wvlt_bwd_update)(const line_buf *src1, const line_buf *src2, line_buf *dst, ui32 repeat)
void(* rev_vert_wvlt_bwd_predict)(const line_buf *src1, const line_buf *src2, line_buf *dst, ui32 repeat)
bool ojph_decode_codeblock(ui8 *coded_data, ui32 *decoded_data, ui32 missing_msbs, ui32 num_passes, ui32 lengths1, ui32 lengths2, ui32 width, ui32 height, ui32 stride, bool stripe_causal)
Decodes one codeblock, processing the cleanup, siginificance propagation, and magnitude refinement pa...
void(* rev_vert_wvlt_fwd_predict)(const line_buf *src1, const line_buf *src2, line_buf *dst, ui32 repeat)
void(* irrev_horz_wvlt_bwd_tx)(line_buf *src, line_buf *ldst, line_buf *hdst, ui32 width, bool even)
void(* irrev_vert_wvlt_K)(const line_buf *src, line_buf *dst, bool L_analysis_or_H_synthesis, ui32 repeat)
static void bb_put_bit(bit_write_buf *bbp, ui32 bit, mem_elastic_allocator *elastic, coded_lists *&cur_coded_list, ui32 &ph_bytes)
static void bb_skip_eph(bit_read_buf *bbp)
void ojph_encode_codeblock(ui32 *buf, ui32 missing_msbs, ui32 num_passes, ui32 width, ui32 height, ui32 stride, ui32 *lengths, ojph::mem_elastic_allocator *elastic, ojph::coded_lists *&coded)
static void bb_expand_buf(bit_write_buf *bbp, mem_elastic_allocator *elastic, coded_lists *&cur_coded_list)
const char OJPH_PN_STRING_BROADCAST[]
int64_t si64
Definition: ojph_defs.h:57
const char OJPH_PN_STRING_IMF[]
uint64_t ui64
Definition: ojph_defs.h:56
@ ERROR
Definition: ojph_message.h:52
@ WARN
Definition: ojph_message.h:51
@ INFO
Definition: ojph_message.h:50
@ NO_MSG
Definition: ojph_message.h:49
uint16_t ui16
Definition: ojph_defs.h:52
static si32 ojph_trunc(float val)
Definition: ojph_arch.h:143
@ OJPH_PN_BROADCAST
@ OJPH_PN_UNDEFINED
static ui32 count_leading_zeros(ui32 val)
Definition: ojph_arch.h:90
int32_t si32
Definition: ojph_defs.h:55
message_error error
uint32_t ui32
Definition: ojph_defs.h:54
uint8_t ui8
Definition: ojph_defs.h:50
#define ojph_max(a, b)
Definition: ojph_defs.h:73
#define OJPH_INT_TO_STRING(I)
Definition: ojph_defs.h:61
#define ojph_div_ceil(a, b)
Definition: ojph_defs.h:70
#define ojph_min(a, b)
Definition: ojph_defs.h:76
#define ojph_unused(x)
Definition: ojph_defs.h:78
#define OJPH_INFO(t,...)
Definition: ojph_message.h:125
#define OJPH_ERROR(t,...)
Definition: ojph_message.h:131
#define OJPH_WARN(t,...)
Definition: ojph_message.h:128
#define OPENJPH_VERSION_PATCH
Definition: ojph_version.h:38
#define OPENJPH_VERSION_MAJOR
Definition: ojph_version.h:36
#define OPENJPH_VERSION_MINOR
Definition: ojph_version.h:37
coded_lists * next_list
Definition: ojph_mem.h:170
size_t size
Definition: ojph_mem.h:152
float * f32
Definition: ojph_mem.h:156
void wrap(T *buffer, size_t num_ele, ui32 pre_size)
si32 * i32
Definition: ojph_mem.h:155
void check_validity(const param_cod &cod, const param_qcd &qcd)
void read(infile_base *file)
bool write(outfile_base *file)
void check_validity(const param_siz &siz)
bool write(outfile_base *file)
bool is_employing_color_transform() const
void read(infile_base *file)
size get_log_precinct_size(ui32 res_num) const
ui8 get_num_decompositions() const
bool packets_may_use_sop() const
void read(infile_base *file, ui32 num_comps)
ui32 get_Kmax(ui32 resolution, ui32 subband) const
void check_validity(const param_siz &siz, const param_cod &cod)
bool write(outfile_base *file)
void read(infile_base *file)
float irrev_get_delta(ui32 resolution, ui32 subband) const
void set_skipped_resolutions(ui32 skipped_resolutions)
ui32 get_bit_depth(ui32 comp_num) const
ui32 get_recon_height(ui32 comp_num) const
bool is_signed(ui32 comp_num) const
bool write(outfile_base *file)
ui32 get_height(ui32 comp_num) const
point get_downsampling(ui32 comp_num) const
void read(infile_base *file)
ui32 get_width(ui32 comp_num) const
ui32 get_recon_width(ui32 comp_num) const
void init(ui32 payload_length=0, ui16 tile_idx=0, ui8 tile_part_index=0, ui8 num_tile_parts=0)
bool read(infile_base *file, bool resilient)
bool write(outfile_base *file, ui32 payload_len)
void set_next_pair(ui16 Ttlm, ui32 Ptlm)
bool write(outfile_base *file)
void init(ui32 num_pairs, Ttlm_Ptlm_pair *store)
void write(outfile_base *file)
ui32 prepare_precinct(int tag_tree_size, ui32 *lev_idx, mem_elastic_allocator *elastic)
void parse(int tag_tree_size, ui32 *lev_idx, mem_elastic_allocator *elastic, ui32 &data_left, infile_base *file, bool skipped)
ui8 * get(ui32 x, ui32 y, ui32 lev)
void init(ui8 *buf, ui32 *lev_idx, ui32 num_levels, size s, int init_val)
size siz
Definition: ojph_base.h:67
point org
Definition: ojph_base.h:66
ui64 area() const
Definition: ojph_base.h:53
ui32 w
Definition: ojph_base.h:50
ui32 h
Definition: ojph_base.h:51