OpenJPH
Open-source implementation of JPEG2000 Part-15
Loading...
Searching...
No Matches
ojph_codestream_local.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_local.cpp
34// Author: Aous Naman
35// Date: 28 August 2019
36//***************************************************************************/
37
38
39#include <climits>
40#include <cmath>
41
42#include "ojph_mem.h"
43#include "ojph_params.h"
45#include "ojph_tile.h"
46
49
50namespace ojph {
51
52 namespace local
53 {
54
57 : precinct_scratch(NULL), allocator(NULL), elastic_alloc(NULL)
58 {
59 tiles = NULL;
60 lines = NULL;
61 comp_size = NULL;
62 recon_comp_size = NULL;
63 allocator = NULL;
64 outfile = NULL;
65 infile = NULL;
66
67 num_comps = 0;
69 planar = -1;
72 need_tlm = false;
73
74 cur_comp = 0;
75 cur_line = 0;
76 cur_tile_row = 0;
77 resilient = false;
79
81
82 atk = atk_store;
83 atk[0].init_irv97();
84 atk[0].link(atk_store + 1);
85 atk[1].init_rev53();
86 atk[1].link(atk_store + 2);
87
89 elastic_alloc = new mem_elastic_allocator(1048576); //1 megabyte
90
93 }
94
97 {
98 if (allocator)
99 delete allocator;
100 if (elastic_alloc)
101 delete elastic_alloc;
102 }
103
106 {
112 if (num_tiles.area() > 65535)
113 OJPH_ERROR(0x00030011, "number of tiles cannot exceed 65535");
114
115 //allocate tiles
117
118 ui32 num_tileparts = 0;
119 point index;
120 rect tile_rect, recon_tile_rect;
121 ui32 ds = 1 << skipped_res_for_recon;
122 for (index.y = 0; index.y < num_tiles.h; ++index.y)
123 {
124 ui32 y0 = sz.get_tile_offset().y
125 + index.y * sz.get_tile_size().h;
126 ui32 y1 = y0 + sz.get_tile_size().h; //end of tile
127
128 tile_rect.org.y = ojph_max(y0, sz.get_image_offset().y);
129 tile_rect.siz.h =
130 ojph_min(y1, sz.get_image_extent().y) - tile_rect.org.y;
131
132 recon_tile_rect.org.y = ojph_max(ojph_div_ceil(y0, ds),
134 recon_tile_rect.siz.h = ojph_min(ojph_div_ceil(y1, ds),
136 - recon_tile_rect.org.y;
137
138 for (index.x = 0; index.x < num_tiles.w; ++index.x)
139 {
140 ui32 x0 = sz.get_tile_offset().x
141 + index.x * sz.get_tile_size().w;
142 ui32 x1 = x0 + sz.get_tile_size().w;
143
144 tile_rect.org.x = ojph_max(x0, sz.get_image_offset().x);
145 tile_rect.siz.w =
146 ojph_min(x1, sz.get_image_extent().x) - tile_rect.org.x;
147
148 recon_tile_rect.org.x = ojph_max(ojph_div_ceil(x0, ds),
150 recon_tile_rect.siz.w = ojph_min(ojph_div_ceil(x1, ds),
152 - recon_tile_rect.org.x;
153
154 ui32 tps = 0; // number of tileparts for this tile
155 tile::pre_alloc(this, tile_rect, recon_tile_rect, tps);
156 num_tileparts += tps;
157 }
158 }
159
160 //allocate lines
161 //These lines are used by codestream to exchange data with external
162 // world
165 allocator->pre_alloc_obj<size>(num_comps); //for *comp_size
166 allocator->pre_alloc_obj<size>(num_comps); //for *recon_comp_size
167 for (ui32 i = 0; i < num_comps; ++i)
169
170 //allocate tlm
171 if (outfile != NULL && need_tlm)
173
174 //precinct scratch buffer
175 ui32 num_decomps = cod.get_num_decompositions();
176 size log_cb = cod.get_log_block_dims();
177
178 size ratio;
179 for (ui32 r = 0; r <= num_decomps; ++r)
180 {
181 size log_PP = cod.get_log_precinct_size(r);
182 ratio.w = ojph_max(ratio.w, log_PP.w - ojph_min(log_cb.w, log_PP.w));
183 ratio.h = ojph_max(ratio.h, log_PP.h - ojph_min(log_cb.h, log_PP.h));
184 }
185 ui32 max_ratio = ojph_max(ratio.w, ratio.h);
186 max_ratio = 1 << max_ratio;
187 // assuming that we have a hierarchy of n levels.
188 // This needs 4/3 times the area, rounded up
189 // (rounding up leaves one extra entry).
190 // This exta entry is necessary
191 // We need 4 such tables. These tables store
192 // 1. missing msbs and 2. their flags,
193 // 3. number of layers and 4. their flags
195 4 * ((max_ratio * max_ratio * 4 + 2) / 3);
196
198 }
199
202 {
203 allocator->alloc();
204
205 //precinct scratch buffer
208
209 //get tiles
210 tiles = this->allocator->post_alloc_obj<tile>((size_t)num_tiles.area());
211
212 ui32 num_tileparts = 0;
213 point index;
214 rect tile_rect;
216 for (index.y = 0; index.y < num_tiles.h; ++index.y)
217 {
218 ui32 y0 = sz.get_tile_offset().y
219 + index.y * sz.get_tile_size().h;
220 ui32 y1 = y0 + sz.get_tile_size().h; //end of tile
221
222 tile_rect.org.y = ojph_max(y0, sz.get_image_offset().y);
223 tile_rect.siz.h =
224 ojph_min(y1, sz.get_image_extent().y) - tile_rect.org.y;
225
226 ui32 offset = 0;
227 for (index.x = 0; index.x < num_tiles.w; ++index.x)
228 {
229 ui32 x0 = sz.get_tile_offset().x
230 + index.x * sz.get_tile_size().w;
231 ui32 x1 = x0 + sz.get_tile_size().w;
232
233 tile_rect.org.x = ojph_max(x0, sz.get_image_offset().x);
234 tile_rect.siz.w =
235 ojph_min(x1, sz.get_image_extent().x) - tile_rect.org.x;
236
237 ui32 tps = 0; // number of tileparts for this tile
238 ui32 idx = index.y * num_tiles.w + index.x;
239 tiles[idx].finalize_alloc(this, tile_rect, idx, offset, tps);
240 num_tileparts += tps;
241 }
242 }
243
244 //allocate lines
245 //These lines are used by codestream to exchange data with external
246 // world
247 this->num_comps = sz.get_num_components();
252 for (ui32 i = 0; i < this->num_comps; ++i)
253 {
254 comp_size[i].w = siz.get_width(i);
255 comp_size[i].h = siz.get_height(i);
256 ui32 cw = siz.get_recon_width(i);
257 recon_comp_size[i].w = cw;
259 lines[i].wrap(allocator->post_alloc_data<si32>(cw, 0), cw, 0);
260 }
261
262 cur_comp = 0;
263 cur_line = 0;
264
265 //allocate tlm
266 if (outfile != NULL && need_tlm)
267 tlm.init(num_tileparts,
269 }
270
271
274 {
275 //two possibilities lossy single tile or lossless
276 //For the following code, we use the least strict profile
277 ojph::param_siz sz(&siz);
278 ojph::param_cod cd(&cod);
279 bool reversible = cd.is_reversible();
280 bool imf2k = !reversible, imf4k = !reversible, imf8k = !reversible;
281 bool imf2kls = reversible, imf4kls = reversible, imf8kls = reversible;
282
283 if (reversible)
284 {
285 point ext = sz.get_image_extent();
286 if (ext.x <= 2048 && ext.y <= 1556)
287 imf2kls &= true;
288 if (ext.x <= 4096 && ext.y <= 3112)
289 imf4kls &= true;
290 if (ext.x <= 8192 && ext.y <= 6224)
291 imf8kls &= true;
292
293 if (!imf2kls && !imf4kls && !imf8kls)
294 OJPH_ERROR(0x000300C1,
295 "Image dimensions do not meet any of the lossless IMF profiles");
296 }
297 else
298 {
299 point ext = sz.get_image_extent();
300 if (ext.x <= 2048 && ext.y <= 1556)
301 imf2k &= true;
302 if (ext.x <= 4096 && ext.y <= 3112)
303 imf4k &= true;
304 if (ext.x <= 8192 && ext.y <= 6224)
305 imf8k &= true;
306
307 if (!imf2k && !imf4k && !imf8k)
308 OJPH_ERROR(0x000300C2,
309 "Image dimensions do not meet any of the lossy IMF profiles");
310 }
311
312
313 if (sz.get_image_offset().x != 0 || sz.get_image_offset().y != 0)
314 OJPH_ERROR(0x000300C3,
315 "For IMF profile, image offset (XOsiz, YOsiz) has to be 0.");
316 if (sz.get_tile_offset().x != 0 || sz.get_tile_offset().y != 0)
317 OJPH_ERROR(0x000300C4,
318 "For IMF profile, tile offset (XTOsiz, YTOsiz) has to be 0.");
319 if (sz.get_num_components() > 3)
320 OJPH_ERROR(0x000300C5,
321 "For IMF profile, the number of components has to be less "
322 " or equal to 3");
323 bool test_ds1 = true, test_ds2 = true;
324 for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
325 {
326 point downsamping = sz.get_downsampling(i);
327 test_ds1 &= downsamping.y == 1;
328 test_ds2 &= downsamping.y == 1;
329
330 test_ds1 &= downsamping.x == 1;
331 if (i == 1 || i == 2)
332 test_ds2 &= downsamping.x == 2;
333 else
334 test_ds2 &= downsamping.x == 1;
335 }
336 if (!test_ds1 && !test_ds2)
337 OJPH_ERROR(0x000300C6,
338 "For IMF profile, either no component downsampling is used,"
339 " or the x-dimension of the 2nd and 3rd components is downsampled"
340 " by 2.");
341
342 bool test_bd = true;
343 for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
344 {
345 ui32 bit_depth = sz.get_bit_depth(i);
346 bool is_signed = sz.is_signed(i);
347 test_bd &= bit_depth >= 8 && bit_depth <= 16 && is_signed == false;
348 }
349 if (!test_bd)
350 OJPH_ERROR(0x000300C7,
351 "For IMF profile, compnent bit_depth has to be between"
352 " 8 and 16 bits inclusively, and the samples must be unsigned");
353
354 if (cd.get_log_block_dims().w != 5 || cd.get_log_block_dims().h != 5)
355 OJPH_ERROR(0x000300C8,
356 "For IMF profile, codeblock dimensions are restricted."
357 " Use \"-block_size {32,32}\" at the commandline");
358
359 ui32 num_decomps = cd.get_num_decompositions();
360 bool test_pz = cd.get_log_precinct_size(0).w == 7
361 && cd.get_log_precinct_size(0).h == 7;
362 for (ui32 i = 1; i <= num_decomps; ++i)
363 test_pz = cd.get_log_precinct_size(i).w == 8
364 && cd.get_log_precinct_size(i).h == 8;
365 if (!test_pz)
366 OJPH_ERROR(0x000300C9,
367 "For IMF profile, precinct sizes are restricted."
368 " Use \"-precincts {128,128},{256,256}\" at the commandline");
369
371 OJPH_ERROR(0x000300CA,
372 "For IMF profile, the CPRL progression order must be used."
373 " Use \"-prog_order CPRL\".");
374
375 imf2k &= num_decomps <= 5;
376 imf2kls &= num_decomps <= 5;
377 imf4k &= num_decomps <= 6;
378 imf4kls &= num_decomps <= 6;
379 imf8k &= num_decomps <= 7;
380 imf8kls &= num_decomps <= 7;
381
382 if (num_decomps == 0 ||
383 (!imf2k && !imf4k && !imf8k && !imf2kls && !imf4kls && !imf8kls))
384 OJPH_ERROR(0x000300CB,
385 "Number of decompositions does not match the IMF profile"
386 " dictated by wavelet reversibility and image dimensions.");
387
388 ui32 tiles_w = sz.get_image_extent().x;
389 tiles_w = ojph_div_ceil(tiles_w, sz.get_tile_size().w);
390 ui32 tiles_h = sz.get_image_extent().y;
391 tiles_h = ojph_div_ceil(tiles_h, sz.get_tile_size().h);
392 ui32 total_tiles = tiles_w * tiles_h;
393
394 if (total_tiles > 1)
395 {
396 if (!reversible)
397 OJPH_ERROR(0x000300CC,
398 "Lossy IMF profile must have one tile.");
399
400 size tt = sz.get_tile_size();
401 imf2kls &= (tt.w == 1024 && tt.h == 1024);
402 imf2kls &= (tt.w >= 1024 && num_decomps <= 4)
403 || (tt.w >= 2048 && num_decomps <= 5);
404 imf4kls &= (tt.w == 1024 && tt.h == 1024)
405 || (tt.w == 2048 && tt.h == 2048);
406 imf4kls &= (tt.w >= 1024 && num_decomps <= 4)
407 || (tt.w >= 2048 && num_decomps <= 5)
408 || (tt.w >= 4096 && num_decomps <= 6);
409 imf8kls &= (tt.w == 1024 && tt.h == 1024)
410 || (tt.w == 2048 && tt.h == 2048)
411 || (tt.w == 4096 && tt.h == 4096);
412 imf8kls &= (tt.w >= 1024 && num_decomps <= 4)
413 || (tt.w >= 2048 && num_decomps <= 5)
414 || (tt.w >= 4096 && num_decomps <= 6)
415 || (tt.w >= 8192 && num_decomps <= 7);
416 if (!imf2kls && !imf4kls && !imf8kls)
417 OJPH_ERROR(0x000300CD,
418 "Number of decompositions does not match the IMF profile"
419 " dictated by wavelet reversibility and image dimensions and"
420 " tiles.");
421 }
422
423 need_tlm = true;
426 {
428 OJPH_WARN(0x000300C1,
429 "In IMF profile, tile part divisions at the component level must be "
430 "employed, while at the resolution level is not allowed. "
431 "This has been corrected.");
432 }
433 }
434
437 {
438 ojph::param_siz sz(&siz);
439 ojph::param_cod cd(&cod);
440
441 if (sz.get_image_offset().x != 0 || sz.get_image_offset().y != 0)
442 OJPH_ERROR(0x000300B1,
443 "For broadcast profile, image offset (XOsiz, YOsiz) has to be 0.");
444 if (sz.get_tile_offset().x != 0 || sz.get_tile_offset().y != 0)
445 OJPH_ERROR(0x000300B2,
446 "For broadcast profile, tile offset (XTOsiz, YTOsiz) has to be 0.");
447 if (sz.get_num_components() > 4)
448 OJPH_ERROR(0x000300B3,
449 "For broadcast profile, the number of components has to be less "
450 " or equal to 4");
451 bool test_ds1 = true, test_ds2 = true;
452 for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
453 {
454 point downsamping = sz.get_downsampling(i);
455 test_ds1 &= downsamping.y == 1;
456 test_ds2 &= downsamping.y == 1;
457
458 test_ds1 &= downsamping.x == 1;
459 if (i == 1 || i == 2)
460 test_ds2 &= downsamping.x == 2;
461 else
462 test_ds2 &= downsamping.x == 1;
463 }
464 if (!test_ds1 && !test_ds2)
465 OJPH_ERROR(0x000300B4,
466 "For broadcast profile, either no component downsampling is used,"
467 " or the x-dimension of the 2nd and 3rd components is downsampled"
468 " by 2.");
469
470 bool test_bd = true;
471 for (ojph::ui32 i = 0; i < sz.get_num_components(); ++i)
472 {
473 ui32 bit_depth = sz.get_bit_depth(i);
474 bool is_signed = sz.is_signed(i);
475 test_bd &= bit_depth >= 8 && bit_depth <= 12 && is_signed == false;
476 }
477 if (!test_bd)
478 OJPH_ERROR(0x000300B5,
479 "For broadcast profile, compnent bit_depth has to be between"
480 " 8 and 12 bits inclusively, and the samples must be unsigned");
481
482 ui32 num_decomps = cd.get_num_decompositions();
483 if (num_decomps == 0 || num_decomps > 5)
484 OJPH_ERROR(0x000300B6,
485 "For broadcast profile, number of decompositions has to be between"
486 "1 and 5 inclusively.");
487
488 if (cd.get_log_block_dims().w < 5 || cd.get_log_block_dims().w > 7)
489 OJPH_ERROR(0x000300B7,
490 "For broadcast profile, codeblock dimensions are restricted such"
491 " that codeblock width has to be either 32, 64, or 128.");
492
493 if (cd.get_log_block_dims().h < 5 || cd.get_log_block_dims().h > 7)
494 OJPH_ERROR(0x000300B8,
495 "For broadcast profile, codeblock dimensions are restricted such"
496 " that codeblock height has to be either 32, 64, or 128.");
497
498 bool test_pz = cd.get_log_precinct_size(0).w == 7
499 && cd.get_log_precinct_size(0).h == 7;
500 for (ui32 i = 1; i <= num_decomps; ++i)
501 test_pz = cd.get_log_precinct_size(i).w == 8
502 && cd.get_log_precinct_size(i).h == 8;
503 if (!test_pz)
504 OJPH_ERROR(0x000300B9,
505 "For broadcast profile, precinct sizes are restricted."
506 " Use \"-precincts {128,128},{256,256}\" at the commandline");
507
509 OJPH_ERROR(0x000300BA,
510 "For broadcast profile, the CPRL progression order must be used."
511 " Use \"-prog_order CPRL\".");
512
513 ui32 tiles_w = sz.get_image_extent().x;
514 tiles_w = ojph_div_ceil(tiles_w, sz.get_tile_size().w);
515 ui32 tiles_h = sz.get_image_extent().y;
516 tiles_h = ojph_div_ceil(tiles_h, sz.get_tile_size().h);
517 ui32 total_tiles = tiles_w * tiles_h;
518
519 if (total_tiles != 1 && total_tiles != 4)
520 OJPH_ERROR(0x000300BB,
521 "The broadcast profile can only have 1 or 4 tiles");
522
523 need_tlm = true;
526 {
528 OJPH_WARN(0x000300B1,
529 "In BROADCAST profile, tile part divisions at the component level "
530 "must be employed, while at the resolution level is not allowed. "
531 "This has been corrected.");
532 }
533 }
534
537 const comment_exchange* comments,
538 ui32 num_comments)
539 {
540 //finalize
547 if (profile == OJPH_PN_IMF)
549 else if (profile == OJPH_PN_BROADCAST)
551
553 if ((po == OJPH_PO_LRCP || po == OJPH_PO_RLCP) &&
555 {
557 OJPH_INFO(0x00030021,
558 "For LRCP and RLCP progression orders, tilepart divisions at the "
559 "component level, means that we have a tilepart for every "
560 "resolution and component.\n");
561 }
563 {
564 tilepart_div &= ~OJPH_TILEPART_COMPONENTS;
565 OJPH_WARN(0x00030021,
566 "For RPCL progression, having tilepart divisions at the component "
567 "level means a tilepart for every precinct, which does not "
568 "make sense, since we can have no more than 255 tile parts. This "
569 "has been corrected by removing tilepart divisions at the component "
570 "level.");
571 }
572 if (po == OJPH_PO_PCRL && tilepart_div != 0)
573 {
574 tilepart_div = 0;
575 OJPH_WARN(0x00030022,
576 "For PCRL progression, having tilepart divisions at the component "
577 "level or the resolution level means a tile part for every "
578 "precinct, which does not make sense, since we can have no more "
579 "than 255 tile parts. This has been corrected by removing tilepart "
580 "divisions; use another progression if you want tileparts.");
581 }
583 {
584 tilepart_div &= ~OJPH_TILEPART_RESOLUTIONS;
585 OJPH_WARN(0x00030023,
586 "For CPRL progression, having tilepart divisions at the resolution "
587 "level means a tile part for every precinct, which does not "
588 "make sense, since we can have no more than 255 tile parts. This "
589 "has been corrected by removing tilepart divisions at the "
590 "resolution level.");
591 }
592
593 if (planar == -1) //not initialized
595 else if (planar == 0) //interleaved is chosen
596 {
597 }
598 else if (planar == 1) //plannar is chosen
599 {
600 if (cod.is_employing_color_transform() == true)
601 OJPH_ERROR(0x00030021,
602 "the planar interface option cannot be used when colour "
603 "transform is employed");
604 }
605 else
606 assert(0);
607
608 assert(this->outfile == NULL);
609 this->outfile = file;
610 this->pre_alloc();
611 this->finalize_alloc();
612
614 if (file->write(&t, 2) != 2)
615 OJPH_ERROR(0x00030022, "Error writing to file");
616
617 if (!siz.write(file))
618 OJPH_ERROR(0x00030023, "Error writing to file");
619
620 if (!cap.write(file))
621 OJPH_ERROR(0x00030024, "Error writing to file");
622
623 if (!cod.write(file))
624 OJPH_ERROR(0x00030025, "Error writing to file");
625
626 if (!cod.write_coc(file, num_comps))
627 OJPH_ERROR(0x0003002E, "Error writing to file");
628
629 if (!qcd.write(file))
630 OJPH_ERROR(0x00030026, "Error writing to file");
631
632 if (!qcd.write_qcc(file, num_comps))
633 OJPH_ERROR(0x0003002D, "Error writing to file");
634
635 if (!nlt.write(file))
636 OJPH_ERROR(0x00030027, "Error writing to file");
637
638 char buf[] = " OpenJPH Ver "
642 size_t len = strlen(buf);
644 *(ui16*)(buf + 2) = swap_byte((ui16)(len - 2));
645 //1 for General use (IS 8859-15:1999 (Latin) values)
646 *(ui16*)(buf + 4) = swap_byte((ui16)(1));
647 if (file->write(buf, len) != len)
648 OJPH_ERROR(0x00030028, "Error writing to file");
649
650 if (comments != NULL) {
651 for (ui32 i = 0; i < num_comments; ++i)
652 {
654 if (file->write(&t, 2) != 2)
655 OJPH_ERROR(0x00030029, "Error writing to file");
656 t = swap_byte((ui16)(comments[i].len + 4));
657 if (file->write(&t, 2) != 2)
658 OJPH_ERROR(0x0003002A, "Error writing to file");
659 //1 for General use (IS 8859-15:1999 (Latin) values)
660 t = swap_byte(comments[i].Rcom);
661 if (file->write(&t, 2) != 2)
662 OJPH_ERROR(0x0003002B, "Error writing to file");
663 if (file->write(comments[i].data, comments[i].len)!=comments[i].len)
664 OJPH_ERROR(0x0003002C, "Error writing to file");
665 }
666 }
667 }
668
670 static
671 int find_marker(infile_base *f, const ui16* char_list, int list_len)
672 {
673 //returns the marker index in char_list, or -1
674 while (!f->eof())
675 {
676 ui8 new_char;
677 size_t num_bytes = f->read(&new_char, 1);
678 if (num_bytes != 1)
679 return -1;
680 if (new_char == 0xFF)
681 {
682 size_t num_bytes = f->read(&new_char, 1);
683
684 if (num_bytes != 1)
685 return -1;
686
687 for (int i = 0; i < list_len; ++i)
688 if (new_char == (char_list[i] & 0xFF))
689 return i;
690 }
691 }
692 return -1;
693 }
694
696 static
697 int skip_marker(infile_base *file, const char *marker,
698 const char *msg, int msg_level, bool resilient)
699 {
700 ojph_unused(marker);
701 ui16 com_len;
702 if (file->read(&com_len, 2) != 2)
703 {
704 if (resilient)
705 return -1;
706 else
707 OJPH_ERROR(0x00030041, "error reading marker");
708 }
709 com_len = swap_byte(com_len);
710 file->seek(com_len - 2, infile_base::OJPH_SEEK_CUR);
711 if (msg != NULL && msg_level != OJPH_MSG_LEVEL::NO_MSG)
712 {
713 if (msg_level == OJPH_MSG_LEVEL::INFO)
714 {
715 OJPH_INFO(0x00030001, "%s", msg);
716 }
717 else if (msg_level == OJPH_MSG_LEVEL::WARN)
718 {
719 OJPH_WARN(0x00030001, "%s", msg);
720 }
721 else if (msg_level == OJPH_MSG_LEVEL::ERROR)
722 {
723 OJPH_ERROR(0x00030001, "%s", msg);
724 }
725 else // there is the option of ALL_MSG but it should not be used here
726 assert(0);
727 }
728 return 0;
729 }
730
733 {
734 ui16 marker_list[20] = { SOC, SIZ, CAP, PRF, CPF, COD, COC, QCD, QCC,
735 RGN, POC, PPM, TLM, PLM, CRG, COM, DFS, ATK, NLT, SOT };
736 find_marker(file, marker_list, 1); //find SOC
737 find_marker(file, marker_list + 1, 1); //find SIZ
738 siz.read(file);
739 int marker_idx = 0;
740 int received_markers = 0; //check that COD, & QCD received
741 while (true)
742 {
743 marker_idx = find_marker(file, marker_list + 2, 18);
744 if (marker_idx == 0)
745 cap.read(file);
746 else if (marker_idx == 1)
747 //Skipping PRF marker segment; this should not cause any issues
748 skip_marker(file, "PRF", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
749 else if (marker_idx == 2)
750 //Skipping CPF marker segment; this should not cause any issues
751 skip_marker(file, "CPF", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
752 else if (marker_idx == 3)
753 {
754 cod.read(file);
755 received_markers |= 1;
757 int num_qlayers = c.get_num_layers();
758 if (num_qlayers != 1)
759 OJPH_ERROR(0x00030053, "The current implementation supports "
760 "1 quality layer only. This codestream has %d quality layers",
761 num_qlayers);
762 }
763 else if (marker_idx == 4)
764 {
766 p->read_coc(file, siz.get_num_components(), &cod);
767 if (p->get_comp_idx() >= siz.get_num_components())
768 OJPH_INFO(0x00030056, "The codestream carries a COC marker "
769 "segment for a component indexed by %d, which is more than the "
770 "allowed index number, since the codestream has %d components",
771 p->get_comp_idx(), num_comps);
773 if (p != q && p->get_comp_idx() == q->get_comp_idx())
774 OJPH_ERROR(0x00030057, "The codestream has two COC marker "
775 "segments for one component of index %d", p->get_comp_idx());
776 }
777 else if (marker_idx == 5)
778 {
779 qcd.read(file);
780 received_markers |= 2;
781 }
782 else if (marker_idx == 6)
783 {
785 p->read_qcc(file, siz.get_num_components());
786 if (p->get_comp_idx() >= siz.get_num_components())
787 OJPH_ERROR(0x00030054, "The codestream carries a QCC marker "
788 "segment for a component indexed by %d, which is more than the "
789 "allowed index number, since the codestream has %d components",
790 p->get_comp_idx(), num_comps);
792 if (p != q && p->get_comp_idx() == q->get_comp_idx())
793 OJPH_ERROR(0x00030055, "The codestream has two QCC marker "
794 "segments for one component of index %d", p->get_comp_idx());
795 }
796 else if (marker_idx == 7)
797 skip_marker(file, "RGN", "RGN is not supported yet",
798 OJPH_MSG_LEVEL::WARN, false);
799 else if (marker_idx == 8)
800 skip_marker(file, "POC", "POC is not supported yet",
801 OJPH_MSG_LEVEL::WARN, false);
802 else if (marker_idx == 9)
803 skip_marker(file, "PPM", "PPM is not supported yet",
804 OJPH_MSG_LEVEL::WARN, false);
805 else if (marker_idx == 10)
806 //Skipping TLM marker segment; this should not cause any issues
807 skip_marker(file, "TLM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
808 else if (marker_idx == 11)
809 //Skipping PLM marker segment; this should not cause any issues
810 skip_marker(file, "PLM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
811 else if (marker_idx == 12)
812 //Skipping CRG marker segment;
813 skip_marker(file, "CRG", "CRG has been ignored; CRG is related to"
814 " where the Cb and Cr colour components are co-sited or located"
815 " with respect to the Y' luma component. Perhaps, it is better"
816 " to get the individual components and assemble the samples"
817 " according to your needs",
818 OJPH_MSG_LEVEL::INFO, false);
819 else if (marker_idx == 13)
820 skip_marker(file, "COM", NULL, OJPH_MSG_LEVEL::NO_MSG, false);
821 else if (marker_idx == 14)
822 dfs.read(file);
823 else if (marker_idx == 15)
824 atk[2].read(file);
825 else if (marker_idx == 16)
826 nlt.read(file);
827 else if (marker_idx == 17)
828 break;
829 else
830 OJPH_ERROR(0x00030051, "File ended before finding a tile segment");
831 }
832
834 siz.link(&cod);
835 if (dfs.exists())
836 siz.link(&dfs);
837
838 if (received_markers != 3)
839 OJPH_ERROR(0x00030052, "markers error, COD and QCD are required");
840
841 this->infile = file;
843 }
844
847 ui32 skipped_res_for_recon)
848 {
850 OJPH_ERROR(0x000300A1,
851 "skipped_resolution for data %d must be equal or smaller than "
852 " skipped_resolution for reconstruction %d\n",
855 OJPH_ERROR(0x000300A2,
856 "skipped_resolution for data %d must be smaller than "
857 " the number of decomposition levels %d\n",
859
860 this->skipped_res_for_read = skipped_res_for_read;
861 this->skipped_res_for_recon = skipped_res_for_recon;
863 }
864
867 {
868 if (infile != NULL)
869 OJPH_ERROR(0x000300A3, "Codestream resilience must be enabled before"
870 " reading file headers.\n");
871 this->resilient = true;
872 }
873
876 {
877 this->pre_alloc();
878 this->finalize_alloc();
879
880 while (true)
881 {
882 param_sot sot;
883 if (sot.read(infile, resilient))
884 {
885 ui64 tile_start_location = (ui64)infile->tell();
886
887 if (sot.get_tile_index() > (int)num_tiles.area())
888 {
889 if (resilient)
890 OJPH_INFO(0x00030061, "wrong tile index")
891 else
892 OJPH_ERROR(0x00030061, "wrong tile index")
893 }
894
895 if (sot.get_tile_part_index())
896 { //tile part
897 if (sot.get_num_tile_parts() &&
899 {
900 if (resilient)
901 OJPH_INFO(0x00030062,
902 "error in tile part number, should be smaller than total"
903 " number of tile parts")
904 else
905 OJPH_ERROR(0x00030062,
906 "error in tile part number, should be smaller than total"
907 " number of tile parts")
908 }
909
910 bool sod_found = false;
911 ui16 other_tile_part_markers[7] = { SOT, POC, PPT, PLT, COM,
912 NLT, SOD };
913 while (true)
914 {
915 int marker_idx = 0;
916 int result = 0;
917 marker_idx = find_marker(infile, other_tile_part_markers + 1, 6);
918 if (marker_idx == 0)
919 result = skip_marker(infile, "POC",
920 "POC marker segment in a tile is not supported yet",
922 else if (marker_idx == 1)
923 result = skip_marker(infile, "PPT",
924 "PPT marker segment in a tile is not supported yet",
926 else if (marker_idx == 2)
927 //Skipping PLT marker segment;this should not cause any issues
928 result = skip_marker(infile, "PLT", NULL,
930 else if (marker_idx == 3)
931 result = skip_marker(infile, "COM", NULL,
933 else if (marker_idx == 4)
934 result = skip_marker(infile, "NLT",
935 "NLT marker in tile is not supported yet",
937 else if (marker_idx == 5)
938 {
939 sod_found = true;
940 break;
941 }
942
943 if (marker_idx == -1) //marker not found
944 {
945 if (resilient)
946 OJPH_INFO(0x00030063,
947 "File terminated early before start of data is found"
948 " for tile indexed %d and tile part %d",
950 else
951 OJPH_ERROR(0x00030063,
952 "File terminated early before start of data is found"
953 " for tile indexed %d and tile part %d",
955 break;
956 }
957 if (result == -1) //file terminated during marker seg. skipping
958 {
959 if (resilient)
960 OJPH_INFO(0x00030064,
961 "File terminated during marker segment skipping")
962 else
963 OJPH_ERROR(0x00030064,
964 "File terminated during marker segment skipping")
965 break;
966 }
967 }
968 if (sod_found)
970 tile_start_location);
971 }
972 else
973 { //first tile part
974 bool sod_found = false;
975 ui16 first_tile_part_markers[12] = { SOT, COD, COC, QCD, QCC, RGN,
976 POC, PPT, PLT, COM, NLT, SOD };
977 while (true)
978 {
979 int marker_idx = 0;
980 int result = 0;
981 marker_idx = find_marker(infile, first_tile_part_markers+1, 11);
982 if (marker_idx == 0)
983 result = skip_marker(infile, "COD",
984 "COD marker segment in a tile is not supported yet",
986 else if (marker_idx == 1)
987 result = skip_marker(infile, "COC",
988 "COC marker segment in a tile is not supported yet",
990 else if (marker_idx == 2)
991 result = skip_marker(infile, "QCD",
992 "QCD marker segment in a tile is not supported yet",
994 else if (marker_idx == 3)
995 result = skip_marker(infile, "QCC",
996 "QCC marker segment in a tile is not supported yet",
998 else if (marker_idx == 4)
999 result = skip_marker(infile, "RGN",
1000 "RGN marker segment in a tile is not supported yet",
1002 else if (marker_idx == 5)
1003 result = skip_marker(infile, "POC",
1004 "POC marker segment in a tile is not supported yet",
1006 else if (marker_idx == 6)
1007 result = skip_marker(infile, "PPT",
1008 "PPT marker segment in a tile is not supported yet",
1010 else if (marker_idx == 7)
1011 //Skipping PLT marker segment;this should not cause any issues
1012 result = skip_marker(infile, "PLT", NULL,
1014 else if (marker_idx == 8)
1015 result = skip_marker(infile, "COM", NULL,
1017 else if (marker_idx == 9)
1018 result = skip_marker(infile, "NLT",
1019 "PPT marker segment in a tile is not supported yet",
1021 else if (marker_idx == 10)
1022 {
1023 sod_found = true;
1024 break;
1025 }
1026
1027 if (marker_idx == -1) //marker not found
1028 {
1029 if (resilient)
1030 OJPH_INFO(0x00030065,
1031 "File terminated early before start of data is found"
1032 " for tile indexed %d and tile part %d",
1034 else
1035 OJPH_ERROR(0x00030065,
1036 "File terminated early before start of data is found"
1037 " for tile indexed %d and tile part %d",
1039 break;
1040 }
1041 if (result == -1) //file terminated during marker seg. skipping
1042 {
1043 if (resilient)
1044 OJPH_INFO(0x00030066,
1045 "File terminated during marker segment skipping")
1046 else
1047 OJPH_ERROR(0x00030066,
1048 "File terminated during marker segment skipping")
1049 break;
1050 }
1051 }
1052 if (sod_found)
1054 tile_start_location);
1055 }
1056 }
1057
1058 // check the next marker; either SOT or EOC,
1059 // if something is broken, just an end of file
1060 ui16 next_markers[2] = { SOT, EOC };
1061 int marker_idx = find_marker(infile, next_markers, 2);
1062 if (marker_idx == -1)
1063 {
1064 OJPH_INFO(0x00030067, "File terminated early");
1065 break;
1066 }
1067 else if (marker_idx == 0)
1068 ;
1069 else if (marker_idx == 1)
1070 break;
1071 }
1072 }
1073
1075 void codestream::set_planar(int planar)
1076 {
1077 this->planar = planar;
1078 }
1079
1081 void codestream::set_profile(const char *s)
1082 {
1083 size_t len = strlen(s);
1084 if (len == 9 && strncmp(s, OJPH_PN_STRING_BROADCAST, 9) == 0)
1086 else if (len == 3 && strncmp(s, OJPH_PN_STRING_IMF, 3) == 0)
1088 else
1089 OJPH_ERROR(0x000300A1, "unkownn or unsupported profile");
1090 }
1091
1094 {
1095 tilepart_div = value;
1096 }
1097
1100 {
1101 need_tlm = needed;
1102 }
1103
1106 {
1107 si32 repeat = (si32)num_tiles.area();
1108 for (si32 i = 0; i < repeat; ++i)
1109 tiles[i].prepare_for_flush();
1110 if (need_tlm)
1111 { //write tlm
1112 for (si32 i = 0; i < repeat; ++i)
1113 tiles[i].fill_tlm(&tlm);
1114 tlm.write(outfile);
1115 }
1116 for (si32 i = 0; i < repeat; ++i)
1117 tiles[i].flush(outfile);
1119 if (!outfile->write(&t, 2))
1120 OJPH_ERROR(0x00030071, "Error writing to file");
1121 }
1122
1125 {
1126 if (infile)
1127 infile->close();
1128 if (outfile)
1129 outfile->close();
1130 }
1131
1134 {
1135 if (line)
1136 {
1137 bool success = false;
1138 while (!success)
1139 {
1140 success = true;
1141 for (ui32 i = 0; i < num_tiles.w; ++i)
1142 {
1143 ui32 idx = i + cur_tile_row * num_tiles.w;
1144 if ((success &= tiles[idx].push(line, cur_comp)) == false)
1145 break;
1146 }
1147 cur_tile_row += success == false ? 1 : 0;
1148 if (cur_tile_row >= num_tiles.h)
1149 cur_tile_row = 0;
1150 }
1151
1152 if (planar) //process one component at a time
1153 {
1154 if (++cur_line >= comp_size[cur_comp].h)
1155 {
1156 cur_line = 0;
1157 cur_tile_row = 0;
1158 if (++cur_comp >= num_comps)
1159 {
1160 next_component = 0;
1161 return NULL;
1162 }
1163 }
1164 }
1165 else //process all component for a line
1166 {
1167 if (++cur_comp >= num_comps)
1168 {
1169 cur_comp = 0;
1170 if (++cur_line >= comp_size[cur_comp].h)
1171 {
1172 next_component = 0;
1173 return NULL;
1174 }
1175 }
1176 }
1177 }
1178
1179 next_component = cur_comp;
1180 return this->lines + cur_comp;
1181 }
1182
1185 {
1186 bool success = false;
1187 while (!success)
1188 {
1189 success = true;
1190 for (ui32 i = 0; i < num_tiles.w; ++i)
1191 {
1192 ui32 idx = i + cur_tile_row * num_tiles.w;
1193 if ((success &= tiles[idx].pull(lines + cur_comp, cur_comp)) == false)
1194 break;
1195 }
1196 cur_tile_row += success == false ? 1 : 0;
1197 if (cur_tile_row >= num_tiles.h)
1198 cur_tile_row = 0;
1199 }
1200 comp_num = cur_comp;
1201
1202 if (planar) //process one component at a time
1203 {
1204 if (++cur_line >= recon_comp_size[cur_comp].h)
1205 {
1206 cur_line = 0;
1207 cur_tile_row = 0;
1208 if (cur_comp++ >= num_comps)
1209 {
1210 comp_num = 0;
1211 return NULL;
1212 }
1213 }
1214 }
1215 else //process all component for a line
1216 {
1217 if (++cur_comp >= num_comps)
1218 {
1219 cur_comp = 0;
1220 if (cur_line++ >= recon_comp_size[cur_comp].h)
1221 {
1222 comp_num = 0;
1223 return NULL;
1224 }
1225 }
1226 }
1227
1228 return lines + comp_num;
1229 }
1230
1231 }
1232}
virtual bool eof()=0
virtual void close()
Definition ojph_file.h:245
virtual si64 tell()=0
virtual size_t read(void *ptr, size_t size)=0
void wrap(T *buffer, size_t num_ele, ui32 pre_size)
line_buf * exchange(line_buf *line, ui32 &next_component)
void restrict_input_resolution(ui32 skipped_res_for_data, ui32 skipped_res_for_recon)
mem_elastic_allocator * elastic_alloc
mem_fixed_allocator * allocator
void write_headers(outfile_base *file, const comment_exchange *comments, ui32 num_comments)
void read_headers(infile_base *file)
line_buf * pull(ui32 &comp_num)
void finalize_alloc(codestream *codestream, const rect &tile_rect, ui32 tile_idx, ui32 &offset, ui32 &num_tileparts)
static void pre_alloc(codestream *codestream, const rect &tile_rect, const rect &recon_tile_rect, ui32 &num_tileparts)
Definition ojph_tile.cpp:56
void parse_tile_header(const param_sot &sot, infile_base *file, const ui64 &tile_start_location)
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:93
virtual size_t write(const void *ptr, size_t size)=0
int get_progression_order() const
ui32 get_num_decompositions() const
size get_log_block_dims() const
bool is_reversible() const
size get_log_precinct_size(ui32 level_num) const
int get_num_layers() const
point get_image_extent() const
ui32 get_bit_depth(ui32 comp_num) const
point get_image_offset() const
size get_tile_size() const
point get_downsampling(ui32 comp_num) const
point get_tile_offset() const
bool is_signed(ui32 comp_num) const
ui32 get_num_components() const
static int find_marker(infile_base *f, const ui16 *char_list, int list_len)
static int skip_marker(infile_base *file, const char *marker, const char *msg, int msg_level, bool resilient)
void init_wavelet_transform_functions()
void init_colour_transform_functions()
static ui16 swap_byte(ui16 t)
const char OJPH_PN_STRING_BROADCAST[]
const char OJPH_PN_STRING_IMF[]
uint64_t ui64
Definition ojph_defs.h:56
uint16_t ui16
Definition ojph_defs.h:52
@ OJPH_TILEPART_RESOLUTIONS
@ OJPH_TILEPART_NO_DIVISIONS
@ OJPH_TILEPART_COMPONENTS
@ OJPH_PN_BROADCAST
@ OJPH_PN_UNDEFINED
int32_t si32
Definition ojph_defs.h:55
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,...)
MACROs to insert file and line number for info, warning, and error.
#define OJPH_ERROR(t,...)
#define OJPH_WARN(t,...)
#define OPENJPH_VERSION_PATCH
#define OPENJPH_VERSION_MAJOR
#define OPENJPH_VERSION_MINOR
bool read(infile_base *file)
void link(param_atk *next)
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)
const param_cod * get_coc(ui32 comp_idx) const
bool write_coc(outfile_base *file, ui32 num_comps)
bool is_employing_color_transform() const
void read(infile_base *file)
size get_log_precinct_size(ui32 res_num) const
void read_coc(infile_base *file, ui32 num_comps, param_cod *top_cod)
void update_atk(const param_atk *atk)
param_cod * add_coc_object(ui32 comp_idx)
bool read(infile_base *file)
bool write(outfile_base *file) const
void read(infile_base *file)
void check_validity(param_siz &siz)
bool write_qcc(outfile_base *file, ui32 num_comps)
void read_qcc(infile_base *file, ui32 num_comps)
void check_validity(const param_siz &siz, const param_cod &cod)
bool write(outfile_base *file)
void read(infile_base *file)
param_qcd * add_qcc_object(ui32 comp_idx)
param_qcd * get_qcc(ui32 comp_idx)
void set_skipped_resolutions(ui32 skipped_resolutions)
ui32 get_recon_height(ui32 comp_num) const
void check_validity(const param_cod &cod)
bool write(outfile_base *file)
ui32 get_height(ui32 comp_num) const
void link(const param_cod *cod)
void read(infile_base *file)
ui32 get_width(ui32 comp_num) const
ui32 get_recon_width(ui32 comp_num) const
bool read(infile_base *file, bool resilient)
bool write(outfile_base *file)
void init(ui32 num_pairs, Ttlm_Ptlm_pair *store)
point org
Definition ojph_base.h:66
ui64 area() const
Definition ojph_base.h:53