OpenJPH
Open-source implementation of JPEG2000 Part-15
Loading...
Searching...
No Matches
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"
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
53namespace ojph {
54
56 //
57 //
58 //
59 //
60 //
62
65 {
66 if (state) delete state;
67 }
68
74
80
86
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
122
125 {
126 state->read_headers(file);
127 }
128
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
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;
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),
271 recon_tile_rect.siz.h = ojph_min(ojph_div_ceil(y1, 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),
287 recon_tile_rect.siz.w = ojph_min(ojph_div_ceil(x1, 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),
376 recon_tile_rect.siz.h = ojph_min(ojph_div_ceil(y1, 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),
393 recon_tile_rect.siz.w = ojph_min(ojph_div_ceil(x1, 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);
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 }
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
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",
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",
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",
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",
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)
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
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
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
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;
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
1346 comps = allocator->post_alloc_obj<tile_comp>(num_comps);
1347 comp_rects = allocator->post_alloc_obj<rect>(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;
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 }
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
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);
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;
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;
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);
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);
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();
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();
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();
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();
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
2440
2441 ++cur_line;
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();
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 {
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);
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);
2507 width, horz_even);
2508 bands[1].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();
2523 }
2524 else
2525 {
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
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);
2551 width, horz_even);
2552 bands[1].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();
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();
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
2597
2598 ++cur_line;
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
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
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,
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
2805 {
2806 cur_precinct_loc.x = 0;
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,
2823 {
2824 cur_precinct_loc.x = 0;
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,
2842 {
2843 cur_precinct_loc.x = 0;
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
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;
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 {
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
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
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 {
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 {
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);
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
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)
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
3701 //allocate codeblock headers
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,
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,
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;
4018 ++cur_line;
4019 }
4020
4023 {
4025 if (mv >= 1u<<(31 - K_max))
4026 {
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 {
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 {
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 {
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)
param_qcd * access_qcd(ui32 comp_num)
mem_elastic_allocator * get_elastic_alloc()
line_buf * exchange(line_buf *line, ui32 &next_component)
mem_fixed_allocator * get_allocator()
void restrict_input_resolution(ui32 skipped_res_for_data, ui32 skipped_res_for_recon)
mem_elastic_allocator * elastic_alloc
mem_fixed_allocator * allocator
void read_headers(infile_base *file)
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)
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_data(size_t num_ele, ui32 pre_size)
Definition ojph_mem.h:89
T * post_alloc_obj(size_t num_ele)
Definition ojph_mem.h:96
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)
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)
void(* ict_forward)(const float *r, const float *g, const float *b, float *y, float *cb, float *cr, ui32 repeat)
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)
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)
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)
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()
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)
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)
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)
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
uint16_t ui16
Definition ojph_defs.h:52
int get_cpu_ext_level()
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,...)
#define OJPH_ERROR(t,...)
#define OJPH_WARN(t,...)
#define OPENJPH_VERSION_PATCH
#define OPENJPH_VERSION_MAJOR
#define OPENJPH_VERSION_MINOR
coded_lists * next_list
Definition ojph_mem.h:170
float * f32
Definition ojph_mem.h:156
void wrap(T *buffer, size_t num_ele, ui32 pre_size)
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
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)
point org
Definition ojph_base.h:66
ui64 area() const
Definition ojph_base.h:53