//***************************************************************************/ // This software is released under the 2-Clause BSD license, included // below. // // Copyright (c) 2019, Aous Naman // Copyright (c) 2019, Kakadu Software Pty Ltd, Australia // Copyright (c) 2019, The University of New South Wales, Australia // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //***************************************************************************/ // This file is part of the OpenJPH software implementation. // File: ojph_params.h // Author: Aous Naman // Date: 28 August 2019 //***************************************************************************/ #ifndef OJPH_PARAMS_H #define OJPH_PARAMS_H #include "ojph_arch.h" #include "ojph_base.h" namespace ojph { /***************************************************************************/ // defined here class param_siz; class param_cod; class param_qcd; class param_cap; class param_nlt; class codestream; /***************************************************************************/ // prototyping from local namespace local { struct param_siz; struct param_cod; struct param_qcd; struct param_cap; struct param_nlt; class codestream; } /***************************************************************************/ class OJPH_EXPORT param_siz { public: param_siz(local::param_siz *p) : state(p) {} //setters void set_image_extent(point extent); void set_tile_size(size s); void set_image_offset(point offset); void set_tile_offset(point offset); void set_num_components(ui32 num_comps); void set_component(ui32 comp_num, const point& downsampling, ui32 bit_depth, bool is_signed); //getters point get_image_extent() const; point get_image_offset() const; size get_tile_size() const; point get_tile_offset() const; ui32 get_num_components() const; ui32 get_bit_depth(ui32 comp_num) const; bool is_signed(ui32 comp_num) const; point get_downsampling(ui32 comp_num) const; //deeper getters ui32 get_recon_width(ui32 comp_num) const; ui32 get_recon_height(ui32 comp_num) const; private: local::param_siz* state; }; /***************************************************************************** * @brief An interface to COD and COC marker segments. * * The param_cod object uses Pimpl design. * The top set of functions give access to the COD marker segment, while * the lower set, the ones that have comp_idx as the first parameter, * gives access to COC marker segment. * The functions: * - set_num_decomposition(ui32 comp_idx, ...) * - set_block_dims(ui32 comp_idx, ...) * - set_precinct_size(ui32 comp_idx, ...) * - set_reversible(ui32 comp_idx, ...) * create a COC segment on first call; subsequent calls to these * functions on the same component index will use the COC segment * created by the first call. On first creation, the COC segment is * initialized to the default COD settings; in particular, 5 levels of * decomposition, 64x64 codeblocks, reversible 5/3 transform and no * precinct size is defined, which gives 32768x32768 precincts. */ class OJPH_EXPORT param_cod { public: param_cod(local::param_cod* p) : state(p) {} // COD marker segment interface void set_num_decomposition(ui32 num_decompositions); void set_block_dims(ui32 width, ui32 height); void set_precinct_size(int num_levels, size* precinct_size); void set_progression_order(const char *name); void set_color_transform(bool color_transform); void set_reversible(bool reversible); ui32 get_num_decompositions() const; size get_block_dims() const; size get_log_block_dims() const; bool is_reversible() const; size get_precinct_size(ui32 level_num) const; size get_log_precinct_size(ui32 level_num) const; int get_progression_order() const; const char* get_progression_order_as_string() const; int get_num_layers() const; bool is_using_color_transform() const; bool packets_may_use_sop() const; bool packets_use_eph() const; bool get_block_vertical_causality() const; // COC marker segment interface void set_num_decomposition(ui32 comp_idx, ui32 num_decompositions); void set_block_dims(ui32 comp_idx, ui32 width, ui32 height); void set_precinct_size(ui32 comp_idx, int num_levels, size* precinct_size); void set_reversible(ui32 comp_idx, bool reversible); ui32 get_num_decompositions(ui32 comp_idx) const; size get_block_dims(ui32 comp_idx) const; size get_log_block_dims(ui32 comp_idx) const; bool is_reversible(ui32 comp_idx) const; size get_precinct_size(ui32 comp_idx, ui32 level_num) const; size get_log_precinct_size(ui32 comp_idx, ui32 level_num) const; bool get_block_vertical_causality(ui32 comp_idx) const; private: local::param_cod* state; }; /***************************************************************************/ /** * @brief Quantization parameters object * */ class OJPH_EXPORT param_qcd { public: enum comp_type : ui8 { // Note the numbers are used by the code OJPH_COMP_Y = 0, OJPH_COMP_CB = 1, OJPH_COMP_CR = 2, OJPH_COMP_UNDEFINED = 0xFF }; static comp_type ui8_2_comp_type(ui8 c) { if (c >= OJPH_COMP_Y && c <= OJPH_COMP_CR) return static_cast(c); else return OJPH_COMP_UNDEFINED; } param_qcd(local::param_qcd* p) : state(p) {} /** * @brief Set the irreversible quantization base delta. * * This represents the default base delta and influences QCD marker * segment * * @param delta */ void set_irrev_quant(float delta); /** * @brief Sets Qfactor * * This is a top level Qfactor; it will automatically set the qfactor; * if you have one or two channels they will be set to luminance * (or Y) visual weighting. If you have three or more, the first three * will be set to Y, Cb, Cr; channels 4 onwards will be set to luminance. * If that does not match the desired behaviour; then do not set the * top level qfactor, but set the Qfactor for individual channels * according to desired visual weighting type, using * set_qfactor(ui32 comp_idx, comp_type ctype, float qfactor); * * Note that setting Qfactor takes precedence over setting an * irreversible quantization base delta. * * @param qfactor Compression quality as an integer between * 1 (worst quality) and 100 (best quality) */ void set_qfactor(float qfactor); /** * @brief Set the irreversible quantization base delta for a specific * component * * This represents the default base delta for component comp_idx, and * influences QCC marker segment for the component, inserting one * if needed, which is usually the case. * * @param comp_idx * @param delta */ void set_irrev_quant(ui32 comp_idx, float delta); /** * @brief Sets Qfactor for a specific component. * * Setting Qfactor takes precedence over setting an irreversible * quantization base delta * * @param comp_idx Component index * @param ctype Indicates whether the component is a Y, Cb or Cr channel, * after the ICT if present * @param qfactor Compression quality as an integer between * 1 (worst quality) and 100 (best quality) */ void set_qfactor(ui32 comp_idx, comp_type ctype, float qfactor); private: local::param_qcd* state; }; /*************************************************************************/ /** * @brief non-linearity point transformation object * (implements NLT marker segment) * * There are a few things to know here. * The NLT marker segment contains the nonlinearity type and the * bit depth and signedness of the component to which it applies. * There is the default component ALL_COMPS which applies to all * components unless it is overridden by another NLT segment marker. * The library checks that the settings make sense, and also make * sure that bit depth and signedness are correct, creating any missing * NLT marker segments in the process. * If all components have the same bit depth and signedness, and need * nonlinearity type 3 (Binary Complement to Sign Magnitude Conversion), * then the best option is to set ALL_COMPS to type 3. * Otherwise, the best option is to set type 3 only to components that * need it, leaving out the default ALL_COMPS nonlinearity not set. * Another option is for the end-user can set the ALL_COMPS to type 3, * and then put exception for the components that does not need type 3, * by setting them to type 0. * * The library, during validity check, which is run when the codestream * is created for writing, will do the following: * -- If ALL_COMPS is set to type 0, it will be ignored, and the * codestream will NOT have the corresponding NLT marker segment. * -- If ALL_COMPS is set to type 3, then the following will happen: * - If all the components (except those with type 0 set for them) have * the same bit depth and signedness, then the ALL_COMPS NLT marker * segment will be respected and inserted into the codestream. * Of course, components with NLT 0 will also have the corresponding * NLT marker segment inserted. * - If components, for which no NTL type 0 is specified, have differing * bit depth or signedness, then the ALL_COMPS will be ignored, and * NLT markers are inserted for each component that needs type 3. * Components that have their component field larger than the number of * components in the codestream are removed. * * It also worth noting that type 3 nonlinearity has no effect on * positive image samples. It is also not recommended for integer-valued * types. It is only recommended for floating-point image samples, for * which some of the samples are negative, where type 3 nonlinearity * should be beneficial. This is because the encoding engine expects * two-complement representation for negative values while floating point * numbers have a sign bit followed by an exponent, which has a biased * integer representation. The core idea is to make floating-point * representation more compatible with integer representation. * */ class OJPH_EXPORT param_nlt { public: enum special_comp_num : ui16 { ALL_COMPS = 65535 }; enum nonlinearity : ui8 { OJPH_NLT_NO_NLT = 0, // supported OJPH_NLT_GAMMA_STYLE_NLT = 1, // not supported OJPH_NLT_LUT_STYLE_NLT = 2, // supported OJPH_NLT_BINARY_COMPLEMENT_NLT = 3, // supported OJPH_NLT_BINARY_COMPLEMENT_PLUS_LUT = 4, // experimental OJPH_NLT_UNDEFINED = 255 // This is used internally and // is not part of the standard }; public: param_nlt(local::param_nlt* p) : state(p) {} /************************************************************************* * @brief Sets nonlinearity to OJPH_NLT_NO_NLT = 0 or * OJPH_NLT_BINARY_COMPLEMENT_NLT = 3, which is sometimes called SMAG or * UMAG. * When creating a codestream for writing, call this function before * you call codestream::write_headers. * * The standard requires "If the binary complement to sign-magnitude * conversion transformation is used, the bit-depth of the input samples * to this transformation shall be equal to the bit-depth of the samples * generated by the transformation, and the signed-ness of the input * samples shall be equal to the signed-ness of the output samples." * * @param comp_num: component number, or ALL_COMPS for all components * @param nlt_type: desired non-linearity from enum nonlinearity, only * OJPH_NLT_NO_NLT and OJPH_NLT_BINARY_COMPLEMENT_NLT are allowed */ void set_nonlinear_transform(ui32 comp_num, ui8 nl_type); /************************************************************************* * @brief Sets nonlinearity to OJPH_NLT_LUT_STYLE_NLT = 2 or * OJPH_NLT_BINARY_COMPLEMENT_PLUS_LUT = 4 nonlinearity. Note that as of * this writing OJPH_NLT_BINARY_COMPLEMENT_PLUS_LUT is not part of the * standard. * When creating a codestream for writing, call this function before * you call codestream::write_headers. * Note that a component, as defined by the codestream headers, has * bitdepth/signedness specified in SIZ marker segment; this is also * the internal format used in encoding/decoding the samples. * The nonlinearity stage allows you to define a different format for * data exchange (for feeding-in and extracting samples) with the library; * this different format is communicated using decoded_bit_depth and * decoded_signedness. Said differently, the nonlinearity can take-in * samples in one format (NLT format) and store them in a different format * (SIZ format). * * The information needed for this call is defined in A.3.10 Non-linearity * point transformation (NLT) of the JPEG2000 Standard Part 2 * * @param comp_num: component number, or ALL_COMPS for all components * @param decoded_bit_depth: the number of bits for the fed-in or * extracted samples * @param decoded_signedness: the signedness of the fed-in or extracted * samples * @param d_min: Dmin parameters as defined in the standard * @param d_max: Dmax parameters as defined in the standard * @param pt_val: PTval parameters as defined in the standard * @param num_points: the number of points in the next `points` array * @param points: An array that has `num_points` entries; the size of * each entry depends on pt_val; 1 byte for pt_val \in [1,8], * 2 bytes for pt_val \in [9,16], and 4 bytes for pt_val \in * [17,32]. * @param nlt_type: desired non-linearity from enum nonlinearity, only * OJPH_NLT_LUT_STYLE_NLT and OJPH_NLT_BINARY_COMPLEMENT_PLUS_LUT * are allowed */ void set_nonlinear_transform(ui32 comp_num, ui8 decoded_bit_depth, bool decoded_signedness, ui32 d_min, ui32 d_max, ui8 pt_val, ui16 num_points, void* points, ui8 nl_type); /************************************************************************* * @brief get the nonlinearity type associated with comp_num, which * should be one from enum nonlinearity * * @param comp_num: component number, or ALL_COMPS for all components * @param decoded_bit_depth: returns the bit depth of the decoded samples * for component samples * @param decoded_signedness: returns signedness of decoded samples for * the component samples * @param type: nonlinearity type * @return true if the nonlinearity for comp_num is set */ bool get_nonlinear_transform(ui32 comp_num, ui8& decoded_bit_depth, bool& decoded_signedness, ui8& nl_type) const; private: local::param_nlt* state; }; /***************************************************************************/ class OJPH_EXPORT comment_exchange { friend class local::codestream; public: comment_exchange() : data(NULL), len(0), Rcom(0) {} void set_string(const char* str); void set_data(const char* data, ui16 len); private: const char* data; ui16 len; ui16 Rcom; }; } #endif // !OJPH_PARAMS_H