From ecd73ef2d2b8834584255f970e393201dda2865f Mon Sep 17 00:00:00 2001 From: Aous Naman Date: Wed, 4 Nov 2020 21:33:56 +1100 Subject: [PATCH] Added support for the QCC marker in the main header. This is made necessary by the fact that Kakadu now produces these markers when Qfactor is used. --- src/core/codestream/ojph_codestream.cpp | 54 ++++++++++------- src/core/codestream/ojph_codestream_local.h | 19 +++++- src/core/codestream/ojph_params.cpp | 65 ++++++++++++++++++++- src/core/codestream/ojph_params_local.h | 34 ++++++++++- src/core/common/ojph_params.h | 12 ++++ src/core/common/ojph_version.h | 2 +- 6 files changed, 157 insertions(+), 29 deletions(-) diff --git a/src/core/codestream/ojph_codestream.cpp b/src/core/codestream/ojph_codestream.cpp index ee532b8..0a5e7a0 100644 --- a/src/core/codestream/ojph_codestream.cpp +++ b/src/core/codestream/ojph_codestream.cpp @@ -216,9 +216,11 @@ namespace ojph { resilient = false; skipped_res_for_read = skipped_res_for_recon = 0; - precinct_scratch_needed_bytes = 0; + used_qcc_fields = 0; + qcc = qcc_store; + allocator = new mem_fixed_allocator; elastic_alloc = new mem_elastic_allocator(1048576); //1 megabyte @@ -229,6 +231,8 @@ namespace ojph { //////////////////////////////////////////////////////////////////////////// codestream::~codestream() { + if (qcc_store != qcc) + delete[] qcc; if (allocator) delete allocator; if (elastic_alloc) @@ -838,8 +842,15 @@ namespace ojph { else if (marker_idx == 5) { qcd.read(file); received_markers |= 2; } else if (marker_idx == 6) - skip_marker(file, "QCC", "QCC is not supported yet", - OJPH_MSG_LEVEL::WARN, false); + { + int num_comps = siz.get_num_components(); + if (qcc == qcc_store && + num_comps * sizeof(param_qcc) > sizeof(qcc_store)) + { + qcc = new param_qcc[num_comps]; + } + qcc[used_qcc_fields++].read(file, num_comps); + } else if (marker_idx == 7) skip_marker(file, "RGN", "RGN is not supported yet", OJPH_MSG_LEVEL::WARN, false); @@ -1903,8 +1914,8 @@ namespace ojph { this->comp_num = comp_num; res = allocator->post_alloc_obj(1); - res->finalize_alloc(codestream, comp_rect, recon_comp_rect, num_decomps, - comp_downsamp, this, NULL); + res->finalize_alloc(codestream, comp_rect, recon_comp_rect, comp_num, + num_decomps, comp_downsamp, this, NULL); } ////////////////////////////////////////////////////////////////////////// @@ -2143,7 +2154,7 @@ namespace ojph { void resolution::finalize_alloc(codestream *codestream, const rect& res_rect, const rect& recon_res_rect, - int res_num, + int comp_num, int res_num, point comp_downsamp, tile_comp *parent_tile, resolution *parent_res) @@ -2161,6 +2172,7 @@ namespace ojph { this->parent = parent_tile; this->parent_res = parent_res; this->res_rect = res_rect; + this->comp_num = comp_num; this->res_num = res_num; //finalize next resolution if (res_num > 0) @@ -2178,8 +2190,8 @@ namespace ojph { next_res_rect.siz.h = try1 - try0; child_res->finalize_alloc(codestream, next_res_rect, - skipped_res_for_recon ? recon_res_rect : next_res_rect, res_num - 1, - comp_downsamp, parent_tile, this); + skipped_res_for_recon ? recon_res_rect : next_res_rect, comp_num, + res_num - 1, comp_downsamp, parent_tile, this); } else child_res = NULL; @@ -3390,7 +3402,7 @@ namespace ojph { { ui32 bit; if (bb_read_bit(&bb, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p1"; } empty_cb = (bit == 0); *inc_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) = (ui8)(1 - bit); *inc_tag_flags.get(x>>cur_lev, y>>cur_lev, cur_lev) = 1; @@ -3415,7 +3427,7 @@ namespace ojph { while (bit == 0) { if (bb_read_bit(&bb, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p2"; } mmsbs += 1 - bit; } *mmsb_tag.get(x>>cur_lev, y>>cur_lev, cur_lev) = (ui8)mmsbs; @@ -3430,26 +3442,26 @@ namespace ojph { //get number of passes ui32 bit, num_passes = 1; if (bb_read_bit(&bb, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p3"; } if (bit) { num_passes = 2; if (bb_read_bit(&bb, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p4"; } if (bit) { if (bb_read_bits(&bb, 2, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p5"; } num_passes = 3 + bit; if (bit == 3) { if (bb_read_bits(&bb, 5, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p6"; } num_passes = 6 + bit; if (bit == 31) { if (bb_read_bits(&bb, 7, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p7"; } num_passes = 37 + bit; } } @@ -3465,17 +3477,17 @@ namespace ojph { while (bit) { if (bb_read_bit(&bb, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p8"; } bits1 += bit; } if (bb_read_bits(&bb, bits1, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p9"; } cp->pass_length[0] = bit; if (num_passes > 1) { if (bb_read_bits(&bb, bits1 + extra_bit, bit) == false) - { data_left = 0; throw "error reading from file"; } + { data_left = 0; throw "error reading from file p10"; } cp->pass_length[1] = bit; } } @@ -3606,11 +3618,11 @@ namespace ojph { cur_cb_row = 0; cur_line = 0; cur_cb_height = 0; - param_qcd qcd = codestream->access_qcd(); - this->K_max = qcd.get_Kmax(this->res_num, band_num); + param_qcd *qcd = codestream->access_qcd(parent->get_comp_num()); + this->K_max = qcd->get_Kmax(this->res_num, band_num); if (!reversible) { - float d = qcd.irrev_get_delta(res_num, subband_num); + float d = qcd->irrev_get_delta(res_num, subband_num); d /= (float)(1u << (31 - this->K_max)); delta = d; delta_inv = (1.0f/d); diff --git a/src/core/codestream/ojph_codestream_local.h b/src/core/codestream/ojph_codestream_local.h index 5b89d31..3fc64e1 100644 --- a/src/core/codestream/ojph_codestream_local.h +++ b/src/core/codestream/ojph_codestream_local.h @@ -85,8 +85,14 @@ namespace ojph { { return ojph::param_cod(&cod); } const param_cod* get_cod() //return internal code { return &cod; } - param_qcd access_qcd() - { return qcd; } + param_qcd* access_qcd(int comp_num) + { + if (used_qcc_fields > 0) + for (int v = 0; v < used_qcc_fields; ++v) + if (qcc[v].get_comp_num() == comp_num) + return qcc + v; + return &qcd; + } mem_fixed_allocator* get_allocator() { return allocator; } mem_elastic_allocator* get_elastic_alloc() { return elastic_alloc; } outfile_base* get_file() { return outfile; } @@ -146,6 +152,11 @@ namespace ojph { param_qcd qcd; param_tlm tlm; + private: // this is to handle qcc + int used_qcc_fields; + param_qcc qcc_store[4], *qcc; // we allocate 4, + // if not enough, we allocate more + private: mem_fixed_allocator *allocator; mem_elastic_allocator *elastic_alloc; @@ -238,7 +249,7 @@ namespace ojph { static void pre_alloc(codestream *codestream, const rect& res_rect, const rect& recon_res_rect, int res_num); void finalize_alloc(codestream *codestream, const rect& res_rect, - const rect& recon_res_rect, + const rect& recon_res_rect, int comp_num, int res_num, point comp_downsamp, tile_comp *parent_tile, resolution *parent_res); @@ -247,6 +258,7 @@ namespace ojph { void push_line(); line_buf* pull_line(); rect get_rect() { return res_rect; } + int get_comp_num() { return comp_num; } ui32 prepare_precinct(); void write_precincts(outfile_base *file); @@ -259,6 +271,7 @@ namespace ojph { private: bool reversible, skipped_res_for_read, skipped_res_for_recon; int num_lines, num_bands, res_num; + int comp_num; point comp_downsamp; rect res_rect; line_buf *lines; diff --git a/src/core/codestream/ojph_params.cpp b/src/core/codestream/ojph_params.cpp index cfbffc4..dd3887a 100644 --- a/src/core/codestream/ojph_params.cpp +++ b/src/core/codestream/ojph_params.cpp @@ -944,7 +944,7 @@ namespace ojph { } else if ((Sqcd & 0x1F) == 2) { - num_decomps = (Lqcd - 4) / 6; + num_decomps = (Lqcd - 5) / 6; if (Lqcd != 5 + 6 * num_decomps) OJPH_ERROR(0x00050086, "wrong Lqcd value in QCD marker"); for (int i = 0; i < 1 + 3 * num_decomps; ++i) @@ -966,6 +966,69 @@ namespace ojph { // ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + void param_qcc::read(infile_base *file, int num_comps) + { + if (file->read(&Lqcd, 2) != 2) + OJPH_ERROR(0x000500A1, "error reading QCC marker"); + Lqcd = swap_byte(Lqcd); + if (num_comps < 257) + { + ui8 v; + if (file->read(&v, 1) != 1) + OJPH_ERROR(0x000500A2, "error reading QCC marker"); + comp_idx = v; + } + else + { + if (file->read(&comp_idx, 2) != 2) + OJPH_ERROR(0x000500A3, "error reading QCC marker"); + comp_idx = swap_byte(comp_idx); + } + if (file->read(&Sqcd, 1) != 1) + OJPH_ERROR(0x000500A4, "error reading QCC marker"); + if ((Sqcd & 0x1F) == 0) + { + int offset = num_comps < 257 ? 5 : 6; + num_decomps = (Lqcd - offset) / 3; + if (Lqcd != offset + 3 * num_decomps) + OJPH_ERROR(0x000500A5, "wrong Lqcd value in QCC marker"); + for (int i = 0; i < 1 + 3 * num_decomps; ++i) + if (file->read(&u8_SPqcd[i], 1) != 1) + OJPH_ERROR(0x000500A6, "error reading QCC marker"); + } + else if ((Sqcd & 0x1F) == 1) + { + int offset = num_comps < 257 ? 6 : 7; + num_decomps = -1; + if (Lqcd != offset) + OJPH_ERROR(0x000500A7, "wrong Lqcc value in QCC marker"); + } + else if ((Sqcd & 0x1F) == 2) + { + int offset = num_comps < 257 ? 6 : 7; + num_decomps = (Lqcd - offset) / 6; + if (Lqcd != offset + 6 * num_decomps) + OJPH_ERROR(0x000500A8, "wrong Lqcd value in QCC marker"); + for (int i = 0; i < 1 + 3 * num_decomps; ++i) + { + if (file->read(&u16_SPqcd[i], 2) != 2) + OJPH_ERROR(0x000500A9, "error reading QCC marker"); + u16_SPqcd[i] = swap_byte(u16_SPqcd[i]); + } + } + else + OJPH_ERROR(0x000500AA, "wrong Sqcd value in QCC marker"); + } + + ////////////////////////////////////////////////////////////////////////// + // + // + // + // + // + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// bool param_sot::write(outfile_base *file, ui32 payload_len) { diff --git a/src/core/codestream/ojph_params_local.h b/src/core/codestream/ojph_params_local.h index 0403bc6..6ca3f78 100644 --- a/src/core/codestream/ojph_params_local.h +++ b/src/core/codestream/ojph_params_local.h @@ -108,6 +108,7 @@ namespace ojph { PLT = 0xFF58, //packet length, tile-part header CPF = 0xFF59, //corresponding profile values QCD = 0xFF5C, //qunatization default (required) + QCC = 0xFF5D, //quantization component COM = 0xFF64, //comment SOT = 0xFF90, //start of tile-part SOP = 0xFF91, //start of packet @@ -116,7 +117,6 @@ namespace ojph { EOC = 0xFFD9, //end of codestream (required) COC = 0xFF53, //coding style component - QCC = 0xFF5D, //quantization component RGN = 0xFF5E, //region of interest POC = 0xFF5F, //progression order change PPM = 0xFF60, //packed packet headers, main header @@ -424,7 +424,14 @@ namespace ojph { friend ::ojph::param_qcd; public: param_qcd() - { memset(this, 0, sizeof(param_qcd)); base_delta = -1.0f; } + { + Lqcd = 0; + Sqcd = 0; + for (int i = 0; i < 97; ++i) + u16_SPqcd[i] = 0; + num_decomps = 0; + base_delta = -1.0f; + } void set_delta(float delta) { base_delta = delta; } void set_rev_quant(int bit_depth, bool is_employing_color_transform); @@ -457,7 +464,7 @@ namespace ojph { bool write(outfile_base *file); void read(infile_base *file); - private: + protected: ui16 Lqcd; ui8 Sqcd; union @@ -469,6 +476,27 @@ namespace ojph { float base_delta; }; + /////////////////////////////////////////////////////////////////////////// + // + // + // + // + // + /////////////////////////////////////////////////////////////////////////// + struct param_qcc : public param_qcd + { + friend ::ojph::param_qcc; + public: + param_qcc() : param_qcd() + { comp_idx = 0; } + + ui16 get_comp_num() { return comp_idx; } + void read(infile_base *file, int num_comps); + + protected: + ui16 comp_idx; + }; + /////////////////////////////////////////////////////////////////////////// // // diff --git a/src/core/common/ojph_params.h b/src/core/common/ojph_params.h index 78c519b..c6889ed 100644 --- a/src/core/common/ojph_params.h +++ b/src/core/common/ojph_params.h @@ -49,6 +49,7 @@ namespace ojph { struct param_siz; struct param_cod; struct param_qcd; + struct param_qcc; struct param_cap; } @@ -165,6 +166,17 @@ namespace ojph { local::param_qcd* state; }; + //////////////////////////////////////////////////////////////////////////// + class param_qcc + { + public: + OJPH_EXPORT + param_qcc(local::param_qcc* p) : state(p) {} + + private: + local::param_qcc* state; + }; + } #endif // !OJPH_PARAMS_H diff --git a/src/core/common/ojph_version.h b/src/core/common/ojph_version.h index 4d226ca..7315253 100644 --- a/src/core/common/ojph_version.h +++ b/src/core/common/ojph_version.h @@ -35,4 +35,4 @@ #define OPENJPH_VERSION_MAJOR 0 #define OPENJPH_VERSION_MINOR 7 -#define OPENJPH_VERSION_PATCH 1 +#define OPENJPH_VERSION_PATCH 2