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  lines = 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  for (ui32 i = 0; i < num_comps; ++i)
304 
305  //allocate tlm
306  if (outfile != NULL)
307  {
309  {
310  ui32 num_pairs = (ui32)num_tiles.area() * num_comps;
312  }
313  else
314  {
315  ui32 num_pairs = (ui32)num_tiles.area();
317  }
318  }
319 
320  //precinct scratch buffer
321  ui32 num_decomps = cod.get_num_decompositions();
322  size log_cb = cod.get_log_block_dims();
323 
324  size ratio;
325  for (ui32 r = 0; r <= num_decomps; ++r)
326  {
327  size log_PP = cod.get_log_precinct_size(r);
328  log_PP.w -= (r ? 1 : 0);
329  log_PP.h -= (r ? 1 : 0);
330  ratio.w = ojph_max(ratio.w, log_PP.w - ojph_min(log_cb.w, log_PP.w));
331  ratio.h = ojph_max(ratio.h, log_PP.h - ojph_min(log_cb.h, log_PP.h));
332  }
333  ui32 max_ratio = ojph_max(ratio.w, ratio.h);
334  max_ratio = 1 << max_ratio;
335  // assuming that we have a hierarchy of n levels.
336  // This needs 4/3 times the area, rounded up
337  // (rounding up leaves one extra entry).
338  // This exta entry is necessary
339  // We need 4 such tables. These tables store
340  // 1. missing msbs and 2. their flags,
341  // 3. number of layers and 4. their flags
343  4 * ((max_ratio * max_ratio * 4 + 2) / 3);
344 
346  }
347 
350  {
351  allocator->alloc();
352 
353  //precinct scratch buffer
356 
357  //get tiles
359 
360  point index;
361  rect tile_rect, recon_tile_rect;
363  ui32 ds = 1 << skipped_res_for_recon;
364  for (index.y = 0; index.y < num_tiles.h; ++index.y)
365  {
366  ui32 y0 = sz.get_tile_offset().y
367  + index.y * sz.get_tile_size().h;
368  ui32 y1 = y0 + sz.get_tile_size().h; //end of tile
369 
370  tile_rect.org.y = ojph_max(y0, sz.get_image_offset().y);
371  tile_rect.siz.h =
372  ojph_min(y1, sz.get_image_extent().y) - tile_rect.org.y;
373 
374  recon_tile_rect.org.y = ojph_max(ojph_div_ceil(y0, ds),
375  ojph_div_ceil(sz.get_image_offset().y, ds));
376  recon_tile_rect.siz.h = ojph_min(ojph_div_ceil(y1, ds),
377  ojph_div_ceil(sz.get_image_extent().y, ds))
378  - recon_tile_rect.org.y;
379 
380  ui32 offset = 0;
381  for (index.x = 0; index.x < num_tiles.w; ++index.x)
382  {
383  ui32 x0 = sz.get_tile_offset().x
384  + index.x * sz.get_tile_size().w;
385  ui32 x1 = x0 + sz.get_tile_size().w;
386 
387  tile_rect.org.x = ojph_max(x0, sz.get_image_offset().x);
388  tile_rect.siz.w =
389  ojph_min(x1, sz.get_image_extent().x) - tile_rect.org.x;
390 
391  recon_tile_rect.org.x = ojph_max(ojph_div_ceil(x0, ds),
392  ojph_div_ceil(sz.get_image_offset().x, ds));
393  recon_tile_rect.siz.w = ojph_min(ojph_div_ceil(x1, ds),
394  ojph_div_ceil(sz.get_image_extent().x, ds))
395  - recon_tile_rect.org.x;
396 
397  ui32 idx = index.y * num_tiles.w + index.x;
398  tiles[idx].finalize_alloc(this, tile_rect, recon_tile_rect,
399  idx, offset);
400  offset += recon_tile_rect.siz.w;
401  }
402  }
403 
404  //allocate lines
405  //These lines are used by codestream to exchange data with external
406  // world
407  this->num_comps = sz.get_num_components();
412  for (ui32 i = 0; i < this->num_comps; ++i)
413  {
414  comp_size[i].w = siz.get_width(i);
415  comp_size[i].h = siz.get_height(i);
416  ui32 cw = siz.get_recon_width(i);
417  recon_comp_size[i].w = cw;
419  lines[i].wrap(allocator->post_alloc_data<si32>(cw, 0), cw, 0);
420  }
421 
422  cur_comp = 0;
423  cur_line = 0;
424 
425  //allocate tlm
426  if (outfile != NULL)
427  {
429  {
430  ui32 num_pairs = (ui32)num_tiles.area() * this->num_comps;
431  tlm.init(num_pairs,
433  }
434  else
435  {
436  ui32 num_pairs = (ui32)num_tiles.area();
437  tlm.init(num_pairs,
439  }
440  }
441  }
442 
443 
446  {
447  //two possibilities lossy single tile or lossless
448  //For the following code, we use the least strict profile
449  ojph::param_siz sz(&siz);
450  ojph::param_cod cd(&cod);
451  bool reversible = cd.is_reversible();
452  bool imf2k = !reversible, imf4k = !reversible, imf8k = !reversible;
453  bool imf2kls = reversible, imf4kls = reversible, imf8kls = reversible;
454 
455  if (reversible)
456  {
457  point ext = sz.get_image_extent();
458  if (ext.x <= 2048 && ext.y <= 1556)
459  imf2kls &= true;
460  if (ext.x <= 4096 && ext.y <= 3112)
461  imf4kls &= true;
462  if (ext.x <= 8192 && ext.y <= 6224)
463  imf8kls &= true;
464 
465  if (!imf2kls && !imf4kls && !imf8kls)
466  OJPH_ERROR(0x000300C1,
467  "Image dimensions do not meet any of the lossless IMF profiles");
468  }
469  else
470  {
471  point ext = sz.get_image_extent();
472  if (ext.x <= 2048 && ext.y <= 1556)
473  imf2k &= true;
474  if (ext.x <= 4096 && ext.y <= 3112)
475  imf4k &= true;
476  if (ext.x <= 8192 && ext.y <= 6224)
477  imf8k &= true;
478 
479  if (!imf2k && !imf4k && !imf8k)
480  OJPH_ERROR(0x000300C2,
481  "Image dimensions do not meet any of the lossy IMF profiles");
482  }
483 
484 
485  if (sz.get_image_offset().x != 0 || sz.get_image_offset().y != 0)
486  OJPH_ERROR(0x000300C3,
487  "For IMF profile, image offset (XOsiz, YOsiz) has to be 0.");
488  if (sz.get_tile_offset().x != 0 || sz.get_tile_offset().y != 0)
489  OJPH_ERROR(0x000300C4,
490  "For IMF profile, tile offset (XTOsiz, YTOsiz) has to be 0.");
491  if (sz.get_num_components() > 3)
492  OJPH_ERROR(0x000300C5,
493  "For IMF profile, the number of components has to be less "
494  " or equal to 3");
495  bool test_ds1 = true, test_ds2 = true;
496  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
497  {
498  point downsamping = sz.get_downsampling(i);
499  test_ds1 &= downsamping.y == 1;
500  test_ds2 &= downsamping.y == 1;
501 
502  test_ds1 &= downsamping.x == 1;
503  if (i == 1 || i == 2)
504  test_ds2 &= downsamping.x == 2;
505  else
506  test_ds2 &= downsamping.x == 1;
507  }
508  if (!test_ds1 && !test_ds2)
509  OJPH_ERROR(0x000300C6,
510  "For IMF profile, either no component downsampling is used,"
511  " or the x-dimension of the 2nd and 3rd components is downsampled"
512  " by 2.");
513 
514  bool test_bd = true;
515  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
516  {
517  ui32 bit_depth = sz.get_bit_depth(i);
518  bool is_signed = sz.is_signed(i);
519  test_bd &= bit_depth >= 8 && bit_depth <= 16 && is_signed == false;
520  }
521  if (!test_bd)
522  OJPH_ERROR(0x000300C7,
523  "For IMF profile, compnent bit_depth has to be between"
524  " 8 and 16 bits inclusively, and the samples must be unsigned");
525 
526  if (cd.get_log_block_dims().w != 5 || cd.get_log_block_dims().h != 5)
527  OJPH_ERROR(0x000300C8,
528  "For IMF profile, codeblock dimensions are restricted."
529  " Use \"-block_size {32,32}\" at the commandline");
530 
531  ui32 num_decomps = cd.get_num_decompositions();
532  bool test_pz = cd.get_log_precinct_size(0).w == 7
533  && cd.get_log_precinct_size(0).h == 7;
534  for (ui32 i = 1; i <= num_decomps; ++i)
535  test_pz = cd.get_log_precinct_size(i).w == 8
536  && cd.get_log_precinct_size(i).h == 8;
537  if (!test_pz)
538  OJPH_ERROR(0x000300C9,
539  "For IMF profile, precinct sizes are restricted."
540  " Use \"-precincts {128,128},{256,256}\" at the commandline");
541 
543  OJPH_ERROR(0x000300CA,
544  "For IMF profile, the CPRL progression order must be used."
545  " Use \"-prog_order CPRL\".");
546 
547  imf2k &= num_decomps <= 5;
548  imf2kls &= num_decomps <= 5;
549  imf4k &= num_decomps <= 6;
550  imf4kls &= num_decomps <= 6;
551  imf8k &= num_decomps <= 7;
552  imf8kls &= num_decomps <= 7;
553 
554  if (num_decomps == 0 ||
555  (!imf2k && !imf4k && !imf8k && !imf2kls && !imf4kls && !imf8kls))
556  OJPH_ERROR(0x000300CB,
557  "Number of decompositions does not match the IMF profile"
558  " dictated by wavelet reversibility and image dimensions.");
559 
560  ui32 tiles_w = sz.get_image_extent().x;
561  tiles_w = ojph_div_ceil(tiles_w, sz.get_tile_size().w);
562  ui32 tiles_h = sz.get_image_extent().y;
563  tiles_h = ojph_div_ceil(tiles_h, sz.get_tile_size().h);
564  ui32 total_tiles = tiles_w * tiles_h;
565 
566  if (total_tiles > 1)
567  {
568  if (!reversible)
569  OJPH_ERROR(0x000300CC,
570  "Lossy IMF profile must have one tile.");
571 
572  size tt = sz.get_tile_size();
573  imf2kls &= (tt.w == 1024 && tt.h == 1024);
574  imf2kls &= (tt.w >= 1024 && num_decomps <= 4)
575  || (tt.w >= 2048 && num_decomps <= 5);
576  imf4kls &= (tt.w == 1024 && tt.h == 1024)
577  || (tt.w == 2048 && tt.h == 2048);
578  imf4kls &= (tt.w >= 1024 && num_decomps <= 4)
579  || (tt.w >= 2048 && num_decomps <= 5)
580  || (tt.w >= 4096 && num_decomps <= 6);
581  imf8kls &= (tt.w == 1024 && tt.h == 1024)
582  || (tt.w == 2048 && tt.h == 2048)
583  || (tt.w == 4096 && tt.h == 4096);
584  imf8kls &= (tt.w >= 1024 && num_decomps <= 4)
585  || (tt.w >= 2048 && num_decomps <= 5)
586  || (tt.w >= 4096 && num_decomps <= 6)
587  || (tt.w >= 8192 && num_decomps <= 7);
588  if (!imf2kls && !imf4kls && !imf8kls)
589  OJPH_ERROR(0x000300CD,
590  "Number of decompositions does not match the IMF profile"
591  " dictated by wavelet reversibility and image dimensions and"
592  " tiles.");
593  }
594 
595  }
596 
599  {
600  ojph::param_siz sz(&siz);
601  ojph::param_cod cd(&cod);
602 
603  if (sz.get_image_offset().x != 0 || sz.get_image_offset().y != 0)
604  OJPH_ERROR(0x000300B1,
605  "For broadcast profile, image offset (XOsiz, YOsiz) has to be 0.");
606  if (sz.get_tile_offset().x != 0 || sz.get_tile_offset().y != 0)
607  OJPH_ERROR(0x000300B2,
608  "For broadcast profile, tile offset (XTOsiz, YTOsiz) has to be 0.");
609  if (sz.get_num_components() > 4)
610  OJPH_ERROR(0x000300B3,
611  "For broadcast profile, the number of components has to be less "
612  " or equal to 4");
613  bool test_ds1 = true, test_ds2 = true;
614  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
615  {
616  point downsamping = sz.get_downsampling(i);
617  test_ds1 &= downsamping.y == 1;
618  test_ds2 &= downsamping.y == 1;
619 
620  test_ds1 &= downsamping.x == 1;
621  if (i == 1 || i == 2)
622  test_ds2 &= downsamping.x == 2;
623  else
624  test_ds2 &= downsamping.x == 1;
625  }
626  if (!test_ds1 && !test_ds2)
627  OJPH_ERROR(0x000300B4,
628  "For broadcast profile, either no component downsampling is used,"
629  " or the x-dimension of the 2nd and 3rd components is downsampled"
630  " by 2.");
631 
632  bool test_bd = true;
633  for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
634  {
635  ui32 bit_depth = sz.get_bit_depth(i);
636  bool is_signed = sz.is_signed(i);
637  test_bd &= bit_depth >= 8 && bit_depth <= 12 && is_signed == false;
638  }
639  if (!test_bd)
640  OJPH_ERROR(0x000300B5,
641  "For broadcast profile, compnent bit_depth has to be between"
642  " 8 and 12 bits inclusively, and the samples must be unsigned");
643 
644  ui32 num_decomps = cd.get_num_decompositions();
645  if (num_decomps == 0 || num_decomps > 5)
646  OJPH_ERROR(0x000300B6,
647  "For broadcast profile, number of decompositions has to be between"
648  "1 and 5 inclusively.");
649 
650  if (cd.get_log_block_dims().w < 5 || cd.get_log_block_dims().w > 7)
651  OJPH_ERROR(0x000300B7,
652  "For broadcast profile, codeblock dimensions are restricted such"
653  " that codeblock width has to be either 32, 64, or 128.");
654 
655  if (cd.get_log_block_dims().h < 5 || cd.get_log_block_dims().h > 7)
656  OJPH_ERROR(0x000300B8,
657  "For broadcast profile, codeblock dimensions are restricted such"
658  " that codeblock height has to be either 32, 64, or 128.");
659 
660  bool test_pz = cd.get_log_precinct_size(0).w == 7
661  && cd.get_log_precinct_size(0).h == 7;
662  for (ui32 i = 1; i <= num_decomps; ++i)
663  test_pz = cd.get_log_precinct_size(i).w == 8
664  && cd.get_log_precinct_size(i).h == 8;
665  if (!test_pz)
666  OJPH_ERROR(0x000300B9,
667  "For broadcast profile, precinct sizes are restricted."
668  " Use \"-precincts {128,128},{256,256}\" at the commandline");
669 
671  OJPH_ERROR(0x000300BA,
672  "For broadcast profile, the CPRL progression order must be used."
673  " Use \"-prog_order CPRL\".");
674 
675  ui32 tiles_w = sz.get_image_extent().x;
676  tiles_w = ojph_div_ceil(tiles_w, sz.get_tile_size().w);
677  ui32 tiles_h = sz.get_image_extent().y;
678  tiles_h = ojph_div_ceil(tiles_h, sz.get_tile_size().h);
679  ui32 total_tiles = tiles_w * tiles_h;
680 
681  if (total_tiles != 1 && total_tiles != 4)
682  OJPH_ERROR(0x000300BB,
683  "The broadcast profile can only have 1 or 4 tiles");
684  }
685 
688  {
689  //finalize
694  if (profile == OJPH_PN_IMF)
696  else if (profile == OJPH_PN_BROADCAST)
698 
699  if (planar == -1) //not initialized
701  else if (planar == 0) //interleaved is chosen
702  {
703  }
704  else if (planar == 1) //plannar is chosen
705  {
706  if (cod.is_employing_color_transform() == true)
707  OJPH_ERROR(0x00030021,
708  "the planar interface option cannot be used when colour "
709  "transform is employed");
710  }
711  else
712  assert(0);
713 
714  assert(this->outfile == NULL);
715  this->outfile = file;
716  this->pre_alloc();
717  this->finalize_alloc();
718 
720  if (file->write(&t, 2) != 2)
721  OJPH_ERROR(0x00030022, "Error writing to file");
722 
723  if (!siz.write(file))
724  OJPH_ERROR(0x00030023, "Error writing to file");
725 
726  if (!cap.write(file))
727  OJPH_ERROR(0x00030024, "Error writing to file");
728 
729  if (!cod.write(file))
730  OJPH_ERROR(0x00030025, "Error writing to file");
731 
732  if (!qcd.write(file))
733  OJPH_ERROR(0x00030026, "Error writing to file");
734 
735  char buf[] = " OpenJPH Ver "
739  size_t len = strlen(buf);
740  *(ui16*)buf = swap_byte(JP2K_MARKER::COM);
741  *(ui16*)(buf + 2) = swap_byte((ui16)(len - 2));
742  //1 for General use (IS 8859-15:1999 (Latin) values)
743  *(ui16*)(buf + 4) = swap_byte((ui16)(1));
744  if (file->write(buf, len) != len)
745  OJPH_ERROR(0x00030027, "Error writing to file");
746  }
747 
749  static
750  int find_marker(infile_base *f, const ui16* char_list, int list_len)
751  {
752  //returns the marker index in char_list, or -1
753  while (!f->eof())
754  {
755  ui8 new_char;
756  size_t num_bytes = f->read(&new_char, 1);
757  if (num_bytes != 1)
758  return -1;
759  if (new_char == 0xFF)
760  {
761  size_t num_bytes = f->read(&new_char, 1);
762 
763  if (num_bytes != 1)
764  return -1;
765 
766  for (int i = 0; i < list_len; ++i)
767  if (new_char == (char_list[i] & 0xFF))
768  return i;
769  }
770  }
771  return -1;
772  }
773 
775  static
776  int skip_marker(infile_base *file, const char *marker,
777  const char *msg, int msg_level, bool resilient)
778  {
779  ojph_unused(marker);
780  ui16 com_len;
781  if (file->read(&com_len, 2) != 2)
782  {
783  if (resilient)
784  return -1;
785  else
786  OJPH_ERROR(0x00030041, "error reading marker");
787  }
788  com_len = swap_byte(com_len);
789  file->seek(com_len - 2, infile_base::OJPH_SEEK_CUR);
790  if (msg != NULL && msg_level != OJPH_MSG_LEVEL::NO_MSG)
791  {
792  if (msg_level == OJPH_MSG_LEVEL::INFO)
793  {
794  OJPH_INFO(0x00030001, "%s\n", msg);
795  }
796  else if (msg_level == OJPH_MSG_LEVEL::WARN)
797  {
798  OJPH_WARN(0x00030001, "%s\n", msg);
799  }
800  else if (msg_level == OJPH_MSG_LEVEL::ERROR)
801  {
802  OJPH_ERROR(0x00030001, "%s\n", msg);
803  }
804  else
805  assert(0);
806  }
807  return 0;
808  }
809 
812  {
813  ui16 marker_list[17] = { SOC, SIZ, CAP, PRF, CPF, COD, COC, QCD, QCC,
814  RGN, POC, PPM, TLM, PLM, CRG, COM, SOT };
815  find_marker(file, marker_list, 1); //find SOC
816  find_marker(file, marker_list + 1, 1); //find SIZ
817  siz.read(file);
818  int marker_idx = 0;
819  int received_markers = 0; //check that COD, & QCD received
820  while (true)
821  {
822  marker_idx = find_marker(file, marker_list + 2, 15);
823  if (marker_idx == 0)
824  cap.read(file);
825  else if (marker_idx == 1)
826  //Skipping PRF marker segment; this should not cause any issues
827  skip_marker(file, "PRF", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
828  else if (marker_idx == 2)
829  //Skipping CPF marker segment; this should not cause any issues
830  skip_marker(file, "CPF", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
831  else if (marker_idx == 3)
832  { cod.read(file); received_markers |= 1; }
833  else if (marker_idx == 4)
834  skip_marker(file, "COC", "COC is not supported yet",
835  OJPH_MSG_LEVEL::WARN, false);
836  else if (marker_idx == 5)
837  { qcd.read(file); received_markers |= 2; }
838  else if (marker_idx == 6)
839  {
841  if (qcc == qcc_store &&
842  num_comps * sizeof(param_qcc) > sizeof(qcc_store))
843  {
844  qcc = new param_qcc[num_comps];
845  }
846  qcc[used_qcc_fields++].read(file, num_comps);
847  }
848  else if (marker_idx == 7)
849  skip_marker(file, "RGN", "RGN is not supported yet",
850  OJPH_MSG_LEVEL::WARN, false);
851  else if (marker_idx == 8)
852  skip_marker(file, "POC", "POC is not supported yet",
853  OJPH_MSG_LEVEL::WARN, false);
854  else if (marker_idx == 9)
855  skip_marker(file, "PPM", "PPM is not supported yet",
856  OJPH_MSG_LEVEL::WARN, false);
857  else if (marker_idx == 10)
858  //Skipping TLM marker segment; this should not cause any issues
859  skip_marker(file, "TLM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
860  else if (marker_idx == 11)
861  //Skipping PLM marker segment; this should not cause any issues
862  skip_marker(file, "PLM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
863  else if (marker_idx == 12)
864  //Skipping CRG marker segment;
865  skip_marker(file, "CRG", "CRG has been ignored; CRG is related to"
866  " where the Cb and Cr colour components are co-sited or located"
867  " with respect to the Y' luma component. Perhaps, it is better"
868  " to get the indivdual components and assemble the samples"
869  " according to your needs",
870  OJPH_MSG_LEVEL::INFO, false);
871  else if (marker_idx == 13)
872  skip_marker(file, "COM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
873  else if (marker_idx == 14)
874  break;
875  else
876  OJPH_ERROR(0x00030051, "File ended before finding a tile segment");
877  }
878 
879  if (received_markers != 3)
880  OJPH_ERROR(0x00030052, "markers error, COD and QCD are required");
881 
882  this->infile = file;
884  }
885 
887  void codestream::restrict_input_resolution(ui32 skipped_res_for_read,
888  ui32 skipped_res_for_recon)
889  {
891  OJPH_ERROR(0x000300A1,
892  "skipped_resolution for data %d must be equal or smaller than "
893  " skipped_resolution for reconstruction %d\n",
896  OJPH_ERROR(0x000300A2,
897  "skipped_resolution for data %d must be smaller than "
898  " the number of decomposition levels %d\n",
900 
901  this->skipped_res_for_read = skipped_res_for_read;
902  this->skipped_res_for_recon = skipped_res_for_recon;
904  }
905 
908  {
909  if (infile != NULL)
910  OJPH_ERROR(0x000300A3, "Codestream resilience must be enabled before"
911  " reading file headers.\n");
912  this->resilient = true;
913  }
914 
917  {
918  this->pre_alloc();
919  this->finalize_alloc();
920 
921  while (true)
922  {
923  param_sot sot;
924  if (sot.read(infile, resilient))
925  {
926  ui64 tile_start_location = (ui64)infile->tell();
927 
928  if (sot.get_tile_index() > (int)num_tiles.area())
929  {
930  if (resilient)
931  OJPH_INFO(0x00030061, "wrong tile index")
932  else
933  OJPH_ERROR(0x00030061, "wrong tile index")
934  }
935 
936  if (sot.get_tile_part_index())
937  { //tile part
938  if (sot.get_num_tile_parts() &&
940  {
941  if (resilient)
942  OJPH_INFO(0x00030062,
943  "error in tile part number, should be smaller than total"
944  " number of tile parts")
945  else
946  OJPH_ERROR(0x00030062,
947  "error in tile part number, should be smaller than total"
948  " number of tile parts")
949  }
950 
951  bool sod_found = false;
952  ui16 other_tile_part_markers[6] = { SOT, POC, PPT, PLT, COM, SOD };
953  while (true)
954  {
955  int marker_idx = 0;
956  int result = 0;
957  marker_idx = find_marker(infile, other_tile_part_markers + 1, 5);
958  if (marker_idx == 0)
959  result = skip_marker(infile, "POC",
960  "POC in a tile is not supported yet",
962  else if (marker_idx == 1)
963  result = skip_marker(infile, "PPT",
964  "PPT in a tile is not supported yet",
966  else if (marker_idx == 2)
967  //Skipping PLT marker segment;this should not cause any issues
968  result = skip_marker(infile, "PLT", NULL,
970  else if (marker_idx == 3)
971  result = skip_marker(infile, "COM", NULL,
973  else if (marker_idx == 4)
974  {
975  sod_found = true;
976  break;
977  }
978 
979  if (marker_idx == -1) //marker not found
980  {
981  if (resilient)
982  OJPH_INFO(0x00030063,
983  "File terminated early before start of data is found"
984  " for tile indexed %d and tile part %d",
985  sot.get_tile_index(), sot.get_tile_part_index())
986  else
987  OJPH_ERROR(0x00030063,
988  "File terminated early before start of data is found"
989  " for tile indexed %d and tile part %d",
990  sot.get_tile_index(), sot.get_tile_part_index())
991  break;
992  }
993  if (result == -1) //file terminated during marker seg. skipping
994  {
995  if (resilient)
996  OJPH_INFO(0x00030064,
997  "File terminated during marker segment skipping")
998  else
999  OJPH_ERROR(0x00030064,
1000  "File terminated during marker segment skipping")
1001  break;
1002  }
1003  }
1004  if (sod_found)
1006  tile_start_location);
1007  }
1008  else
1009  { //first tile part
1010  bool sod_found = false;
1011  ui16 first_tile_part_markers[11] = { SOT, COD, COC, QCD, QCC, RGN,
1012  POC, PPT, PLT, COM, SOD };
1013  while (true)
1014  {
1015  int marker_idx = 0;
1016  int result = 0;
1017  marker_idx = find_marker(infile, first_tile_part_markers+1, 10);
1018  if (marker_idx == 0)
1019  result = skip_marker(infile, "COD",
1020  "COD in a tile is not supported yet",
1022  else if (marker_idx == 1)
1023  result = skip_marker(infile, "COC",
1024  "COC in a tile is not supported yet",
1026  else if (marker_idx == 2)
1027  result = skip_marker(infile, "QCD",
1028  "QCD in a tile is not supported yet",
1030  else if (marker_idx == 3)
1031  result = skip_marker(infile, "QCC",
1032  "QCC in a tile is not supported yet",
1034  else if (marker_idx == 4)
1035  result = skip_marker(infile, "RGN",
1036  "RGN in a tile is not supported yet",
1038  else if (marker_idx == 5)
1039  result = skip_marker(infile, "POC",
1040  "POC in a tile is not supported yet",
1042  else if (marker_idx == 6)
1043  result = skip_marker(infile, "PPT",
1044  "PPT in a tile is not supported yet",
1046  else if (marker_idx == 7)
1047  //Skipping PLT marker segment;this should not cause any issues
1048  result = skip_marker(infile, "PLT", NULL,
1050  else if (marker_idx == 8)
1051  result = skip_marker(infile, "COM", NULL,
1053  else if (marker_idx == 9)
1054  {
1055  sod_found = true;
1056  break;
1057  }
1058 
1059  if (marker_idx == -1) //marker not found
1060  {
1061  if (resilient)
1062  OJPH_INFO(0x00030065,
1063  "File terminated early before start of data is found"
1064  " for tile indexed %d and tile part %d",
1065  sot.get_tile_index(), sot.get_tile_part_index())
1066  else
1067  OJPH_ERROR(0x00030065,
1068  "File terminated early before start of data is found"
1069  " for tile indexed %d and tile part %d",
1070  sot.get_tile_index(), sot.get_tile_part_index())
1071  break;
1072  }
1073  if (result == -1) //file terminated during marker seg. skipping
1074  {
1075  if (resilient)
1076  OJPH_INFO(0x00030066,
1077  "File terminated during marker segment skipping")
1078  else
1079  OJPH_ERROR(0x00030066,
1080  "File terminated during marker segment skipping")
1081  break;
1082  }
1083  }
1084  if (sod_found)
1086  tile_start_location);
1087  }
1088  }
1089 
1090  // check the next marker; either SOT or EOC,
1091  // if something is broken, just an end of file
1092  ui16 next_markers[2] = { SOT, EOC };
1093  int marker_idx = find_marker(infile, next_markers, 2);
1094  if (marker_idx == -1)
1095  {
1096  OJPH_INFO(0x00030067, "File terminated early");
1097  break;
1098  }
1099  else if (marker_idx == 0)
1100  ;
1101  else if (marker_idx == 1)
1102  break;
1103  }
1104  }
1105 
1107  void codestream::set_planar(int planar)
1108  {
1109  this->planar = planar;
1110  }
1111 
1113  void codestream::set_profile(const char *s)
1114  {
1115  size_t len = strlen(s);
1116  if (len == 9 && strncmp(s, OJPH_PN_STRING_BROADCAST, 9) == 0)
1118  else if (len == 3 && strncmp(s, OJPH_PN_STRING_IMF, 3) == 0)
1119  profile = OJPH_PN_IMF;
1120  else
1121  OJPH_ERROR(0x000300A1, "unkownn or unsupported profile");
1122  }
1123 
1126  {
1127  si32 repeat = (si32)num_tiles.area();
1128  for (si32 i = 0; i < repeat; ++i)
1129  tiles[i].prepare_for_flush();
1131  { //write tlm
1132  for (si32 i = 0; i < repeat; ++i)
1133  tiles[i].fill_tlm(&tlm);
1134  tlm.write(outfile);
1135  }
1136  for (si32 i = 0; i < repeat; ++i)
1137  tiles[i].flush(outfile);
1139  if (!outfile->write(&t, 2))
1140  OJPH_ERROR(0x00030071, "Error writing to file");
1141  }
1142 
1145  {
1146  if (infile)
1147  infile->close();
1148  if (outfile)
1149  outfile->close();
1150  }
1151 
1153  line_buf* codestream::exchange(line_buf *line, ui32 &next_component)
1154  {
1155  if (line)
1156  {
1157  bool success = false;
1158  while (!success)
1159  {
1160  success = true;
1161  for (ui32 i = 0; i < num_tiles.w; ++i)
1162  {
1163  ui32 idx = i + cur_tile_row * num_tiles.w;
1164  if ((success &= tiles[idx].push(line, cur_comp)) == false)
1165  break;
1166  }
1167  cur_tile_row += success == false ? 1 : 0;
1168  if (cur_tile_row >= num_tiles.h)
1169  cur_tile_row = 0;
1170  }
1171 
1172  if (planar) //process one component at a time
1173  {
1174  if (++cur_line >= comp_size[cur_comp].h)
1175  {
1176  cur_line = 0;
1177  cur_tile_row = 0;
1178  if (++cur_comp >= num_comps)
1179  {
1180  next_component = 0;
1181  return NULL;
1182  }
1183  }
1184  }
1185  else //process all component for a line
1186  {
1187  if (++cur_comp >= num_comps)
1188  {
1189  cur_comp = 0;
1190  if (++cur_line >= comp_size[cur_comp].h)
1191  {
1192  next_component = 0;
1193  return NULL;
1194  }
1195  }
1196  }
1197  }
1198 
1199  next_component = cur_comp;
1200  return this->lines + cur_comp;
1201  }
1202 
1205  {
1206  bool success = false;
1207  while (!success)
1208  {
1209  success = true;
1210  for (ui32 i = 0; i < num_tiles.w; ++i)
1211  {
1212  ui32 idx = i + cur_tile_row * num_tiles.w;
1213  if ((success &= tiles[idx].pull(lines + cur_comp, cur_comp)) == false)
1214  break;
1215  }
1216  cur_tile_row += success == false ? 1 : 0;
1217  if (cur_tile_row >= num_tiles.h)
1218  cur_tile_row = 0;
1219  }
1220  comp_num = cur_comp;
1221 
1222  if (planar) //process one component at a time
1223  {
1224  if (++cur_line >= recon_comp_size[cur_comp].h)
1225  {
1226  cur_line = 0;
1227  cur_tile_row = 0;
1228  if (cur_comp++ >= num_comps)
1229  {
1230  comp_num = 0;
1231  return NULL;
1232  }
1233  }
1234  }
1235  else //process all component for a line
1236  {
1237  if (++cur_comp >= num_comps)
1238  {
1239  cur_comp = 0;
1240  if (cur_line++ >= recon_comp_size[cur_comp].h)
1241  {
1242  comp_num = 0;
1243  return NULL;
1244  }
1245  }
1246  }
1247 
1248  return lines + comp_num;
1249  }
1250 
1252  //
1253  //
1254  //
1255  //
1256  //
1258 
1260  void tile::pre_alloc(codestream *codestream, const rect& tile_rect,
1261  const rect& recon_tile_rect)
1262  {
1264 
1265  //allocate tiles_comp
1266  const param_siz *szp = codestream->get_siz();
1268  allocator->pre_alloc_obj<tile_comp>(num_comps);
1269  allocator->pre_alloc_obj<rect>(num_comps); //for comp_rects
1270  allocator->pre_alloc_obj<rect>(num_comps); //for recon_comp_rects
1271  allocator->pre_alloc_obj<ui32>(num_comps); //for line_offsets
1272  allocator->pre_alloc_obj<ui32>(num_comps); //for num_bits
1273  allocator->pre_alloc_obj<bool>(num_comps); //for is_signed
1274  allocator->pre_alloc_obj<ui32>(num_comps); //for cur_line
1275 
1276  int profile = codestream->get_profile();
1278  allocator->pre_alloc_obj<ui32>(num_comps); //for num_comp_bytes
1279  else
1280  allocator->pre_alloc_obj<ui32>(1);
1281 
1282  ui32 tx0 = tile_rect.org.x;
1283  ui32 ty0 = tile_rect.org.y;
1284  ui32 tx1 = tile_rect.org.x + tile_rect.siz.w;
1285  ui32 ty1 = tile_rect.org.y + tile_rect.siz.h;
1286  ui32 recon_tx0 = recon_tile_rect.org.x;
1287  ui32 recon_ty0 = recon_tile_rect.org.y;
1288  ui32 recon_tx1 = recon_tile_rect.org.x + recon_tile_rect.siz.w;
1289  ui32 recon_ty1 = recon_tile_rect.org.y + recon_tile_rect.siz.h;
1290 
1291  ui32 width = 0;
1292  for (ui32 i = 0; i < num_comps; ++i)
1293  {
1294  point downsamp = szp->get_downsampling(i);
1295 
1296  ui32 tcx0 = ojph_div_ceil(tx0, downsamp.x);
1297  ui32 tcy0 = ojph_div_ceil(ty0, downsamp.y);
1298  ui32 tcx1 = ojph_div_ceil(tx1, downsamp.x);
1299  ui32 tcy1 = ojph_div_ceil(ty1, downsamp.y);
1300  ui32 recon_tcx0 = ojph_div_ceil(recon_tx0, downsamp.x);
1301  ui32 recon_tcy0 = ojph_div_ceil(recon_ty0, downsamp.y);
1302  ui32 recon_tcx1 = ojph_div_ceil(recon_tx1, downsamp.x);
1303  ui32 recon_tcy1 = ojph_div_ceil(recon_ty1, downsamp.y);
1304 
1305  rect comp_rect;
1306  comp_rect.org.x = tcx0;
1307  comp_rect.org.y = tcy0;
1308  comp_rect.siz.w = tcx1 - tcx0;
1309  comp_rect.siz.h = tcy1 - tcy0;
1310 
1311  rect recon_comp_rect;
1312  recon_comp_rect.org.x = recon_tcx0;
1313  recon_comp_rect.org.y = recon_tcy0;
1314  recon_comp_rect.siz.w = recon_tcx1 - recon_tcx0;
1315  recon_comp_rect.siz.h = recon_tcy1 - recon_tcy0;
1316 
1317  tile_comp::pre_alloc(codestream, comp_rect, recon_comp_rect);
1318  width = ojph_max(width, recon_comp_rect.siz.w);
1319  }
1320 
1321  //allocate lines
1323  {
1324  allocator->pre_alloc_obj<line_buf>(3);
1325  for (int i = 0; i < 3; ++i)
1326  allocator->pre_alloc_data<si32>(width, 0);
1327  }
1328  }
1329 
1332  const rect& recon_tile_rect,
1333  ui32 tile_idx, ui32 offset)
1334  {
1335  //this->parent = codestream;
1337 
1338  sot.init(0, (ui16)tile_idx, 0, 1);
1340 
1341  //allocate tiles_comp
1342  const param_siz *szp = codestream->get_siz();
1343 
1344  num_comps = szp->get_num_components();
1346  comps = allocator->post_alloc_obj<tile_comp>(num_comps);
1347  comp_rects = allocator->post_alloc_obj<rect>(num_comps);
1349  line_offsets = allocator->post_alloc_obj<ui32>(num_comps);
1350  num_bits = allocator->post_alloc_obj<ui32>(num_comps);
1351  is_signed = allocator->post_alloc_obj<bool>(num_comps);
1352  cur_line = allocator->post_alloc_obj<ui32>(num_comps);
1353 
1357  else
1358  num_comp_bytes = allocator->post_alloc_obj<ui32>(1);
1359 
1360  this->resilient = codestream->is_resilient();
1361  this->tile_rect = tile_rect;
1362  this->recon_tile_rect = recon_tile_rect;
1363 
1364  ui32 tx0 = tile_rect.org.x;
1365  ui32 ty0 = tile_rect.org.y;
1366  ui32 tx1 = tile_rect.org.x + tile_rect.siz.w;
1367  ui32 ty1 = tile_rect.org.y + tile_rect.siz.h;
1368  ui32 recon_tx0 = recon_tile_rect.org.x;
1369  ui32 recon_ty0 = recon_tile_rect.org.y;
1370  ui32 recon_tx1 = recon_tile_rect.org.x + recon_tile_rect.siz.w;
1371  ui32 recon_ty1 = recon_tile_rect.org.y + recon_tile_rect.siz.h;
1372 
1373  ui32 width = 0;
1374  for (ui32 i = 0; i < num_comps; ++i)
1375  {
1376  point downsamp = szp->get_downsampling(i);
1377 
1378  ui32 tcx0 = ojph_div_ceil(tx0, downsamp.x);
1379  ui32 tcy0 = ojph_div_ceil(ty0, downsamp.y);
1380  ui32 tcx1 = ojph_div_ceil(tx1, downsamp.x);
1381  ui32 tcy1 = ojph_div_ceil(ty1, downsamp.y);
1382  ui32 recon_tcx0 = ojph_div_ceil(recon_tx0, downsamp.x);
1383  ui32 recon_tcy0 = ojph_div_ceil(recon_ty0, downsamp.y);
1384  ui32 recon_tcx1 = ojph_div_ceil(recon_tx1, downsamp.x);
1385  ui32 recon_tcy1 = ojph_div_ceil(recon_ty1, downsamp.y);
1386 
1387  line_offsets[i] =
1388  recon_tcx0 - ojph_div_ceil(recon_tx0 - offset, downsamp.x);
1389  comp_rects[i].org.x = tcx0;
1390  comp_rects[i].org.y = tcy0;
1391  comp_rects[i].siz.w = tcx1 - tcx0;
1392  comp_rects[i].siz.h = tcy1 - tcy0;
1393  recon_comp_rects[i].org.x = recon_tcx0;
1394  recon_comp_rects[i].org.y = recon_tcy0;
1395  recon_comp_rects[i].siz.w = recon_tcx1 - recon_tcx0;
1396  recon_comp_rects[i].siz.h = recon_tcy1 - recon_tcy0;
1397 
1398  comps[i].finalize_alloc(codestream, this, i, comp_rects[i],
1399  recon_comp_rects[i]);
1400  width = ojph_max(width, recon_comp_rects[i].siz.w);
1401 
1402  num_bits[i] = szp->get_bit_depth(i);
1403  is_signed[i] = szp->is_signed(i);
1404  cur_line[i] = 0;
1405  }
1406 
1407  //allocate lines
1408  const param_cod* cdp = codestream->get_cod();
1409  this->reversible = cdp->is_reversible();
1411  if (this->employ_color_transform)
1412  {
1413  num_lines = 3;
1414  lines = allocator->post_alloc_obj<line_buf>(num_lines);
1415  for (int i = 0; i < 3; ++i)
1416  lines[i].wrap(
1417  allocator->post_alloc_data<si32>(width,0),width,0);
1418  }
1419  else
1420  {
1421  lines = NULL;
1422  num_lines = 0;
1423  }
1424  next_tile_part = 0;
1425  }
1426 
1428  bool tile::push(line_buf *line, ui32 comp_num)
1429  {
1430  assert(comp_num < num_comps);
1431  if (cur_line[comp_num] >= comp_rects[comp_num].siz.h)
1432  return false;
1433  cur_line[comp_num]++;
1434 
1435  //converts to signed representation
1436  //employs color transform if there is a need
1437  if (!employ_color_transform || comp_num >= 3)
1438  {
1439  assert(comp_num < num_comps);
1440  ui32 comp_width = comp_rects[comp_num].siz.w;
1441  line_buf *tc = comps[comp_num].get_line();
1442  if (reversible)
1443  {
1444  int shift = 1 << (num_bits[comp_num] - 1);
1445  const si32 *sp = line->i32 + line_offsets[comp_num];
1446  si32* dp = tc->i32;
1447  if (is_signed[comp_num])
1448  memcpy(dp, sp, comp_width * sizeof(si32));
1449  else
1450  cnvrt_si32_to_si32_shftd(sp, dp, -shift, comp_width);
1451  }
1452  else
1453  {
1454  float mul = 1.0f / (float)(1<<num_bits[comp_num]);
1455  const si32 *sp = line->i32 + line_offsets[comp_num];
1456  float *dp = tc->f32;
1457  if (is_signed[comp_num])
1458  cnvrt_si32_to_float(sp, dp, mul, comp_width);
1459  else
1460  cnvrt_si32_to_float_shftd(sp, dp, mul, comp_width);
1461  }
1462  comps[comp_num].push_line();
1463  }
1464  else
1465  {
1466  ui32 comp_width = comp_rects[comp_num].siz.w;
1467  if (reversible)
1468  {
1469  int shift = 1 << (num_bits[comp_num] - 1);
1470  const si32 *sp = line->i32 + line_offsets[comp_num];
1471  si32 *dp = lines[comp_num].i32;
1472  if (is_signed[comp_num])
1473  memcpy(dp, sp, comp_width * sizeof(si32));
1474  else
1475  cnvrt_si32_to_si32_shftd(sp, dp, -shift, comp_width);
1476  if (comp_num == 2)
1477  { // reversible color transform
1478  rct_forward(lines[0].i32, lines[1].i32, lines[2].i32,
1479  comps[0].get_line()->i32,
1480  comps[1].get_line()->i32,
1481  comps[2].get_line()->i32, comp_width);
1482  comps[0].push_line();
1483  comps[1].push_line();
1484  comps[2].push_line();
1485  }
1486  }
1487  else
1488  {
1489  float mul = 1.0f / (float)(1<<num_bits[comp_num]);
1490  const si32 *sp = line->i32 + line_offsets[comp_num];
1491  float *dp = lines[comp_num].f32;
1492  if (is_signed[comp_num])
1493  cnvrt_si32_to_float(sp, dp, mul, comp_width);
1494  else
1495  cnvrt_si32_to_float_shftd(sp, dp, mul, comp_width);
1496  if (comp_num == 2)
1497  { // irreversible color transform
1498  ict_forward(lines[0].f32, lines[1].f32, lines[2].f32,
1499  comps[0].get_line()->f32,
1500  comps[1].get_line()->f32,
1501  comps[2].get_line()->f32, comp_width);
1502  comps[0].push_line();
1503  comps[1].push_line();
1504  comps[2].push_line();
1505  }
1506  }
1507  }
1508 
1509  return true;
1510  }
1511 
1513  bool tile::pull(line_buf* tgt_line, ui32 comp_num)
1514  {
1515  assert(comp_num < num_comps);
1516  if (cur_line[comp_num] >= recon_comp_rects[comp_num].siz.h)
1517  return false;
1518 
1519  cur_line[comp_num]++;
1520 
1521  if (!employ_color_transform || num_comps == 1)
1522  {
1523  line_buf *src_line = comps[comp_num].pull_line();
1524  ui32 comp_width = recon_comp_rects[comp_num].siz.w;
1525  if (reversible)
1526  {
1527  int shift = 1 << (num_bits[comp_num] - 1);
1528  const si32 *sp = src_line->i32;
1529  si32* dp = tgt_line->i32 + line_offsets[comp_num];
1530  if (is_signed[comp_num])
1531  memcpy(dp, sp, comp_width * sizeof(si32));
1532  else
1533  cnvrt_si32_to_si32_shftd(sp, dp, +shift, comp_width);
1534  }
1535  else
1536  {
1537  float mul = (float)(1 << num_bits[comp_num]);
1538  const float *sp = src_line->f32;
1539  si32 *dp = tgt_line->i32 + line_offsets[comp_num];
1540  if (is_signed[comp_num])
1541  cnvrt_float_to_si32(sp, dp, mul, comp_width);
1542  else
1543  cnvrt_float_to_si32_shftd(sp, dp, mul, comp_width);
1544  }
1545  }
1546  else
1547  {
1548  assert(num_comps >= 3);
1549  ui32 comp_width = recon_comp_rects[comp_num].siz.w;
1550  if (comp_num == 0)
1551  {
1552  if (reversible)
1553  rct_backward(comps[0].pull_line()->i32, comps[1].pull_line()->i32,
1554  comps[2].pull_line()->i32, lines[0].i32, lines[1].i32,
1555  lines[2].i32, comp_width);
1556  else
1557  ict_backward(comps[0].pull_line()->f32, comps[1].pull_line()->f32,
1558  comps[2].pull_line()->f32, lines[0].f32, lines[1].f32,
1559  lines[2].f32, comp_width);
1560  }
1561  if (reversible)
1562  {
1563  int shift = 1 << (num_bits[comp_num] - 1);
1564  const si32 *sp;
1565  if (comp_num < 3)
1566  sp = lines[comp_num].i32;
1567  else
1568  sp = comps[comp_num].pull_line()->i32;
1569  si32* dp = tgt_line->i32 + line_offsets[comp_num];
1570  if (is_signed[comp_num])
1571  memcpy(dp, sp, comp_width * sizeof(si32));
1572  else
1573  cnvrt_si32_to_si32_shftd(sp, dp, +shift, comp_width);
1574  }
1575  else
1576  {
1577  float mul = (float)(1 << num_bits[comp_num]);
1578  const float *sp;
1579  if (comp_num < 3)
1580  sp = lines[comp_num].f32;
1581  else
1582  sp = comps[comp_num].pull_line()->f32;
1583  si32 *dp = tgt_line->i32 + line_offsets[comp_num];
1584  if (is_signed[comp_num])
1585  cnvrt_float_to_si32(sp, dp, mul, comp_width);
1586  else
1587  cnvrt_float_to_si32_shftd(sp, dp, mul, comp_width);
1588  }
1589  }
1590 
1591  return true;
1592  }
1593 
1594 
1597  {
1598  //prepare precinct headers
1600  for (ui32 c = 0; c < num_comps; ++c)
1601  num_comp_bytes[c] = comps[c].prepare_precincts();
1602  else
1603  {
1604  num_comp_bytes[0] = 0;
1605  for (ui32 c = 0; c < num_comps; ++c)
1606  num_comp_bytes[0] += comps[c].prepare_precincts();
1607  }
1608  }
1609 
1612  {
1614  {
1615  for (ui32 c = 0; c < num_comps; ++c)
1617  }
1618  else
1620  }
1621 
1622 
1625  {
1626  ui32 max_decompositions = 0;
1627  for (ui32 c = 0; c < num_comps; ++c)
1628  max_decompositions = ojph_max(max_decompositions,
1629  comps[c].get_num_decompositions());
1630 
1632  {
1633  //write tile header
1634  if (!sot.write(file, num_comp_bytes[0]))
1635  OJPH_ERROR(0x00030081, "Error writing to file");
1636 
1637  //write start of data
1639  if (!file->write(&t, 2))
1640  OJPH_ERROR(0x00030082, "Error writing to file");
1641  }
1642 
1643 
1644  //sequence the writing of precincts according to progression order
1646  {
1647  for (ui32 r = 0; r <= max_decompositions; ++r)
1648  for (ui32 c = 0; c < num_comps; ++c)
1649  comps[c].write_precincts(r, file);
1650  }
1651  else if (prog_order == OJPH_PO_RPCL)
1652  {
1653  for (ui32 r = 0; r <= max_decompositions; ++r)
1654  {
1655  while (true)
1656  {
1657  bool found = false;
1658  ui32 comp_num = 0;
1659  point smallest(INT_MAX, INT_MAX), cur;
1660  for (ui32 c = 0; c < num_comps; ++c)
1661  {
1662  if (!comps[c].get_top_left_precinct(r, cur))
1663  continue;
1664  else
1665  found = true;
1666 
1667  if (cur.y < smallest.y)
1668  { smallest = cur; comp_num = c; }
1669  else if (cur.y == smallest.y && cur.x < smallest.x)
1670  { smallest = cur; comp_num = c; }
1671  }
1672  if (found == true)
1673  comps[comp_num].write_one_precinct(r, file);
1674  else
1675  break;
1676  }
1677  }
1678  }
1679  else if (prog_order == OJPH_PO_PCRL)
1680  {
1681  while (true)
1682  {
1683  bool found = false;
1684  ui32 comp_num = 0;
1685  ui32 res_num = 0;
1686  point smallest(INT_MAX, INT_MAX), cur;
1687  for (ui32 c = 0; c < num_comps; ++c)
1688  {
1689  for (ui32 r = 0; r <= comps[c].get_num_decompositions(); ++r)
1690  {
1691  if (!comps[c].get_top_left_precinct(r, cur))
1692  continue;
1693  else
1694  found = true;
1695 
1696  if (cur.y < smallest.y)
1697  { smallest = cur; comp_num = c; res_num = r; }
1698  else if (cur.y == smallest.y && cur.x < smallest.x)
1699  { smallest = cur; comp_num = c; res_num = r; }
1700  else if (cur.y == smallest.y && cur.x == smallest.x &&
1701  c < comp_num)
1702  { smallest = cur; comp_num = c; res_num = r; }
1703  else if (cur.y == smallest.y && cur.x == smallest.x &&
1704  c == comp_num && r < res_num)
1705  { smallest = cur; comp_num = c; res_num = r; }
1706  }
1707  }
1708  if (found == true)
1709  comps[comp_num].write_one_precinct(res_num, file);
1710  else
1711  break;
1712  }
1713  }
1714  else if (prog_order == OJPH_PO_CPRL)
1715  {
1716  for (ui32 c = 0; c < num_comps; ++c)
1717  {
1719  {
1720  //write tile header
1721  if (!sot.write(file, num_comp_bytes[c], (ui8)c, (ui8)num_comps))
1722  OJPH_ERROR(0x00030083, "Error writing to file");
1723 
1724  //write start of data
1726  if (!file->write(&t, 2))
1727  OJPH_ERROR(0x00030084, "Error writing to file");
1728  }
1729 
1730  while (true)
1731  {
1732  bool found = false;
1733  ui32 res_num = 0;
1734  point smallest(INT_MAX, INT_MAX), cur;
1735  for (ui32 r = 0; r <= max_decompositions; ++r)
1736  {
1737  if (!comps[c].get_top_left_precinct(r, cur)) //res exist?
1738  continue;
1739  else
1740  found = true;
1741 
1742  if (cur.y < smallest.y)
1743  { smallest = cur; res_num = r; }
1744  else if (cur.y == smallest.y && cur.x < smallest.x)
1745  { smallest = cur; res_num = r; }
1746  }
1747  if (found == true)
1748  comps[c].write_one_precinct(res_num, file);
1749  else
1750  break;
1751  }
1752  }
1753  }
1754  else
1755  assert(0);
1756 
1757  }
1758 
1761  const ui64& tile_start_location)
1762  {
1764  {
1765  if (resilient)
1766  OJPH_INFO(0x00030091, "wrong tile part index")
1767  else
1768  OJPH_ERROR(0x00030091, "wrong tile part index")
1769  }
1770  ++next_tile_part;
1771 
1772  //tile_end_location used on failure
1773  ui64 tile_end_location = tile_start_location + sot.get_payload_length();
1774 
1775  ui32 data_left = sot.get_payload_length(); //bytes left to parse
1776  data_left -= (ui32)((ui64)file->tell() - tile_start_location);
1777 
1778  if (data_left == 0)
1779  return;
1780 
1781  ui32 max_decompositions = 0;
1782  for (ui32 c = 0; c < num_comps; ++c)
1783  max_decompositions = ojph_max(max_decompositions,
1784  comps[c].get_num_decompositions());
1785 
1786  try
1787  {
1788  //sequence the reading of precincts according to progression order
1790  {
1791  max_decompositions -= skipped_res_for_read;
1792  for (ui32 r = 0; r <= max_decompositions; ++r)
1793  for (ui32 c = 0; c < num_comps; ++c)
1794  if (data_left > 0)
1795  comps[c].parse_precincts(r, data_left, file);
1796  }
1797  else if (prog_order == OJPH_PO_RPCL)
1798  {
1799  max_decompositions -= skipped_res_for_read;
1800  for (ui32 r = 0; r <= max_decompositions; ++r)
1801  {
1802  while (true)
1803  {
1804  bool found = false;
1805  ui32 comp_num = 0;
1806  point smallest(INT_MAX, INT_MAX), cur;
1807  for (ui32 c = 0; c < num_comps; ++c)
1808  {
1809  if (!comps[c].get_top_left_precinct(r, cur))
1810  continue;
1811  else
1812  found = true;
1813 
1814  if (cur.y < smallest.y)
1815  { smallest = cur; comp_num = c; }
1816  else if (cur.y == smallest.y && cur.x < smallest.x)
1817  { smallest = cur; comp_num = c; }
1818  }
1819  if (found == true && data_left > 0)
1820  comps[comp_num].parse_one_precinct(r, data_left, file);
1821  else
1822  break;
1823  }
1824  }
1825  }
1826  else if (prog_order == OJPH_PO_PCRL)
1827  {
1828  while (true)
1829  {
1830  bool found = false;
1831  ui32 comp_num = 0;
1832  ui32 res_num = 0;
1833  point smallest(INT_MAX, INT_MAX), cur;
1834  for (ui32 c = 0; c < num_comps; ++c)
1835  {
1836  for (ui32 r = 0; r <= comps[c].get_num_decompositions(); ++r)
1837  {
1838  if (!comps[c].get_top_left_precinct(r, cur))
1839  continue;
1840  else
1841  found = true;
1842 
1843  if (cur.y < smallest.y)
1844  { smallest = cur; comp_num = c; res_num = r; }
1845  else if (cur.y == smallest.y && cur.x < smallest.x)
1846  { smallest = cur; comp_num = c; res_num = r; }
1847  else if (cur.y == smallest.y && cur.x == smallest.x &&
1848  c < comp_num)
1849  { smallest = cur; comp_num = c; res_num = r; }
1850  else if (cur.y == smallest.y && cur.x == smallest.x &&
1851  c == comp_num && r < res_num)
1852  { smallest = cur; comp_num = c; res_num = r; }
1853  }
1854  }
1855  if (found == true && data_left > 0)
1856  comps[comp_num].parse_one_precinct(res_num, data_left, file);
1857  else
1858  break;
1859  }
1860  }
1861  else if (prog_order == OJPH_PO_CPRL)
1862  {
1863  for (ui32 c = 0; c < num_comps; ++c)
1864  {
1865  while (true)
1866  {
1867  bool found = false;
1868  ui32 res_num = 0;
1869  point smallest(INT_MAX, INT_MAX), cur;
1870  for (ui32 r = 0; r <= max_decompositions; ++r)
1871  {
1872  if (!comps[c].get_top_left_precinct(r, cur)) //res exist?
1873  continue;
1874  else
1875  found = true;
1876 
1877  if (cur.y < smallest.y)
1878  { smallest = cur; res_num = r; }
1879  else if (cur.y == smallest.y && cur.x < smallest.x)
1880  { smallest = cur; res_num = r; }
1881  }
1882  if (found == true && data_left > 0)
1883  comps[c].parse_one_precinct(res_num, data_left, file);
1884  else
1885  break;
1886  }
1887  }
1888  }
1889  else
1890  assert(0);
1891 
1892  }
1893  catch (const char *error)
1894  {
1895  if (resilient)
1896  OJPH_INFO(0x00030092, "%s", error)
1897  else
1898  OJPH_ERROR(0x00030092, "%s", error)
1899  }
1900  file->seek((si64)tile_end_location, infile_base::OJPH_SEEK_SET);
1901  }
1902 
1904  //
1905  //
1906  //
1907  //
1908  //
1910 
1913  const rect& recon_comp_rect)
1914  {
1916 
1917  //allocate a resolution
1919  allocator->pre_alloc_obj<resolution>(1);
1920 
1921  resolution::pre_alloc(codestream, comp_rect, recon_comp_rect,
1922  num_decomps);
1923  }
1924 
1927  ui32 comp_num, const rect& comp_rect,
1928  const rect& recon_comp_rect)
1929  {
1931 
1932  //allocate a resolution
1934 
1936  this->comp_rect = comp_rect;
1937  this->parent_tile = parent;
1938 
1939  this->comp_num = comp_num;
1940  res = allocator->post_alloc_obj<resolution>(1);
1941  res->finalize_alloc(codestream, comp_rect, recon_comp_rect, comp_num,
1942  num_decomps, comp_downsamp, this, NULL);
1943  }
1944 
1947  {
1948  return res->get_line();
1949  }
1950 
1953  {
1954  res->push_line();
1955  }
1956 
1959  {
1960  return res->pull_line();
1961  }
1962 
1965  {
1966  return res->prepare_precinct();
1967  }
1968 
1971  {
1972  assert(res_num <= num_decomps);
1973  res_num = num_decomps - res_num; //how many levels to go down
1974  resolution *r = res;
1975  while (res_num > 0 && r != NULL)
1976  {
1977  r = r->next_resolution();
1978  --res_num;
1979  }
1980  if (r) //resolution does not exist if r is NULL
1981  r->write_precincts(file);
1982  }
1983 
1986  {
1987  assert(res_num <= num_decomps);
1988  res_num = num_decomps - res_num;
1989  resolution *r = res;
1990  while (res_num > 0 && r != NULL)
1991  {
1992  r = r->next_resolution();
1993  --res_num;
1994  }
1995  if (r) //resolution does not exist if r is NULL
1996  return r->get_top_left_precinct(top_left);
1997  else
1998  return false;
1999  }
2000 
2003  {
2004  assert(res_num <= num_decomps);
2005  res_num = num_decomps - res_num;
2006  resolution *r = res;
2007  while (res_num > 0 && r != NULL)
2008  {
2009  r = r->next_resolution();
2010  --res_num;
2011  }
2012  if (r) //resolution does not exist if r is NULL
2013  r->write_one_precinct(file);
2014  }
2015 
2017  void tile_comp::parse_precincts(ui32 res_num, ui32& data_left,
2018  infile_base *file)
2019  {
2020  assert(res_num <= num_decomps);
2021  res_num = num_decomps - res_num; //how many levels to go down
2022  resolution *r = res;
2023  while (res_num > 0 && r != NULL)
2024  {
2025  r = r->next_resolution();
2026  --res_num;
2027  }
2028  if (r) //resolution does not exist if r is NULL
2029  r->parse_all_precincts(data_left, file);
2030  }
2031 
2032 
2034  void tile_comp::parse_one_precinct(ui32 res_num, ui32& data_left,
2035  infile_base *file)
2036  {
2037  assert(res_num <= num_decomps);
2038  res_num = num_decomps - res_num;
2039  resolution *r = res;
2040  while (res_num > 0 && r != NULL)
2041  {
2042  r = r->next_resolution();
2043  --res_num;
2044  }
2045  if (r) //resolution does not exist if r is NULL
2046  r->parse_one_precinct(data_left, file);
2047  }
2048 
2049 
2050 
2052  //
2053  //
2054  //
2055  //
2056  //
2058 
2060  static void rotate_buffers(line_buf *line1, line_buf* line2,
2061  line_buf *line3, line_buf* line4)
2062  {
2063  assert(line1->size == line2->size &&
2064  line1->pre_size == line2->pre_size &&
2065  line1->size == line3->size &&
2066  line1->pre_size == line3->pre_size &&
2067  line1->size == line4->size &&
2068  line1->pre_size == line4->pre_size);
2069  si32* p = line4->i32;
2070  line4->i32 = line3->i32;
2071  line3->i32 = line2->i32;
2072  line2->i32 = line1->i32;
2073  line1->i32 = p;
2074  }
2075 
2077  static void rotate_buffers(line_buf *line1, line_buf* line2,
2078  line_buf *line3, line_buf* line4,
2079  line_buf *line5, line_buf* line6)
2080  {
2081  assert(line1->size == line2->size &&
2082  line1->pre_size == line2->pre_size &&
2083  line1->size == line3->size &&
2084  line1->pre_size == line3->pre_size &&
2085  line1->size == line4->size &&
2086  line1->pre_size == line4->pre_size &&
2087  line1->size == line5->size &&
2088  line1->pre_size == line5->pre_size &&
2089  line1->size == line6->size &&
2090  line1->pre_size == line6->pre_size);
2091  si32* p = line6->i32;
2092  line6->i32 = line5->i32;
2093  line5->i32 = line4->i32;
2094  line4->i32 = line3->i32;
2095  line3->i32 = line2->i32;
2096  line2->i32 = line1->i32;
2097  line1->i32 = p;
2098  }
2099 
2102  const rect& recon_res_rect, ui32 res_num)
2103  {
2105  const param_cod* cdp = codestream->get_cod();
2108  bool skipped_res_for_recon = res_num > t;
2109 
2110  //create next resolution
2111  if (res_num > 0)
2112  {
2113  //allocate a resolution
2114  allocator->pre_alloc_obj<resolution>(1);
2115  ui32 trx0 = ojph_div_ceil(res_rect.org.x, 2);
2116  ui32 try0 = ojph_div_ceil(res_rect.org.y, 2);
2117  ui32 trx1 = ojph_div_ceil(res_rect.org.x + res_rect.siz.w, 2);
2118  ui32 try1 = ojph_div_ceil(res_rect.org.y + res_rect.siz.h, 2);
2119  rect next_res_rect;
2120  next_res_rect.org.x = trx0;
2121  next_res_rect.org.y = try0;
2122  next_res_rect.siz.w = trx1 - trx0;
2123  next_res_rect.siz.h = try1 - try0;
2124 
2125  resolution::pre_alloc(codestream, next_res_rect,
2126  skipped_res_for_recon ? recon_res_rect : next_res_rect, res_num - 1);
2127  }
2128 
2129  //allocate subbands
2130  ui32 trx0 = res_rect.org.x;
2131  ui32 try0 = res_rect.org.y;
2132  ui32 trx1 = res_rect.org.x + res_rect.siz.w;
2133  ui32 try1 = res_rect.org.y + res_rect.siz.h;
2134  allocator->pre_alloc_obj<subband>(4);
2135  if (res_num > 0)
2136  {
2137  for (ui32 i = 1; i < 4; ++i)
2138  {
2139  ui32 tbx0 = (trx0 - (i&1) + 1) >> 1;
2140  ui32 tbx1 = (trx1 - (i&1) + 1) >> 1;
2141  ui32 tby0 = (try0 - (i>>1) + 1) >> 1;
2142  ui32 tby1 = (try1 - (i>>1) + 1) >> 1;
2143 
2144  rect band_rect;
2145  band_rect.org.x = tbx0;
2146  band_rect.org.y = tby0;
2147  band_rect.siz.w = tbx1 - tbx0;
2148  band_rect.siz.h = tby1 - tby0;
2149  subband::pre_alloc(codestream, band_rect, res_num);
2150  }
2151  }
2152  else
2154 
2155  //prealloc precincts
2158  if (trx0 != trx1 && try0 != try1)
2159  {
2160  num_precincts.w = (trx1 + (1<<log_PP.w) - 1) >> log_PP.w;
2161  num_precincts.w -= trx0 >> log_PP.w;
2162  num_precincts.h = (try1 + (1<<log_PP.h) - 1) >> log_PP.h;
2163  num_precincts.h -= try0 >> log_PP.h;
2164  allocator->pre_alloc_obj<precinct>(num_precincts.area());
2165  }
2166 
2167  //allocate lines
2168  if (skipped_res_for_recon == false)
2169  {
2170  bool reversible = cdp->is_reversible();
2171  ui32 num_lines = reversible ? 4 : 6;
2172  allocator->pre_alloc_obj<line_buf>(num_lines);
2173 
2174  ui32 width = res_rect.siz.w + 1;
2175  for (ui32 i = 0; i < num_lines; ++i)
2176  allocator->pre_alloc_data<si32>(width, 1);
2177  }
2178  }
2179 
2182  const rect& res_rect,
2183  const rect& recon_res_rect,
2184  ui32 comp_num, ui32 res_num,
2185  point comp_downsamp,
2186  tile_comp *parent_tile_comp,
2187  resolution *parent_res)
2188  {
2191  ui32 t, num_decomps = codestream->get_cod()->get_num_decompositions();
2192  t = num_decomps - codestream->get_skipped_res_for_recon();
2194  t = num_decomps - codestream->get_skipped_res_for_read();
2196  const param_cod* cdp = codestream->get_cod();
2197 
2198  this->comp_downsamp = comp_downsamp;
2199  this->parent_comp = parent_tile_comp;
2200  this->parent_res = parent_res;
2201  this->res_rect = res_rect;
2202  this->comp_num = comp_num;
2203  this->res_num = res_num;
2204  //finalize next resolution
2205  if (res_num > 0)
2206  {
2207  //allocate a resolution
2208  child_res = allocator->post_alloc_obj<resolution>(1);
2209  ui32 trx0 = ojph_div_ceil(res_rect.org.x, 2);
2210  ui32 try0 = ojph_div_ceil(res_rect.org.y, 2);
2211  ui32 trx1 = ojph_div_ceil(res_rect.org.x + res_rect.siz.w, 2);
2212  ui32 try1 = ojph_div_ceil(res_rect.org.y + res_rect.siz.h, 2);
2213  rect next_res_rect;
2214  next_res_rect.org.x = trx0;
2215  next_res_rect.org.y = try0;
2216  next_res_rect.siz.w = trx1 - trx0;
2217  next_res_rect.siz.h = try1 - try0;
2218 
2219  child_res->finalize_alloc(codestream, next_res_rect,
2220  skipped_res_for_recon ? recon_res_rect : next_res_rect, comp_num,
2221  res_num - 1, comp_downsamp, parent_tile_comp, this);
2222  }
2223  else
2224  child_res = NULL;
2225 
2226  //allocate subbands
2227  ui32 trx0 = res_rect.org.x;
2228  ui32 try0 = res_rect.org.y;
2229  ui32 trx1 = res_rect.org.x + res_rect.siz.w;
2230  ui32 try1 = res_rect.org.y + res_rect.siz.h;
2231  bands = allocator->post_alloc_obj<subband>(4);
2232  if (res_num > 0)
2233  {
2234  this->num_bands = 3;
2235  for (ui32 i = 1; i < 4; ++i)
2236  {
2237  ui32 tbx0 = (trx0 - (i&1) + 1) >> 1;
2238  ui32 tbx1 = (trx1 - (i&1) + 1) >> 1;
2239  ui32 tby0 = (try0 - (i>>1) + 1) >> 1;
2240  ui32 tby1 = (try1 - (i>>1) + 1) >> 1;
2241 
2242  rect band_rect;
2243  band_rect.org.x = tbx0;
2244  band_rect.org.y = tby0;
2245  band_rect.siz.w = tbx1 - tbx0;
2246  band_rect.siz.h = tby1 - tby0;
2247  bands[i].finalize_alloc(codestream, band_rect, this, res_num, i);
2248  }
2249  }
2250  else {
2251  this->num_bands = 1;
2252  bands[0].finalize_alloc(codestream, res_rect, this, res_num, 0);
2253  }
2254 
2255  //finalize precincts
2257  num_precincts = size();
2258  precincts = NULL;
2259  if (trx0 != trx1 && try0 != try1)
2260  {
2261  num_precincts.w = (trx1 + (1<<log_PP.w) - 1) >> log_PP.w;
2262  num_precincts.w -= trx0 >> log_PP.w;
2263  num_precincts.h = (try1 + (1<<log_PP.h) - 1) >> log_PP.h;
2264  num_precincts.h -= try0 >> log_PP.h;
2266  ui64 num = num_precincts.area();
2267  for (ui64 i = 0; i < num; ++i)
2268  precincts[i] = precinct();
2269  }
2270  // precincts will be initialized in full shortly
2271 
2272  ui32 x_lower_bound = (trx0 >> log_PP.w) << log_PP.w;
2273  ui32 y_lower_bound = (try0 >> log_PP.h) << log_PP.h;
2274 
2275  point proj_factor;
2276  proj_factor.x = comp_downsamp.x * (1<<(num_decomps - res_num));
2277  proj_factor.y = comp_downsamp.y * (1<<(num_decomps - res_num));
2278  precinct *pp = precincts;
2279 
2280  point tile_top_left = parent_tile_comp->get_tile()->get_tile_rect().org;
2281  for (ui32 y = 0; y < num_precincts.h; ++y)
2282  {
2283  ui32 ppy0 = y_lower_bound + (y << log_PP.h);
2284  for (ui32 x = 0; x < num_precincts.w; ++x, ++pp)
2285  {
2286  ui32 ppx0 = x_lower_bound + (x << log_PP.w);
2287  point t(proj_factor.x * ppx0, proj_factor.y * ppy0);
2288  t.x = t.x > tile_top_left.x ? t.x : tile_top_left.x;
2289  t.y = t.y > tile_top_left.y ? t.y : tile_top_left.y;
2290  pp->img_point = t;
2291  pp->num_bands = num_bands;
2292  pp->bands = bands;
2293  pp->may_use_sop = cdp->packets_may_use_sop();
2294  pp->uses_eph = cdp->packets_use_eph();
2296  pp->coded = NULL;
2297  }
2298  }
2299  if (num_bands == 1)
2301  else
2302  for (int i = 1; i < 4; ++i)
2303  bands[i].get_cb_indices(num_precincts, precincts);
2304 
2305  size log_cb = cdp->get_log_block_dims();
2306  log_PP.w -= (res_num?1:0);
2307  log_PP.h -= (res_num?1:0);
2308  size ratio;
2309  ratio.w = log_PP.w - ojph_min(log_cb.w, log_PP.w);
2310  ratio.h = log_PP.h - ojph_min(log_cb.h, log_PP.h);
2311  max_num_levels = ojph_max(ratio.w, ratio.h);
2312  ui32 val = 1u << (max_num_levels << 1);
2313  tag_tree_size = (int)((val * 4 + 2) / 3);
2314  ++max_num_levels;
2315  level_index[0] = 0;
2316  for (ui32 i = 1; i <= max_num_levels; ++i, val >>= 2)
2317  level_index[i] = level_index[i - 1] + val;
2318  cur_precinct_loc = point(0, 0);
2319 
2320  //allocate lines
2321  if (skipped_res_for_recon == false)
2322  {
2323  this->reversible = cdp->is_reversible();
2324  this->num_lines = this->reversible ? 4 : 6;
2325  lines = allocator->post_alloc_obj<line_buf>(num_lines);
2326 
2327  ui32 width = res_rect.siz.w + 1;
2328  for (ui32 i = 0; i < num_lines; ++i)
2329  lines[i].wrap(allocator->post_alloc_data<si32>(width, 1), width, 1);
2330  cur_line = 0;
2331  vert_even = (res_rect.org.y & 1) == 0;
2332  horz_even = (res_rect.org.x & 1) == 0;
2333  }
2334  }
2335 
2338  {
2339  if (res_num == 0)
2340  {
2341  assert(num_bands == 1 && child_res == NULL);
2342  bands[0].exchange_buf(lines + 0);//line at location 0
2343  bands[0].push_line();
2344  return;
2345  }
2346 
2347  ui32 width = res_rect.siz.w;
2348  if (width == 0)
2349  return;
2350  if (reversible)
2351  {
2352  //vertical transform
2353  assert(num_lines >= 4);
2354  if (vert_even)
2355  {
2357  cur_line > 1 ? lines + 2 : lines,
2358  lines + 1, width);
2360  cur_line > 2 ? lines + 3 : lines + 1,
2361  lines + 2, width);
2362 
2363  // push to horizontal transform lines[2](L) and lines[1] (H)
2364  if (cur_line >= 1)
2365  {
2367  bands[3].get_line(), width, horz_even);
2368  bands[2].push_line();
2369  bands[3].push_line();
2370  }
2371  if (cur_line >= 2)
2372  {
2374  bands[1].get_line(), width, horz_even);
2375  bands[1].push_line();
2376  child_res->push_line();
2377  }
2378  }
2379 
2380  if (cur_line >= res_rect.siz.h - 1)
2381  { //finished, so we need to process any lines left
2382  if (cur_line)
2383  {
2384  if (vert_even)
2385  {
2387  lines, width);
2388  //push lines[0] to L
2390  bands[1].get_line(), width, horz_even);
2391  bands[1].push_line();
2392  child_res->push_line();
2393  }
2394  else
2395  {
2397  lines, width);
2399  cur_line > 1 ? lines + 2:lines,
2400  lines + 1, width);
2401 
2402  // push to horizontal transform lines[1](L) and line[0] (H)
2403  //line[0] to H
2405  bands[3].get_line(), width, horz_even);
2406  bands[2].push_line();
2407  bands[3].push_line();
2408  //line[1] to L
2410  bands[1].get_line(), width, horz_even);
2411  bands[1].push_line();
2412  child_res->push_line();
2413  }
2414  }
2415  else
2416  { //only one line
2417  if (vert_even)
2418  {
2419  //push to L
2421  bands[1].get_line(), width, horz_even);
2422  bands[1].push_line();
2423  child_res->push_line();
2424  }
2425  else
2426  {
2427  si32 *sp = lines[0].i32;
2428  for (ui32 i = width; i > 0; --i)
2429  *sp++ <<= 1;
2430  //push to H
2432  bands[3].get_line(), width, horz_even);
2433  bands[2].push_line();
2434  bands[3].push_line();
2435  }
2436  }
2437  }
2438 
2439  rotate_buffers(lines, lines+1, lines+2, lines+3);
2440 
2441  ++cur_line;
2442  vert_even = !vert_even;
2443  }
2444  else
2445  {
2446  //vertical transform
2447  assert(num_lines >= 6);
2448  if (vert_even)
2449  {
2451  cur_line > 1 ? lines + 2 : lines,
2452  lines + 1, 0, width);
2454  cur_line > 2 ? lines + 3 : lines + 1,
2455  lines + 2, 1, width);
2457  cur_line > 3 ? lines + 4 : lines + 2,
2458  lines + 3, 2, width);
2460  cur_line > 4 ? lines + 5 : lines + 3,
2461  lines + 4, 3, width);
2462 
2463  // push to horizontal transform lines[4](L) and lines[3] (H)
2464  if (cur_line >= 3)
2465  {
2466  irrev_vert_wvlt_K(lines + 3, lines + 5,
2467  false, width);
2469  bands[3].get_line(), width, horz_even);
2470  bands[2].push_line();
2471  bands[3].push_line();
2472  }
2473  if (cur_line >= 4)
2474  {
2475  irrev_vert_wvlt_K(lines + 4, lines + 5,
2476  true, width);
2478  bands[1].get_line(), width, horz_even);
2479  bands[1].push_line();
2480  child_res->push_line();
2481  }
2482  }
2483 
2484  if (cur_line >= res_rect.siz.h - 1)
2485  { //finished, so we need to process any left line
2486  if (cur_line)
2487  {
2488  if (vert_even)
2489  {
2490  irrev_vert_wvlt_step(lines + 1, lines + 1,
2491  lines, 1, width);
2493  cur_line > 1 ? lines + 2 : lines,
2494  lines + 1, 2, width);
2496  cur_line > 2 ? lines + 3 : lines + 1,
2497  lines + 2, 3, width);
2498  irrev_vert_wvlt_step(lines + 1, lines + 1,
2499  lines, 3, width);
2500  //push lines[2] to L, lines[1] to H, and lines[0] to L
2501  if (cur_line >= 2)
2502  {
2503  irrev_vert_wvlt_K(lines + 2, lines + 5,
2504  true, width);
2506  child_res->get_line(), bands[1].get_line(),
2507  width, horz_even);
2508  bands[1].push_line();
2509  child_res->push_line();
2510  }
2511  irrev_vert_wvlt_K(lines + 1, lines + 5,
2512  false, width);
2514  bands[3].get_line(), width, horz_even);
2515  bands[2].push_line();
2516  bands[3].push_line();
2518  true, width);
2520  bands[1].get_line(), width, horz_even);
2521  bands[1].push_line();
2522  child_res->push_line();
2523  }
2524  else
2525  {
2526  irrev_vert_wvlt_step(lines + 1, lines + 1,
2527  lines, 0, width);
2529  cur_line > 1 ? lines + 2 : lines,
2530  lines + 1, 1, width);
2532  cur_line > 2 ? lines + 3 : lines + 1,
2533  lines + 2, 2, width);
2535  cur_line > 3 ? lines + 4 : lines + 2,
2536  lines + 3, 3, width);
2537 
2538  irrev_vert_wvlt_step(lines + 1, lines + 1,
2539  lines, 2, width);
2541  cur_line > 1 ? lines + 2 : lines,
2542  lines + 1, 3, width);
2543 
2544  //push lines[3] L, lines[2] H, lines[1] L, and lines[0] H
2545  if (cur_line >= 3)
2546  {
2547  irrev_vert_wvlt_K(lines + 3, lines + 5,
2548  true, width);
2550  child_res->get_line(), bands[1].get_line(),
2551  width, horz_even);
2552  bands[1].push_line();
2553  child_res->push_line();
2554  }
2555  irrev_vert_wvlt_K(lines + 2, lines + 5,
2556  false, width);
2558  bands[3].get_line(), width, horz_even);
2559  bands[2].push_line();
2560  bands[3].push_line();
2561  irrev_vert_wvlt_K(lines + 1, lines + 5,
2562  true, width);
2564  bands[1].get_line(), width, horz_even);
2565  bands[1].push_line();
2566  child_res->push_line();
2568  false, width);
2570  bands[3].get_line(), width, horz_even);
2571  bands[2].push_line();
2572  bands[3].push_line();
2573  }
2574  }
2575  else
2576  { //only one line
2577  if (vert_even)
2578  {
2579  //push to L
2581  bands[1].get_line(), width, horz_even);
2582  bands[1].push_line();
2583  child_res->push_line();
2584  }
2585  else
2586  {
2587  //push to H
2589  bands[3].get_line(), width, horz_even);
2590  bands[2].push_line();
2591  bands[3].push_line();
2592  }
2593  }
2594  }
2595 
2596  rotate_buffers(lines, lines+1, lines+2, lines+3, lines+4, lines+5);
2597 
2598  ++cur_line;
2599  vert_even = !vert_even;
2600  }
2601  }
2602 
2605  {
2606  if (res_num == 0)
2607  {
2608  assert(num_bands == 1 && child_res == NULL);
2609  return bands[0].pull_line();
2610  }
2611 
2612  if (skipped_res_for_recon == true)
2613  return child_res->pull_line();
2614 
2615  ui32 width = res_rect.siz.w;
2616  if (width == 0)
2617  return lines;
2618  if (reversible)
2619  {
2620  assert(num_lines >= 4);
2621  if (res_rect.siz.h > 1)
2622  {
2623  do
2624  {
2625  //horizontal transform
2626  if (cur_line < res_rect.siz.h)
2627  {
2628  if (vert_even)
2631  width, horz_even);
2632  else
2634  bands[2].pull_line(), bands[3].pull_line(),
2635  width, horz_even);
2636  }
2637 
2638  //vertical transform
2639  if (!vert_even)
2640  {
2642  cur_line > 1 ? lines + 2 : lines,
2643  cur_line < res_rect.siz.h ? lines : lines + 2,
2644  lines + 1, width);
2646  cur_line > 2 ? lines + 3 : lines + 1,
2647  cur_line < res_rect.siz.h + 1 ? lines + 1 : lines + 3,
2648  lines + 2, width);
2649  }
2650 
2651  vert_even = !vert_even;
2652  rotate_buffers(lines, lines+1, lines+2, lines+3);
2653  ++cur_line;
2654  }
2655  while (cur_line < 3);
2656  memcpy(lines[0].i32, lines[3].i32, res_rect.siz.w * sizeof(si32));
2657  return lines;
2658  }
2659  else if (res_rect.siz.h == 1)
2660  {
2661  if (vert_even)
2662  {
2664  bands[1].pull_line(), width, horz_even);
2665  }
2666  else
2667  {
2669  bands[3].pull_line(), width, horz_even);
2670  if (width)
2671  {
2672  si32 *sp = lines[0].i32;
2673  for (ui32 i = width; i > 0; --i)
2674  *sp++ >>= 1;
2675  }
2676  }
2677  return lines;
2678  }
2679  else
2680  return lines;
2681  }
2682  else
2683  {
2684  assert(num_lines >= 6);
2685  if (res_rect.siz.h > 1)
2686  {
2687  do
2688  {
2689  //horizontal transform
2690  if (cur_line < res_rect.siz.h)
2691  {
2692  if (vert_even)
2693  {
2696  width, horz_even);
2697  irrev_vert_wvlt_K(lines, lines, false, width);
2698  }
2699  else
2700  {
2702  bands[2].pull_line(), bands[3].pull_line(),
2703  width, horz_even);
2704  irrev_vert_wvlt_K(lines, lines, true, width);
2705  }
2706  }
2707 
2708  //vertical transform
2709  if (!vert_even)
2710  {
2712  cur_line > 1 ? lines + 2 : lines,
2713  cur_line < res_rect.siz.h ? lines : lines + 2,
2714  lines + 1, 7, width);
2716  cur_line > 2 ? lines + 3 : lines + 1,
2717  cur_line < res_rect.siz.h + 1 ? lines + 1 : lines + 3,
2718  lines + 2, 6, width);
2720  cur_line > 3 ? lines + 4 : lines + 2,
2721  cur_line < res_rect.siz.h + 2 ? lines + 2 : lines + 4,
2722  lines + 3, 5, width);
2724  cur_line > 4 ? lines + 5 : lines + 3,
2725  cur_line < res_rect.siz.h + 3 ? lines + 3 : lines + 5,
2726  lines + 4, 4, width);
2727  }
2728 
2729  vert_even = !vert_even;
2731  ++cur_line;
2732  }
2733  while (cur_line < 5);
2734  memcpy(lines[0].f32, lines[5].f32, res_rect.siz.w * sizeof(float));
2735  return lines;
2736  }
2737  else if (res_rect.siz.h == 1)
2738  {
2739  if (vert_even)
2740  {
2742  bands[1].pull_line(), width, horz_even);
2743  }
2744  else
2745  {
2747  bands[3].pull_line(), width, horz_even);
2748  if (width)
2749  {
2750  float *sp = lines[0].f32;
2751  for (ui32 i = width; i > 0; --i)
2752  *sp++ *= 0.5f;
2753  }
2754  }
2755  return lines;
2756  }
2757  else
2758  return lines;
2759  }
2760  }
2761 
2764  {
2765  ui32 used_bytes = 0;
2766  if (res_num != 0)
2767  used_bytes = child_res->prepare_precinct();
2768 
2769  si32 repeat = (si32)num_precincts.area();
2770  for (si32 i = 0; i < repeat; ++i)
2771  used_bytes += precincts[i].prepare_precinct(tag_tree_size,
2772  level_index, elastic);
2773 
2774  return used_bytes;
2775  }
2776 
2779  {
2780  precinct *p = precincts;
2781  for (si32 i = 0; i < (si32)num_precincts.area(); ++i)
2782  p[i].write(file);
2783  }
2784 
2787  {
2789  if (idx < num_precincts.area())
2790  {
2791  top_left = precincts[idx].img_point;
2792  return true;
2793  }
2794  return false;
2795  }
2796 
2799  {
2801  assert(idx < num_precincts.area());
2802  precincts[idx].write(file);
2803 
2804  if (++cur_precinct_loc.x >= num_precincts.w)
2805  {
2806  cur_precinct_loc.x = 0;
2807  ++cur_precinct_loc.y;
2808  }
2809  }
2810 
2813  {
2814  precinct *p = precincts;
2816  for (ui32 i = idx; i < num_precincts.area(); ++i)
2817  {
2818  if (data_left == 0)
2819  break;
2820  p[i].parse(tag_tree_size, level_index, elastic, data_left, file,
2822  if (++cur_precinct_loc.x >= num_precincts.w)
2823  {
2824  cur_precinct_loc.x = 0;
2825  ++cur_precinct_loc.y;
2826  }
2827  }
2828  }
2829 
2832  {
2834  assert(idx < num_precincts.area());
2835 
2836  if (data_left == 0)
2837  return;
2838  precinct *p = precincts + idx;
2839  p->parse(tag_tree_size, level_index, elastic, data_left, file,
2841  if (++cur_precinct_loc.x >= num_precincts.w)
2842  {
2843  cur_precinct_loc.x = 0;
2844  ++cur_precinct_loc.y;
2845  }
2846  }
2847 
2849  //
2850  //
2851  //
2852  //
2853  //
2855 
2858  {
2859  static const int needed;
2860 
2861  bit_write_buf() { ccl = NULL; avail_bits = 0; tmp = 0; }
2865  };
2866 
2868  const int bit_write_buf::needed = 512;
2869 
2871  static inline
2873  coded_lists*& cur_coded_list)
2874  {
2875  assert(cur_coded_list == NULL);
2876  elastic->get_buffer(bit_write_buf::needed, cur_coded_list);
2877  bbp->ccl = cur_coded_list;
2878  bbp->tmp = 0;
2879  }
2880 
2882  static inline
2884  coded_lists*& cur_coded_list)
2885  {
2886  bb_expand_buf(bbp, elastic, cur_coded_list);
2887  bbp->avail_bits = 8;
2888  }
2889 
2891  static inline
2893  mem_elastic_allocator *elastic,
2894  coded_lists*& cur_coded_list, ui32& ph_bytes)
2895  {
2896  --bbp->avail_bits;
2897  bbp->tmp |= (bit & 1) << bbp->avail_bits;
2898  if (bbp->avail_bits <= 0)
2899  {
2900  bbp->avail_bits = 8 - (bbp->tmp != 0xFF ? 0 : 1);
2901  bbp->ccl->buf[bbp->ccl->buf_size - bbp->ccl->avail_size] =
2902  (ui8)(bbp->tmp & 0xFF);
2903  bbp->tmp = 0;
2904  --bbp->ccl->avail_size;
2905  if (bbp->ccl->avail_size == 0)
2906  {
2907  bb_expand_buf(bbp, elastic, cur_coded_list->next_list);
2908  cur_coded_list = cur_coded_list->next_list;
2909  ph_bytes += bit_write_buf::needed;
2910  }
2911  }
2912  }
2913 
2915  static inline
2916  void bb_put_bits(bit_write_buf *bbp, ui32 data, int num_bits,
2917  mem_elastic_allocator *elastic,
2918  coded_lists*& cur_coded_list, ui32& ph_bytes)
2919  {
2920 // assert(num_bits <= 32);
2921  for (int i = num_bits - 1; i >= 0; --i)
2922  bb_put_bit(bbp, data >> i, elastic, cur_coded_list, ph_bytes);
2923 // while (num_bits) {
2924 // int tx_bits = num_bits < bbp->avail_bits ? num_bits : bbp->avail_bits;
2925 // bbp->tmp |= (data >> (num_bits - tx_bits)) & ((1 << tx_bits) - 1);
2926 // bbp->avail_bits -= tx_bits;
2927 // if (bbp->avail_bits <= 0)
2928 // {
2929 // bbp->avail_bits = 8 - (bbp->tmp != 0xFF ? 0 : 1);
2930 // bbp->buf[bbp->buf_size - bbp->avail_size] = (ui8)(bbp->tmp & 0xFF);
2931 // bbp->tmp = 0;
2932 // --bbp->avail_size;
2933 // if (bbp->avail_size == 0)
2934 // {
2935 // bb_expand_buf(bbp, elastic, cur_coded_list->next_list);
2936 // cur_coded_list = cur_coded_list->next_list;
2937 // ph_bytes += bit_buffer::needed;
2938 // }
2939 // }
2940 // }
2941  }
2942 
2944  static inline
2946  {
2947  if (bbp->avail_bits < 8) //bits have been written
2948  {
2949  ui8 val = (ui8)(bbp->tmp & 0xFF);
2950  bbp->ccl->buf[bbp->ccl->buf_size - bbp->ccl->avail_size] = val;
2951  --bbp->ccl->avail_size;
2952  }
2953  }
2954 
2956  struct tag_tree
2957  {
2958  void init(ui8* buf, ui32 *lev_idx, ui32 num_levels, size s, int init_val)
2959  {
2960  for (ui32 i = 0; i <= num_levels; ++i) //on extra level
2961  levs[i] = buf + lev_idx[i];
2962  for (ui32 i = num_levels + 1; i < 16; ++i)
2963  levs[i] = (ui8*)INT_MAX; //make it crash on error
2964  width = s.w;
2965  height = s.h;
2966  for (ui32 i = 0; i < num_levels; ++i)
2967  {
2968  ui32 size = 1u << ((num_levels - 1 - i) << 1);
2969  memset(levs[i], init_val, size);
2970  }
2971  *levs[num_levels] = 0;
2972  this->num_levels = num_levels;
2973  }
2974 
2975  ui8* get(ui32 x, ui32 y, ui32 lev)
2976  {
2977  return levs[lev] + (x + y * ((width + (1 << lev) - 1) >> lev));
2978  }
2979 
2981  ui8* levs[16]; // you cannot have this high number of levels
2982  };
2983 
2985  static inline ui32 log2ceil(ui32 x)
2986  {
2987  ui32 t = 31 - count_leading_zeros(x);
2988  return t + (x & (x - 1) ? 1 : 0);
2989  }
2990 
2992  ui32 precinct::prepare_precinct(int tag_tree_size, ui32* lev_idx,
2993  mem_elastic_allocator* elastic)
2994  {
2995  bit_write_buf bb;
2996  coded_lists *cur_coded_list = NULL;
2997  ui32 cb_bytes = 0; //cb_bytes;
2998  ui32 ph_bytes = 0; //precinct header size
2999  int sst = num_bands == 3 ? 1 : 0;
3000  int send = num_bands == 3 ? 4 : 1;
3001  int num_skipped_subbands = 0;
3002  for (int s = sst; s < send; ++s)
3003  {
3004  if (cb_idxs[s].siz.w == 0 || cb_idxs[s].siz.h == 0)
3005  continue;
3006 
3007  ui32 num_levels = 1 +
3008  ojph_max(log2ceil(cb_idxs[s].siz.w), log2ceil(cb_idxs[s].siz.h));
3009 
3010  //create quad trees for inclusion and missing msbs
3011  tag_tree inc_tag, inc_tag_flags, mmsb_tag, mmsb_tag_flags;
3012  inc_tag.init(scratch, lev_idx, num_levels, cb_idxs[s].siz, 255);
3013  inc_tag_flags.init(scratch + tag_tree_size,
3014  lev_idx, num_levels, cb_idxs[s].siz, 0);
3015  mmsb_tag.init(scratch + (tag_tree_size<<1),
3016  lev_idx, num_levels, cb_idxs[s].siz, 255);
3017  mmsb_tag_flags.init(scratch + (tag_tree_size<<1) + tag_tree_size,
3018  lev_idx, num_levels, cb_idxs[s].siz, 0);
3019  ui32 band_width = bands[s].num_blocks.w;
3020  coded_cb_header *cp = bands[s].coded_cbs;
3021  cp += cb_idxs[s].org.x + cb_idxs[s].org.y * band_width;
3022  for (ui32 y = 0; y < cb_idxs[s].siz.h; ++y)
3023  {
3024  for (ui32 x = 0; x < cb_idxs[s].siz.w; ++x)
3025  {
3026  coded_cb_header *p = cp + x;
3027  *inc_tag.get(x, y, 0) = (p->next_coded == NULL); //1 if true
3028  *mmsb_tag.get(x, y, 0) = (ui8)p->missing_msbs;
3029  }
3030  cp += band_width;
3031  }
3032  for (ui32 lev = 1; lev < num_levels; ++lev)
3033  {
3034  ui32 height = (cb_idxs[s].siz.h + (1<<lev) - 1) >> lev;
3035  ui32 width = (cb_idxs[s].siz.w + (1<<lev) - 1) >> lev;
3036  for (ui32 y = 0; y < height; ++y)
3037  {
3038  for (ui32 x = 0; x < width; ++x)
3039  {
3040  ui8 t1, t2;
3041  t1 = ojph_min(*inc_tag.get(x<<1, y<<1, lev-1),
3042  *inc_tag.get((x<<1) + 1, y<<1, lev-1));
3043  t2 = ojph_min(*inc_tag.get(x<<1, (y<<1) + 1, lev-1),
3044  *inc_tag.get((x<<1) + 1, (y<<1) + 1, lev-1));
3045  *inc_tag.get(x, y, lev) = ojph_min(t1, t2);
3046  *inc_tag_flags.get(x, y, lev) = 0;
3047  t1 = ojph_min(*mmsb_tag.get(x<<1, y<<1, lev-1),
3048  *mmsb_tag.get((x<<1) + 1, y<<1, lev-1));
3049  t2 = ojph_min(*mmsb_tag.get(x<<1, (y<<1) + 1, lev-1),
3050  *mmsb_tag.get((x<<1) + 1, (y<<1) + 1, lev-1));
3051  *mmsb_tag.get(x, y, lev) = ojph_min(t1, t2);
3052  *mmsb_tag_flags.get(x, y, lev) = 0;
3053  }
3054  }
3055  }
3056  *inc_tag.get(0,0,num_levels) = 0;
3057  *inc_tag_flags.get(0,0,num_levels) = 0;
3058  *mmsb_tag.get(0,0,num_levels) = 0;
3059  *mmsb_tag_flags.get(0,0,num_levels) = 0;
3060  if (*inc_tag.get(0, 0, num_levels-1) != 0) //empty subband
3061  {
3062  if (coded) //non empty precinct, tag tree top is 0
3063  bb_put_bits(&bb, 0, 1, elastic, cur_coded_list, ph_bytes);
3064  else
3065  ++num_skipped_subbands;
3066  continue;
3067  }
3068  //now we are in a position to code
3069  if (coded == NULL)
3070  {
3071  bb_init(&bb, elastic, cur_coded_list);
3072  coded = cur_coded_list;
3073  //store non empty packet
3074  bb_put_bit(&bb, 1, elastic, cur_coded_list, ph_bytes);
3075 
3076  // if the first one or two subbands are empty (has codeblocks but
3077  // no data in them), we need to code them here.
3078  bb_put_bits(&bb, 0, num_skipped_subbands, elastic, cur_coded_list,
3079  ph_bytes);
3080  num_skipped_subbands = 0; //this line is not needed
3081  }
3082 
3083  ui32 width = cb_idxs[s].siz.w;
3084  ui32 height = cb_idxs[s].siz.h;
3085  for (ui32 y = 0; y < height; ++y)
3086  {
3087  cp = bands[s].coded_cbs;
3088  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3089  for (ui32 x = 0; x < width; ++x, ++cp)
3090  {
3091  //inclusion bits
3092  for (ui32 cur_lev = num_levels; cur_lev > 0; --cur_lev)
3093  {
3094  ui32 levm1 = cur_lev - 1;
3095  //check sent
3096  if (*inc_tag_flags.get(x>>levm1, y>>levm1, levm1) == 0)
3097  {
3098  ui32 skipped = *inc_tag.get(x>>levm1, y>>levm1, levm1);
3099  skipped -= *inc_tag.get(x>>cur_lev, y>>cur_lev, cur_lev);
3100  assert(skipped <= 1); // for HTJ2K, this should 0 or 1
3101  bb_put_bits(&bb, 1 - skipped, 1,
3102  elastic, cur_coded_list, ph_bytes);
3103  *inc_tag_flags.get(x>>levm1, y>>levm1, levm1) = 1;
3104  }
3105  if (*inc_tag.get(x>>levm1, y>>levm1, levm1) > 0)
3106  break;
3107  }
3108 
3109  if (cp->num_passes == 0) //empty codeblock
3110  continue;
3111 
3112  //missing msbs
3113  for (ui32 cur_lev = num_levels; cur_lev > 0; --cur_lev)
3114  {
3115  ui32 levm1 = cur_lev - 1;
3116  //check sent
3117  if (*mmsb_tag_flags.get(x>>levm1, y>>levm1, levm1) == 0)
3118  {
3119  int num_zeros = *mmsb_tag.get(x>>levm1, y>>levm1, levm1);
3120  num_zeros -= *mmsb_tag.get(x>>cur_lev, y>>cur_lev, cur_lev);
3121  bb_put_bits(&bb, 1, num_zeros + 1,
3122  elastic, cur_coded_list, ph_bytes);
3123  *mmsb_tag_flags.get(x>>levm1, y>>levm1, levm1) = 1;
3124  }
3125  }
3126 
3127  //number of coding passes
3128  switch (cp->num_passes)
3129  {
3130  case 3:
3131  bb_put_bits(&bb, 12, 4, elastic, cur_coded_list, ph_bytes);
3132  break;
3133  case 2:
3134  bb_put_bits(&bb, 2, 2, elastic, cur_coded_list, ph_bytes);
3135  break;
3136  case 1:
3137  bb_put_bits(&bb, 0, 1, elastic, cur_coded_list, ph_bytes);
3138  break;
3139  default:
3140  assert(0);
3141  }
3142 
3143  //pass lengths
3144  //either one, two, or three passes, but only one or two lengths
3145  int bits1 = 32 - (int)count_leading_zeros(cp->pass_length[0]);
3146  int extra_bit = cp->num_passes > 2 ? 1 : 0; //for 2nd length
3147  int bits2 = 0;
3148  if (cp->num_passes > 1)
3149  bits2 = 32 - (int)count_leading_zeros(cp->pass_length[1]);
3150  int bits = ojph_max(bits1, bits2 - extra_bit) - 3;
3151  bits = ojph_max(bits, 0);
3152  bb_put_bits(&bb, 0xFFFFFFFEu, bits+1,
3153  elastic, cur_coded_list, ph_bytes);
3154 
3155  bb_put_bits(&bb, cp->pass_length[0], bits+3,
3156  elastic, cur_coded_list, ph_bytes);
3157  if (cp->num_passes > 1)
3158  bb_put_bits(&bb, cp->pass_length[1], bits+3+extra_bit,
3159  elastic, cur_coded_list, ph_bytes);
3160 
3161  cb_bytes += cp->pass_length[0] + cp->pass_length[1];
3162  }
3163  }
3164  }
3165 
3166  if (coded)
3167  {
3168  bb_terminate(&bb);
3169  ph_bytes += cur_coded_list->buf_size - cur_coded_list->avail_size;
3170  }
3171 
3172  return coded ? cb_bytes + ph_bytes : 1;
3173  }
3174 
3177  {
3178  if (coded)
3179  {
3180  //write packet header
3181  coded_lists *ccl = coded;
3182  while (ccl)
3183  {
3184  file->write(ccl->buf, ccl->buf_size - ccl->avail_size);
3185  ccl = ccl->next_list;
3186  }
3187 
3188  //write codeblocks
3189  int sst = num_bands == 3 ? 1 : 0;
3190  int send = num_bands == 3 ? 4 : 1;
3191  for (int s = sst; s < send; ++s)
3192  {
3193  ui32 band_width = bands[s].num_blocks.w;
3194  ui32 width = cb_idxs[s].siz.w;
3195  ui32 height = cb_idxs[s].siz.h;
3196  for (ui32 y = 0; y < height; ++y)
3197  {
3198  coded_cb_header *cp = bands[s].coded_cbs;
3199  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3200  for (ui32 x = 0; x < width; ++x, ++cp)
3201  {
3202  coded_lists *ccl = cp->next_coded;
3203  while (ccl)
3204  {
3205  file->write(ccl->buf, ccl->buf_size - ccl->avail_size);
3206  ccl = ccl->next_list;
3207  }
3208  }
3209  }
3210  }
3211  }
3212  else
3213  {
3214  //empty packet
3215  char buf = 0x00;
3216  file->write(&buf, 1);
3217  }
3218  }
3219 
3222  {
3226  bool unstuff;
3228  };
3229 
3231  static inline
3232  void bb_init(bit_read_buf *bbp, ui32 bytes_left, infile_base* file)
3233  {
3234  bbp->avail_bits = 0;
3235  bbp->file = file;
3236  bbp->bytes_left = bytes_left;
3237  bbp->tmp = 0;
3238  bbp->unstuff = false;
3239  }
3240 
3242  static inline
3244  {
3245  if (bbp->bytes_left > 0)
3246  {
3247  ui32 t = 0;
3248  if (bbp->file->read(&t, 1) != 1)
3249  throw "error reading from file";
3250  bbp->tmp = t;
3251  bbp->avail_bits = 8 - bbp->unstuff;
3252  bbp->unstuff = (t == 0xFF);
3253  --bbp->bytes_left;
3254  return true;
3255  }
3256  else
3257  {
3258  bbp->tmp = 0;
3259  bbp->avail_bits = 8 - bbp->unstuff;
3260  bbp->unstuff = false;
3261  return false;
3262  }
3263  }
3264 
3266  static inline
3267  bool bb_read_bit(bit_read_buf *bbp, ui32& bit)
3268  {
3269  bool result = true;
3270  if (bbp->avail_bits == 0)
3271  result = bb_read(bbp);
3272  bit = (bbp->tmp >> --bbp->avail_bits) & 1;
3273  return result;
3274  }
3275 
3277  static inline
3278  bool bb_read_bits(bit_read_buf *bbp, int num_bits, ui32& bits)
3279  {
3280  assert(num_bits <= 32);
3281 
3282  bits = 0;
3283  bool result = true;
3284  while (num_bits) {
3285  if (bbp->avail_bits == 0)
3286  result = bb_read(bbp);
3287  int tx_bits = ojph_min(bbp->avail_bits, num_bits);
3288  bits <<= tx_bits;
3289  bbp->avail_bits -= tx_bits;
3290  num_bits -= tx_bits;
3291  bits |= (bbp->tmp >> bbp->avail_bits) & ((1 << tx_bits) - 1);
3292  }
3293  return result;
3294  }
3295 
3297  static inline
3298  bool bb_read_chunk(bit_read_buf *bbp, ui32 num_bytes,
3299  coded_lists*& cur_coded_list,
3300  mem_elastic_allocator *elastic)
3301  {
3302  assert(bbp->avail_bits == 0 && bbp->unstuff == false);
3303  ui32 bytes = ojph_min(num_bytes, bbp->bytes_left);
3305  + coded_cb_header::suffix_buf_size, cur_coded_list);
3306  ui32 bytes_read = (ui32)bbp->file->read(
3307  cur_coded_list->buf + coded_cb_header::prefix_buf_size, bytes);
3308  if (num_bytes > bytes_read)
3309  memset(cur_coded_list->buf + coded_cb_header::prefix_buf_size + bytes,
3310  0, num_bytes - bytes_read);
3311  bbp->bytes_left -= bytes_read;
3312  return bytes_read == bytes;
3313  }
3314 
3316  static inline
3318  {
3319  if (bbp->bytes_left >= 2)
3320  {
3321  ui8 marker[2];
3322  if (bbp->file->read(marker, 2) != 2)
3323  throw "error reading from file";
3324  bbp->bytes_left -= 2;
3325  if ((int)marker[0] != (EPH >> 8) || (int)marker[1] != (EPH & 0xFF))
3326  throw "should find EPH, but found something else";
3327  }
3328  }
3329 
3331  static inline
3332  bool bb_terminate(bit_read_buf *bbp, bool uses_eph)
3333  {
3334  bool result = true;
3335  if (bbp->unstuff)
3336  result = bb_read(bbp);
3337  assert(bbp->unstuff == false);
3338  if (uses_eph)
3339  bb_skip_eph(bbp);
3340  bbp->tmp = 0;
3341  bbp->avail_bits = 0;
3342  return result;
3343  }
3344 
3346  static inline
3348  {
3349  if (bbp->bytes_left >= 2)
3350  {
3351  ui8 marker[2];
3352  if (bbp->file->read(marker, 2) != 2)
3353  throw "error reading from file";
3354  if ((int)marker[0] == (SOP >> 8) && (int)marker[1] == (SOP & 0xFF))
3355  {
3356  bbp->bytes_left -= 2;
3357  if (bbp->bytes_left >= 4)
3358  {
3359  ui16 com_len;
3360  if (bbp->file->read(&com_len, 2) != 2)
3361  throw "error reading from file";
3362  com_len = swap_byte(com_len);
3363  if (com_len != 4)
3364  throw "something is wrong with SOP length";
3365  int result =
3366  bbp->file->seek(com_len - 2, infile_base::OJPH_SEEK_CUR);
3367  if (result != 0)
3368  throw "error seeking file";
3369  bbp->bytes_left -= com_len;
3370  }
3371  else
3372  throw "precinct truncated early";
3373  return true;
3374  }
3375  else
3376  {
3377  //put the bytes back
3378  if (bbp->file->seek(-2, infile_base::OJPH_SEEK_CUR) != 0)
3379  throw "error seeking file";
3380  return false;
3381  }
3382  }
3383 
3384  return false;
3385  }
3386 
3388  void precinct::parse(int tag_tree_size, ui32* lev_idx,
3389  mem_elastic_allocator *elastic,
3390  ui32 &data_left, infile_base *file,
3391  bool skipped)
3392  {
3393  assert(data_left > 0);
3394  bit_read_buf bb;
3395  bb_init(&bb, data_left, file);
3396  if (may_use_sop)
3397  bb_skip_sop(&bb);
3398 
3399  int sst = num_bands == 3 ? 1 : 0;
3400  int send = num_bands == 3 ? 4 : 1;
3401  bool empty_packet = true;
3402  for (int s = sst; s < send; ++s)
3403  {
3404  if (cb_idxs[s].siz.w == 0 || cb_idxs[s].siz.h == 0)
3405  continue;
3406 
3407  if (empty_packet) //one bit to check if the packet is empty
3408  {
3409  ui32 bit;
3410  bb_read_bit(&bb, bit);
3411  if (bit == 0) //empty packet
3412  { bb_terminate(&bb, uses_eph); data_left = bb.bytes_left; return; }
3413  empty_packet = false;
3414  }
3415 
3416  ui32 num_levels = 1 +
3417  ojph_max(log2ceil(cb_idxs[s].siz.w), log2ceil(cb_idxs[s].siz.h));
3418 
3419  //create quad trees for inclusion and missing msbs
3420  tag_tree inc_tag, inc_tag_flags, mmsb_tag, mmsb_tag_flags;
3421  inc_tag.init(scratch, lev_idx, num_levels, cb_idxs[s].siz, 0);
3422  *inc_tag.get(0, 0, num_levels) = 0;
3423  inc_tag_flags.init(scratch + tag_tree_size, lev_idx, num_levels,
3424  cb_idxs[s].siz, 0);
3425  *inc_tag_flags.get(0, 0, num_levels) = 0;
3426  mmsb_tag.init(scratch + (tag_tree_size<<1), lev_idx, num_levels,
3427  cb_idxs[s].siz, 0);
3428  *mmsb_tag.get(0, 0, num_levels) = 0;
3429  mmsb_tag_flags.init(scratch + (tag_tree_size<<1) + tag_tree_size,
3430  lev_idx, num_levels, cb_idxs[s].siz, 0);
3431  *mmsb_tag_flags.get(0, 0, num_levels) = 0;
3432 
3433  //
3434  ui32 band_width = bands[s].num_blocks.w;
3435  ui32 width = cb_idxs[s].siz.w;
3436  ui32 height = cb_idxs[s].siz.h;
3437  for (ui32 y = 0; y < height; ++y)
3438  {
3439  coded_cb_header *cp = bands[s].coded_cbs;
3440  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3441  for (ui32 x = 0; x < width; ++x, ++cp)
3442  {
3443  //process inclusion
3444  bool empty_cb = false;
3445  for (ui32 cl = num_levels; cl > 0; --cl)
3446  {
3447  ui32 cur_lev = cl - 1;
3448  empty_cb = *inc_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) == 1;
3449  if (empty_cb)
3450  break;
3451  //check received
3452  if (*inc_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) == 0)
3453  {
3454  ui32 bit;
3455  if (bb_read_bit(&bb, bit) == false)
3456  { data_left = 0; throw "error reading from file p1"; }
3457  empty_cb = (bit == 0);
3458  *inc_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) = (ui8)(1 - bit);
3459  *inc_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) = 1;
3460  }
3461  if (empty_cb)
3462  break;
3463  }
3464 
3465  if (empty_cb)
3466  continue;
3467 
3468  //process missing msbs
3469  ui32 mmsbs = 0;
3470  for (ui32 levp1 = num_levels; levp1 > 0; --levp1)
3471  {
3472  ui32 cur_lev = levp1 - 1;
3473  mmsbs = *mmsb_tag.get(x>>levp1, y>>levp1, levp1);
3474  //check received
3475  if (*mmsb_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) == 0)
3476  {
3477  ui32 bit = 0;
3478  while (bit == 0)
3479  {
3480  if (bb_read_bit(&bb, bit) == false)
3481  { data_left = 0; throw "error reading from file p2"; }
3482  mmsbs += 1 - bit;
3483  }
3484  *mmsb_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) = (ui8)mmsbs;
3485  *mmsb_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) = 1;
3486  }
3487  }
3488 
3489  if (mmsbs > cp->Kmax)
3490  throw "error in parsing a tile header; "
3491  "missing msbs are larger or equal to Kmax. The most likely "
3492  "cause is a corruption in the bitstream.";
3493  cp->missing_msbs = mmsbs;
3494 
3495  //get number of passes
3496  ui32 bit, num_passes = 1;
3497  if (bb_read_bit(&bb, bit) == false)
3498  { data_left = 0; throw "error reading from file p3"; }
3499  if (bit)
3500  {
3501  num_passes = 2;
3502  if (bb_read_bit(&bb, bit) == false)
3503  { data_left = 0; throw "error reading from file p4"; }
3504  if (bit)
3505  {
3506  if (bb_read_bits(&bb, 2, bit) == false)
3507  { data_left = 0; throw "error reading from file p5"; }
3508  num_passes = 3 + bit;
3509  if (bit == 3)
3510  {
3511  if (bb_read_bits(&bb, 5, bit) == false)
3512  { data_left = 0; throw "error reading from file p6"; }
3513  num_passes = 6 + bit;
3514  if (bit == 31)
3515  {
3516  if (bb_read_bits(&bb, 7, bit) == false)
3517  { data_left = 0; throw "error reading from file p7"; }
3518  num_passes = 37 + bit;
3519  }
3520  }
3521  }
3522  }
3523  cp->num_passes = num_passes;
3524 
3525  //parse pass lengths
3526  //for one pass, one length, but for 2 or 3 passes, two lengths
3527  int extra_bit = cp->num_passes > 2 ? 1 : 0;
3528  int bits1 = 3;
3529  bit = 1;
3530  while (bit)
3531  {
3532  if (bb_read_bit(&bb, bit) == false)
3533  { data_left = 0; throw "error reading from file p8"; }
3534  bits1 += bit;
3535  }
3536 
3537  if (bb_read_bits(&bb, bits1, bit) == false)
3538  { data_left = 0; throw "error reading from file p9"; }
3539  cp->pass_length[0] = bit;
3540  if (num_passes > 1)
3541  {
3542  if (bb_read_bits(&bb, bits1 + extra_bit, bit) == false)
3543  { data_left = 0; throw "error reading from file p10"; }
3544  cp->pass_length[1] = bit;
3545  }
3546  }
3547  }
3548  }
3549  bb_terminate(&bb, uses_eph);
3550  //read codeblock data
3551  for (int s = sst; s < send; ++s)
3552  {
3553  ui32 band_width = bands[s].num_blocks.w;
3554  ui32 width = cb_idxs[s].siz.w;
3555  ui32 height = cb_idxs[s].siz.h;
3556  for (ui32 y = 0; y < height; ++y)
3557  {
3558  coded_cb_header *cp = bands[s].coded_cbs;
3559  cp += cb_idxs[s].org.x + (y + cb_idxs[s].org.y) * band_width;
3560  for (ui32 x = 0; x < width; ++x, ++cp)
3561  {
3562  ui32 num_bytes = cp->pass_length[0] + cp->pass_length[1];
3563  if (data_left)
3564  {
3565  if (num_bytes)
3566  {
3567  if (skipped)
3568  { //no need to read
3569  si64 cur_loc = file->tell();
3570  ui32 t = ojph_min(num_bytes, bb.bytes_left);
3571  file->seek(t, infile_base::OJPH_SEEK_CUR);
3572  ui32 bytes_read = (ui32)(file->tell() - cur_loc);
3573  cp->pass_length[0] = cp->pass_length[1] = 0;
3574  bb.bytes_left -= bytes_read;
3575  assert(bytes_read == t || bb.bytes_left == 0);
3576  }
3577  else
3578  {
3579  if (!bb_read_chunk(&bb, num_bytes, cp->next_coded, elastic))
3580  {
3581  //no need to decode a broken codeblock
3582  cp->pass_length[0] = cp->pass_length[1] = 0;
3583  data_left = 0;
3584  }
3585  }
3586  }
3587  }
3588  else
3589  cp->pass_length[0] = cp->pass_length[1] = 0;
3590  }
3591  }
3592  }
3593  data_left = bb.bytes_left;
3594  }
3595 
3597  //
3598  //
3599  //
3600  //
3601  //
3603 
3606  ui32 res_num)
3607  {
3609 
3610  bool empty = ((band_rect.siz.w == 0) || (band_rect.siz.h == 0));
3611  if (empty)
3612  return;
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  num_blocks.w = (tbx1 + (1 << xcb_prime) - 1) >> xcb_prime;
3630  num_blocks.w -= tbx0 >> xcb_prime;
3631  num_blocks.h = (tby1 + (1 << ycb_prime) - 1) >> ycb_prime;
3632  num_blocks.h -= tby0 >> ycb_prime;
3633 
3634  allocator->pre_alloc_obj<codeblock>(num_blocks.w);
3635  //allocate codeblock headers
3637 
3638  for (ui32 i = 0; i < num_blocks.w; ++i)
3639  codeblock::pre_alloc(codestream, nominal);
3640 
3641  //allocate lines
3642  allocator->pre_alloc_obj<line_buf>(1);
3643  //allocate line_buf
3644  ui32 width = band_rect.siz.w + 1;
3645  allocator->pre_alloc_data<si32>(width, 1);
3646  }
3647 
3650  const rect &band_rect,
3651  resolution* res, ui32 res_num,
3652  ui32 subband_num)
3653  {
3656 
3657  this->res_num = res_num;
3658  this->band_num = subband_num;
3659  this->band_rect = band_rect;
3660  this->parent = res;
3661 
3662  const param_cod* cdp = codestream->get_cod();
3663  this->reversible = cdp->is_reversible();
3664  size log_cb = cdp->get_log_block_dims();
3666 
3667  xcb_prime = ojph_min(log_cb.w, log_PP.w - (res_num?1:0));
3668  ycb_prime = ojph_min(log_cb.h, log_PP.h - (res_num?1:0));
3669 
3670  size nominal(1 << xcb_prime, 1 << ycb_prime);
3671 
3672  cur_cb_row = 0;
3673  cur_line = 0;
3674  cur_cb_height = 0;
3676  this->K_max = qcd->get_Kmax(this->res_num, band_num);
3677  if (!reversible)
3678  {
3679  float d = qcd->irrev_get_delta(res_num, subband_num);
3680  d /= (float)(1u << (31 - this->K_max));
3681  delta = d;
3682  delta_inv = (1.0f/d);
3683  }
3684 
3685  this->empty = ((band_rect.siz.w == 0) || (band_rect.siz.h == 0));
3686  if (this->empty)
3687  return;
3688 
3689  ui32 tbx0 = band_rect.org.x;
3690  ui32 tby0 = band_rect.org.y;
3691  ui32 tbx1 = band_rect.org.x + band_rect.siz.w;
3692  ui32 tby1 = band_rect.org.y + band_rect.siz.h;
3693 
3694  num_blocks = size();
3695  num_blocks.w = (tbx1 + (1 << xcb_prime) - 1) >> xcb_prime;
3696  num_blocks.w -= tbx0 >> xcb_prime;
3697  num_blocks.h = (tby1 + (1 << ycb_prime) - 1) >> ycb_prime;
3698  num_blocks.h -= tby0 >> ycb_prime;
3699 
3700  blocks = allocator->post_alloc_obj<codeblock>(num_blocks.w);
3701  //allocate codeblock headers
3702  coded_cb_header *cp = coded_cbs =
3704  memset(coded_cbs, 0, sizeof(coded_cb_header) * num_blocks.area());
3705  for (int i = (int)num_blocks.area(); i > 0; --i, ++cp)
3706  cp->Kmax = K_max;
3707 
3708  ui32 x_lower_bound = (tbx0 >> xcb_prime) << xcb_prime;
3709  ui32 y_lower_bound = (tby0 >> ycb_prime) << ycb_prime;
3710 
3711  size cb_size;
3712  cb_size.h = ojph_min(tby1, y_lower_bound + nominal.h) - tby0;
3713  cur_cb_height = (si32)cb_size.h;
3714  int line_offset = 0;
3715  for (ui32 i = 0; i < num_blocks.w; ++i)
3716  {
3717  ui32 cbx0 = ojph_max(tbx0, x_lower_bound + i * nominal.w);
3718  ui32 cbx1 = ojph_min(tbx1, x_lower_bound + (i + 1) * nominal.w);
3719  cb_size.w = cbx1 - cbx0;
3720  blocks[i].finalize_alloc(codestream, this, nominal, cb_size,
3721  coded_cbs + i, K_max, line_offset);
3722  line_offset += cb_size.w;
3723  }
3724 
3725  //allocate lines
3726  lines = allocator->post_alloc_obj<line_buf>(1);
3727  //allocate line_buf
3728  ui32 width = band_rect.siz.w + 1;
3729  lines->wrap(allocator->post_alloc_data<si32>(width,1),width,1);
3730  }
3731 
3733  void subband::get_cb_indices(const size& num_precincts,
3734  precinct *precincts)
3735  {
3736  if (empty)
3737  return;
3738 
3739  rect res_rect = parent->get_rect();
3740  ui32 trx0 = res_rect.org.x;
3741  ui32 try0 = res_rect.org.y;
3742  ui32 trx1 = res_rect.org.x + res_rect.siz.w;
3743  ui32 try1 = res_rect.org.y + res_rect.siz.h;
3744 
3745  ui32 pc_lft = (res_rect.org.x >> log_PP.w) << log_PP.w;
3746  ui32 pc_top = (res_rect.org.y >> log_PP.h) << log_PP.h;
3747 
3748  ui32 pcx0, pcx1, pcy0, pcy1, shift = (band_num != 0 ? 1 : 0);
3749  ui32 yb, xb, coly = 0, colx = 0;
3750  for (ui32 y = 0; y < num_precincts.h; ++y)
3751  {
3752  pcy0 = ojph_max(try0, pc_top + (y << log_PP.h));
3753  pcy1 = ojph_min(try1, pc_top + ((y + 1) << log_PP.h));
3754  pcy0 = (pcy0 - (band_num >> 1) + (1<<shift) - 1) >> shift;
3755  pcy1 = (pcy1 - (band_num >> 1) + (1<<shift) - 1) >> shift;
3756 
3757  precinct *p = precincts + y * num_precincts.w;
3758  yb = ((pcy1 + (1<<ycb_prime) - 1) >> ycb_prime);
3759  yb -= (pcy0 >> ycb_prime);
3760  colx = 0;
3761 
3762  for (ui32 x = 0; x < num_precincts.w; ++x, ++p)
3763  {
3764  pcx0 = ojph_max(trx0, pc_lft + (x << log_PP.w));
3765  pcx1 = ojph_min(trx1, pc_lft + ((x + 1) << log_PP.w));
3766  pcx0 = (pcx0 - (band_num & 1) + (1<<shift) - 1) >> shift;
3767  pcx1 = (pcx1 - (band_num & 1) + (1<<shift) - 1) >> shift;
3768 
3769  rect *bp = p->cb_idxs + band_num;
3770  xb = ((pcx1 + (1<<xcb_prime) - 1) >> xcb_prime);
3771  xb -= (pcx0 >> xcb_prime);
3772 
3773  bp->org.x = colx;
3774  bp->org.y = coly;
3775  bp->siz.w = xb;
3776  bp->siz.h = yb;
3777 
3778  colx += xb;
3779  }
3780  coly += yb;
3781  }
3782  assert(colx == num_blocks.w && coly == num_blocks.h);
3783  }
3784 
3787  {
3788  if (empty)
3789  return;
3790 
3791  assert(l->pre_size == lines[0].pre_size && l->size == lines[0].size);
3792  si32* t = lines[0].i32;
3793  lines[0].i32 = l->i32;
3794  l->i32 = t;
3795  }
3796 
3799  {
3800  if (empty)
3801  return;
3802 
3803  //push to codeblocks
3804  for (ui32 i = 0; i < num_blocks.w; ++i)
3805  blocks[i].push(lines + 0);
3806  if (++cur_line >= cur_cb_height)
3807  {
3808  for (ui32 i = 0; i < num_blocks.w; ++i)
3809  blocks[i].encode(elastic);
3810 
3811  if (++cur_cb_row < num_blocks.h)
3812  {
3813  cur_line = 0;
3814 
3815  ui32 tbx0 = band_rect.org.x;
3816  ui32 tby0 = band_rect.org.y;
3817  ui32 tbx1 = band_rect.org.x + band_rect.siz.w;
3818  ui32 tby1 = band_rect.org.y + band_rect.siz.h;
3819  size nominal(1 << xcb_prime, 1 << ycb_prime);
3820 
3821  ui32 x_lower_bound = (tbx0 >> xcb_prime) << xcb_prime;
3822  ui32 y_lower_bound = (tby0 >> ycb_prime) << ycb_prime;
3823  ui32 cby0 = y_lower_bound + cur_cb_row * nominal.h;
3824  ui32 cby1 = ojph_min(tby1, cby0 + nominal.h);
3825 
3826  size cb_size;
3827  cb_size.h = cby1 - ojph_max(tby0, cby0);
3828  cur_cb_height = (int)cb_size.h;
3829  for (ui32 i = 0; i < num_blocks.w; ++i)
3830  {
3831  ui32 cbx0 = ojph_max(tbx0, x_lower_bound + i * nominal.w);
3832  ui32 cbx1 = ojph_min(tbx1, x_lower_bound + (i + 1) * nominal.w);
3833  cb_size.w = cbx1 - cbx0;
3834  blocks[i].recreate(cb_size,
3835  coded_cbs + i + cur_cb_row * num_blocks.w);
3836  }
3837  }
3838  }
3839  }
3840 
3843  {
3844  if (empty)
3845  return lines;
3846 
3847  //pull from codeblocks
3848  if (--cur_line <= 0)
3849  {
3850  if (cur_cb_row < num_blocks.h)
3851  {
3852  ui32 tbx0 = band_rect.org.x;
3853  ui32 tby0 = band_rect.org.y;
3854  ui32 tbx1 = band_rect.org.x + band_rect.siz.w;
3855  ui32 tby1 = band_rect.org.y + band_rect.siz.h;
3856  size nominal(1 << xcb_prime, 1 << ycb_prime);
3857 
3858  ui32 x_lower_bound = (tbx0 >> xcb_prime) << xcb_prime;
3859  ui32 y_lower_bound = (tby0 >> ycb_prime) << ycb_prime;
3860  ui32 cby0 = ojph_max(tby0, y_lower_bound + cur_cb_row * nominal.h);
3861  ui32 cby1 = ojph_min(tby1, y_lower_bound+(cur_cb_row+1)*nominal.h);
3862 
3863  size cb_size;
3864  cb_size.h = cby1 - cby0;
3865  cur_line = cur_cb_height = (int)cb_size.h;
3866  for (ui32 i = 0; i < num_blocks.w; ++i)
3867  {
3868  ui32 cbx0 = ojph_max(tbx0, x_lower_bound + i * nominal.w);
3869  ui32 cbx1 = ojph_min(tbx1, x_lower_bound + (i + 1) * nominal.w);
3870  cb_size.w = cbx1 - cbx0;
3871  blocks[i].recreate(cb_size,
3872  coded_cbs + i + cur_cb_row * num_blocks.w);
3873  blocks[i].decode();
3874  }
3875  ++cur_cb_row;
3876  }
3877  }
3878 
3879  assert(cur_line >= 0);
3880 
3881  //pull from codeblocks
3882  for (ui32 i = 0; i < num_blocks.w; ++i)
3883  blocks[i].pull_line(lines + 0);
3884 
3885  return lines;
3886  }
3887 
3888 
3890  //
3891  //
3892  //
3893  //
3894  //
3896 
3899 
3902  const size& nominal)
3903  {
3905 
3906  ui32 stride = (nominal.w + 7) & ~7U; // a multiple of 8
3907  allocator->pre_alloc_data<ui32>(nominal.h * stride, 0);
3908  }
3909 
3912  subband *parent, const size& nominal,
3913  const size& cb_size,
3914  coded_cb_header* coded_cb,
3915  ui32 K_max, int line_offset)
3916  {
3918 
3919  this->stride = (nominal.w + 7) & ~7U; // a multiple of 8
3920  this->buf_size = this->stride * nominal.h;
3921  this->buf = allocator->post_alloc_data<ui32>(this->buf_size, 0);
3922 
3923  this->nominal_size = nominal;
3924  this->cb_size = cb_size;
3925  this->parent = parent;
3926  this->line_offset = line_offset;
3927  this->cur_line = 0;
3928  this->delta = parent->get_delta();
3929  this->delta_inv = 1.0f / this->delta;
3930  this->K_max = K_max;
3931  for (int i = 0; i < 8; ++i)
3932  this->max_val[i] = 0;
3934  this->reversible = cod.is_reversible();
3935  this->resilient = codestream->is_resilient();
3937  this->zero_block = false;
3938  this->coded_cb = coded_cb;
3939 
3940 #if !defined(OJPH_ENABLE_WASM_SIMD) || !defined(OJPH_EMSCRIPTEN)
3941 
3945  if (reversible) {
3948  }
3949  else
3950  {
3953  }
3954 
3955 #ifndef OJPH_DISABLE_INTEL_SIMD
3956 
3959 
3962  if (reversible) {
3965  }
3966  else {
3969  }
3970  }
3971 
3974 
3975 
3978 
3981  if (reversible) {
3984  }
3985  else {
3988  }
3989  }
3990 
3991 #endif // !OJPH_DISABLE_INTEL_SIMD
3992 
3993 #else // OJPH_ENABLE_WASM_SIMD
3994 
3998  if (reversible) {
4001  }
4002  else {
4005  }
4006 
4007 #endif // !OJPH_ENABLE_WASM_SIMD
4008 
4009  }
4010 
4013  {
4014  // convert to sign and magnitude and keep max_val
4015  const si32 *sp = line->i32 + line_offset;
4016  ui32 *dp = buf + cur_line * stride;
4017  tx_to_cb(sp, dp, K_max, delta_inv, cb_size.w, max_val);
4018  ++cur_line;
4019  }
4020 
4023  {
4024  ui32 mv = find_max_val(max_val);
4025  if (mv >= 1u<<(31 - K_max))
4026  {
4027  coded_cb->missing_msbs = K_max - 1;
4028  assert(coded_cb->missing_msbs > 0);
4029  assert(coded_cb->missing_msbs < K_max);
4030  coded_cb->num_passes = 1;
4031 
4034  elastic, coded_cb->next_coded);
4035  }
4036  }
4037 
4039  void codeblock::recreate(const size &cb_size, coded_cb_header* coded_cb)
4040  {
4041  assert(cb_size.h * stride <= buf_size && cb_size.w <= stride);
4042  this->cb_size = cb_size;
4043  this->coded_cb = coded_cb;
4044  this->cur_line = 0;
4045  for (int i = 0; i < 8; ++i)
4046  this->max_val[i] = 0;
4047  this->zero_block = false;
4048  }
4049 
4052  {
4053  if (coded_cb->pass_length[0] > 0 && coded_cb->num_passes > 0 &&
4054  coded_cb->next_coded != NULL)
4055  {
4056  bool result = decode_cb(
4061 
4062  if (result == false)
4063  {
4064  if (resilient == true)
4065  zero_block = true;
4066  else
4067  OJPH_ERROR(0x000300A1, "Error decoding a codeblock\n");
4068  }
4069  }
4070  else
4071  zero_block = true;
4072  }
4073 
4075  void codeblock::gen_mem_clear(void* addr, size_t count)
4076  {
4077  ui32* p = (ui32*)addr;
4078  for (size_t i = 0; i < count; i += 4, p += 1)
4079  *p = 0;
4080  }
4081 
4083  void codeblock::gen_rev_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max,
4084  float delta_inv, ui32 count,
4085  ui32* max_val)
4086  {
4088  ui32 shift = 31 - K_max;
4089  // convert to sign and magnitude and keep max_val
4090  ui32 tmax = *max_val;
4091  si32 *p = (si32*)sp;
4092  for (ui32 i = count; i > 0; --i)
4093  {
4094  si32 v = *p++;
4095  ui32 sign = v >= 0 ? 0 : 0x80000000;
4096  ui32 val = (ui32)(v >= 0 ? v : -v);
4097  val <<= shift;
4098  *dp++ = sign | val;
4099  tmax |= val; // it is more efficient to use or than max
4100  }
4101  *max_val = tmax;
4102  }
4103 
4105  void codeblock::gen_irv_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max,
4106  float delta_inv, ui32 count,
4107  ui32* max_val)
4108  {
4109  ojph_unused(K_max);
4110  //quantize and convert to sign and magnitude and keep max_val
4111  ui32 tmax = *max_val;
4112  float *p = (float*)sp;
4113  for (ui32 i = count; i > 0; --i)
4114  {
4115  float v = *p++;
4116  si32 t = ojph_trunc(v * delta_inv);
4117  ui32 sign = t >= 0 ? 0 : 0x80000000;
4118  ui32 val = (ui32)(t >= 0 ? t : -t);
4119  *dp++ = sign | val;
4120  tmax |= val; // it is more efficient to use or than max
4121  }
4122  *max_val = tmax;
4123  }
4124 
4126  void codeblock::gen_rev_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max,
4127  float delta, ui32 count)
4128  {
4129  ojph_unused(delta);
4130  ui32 shift = 31 - K_max;
4131  //convert to sign and magnitude
4132  si32 *p = (si32*)dp;
4133  for (ui32 i = count; i > 0; --i)
4134  {
4135  ui32 v = *sp++;
4136  si32 val = (v & 0x7FFFFFFF) >> shift;
4137  *p++ = (v & 0x80000000) ? -val : val;
4138  }
4139  }
4140 
4142  void codeblock::gen_irv_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max,
4143  float delta, ui32 count)
4144  {
4145  ojph_unused(K_max);
4146  //convert to sign and magnitude
4147  float *p = (float*)dp;
4148  for (ui32 i = count; i > 0; --i)
4149  {
4150  ui32 v = *sp++;
4151  float val = (float)(v & 0x7FFFFFFF) * delta;
4152  *p++ = (v & 0x80000000) ? -val : val;
4153  }
4154  }
4155 
4158  {
4159  si32 *dp = line->i32 + line_offset;
4160  if (!zero_block)
4161  {
4162  //convert to sign and magnitude
4163  const ui32 *sp = buf + cur_line * stride;
4164  tx_from_cb(sp, dp, K_max, delta, cb_size.w);
4165  }
4166  else
4167  mem_clear(dp, cb_size.w * sizeof(*dp));
4168  ++cur_line;
4169  assert(cur_line <= cb_size.h);
4170  }
4171 
4172  }
4173 }
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
bool(* cb_decoder_fun)(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)
static void gen_mem_clear(void *addr, size_t count)
static void gen_rev_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
static ui32 gen_find_max_val(ui32 *addr)
static void pre_alloc(codestream *codestream, const size &nominal)
static void gen_irv_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
void push(line_buf *line)
static cb_decoder_fun decode_cb
void encode(mem_elastic_allocator *elastic)
void recreate(const size &cb_size, coded_cb_header *coded_cb)
static void gen_irv_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
void finalize_alloc(codestream *codestream, subband *parent, const size &nominal, const size &cb_size, coded_cb_header *coded_cb, ui32 K_max, int tbx0)
static void gen_rev_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
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)
bool ojph_decode_codeblock_wasm(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(* cnvrt_float_to_si32)(const float *sp, si32 *dp, float mul, ui32 width)
Definition: ojph_colour.cpp:66
ui32 avx2_find_max_val(ui32 *address)
void avx2_irv_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
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)
bool ojph_decode_codeblock_ssse3(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(* cnvrt_si32_to_float_shftd)(const si32 *sp, float *dp, float mul, ui32 width)
Definition: ojph_colour.cpp:54
void(* ict_forward)(const float *r, const float *g, const float *b, float *y, float *cb, float *cr, ui32 repeat)
Definition: ojph_colour.cpp:80
void sse2_irv_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
void(* rev_horz_wvlt_bwd_tx)(line_buf *dst, line_buf *lsrc, line_buf *hsrc, ui32 width, bool even)
void avx_mem_clear(void *addr, size_t count)
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:85
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:75
void wasm_irv_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
void init_wavelet_transform_functions()
void avx2_rev_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
void init_colour_transform_functions()
Definition: ojph_colour.cpp:92
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:62
void wasm_irv_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
void sse2_irv_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
void sse_mem_clear(void *addr, size_t count)
static ui32 log2ceil(ui32 x)
void wasm_rev_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
void sse2_rev_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
void sse2_rev_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
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:58
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:70
void wasm_mem_clear(void *addr, size_t count)
ui32 sse2_find_max_val(ui32 *address)
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 wasm_rev_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
void avx2_rev_tx_from_cb(const ui32 *sp, void *dp, ui32 K_max, float delta, ui32 count)
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 avx2_irv_tx_to_cb(const void *sp, ui32 *dp, ui32 K_max, float delta_inv, ui32 count, ui32 *max_val)
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)
ui32 wasm_find_max_val(ui32 *address)
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
@ X86_CPU_EXT_LEVEL_AVX2
Definition: ojph_arch.h:83
@ X86_CPU_EXT_LEVEL_AVX
Definition: ojph_arch.h:82
@ X86_CPU_EXT_LEVEL_SSE2
Definition: ojph_arch.h:77
@ X86_CPU_EXT_LEVEL_SSE
Definition: ojph_arch.h:76
@ X86_CPU_EXT_LEVEL_SSSE3
Definition: ojph_arch.h:79
@ 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
int get_cpu_ext_level()
Definition: ojph_arch.cpp:182
static si32 ojph_trunc(float val)
Definition: ojph_arch.h:162
@ OJPH_PN_BROADCAST
@ OJPH_PN_UNDEFINED
static ui32 count_leading_zeros(ui32 val)
Definition: ojph_arch.h:109
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