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