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_params_local.h 34 // Author: Aous Naman 35 // Date: 28 August 2019 36 //***************************************************************************/ 37 38 39 #ifndef OJPH_PARAMS_LOCAL_H 40 #define OJPH_PARAMS_LOCAL_H 41 42 #include <cstring> 43 #include <cassert> 44 45 #include "ojph_defs.h" 46 #include "ojph_arch.h" 47 #include "ojph_message.h" 48 49 namespace ojph { 50 51 //////////////////////////////////////////////////////////////////////////// 52 class outfile_base; 53 class infile_base; 54 55 //////////////////////////////////////////////////////////////////////////// 56 enum PROGRESSION_ORDER : si32 57 { 58 OJPH_PO_LRCP = 0, 59 OJPH_PO_RLCP = 1, 60 OJPH_PO_RPCL = 2, 61 OJPH_PO_PCRL = 3, 62 OJPH_PO_CPRL = 4 63 }; 64 65 //////////////////////////////////////////////////////////////////////////// 66 const char OJPH_PO_STRING_LRCP[] = "LRCP"; 67 const char OJPH_PO_STRING_RLCP[] = "RLCP"; 68 const char OJPH_PO_STRING_RPCL[] = "RPCL"; 69 const char OJPH_PO_STRING_PCRL[] = "PCRL"; 70 const char OJPH_PO_STRING_CPRL[] = "CPRL"; 71 72 //////////////////////////////////////////////////////////////////////////// 73 enum OJPH_PROFILE_NUM : si32 74 { 75 OJPH_PN_UNDEFINED = 0, 76 OJPH_PN_PROFILE0 = 1, 77 OJPH_PN_PROFILE1 = 2, 78 OJPH_PN_CINEMA2K = 3, 79 OJPH_PN_CINEMA4K = 4, 80 OJPH_PN_CINEMAS2K = 5, 81 OJPH_PN_CINEMAS4K = 6, 82 OJPH_PN_BROADCAST = 7, 83 OJPH_PN_IMF = 8 84 }; 85 86 //////////////////////////////////////////////////////////////////////////// 87 const char OJPH_PN_STRING_PROFILE0[] = "PROFILE0"; 88 const char OJPH_PN_STRING_PROFILE1[] = "PROFILE1"; 89 const char OJPH_PN_STRING_CINEMA2K[] = "CINEMA2K"; 90 const char OJPH_PN_STRING_CINEMA4K[] = "CINEMA4K"; 91 const char OJPH_PN_STRING_CINEMAS2K[] = "CINEMAS2K"; 92 const char OJPH_PN_STRING_CINEMAS4K[] = "CINEMAS4K"; 93 const char OJPH_PN_STRING_BROADCAST[] = "BROADCAST"; 94 const char OJPH_PN_STRING_IMF[] = "IMF"; 95 96 namespace local { 97 98 ////////////////////////////////////////////////////////////////////////// 99 enum JP2K_MARKER : ui16 100 { 101 SOC = 0xFF4F, //start of codestream (required) 102 CAP = 0xFF50, //extended capability 103 SIZ = 0xFF51, //image and tile size (required) 104 COD = 0xFF52, //coding style default (required) 105 TLM = 0xFF55, //tile-part lengths 106 PRF = 0xFF56, //profile 107 PLM = 0xFF57, //packet length, main header 108 PLT = 0xFF58, //packet length, tile-part header 109 CPF = 0xFF59, //corresponding profile values 110 QCD = 0xFF5C, //qunatization default (required) 111 QCC = 0xFF5D, //quantization component 112 COM = 0xFF64, //comment 113 SOT = 0xFF90, //start of tile-part 114 SOP = 0xFF91, //start of packet 115 EPH = 0xFF92, //end of packet 116 SOD = 0xFF93, //start of data 117 EOC = 0xFFD9, //end of codestream (required) 118 119 COC = 0xFF53, //coding style component 120 RGN = 0xFF5E, //region of interest 121 POC = 0xFF5F, //progression order change 122 PPM = 0xFF60, //packed packet headers, main header 123 PPT = 0xFF61, //packed packet headers, tile-part header 124 CRG = 0xFF63, //component registration 125 }; 126 127 ////////////////////////////////////////////////////////////////////////// 128 // 129 // 130 // 131 // 132 // 133 ////////////////////////////////////////////////////////////////////////// 134 struct siz_comp_info 135 { 136 ui8 SSiz; 137 ui8 XRsiz; 138 ui8 YRsiz; 139 }; 140 141 ////////////////////////////////////////////////////////////////////////// 142 struct param_siz 143 { 144 friend ::ojph::param_siz; 145 146 public: param_sizparam_siz147 param_siz() 148 { 149 memset(this, 0, sizeof(param_siz)); 150 cptr = store; 151 old_Csiz = 4; 152 Rsiz = 0x4000; //for jph, bit 14 of Rsiz is 1 153 } 154 ~param_sizparam_siz155 ~param_siz() 156 { 157 if (cptr != store) delete[] cptr; 158 } 159 set_num_componentsparam_siz160 void set_num_components(int num_comps) 161 { 162 Csiz = (ui16)num_comps; 163 if (Csiz > old_Csiz) 164 { 165 if (cptr != store) 166 delete[] cptr; 167 cptr = new siz_comp_info[num_comps]; 168 old_Csiz = Csiz; 169 } 170 memset(cptr, 0, sizeof(local::siz_comp_info) * num_comps); 171 } 172 set_comp_infoparam_siz173 void set_comp_info(si32 comp_num, const point& downsampling, 174 si32 bit_depth, bool is_signed) 175 { 176 assert(comp_num < Csiz); 177 assert(downsampling.x != 0 && downsampling.y != 0); 178 cptr[comp_num].SSiz = (ui8)(bit_depth - 1 + (is_signed ? 0x80 : 0)); 179 cptr[comp_num].XRsiz = (ui8)downsampling.x; 180 cptr[comp_num].YRsiz = (ui8)downsampling.y; 181 } 182 check_validityparam_siz183 void check_validity() 184 { 185 if (XTsiz == 0 && YTsiz == 0) 186 { XTsiz = Xsiz - XOsiz; YTsiz = Ysiz - YOsiz; } 187 if (Xsiz == 0 || Ysiz == 0 || XTsiz == 0 || YTsiz == 0) 188 OJPH_ERROR(0x00040001, 189 "You cannot set image extent nor tile size to zero"); 190 if (XTOsiz > XOsiz || YTOsiz > YOsiz) 191 OJPH_ERROR(0x00040002, 192 "tile offset has to be smaller than image offset"); 193 if (XTsiz + XTOsiz <= XOsiz || YTsiz + YTOsiz <= YOsiz) 194 OJPH_ERROR(0x00040003, 195 "the top left tile must intersect with the image"); 196 } 197 get_num_componentsparam_siz198 ui16 get_num_components() const { return Csiz; } get_bit_depthparam_siz199 si32 get_bit_depth(si32 comp_num) const 200 { 201 assert(comp_num < Csiz); 202 return (cptr[comp_num].SSiz & 0x7F) + 1; 203 } is_signedparam_siz204 bool is_signed(si32 comp_num) const 205 { 206 assert(comp_num < Csiz); 207 return (cptr[comp_num].SSiz & 0x80) != 0; 208 } get_downsamplingparam_siz209 point get_downsampling(si32 comp_num) const 210 { 211 assert(comp_num < Csiz); 212 return point(cptr[comp_num].XRsiz, cptr[comp_num].YRsiz); 213 } 214 215 bool write(outfile_base *file); 216 void read(infile_base *file); 217 set_skipped_resolutionsparam_siz218 void set_skipped_resolutions(int skipped_resolutions) 219 { 220 this->skipped_resolutions = skipped_resolutions; 221 } get_widthparam_siz222 ui32 get_width(int comp_num) const 223 { 224 assert(comp_num < get_num_components()); 225 ui32 ds = (ui32)cptr[comp_num].XRsiz; 226 ui32 t = ojph_div_ceil(Xsiz, ds) - ojph_div_ceil(XOsiz, ds); 227 return t; 228 } get_heightparam_siz229 ui32 get_height(int comp_num) const 230 { 231 assert(comp_num < get_num_components()); 232 ui32 ds = (ui32)cptr[comp_num].YRsiz; 233 ui32 t = ojph_div_ceil(Ysiz, ds) - ojph_div_ceil(YOsiz, ds); 234 return t; 235 } get_recon_widthparam_siz236 ui32 get_recon_width(int comp_num) const 237 { 238 assert(comp_num < get_num_components()); 239 ui32 ds = (ui32)cptr[comp_num].XRsiz * (1u << skipped_resolutions); 240 ui32 t = ojph_div_ceil(Xsiz, ds) - ojph_div_ceil(XOsiz, ds); 241 return t; 242 } get_recon_heightparam_siz243 ui32 get_recon_height(int comp_num) const 244 { 245 assert(comp_num < get_num_components()); 246 ui32 ds = (ui32)cptr[comp_num].YRsiz * (1u << skipped_resolutions); 247 ui32 t = ojph_div_ceil(Ysiz, ds) - ojph_div_ceil(YOsiz, ds); 248 return t; 249 } 250 251 private: 252 ui16 Lsiz; 253 ui16 Rsiz; 254 ui32 Xsiz; 255 ui32 Ysiz; 256 ui32 XOsiz; 257 ui32 YOsiz; 258 ui32 XTsiz; 259 ui32 YTsiz; 260 ui32 XTOsiz; 261 ui32 YTOsiz; 262 ui16 Csiz; 263 siz_comp_info* cptr; 264 265 private: 266 int skipped_resolutions; 267 int old_Csiz; 268 siz_comp_info store[4]; 269 param_siz(const param_siz&) = delete; //prevent copy constructor 270 param_siz& operator=(const param_siz&) = delete; //prevent copy 271 }; 272 273 /////////////////////////////////////////////////////////////////////////// 274 // 275 // 276 // 277 // 278 // 279 /////////////////////////////////////////////////////////////////////////// 280 struct cod_SPcod 281 { 282 ui8 num_decomp; 283 ui8 block_width; 284 ui8 block_height; 285 ui8 block_style; 286 ui8 wavelet_trans; 287 ui8 precinct_size[33]; //num_decomp is in [0,32] 288 }; 289 290 /////////////////////////////////////////////////////////////////////////// 291 typedef cod_SPcod cod_SPcoc; 292 293 /////////////////////////////////////////////////////////////////////////// 294 struct cod_SGcod 295 { 296 ui8 prog_order; 297 ui16 num_layers; 298 ui8 mc_trans; 299 }; 300 301 /////////////////////////////////////////////////////////////////////////// 302 struct param_cod 303 { 304 friend ::ojph::param_cod; 305 public: param_codparam_cod306 param_cod() 307 { 308 memset(this, 0, sizeof(param_cod)); 309 SPcod.block_style = 0x40; 310 SGCod.prog_order = 2; 311 SGCod.num_layers = 1; 312 SGCod.mc_trans = 0; 313 SPcod.num_decomp = 5; 314 SPcod.block_width = 4; //64 315 SPcod.block_height = 4; //64 316 set_reversible(false); 317 } 318 set_reversibleparam_cod319 void set_reversible(bool reversible) 320 { 321 SPcod.wavelet_trans = reversible ? 1 : 0; 322 } 323 employ_color_transformparam_cod324 void employ_color_transform(ui8 val) 325 { 326 assert(val == 0 || val == 1); 327 SGCod.mc_trans = val; 328 } 329 check_validityparam_cod330 void check_validity(const param_siz& siz) 331 { 332 //check that colour transform and match number of components and 333 // downsampling 334 int num_comps = siz.get_num_components(); 335 if (SGCod.mc_trans == 1 && num_comps < 3) 336 OJPH_ERROR(0x00040011, 337 "color transform can only be employed when the image has 3 or " 338 "more color components"); 339 340 if (SGCod.mc_trans == 1) 341 { 342 bool test = false; 343 point p = siz.get_downsampling(0); 344 for (int i = 1; i < 3; ++i) 345 { 346 point p1 = siz.get_downsampling(i); 347 test = test || (p.x != p1.x || p.y != p1.y); 348 } 349 if (test) 350 OJPH_ERROR(0x00040012, 351 "when color transform is used, the first 3 colour " 352 "components must have the same downsampling."); 353 } 354 355 //check the progression order matches downsampling 356 if (SGCod.prog_order == 2 || SGCod.prog_order == 3) 357 { 358 int num_comps = siz.get_num_components(); 359 for (int i = 0; i < num_comps; ++i) 360 { 361 point r = siz.get_downsampling(i); 362 if (r.x & (r.x - 1) || r.y & (r.y - 1)) 363 OJPH_ERROR(0x00040013, "For RPCL and PCRL progression orders," 364 "component downsampling factors have to be powers of 2"); 365 } 366 } 367 } 368 get_num_decompositionsparam_cod369 ui8 get_num_decompositions() const 370 { return SPcod.num_decomp; } get_block_dimsparam_cod371 size get_block_dims() const 372 { 373 return size(1 << (SPcod.block_width + 2), 374 1 << (SPcod.block_height + 2)); 375 } is_reversibleparam_cod376 bool is_reversible() const 377 { return (SPcod.wavelet_trans == 1); } is_employing_color_transformparam_cod378 bool is_employing_color_transform() const 379 { return (SGCod.mc_trans == 1); } get_log_block_dimsparam_cod380 size get_log_block_dims() const 381 { return size(SPcod.block_width + 2, SPcod.block_height + 2); } get_precinct_sizeparam_cod382 size get_precinct_size(int res_num) const 383 { 384 size t = get_log_precinct_size(res_num); 385 t.w = 1 << t.w; 386 t.h = 1 << t.h; 387 return t; 388 } get_log_precinct_sizeparam_cod389 size get_log_precinct_size(int res_num) const 390 { 391 assert(res_num <= SPcod.num_decomp); 392 size ps(15, 15); 393 if (Scod & 1) 394 { 395 ps.w = SPcod.precinct_size[res_num] & 0xF; 396 ps.h = SPcod.precinct_size[res_num] >> 4; 397 } 398 return ps; 399 } packets_may_use_sopparam_cod400 bool packets_may_use_sop() const 401 { return (Scod & 2) == 2; } packets_use_ephparam_cod402 bool packets_use_eph() const 403 { return (Scod & 4) == 4; } 404 405 bool write(outfile_base *file); 406 void read(infile_base *file); 407 408 private: 409 ui16 Lcod; 410 ui8 Scod; 411 cod_SGcod SGCod; 412 cod_SPcod SPcod; 413 }; 414 415 /////////////////////////////////////////////////////////////////////////// 416 // 417 // 418 // 419 // 420 // 421 /////////////////////////////////////////////////////////////////////////// 422 struct param_qcd 423 { 424 friend ::ojph::param_qcd; 425 public: param_qcdparam_qcd426 param_qcd() 427 { 428 Lqcd = 0; 429 Sqcd = 0; 430 for (int i = 0; i < 97; ++i) 431 u16_SPqcd[i] = 0; 432 num_decomps = 0; 433 base_delta = -1.0f; 434 } 435 set_deltaparam_qcd436 void set_delta(float delta) { base_delta = delta; } 437 void set_rev_quant(int bit_depth, bool is_employing_color_transform); 438 void set_irrev_quant(); 439 check_validityparam_qcd440 void check_validity(const param_siz& siz, const param_cod& cod) 441 { 442 num_decomps = cod.get_num_decompositions(); 443 if (cod.is_reversible()) 444 { 445 int bit_depth = 0; 446 for (int i = 0; i < siz.get_num_components(); ++i) 447 bit_depth = ojph_max(bit_depth, siz.get_bit_depth(i)); 448 set_rev_quant(bit_depth, cod.is_employing_color_transform()); 449 } 450 else 451 { 452 if (base_delta == -1.0f) 453 base_delta = 1.0f / 454 (float)(1 << (siz.get_bit_depth(0) + siz.is_signed(0))); 455 set_irrev_quant(); 456 } 457 } 458 459 int get_num_guard_bits() const; 460 int get_MAGBp() const; 461 int get_Kmax(int resolution, int subband) const; 462 float irrev_get_delta(int resolution, int subband) const; 463 464 bool write(outfile_base *file); 465 void read(infile_base *file); 466 467 protected: 468 ui16 Lqcd; 469 ui8 Sqcd; 470 union 471 { 472 ui8 u8_SPqcd[97]; 473 ui16 u16_SPqcd[97]; 474 }; 475 int num_decomps; 476 float base_delta; 477 }; 478 479 /////////////////////////////////////////////////////////////////////////// 480 // 481 // 482 // 483 // 484 // 485 /////////////////////////////////////////////////////////////////////////// 486 struct param_qcc : public param_qcd 487 { 488 friend ::ojph::param_qcc; 489 public: param_qccparam_qcc490 param_qcc() : param_qcd() 491 { comp_idx = 0; } 492 get_comp_numparam_qcc493 ui16 get_comp_num() { return comp_idx; } 494 void read(infile_base *file, int num_comps); 495 496 protected: 497 ui16 comp_idx; 498 }; 499 500 /////////////////////////////////////////////////////////////////////////// 501 // 502 // 503 // 504 // 505 // 506 /////////////////////////////////////////////////////////////////////////// 507 struct param_cap 508 { 509 public: param_capparam_cap510 param_cap() 511 { 512 memset(this, 0, sizeof(param_cap)); 513 Lcap = 8; 514 Pcap = 0x00020000; //for jph, Pcap^15 must be set, the 15th MSB 515 } 516 check_validityparam_cap517 void check_validity(const param_cod& cod, const param_qcd& qcd) 518 { 519 if (cod.is_reversible()) 520 Ccap[0] &= 0xFFDF; 521 else 522 Ccap[0] |= 0x0020; 523 Ccap[0] &= 0xFFE0; 524 int Bp = 0; 525 int B = qcd.get_MAGBp(); 526 if (B <= 8) 527 Bp = 0; 528 else if (B < 28) 529 Bp = B - 8; 530 else if (B < 48) 531 Bp = 13 + (B >> 2); 532 else 533 Bp = 31; 534 Ccap[0] |= (ui16)Bp; 535 } 536 537 bool write(outfile_base *file); 538 void read(infile_base *file); 539 540 private: 541 ui16 Lcap; 542 ui32 Pcap; 543 ui16 Ccap[32]; //a maximum of 32 544 }; 545 546 547 /////////////////////////////////////////////////////////////////////////// 548 // 549 // 550 // 551 // 552 // 553 /////////////////////////////////////////////////////////////////////////// 554 struct param_sot 555 { 556 public: 557 void init(ui32 payload_length = 0, ui16 tile_idx = 0, 558 ui8 tile_part_index = 0, ui8 num_tile_parts = 0) 559 { 560 Lsot = 10; 561 Psot = payload_length + 12; //total = payload + SOT marker 562 Isot = tile_idx; 563 TPsot = tile_part_index; 564 TNsot = num_tile_parts; 565 } 566 567 bool write(outfile_base *file, ui32 payload_len); 568 bool write(outfile_base *file, ui32 payload_len, ui8 TPsot, ui8 TNsot); 569 bool read(infile_base *file, bool resilient); 570 get_tile_indexparam_sot571 ui16 get_tile_index() const { return Isot; } get_payload_lengthparam_sot572 ui32 get_payload_length() const { return Psot > 0 ? Psot - 12 : 0; } get_tile_part_indexparam_sot573 ui8 get_tile_part_index() const { return TPsot; } get_num_tile_partsparam_sot574 ui8 get_num_tile_parts() const { return TNsot; } 575 576 private: 577 ui16 Lsot; 578 ui16 Isot; 579 ui32 Psot; 580 ui8 TPsot; 581 ui8 TNsot; 582 }; 583 584 /////////////////////////////////////////////////////////////////////////// 585 // 586 // 587 // 588 // 589 // 590 /////////////////////////////////////////////////////////////////////////// 591 struct param_tlm 592 { 593 struct Ttlm_Ptlm_pair 594 { 595 ui16 Ttlm; 596 ui32 Ptlm; 597 }; 598 599 public: param_tlmparam_tlm600 param_tlm() { pairs = NULL; num_pairs = 0; next_pair_index = 0; }; 601 void init(int num_pairs, Ttlm_Ptlm_pair* store); 602 603 void set_next_pair(ui16 Ttlm, ui32 Ptlm); 604 bool write(outfile_base *file); 605 606 private: 607 ui16 Ltlm; 608 ui8 Ztlm; 609 ui8 Stlm; 610 Ttlm_Ptlm_pair* pairs; 611 int num_pairs; 612 int next_pair_index; 613 614 }; 615 } 616 } 617 618 #endif // !OJPH_PARAMS_LOCAL_H 619