From a4d16ece9434ce21deb717f6d79882390b14bd46 Mon Sep 17 00:00:00 2001 From: Aous Naman Date: Thu, 6 Jun 2024 19:20:14 +1000 Subject: [PATCH 1/2] Commented ojph_codestream.h --- src/core/common/ojph_codestream.h | 251 ++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) diff --git a/src/core/common/ojph_codestream.h b/src/core/common/ojph_codestream.h index d496866..5f6dcdb 100644 --- a/src/core/common/ojph_codestream.h +++ b/src/core/common/ojph_codestream.h @@ -65,39 +65,290 @@ namespace ojph { class infile_base; //////////////////////////////////////////////////////////////////////////// + /** + * @brief The object represent a codestream. + * + * Most end-user use this object to create a j2c codestream. The object + * currently can be used in one of two modes, reading or writing. + * + * We try to follow the pImpl (pointer to Implementation) approach; + * therefore, objects in the ojph namespace hold pointers to internal + * implementations. The actual implementation is usually in the + * ojph::local namespace. The actual implementation of the + * ojph::codestream object is in ojph_codestream.cpp, while the actual + * implementation can be found in ojph_codestream_local.h and + * ojph_codestream_local.cpp. + * + * Most of these member functions provides nothing more than calls + * into the internal implementation. See ojph_codestream_local.h for + * more documentation -- yet to be added. + * + */ class OJPH_EXPORT codestream { public: + /** + * @brief default constructor + * + * This object instantiate the actual implementation object + * local::codestream, using new. + * + */ codestream(); + /** + * @brief default destructor + * + * This object destroys the internal local::codestream object. + * + */ ~codestream(); + /** + * @brief Sets the sequence of pushing or pull rows from the machinery. + * + * For this function, planar means that the machinery processes one + * colour component in full before processing the next component. This + * more efficient because the cache is used for one component instead of + * many components, but it is not practical when a color transform is + * employed. This is because we need to employ the transform to the first + * three components. Therefore, planar, while recommended, can only be + * used when there is no color transform. + * + * @param planar true for when components are pushed in full one at + * a time. + */ void set_planar(bool planar); + + /** + * @brief Sets the codestream profile. + * + * This is currently rather incomplete, but it accepts two profiles + * IMF and BROADCAST. More work is needed to improve this. + * Note that Rsiz field in the SIZ marker segment is not set properly. + * + * @param s a string of the profile name, value can be from + * OJPH_PN_STRING_XXXX, where only IMF and BROADCAST + * are currently supported. + */ void set_profile(const char* s); + + /** + * @brief Sets the locations where a tile is partitioned into tile parts. + * + * This function signals that we are interested in partitioning each tile + * into tile parts at resolution or component level, or both. This is + * useful when used with the TLM marker segment, because the TLM marker + * segment provides information about the locations of these partitions in + * the file. This way we can identify where resolution information ends + * within the codestream. It is also useful when large images are + * compressed, because an unpartitioned tile cannot be more than 4GB, but + * when partitioned, each tile part can be 4GB -- it is possible to + * partition at precinct boundaries to better utilize tile parts, and + * achieve a tile in the vicinity of 1TB, but this option is currently + * unsupported. + * + * @param at_resolutions partitions the tile into tile parts at + * resolutions. + * @param at_components partitions every tile into tile parts are + * components + */ void set_tilepart_divisions(bool at_resolutions, bool at_components); + + /** + * @brief Query if the tile will be partitioned at resolution boundary. + * + * @return true if resolution-boundary tile partitioning is employed. + * @return false if resolution-boundary tile partitioning is not + * requested. + */ bool is_tilepart_division_at_resolutions(); + + /** + * @brief Query if the tile will be partitioned at component boundary. + * + * @return true if component-boundary tile partitioning is employed. + * @return false if component-boundary tile partitioning is not + * requested. + */ bool is_tilepart_division_at_components(); + /** + * @brief Request the addition of the optional TLM marker segment. + * This request should occur before writing codestream headers + * ojph::codestream::write_headers()) + * + * @param needed true when the marker is needed. + */ void request_tlm_marker(bool needed); + + /** + * @brief Query if the optional TLM marker segment is to be added. + * + * @return true if the addition of the optional TLM marker segment + * is to be added. + * @return false if the addition of the optional TLM marker segment + * was not requested. + */ + bool is_tlm_requested(); + /** + * @brief Writes codestream headers when the codestream is used for + * writing. This function should be called after setting all the + * codestream parameters, but before pushing image lines using + * ojph::codestream::exchange(). + * + * @param file A class inherited from outfile_base, which used to store + * compressed image bitstream. This enables storing the + * compressed bitstream to memory or an actual file. + * @param comments A pointer to an array of comment_exchange objects. + * Each object stores one comment to be inserted in the + * bitstreams. The number of elements in the array + * should be equal to num_comments. + * @param num_comments The number of elements in the `comments` array. + * + */ void write_headers(outfile_base *file, const comment_exchange* comments = NULL, ui32 num_comments = 0); + + /** + * @brief This call is used to send image data rows to the library. + * We expect to send one row from a single component with + * each call. The first call is always with line == NULL; + * the call would return a line_buf, and the component + * number or index in `next_component.` The caller would + * then need to fill the buffer of the line_buf with one + * row from the component indexed by `next_component`, and + * call exchange again to pass the component and get a + * new line_buf. + * + * @param line A line_buf object; first call should supply NULL. + * Subsequent calls should pass the line_buf object + * obtained in the previous call. + * @param next_component returns a component index; the end user must + * fill the returned line_buf from the component + * indexed by this index. + * @return line_buf* A line_buf which must be filled with the component + * indexed by `next_component`, before calling + * exchange again to pass this line. + */ + line_buf* exchange(line_buf* line, ui32& next_component); + + /** + * @brief This is the last call to a writing (encoding) codestream. + * This will write encoded bitstream data to the file. This + * call does not close the file, because, in the future, we + * might wish to write more data to the file. If you do not + * want to write more data, then call codestream::close(). + */ void flush(); + /** + * @brief This enables codestream resilience; that is, the library tries + * its best to decode the codestream, even if there are errors. + * This call is for a decoding (or reading) codestream, and + * should be called before all other calls, before + * codestream::read_headers(). + */ void enable_resilience(); // before read_headers + + /** + * @brief This call reads the headers of a codestream. It is for a + * reading (or decoding) codestream, and should be called + * after codestream::enable_resilience(), but before + * codestream::restrict_input_resolution(). + * + * @param file The file to read from. The file should be inherited from + * ojph::infile_base; this enables reading from an actual file + * or from memory-based file. + */ void read_headers(infile_base *file); // before resolution restrictions + + /** + * @brief This function restricts resolution decoding for a codestream. + * It is for a reading (decoding) codestream. We can limit the + * restrictions to decoding and reconstruction resolution, + * or decoding only. Call this function after + * codestream::read_headers() but before codestream::create() + * + * @param skipped_res_for_data specifies for how many fine resolutions + * decoding is skipped, i.e., reading and + * decoding is not performed for this number + * of fine resolutions. + * @param skipped_res_for_recon specifies for how many fine resolutions + * reconstruction is skipped; the resulting + * image is smaller than the original. This + * number should be smaller or equal to + * `skipped_res_for_data,` as it does not + * make sense otherwise. + */ void restrict_input_resolution(ui32 skipped_res_for_data, ui32 skipped_res_for_recon); //before create + + /** + * @brief This call is for a decoding (or reading) codestream. Call this + * function after calling restrict_input_resolution(), if + * restrictions are needed. + */ void create(); + + /** + * @brief This call is to pull one row from the codestream, being + * decoded. The returned line_buf object holds one row from + * the image; the returned comp_num tells the reader the + * component to which this row belongs. + * + * @param comp_num returns the component to which the returned + * line_buf object belongs. + * @return line_buf* this object holds one row of the component indexed + * by comp_num. + */ line_buf* pull(ui32 &comp_num); + /** + * @brief Call this function to close the underlying file; works for both + * encoding and decoding codestreams. + * + */ void close(); + /** + * @brief Returns the underlying SIZ marker segment object + * + * @return param_siz This object holds SIZ marker segment information, + * which are related to codestream dimensions, number + * of components, bit depth, ... etc. + */ param_siz access_siz(); + + /** + * @brief Returns the underlying COD marker segment object + * + * @return param_cod This object holds COD marker segment information, + * which are related to coding parameters, such as + * codeblock sizes, progression order, reversible, + * ... etc. + */ param_cod access_cod(); + + /** + * @brief Returns the underlying QCD marker segment object + * + * @return param_qcd This object holds QCD marker segment information, + * which are related to quantization parameters -- + * quantization step size for each subband. + */ param_qcd access_qcd(); + + /** + * @brief Query if the codestream extraction is planar or not. + * See the documentation for ojph::codestream::set_planar() + * + * @return true if it is planar + * @return false if it is not planar (interleaved) + */ bool is_planar() const; private: From 6f413ff7d8870aa0deb4bd278efbd25d50d912f7 Mon Sep 17 00:00:00 2001 From: Aous Naman Date: Thu, 20 Jun 2024 13:17:16 +1000 Subject: [PATCH 2/2] Correcting a bug in ojph_message, and adding documentation to ojph_message.h --- src/core/common/ojph_message.h | 197 +++++++++++++++++++++++++++---- src/core/common/ojph_version.h | 4 +- src/core/others/ojph_message.cpp | 39 +++--- 3 files changed, 192 insertions(+), 48 deletions(-) diff --git a/src/core/common/ojph_message.h b/src/core/common/ojph_message.h index 45e3d7d..2271d0f 100644 --- a/src/core/common/ojph_message.h +++ b/src/core/common/ojph_message.h @@ -43,7 +43,12 @@ namespace ojph { - //////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief This enum is use to specify the level of severity of message while + * processing markers + * + */ enum OJPH_MSG_LEVEL : int { NO_MSG = 0, @@ -52,67 +57,206 @@ namespace ojph { ERROR = 3 }; - //////////////////////////////////////////////////////////////////////////// - class message_base { + ////////////////////////////////////////////////////////////////////////////// + /** + * @remark + * There are 3 levels of messaging; they are in order of level of + * severity: INFO, WARNING, and ERROR. ERROR is the most severe and + * code execution must be terminated. + * + * @remark + * The library provides two way to customize the reporting associated with + * each messaging level: + * 1. Calling set_XXXX_stream; this sets the library's output file stream + * to a user defined stream, such as std_err or a log file; it can + * also be set to NULL to prevent reporting. + * 2. Calling configure_XXXX to pass a pointer to an object from a class + * derived from the corresponding message_XXXX class. The derived + * class must override the virtual operator() to perform the desired + * behaviour. Remember for message_error, the user must throw an + * exception at the end of the implementation of operator(). + * + * The customization is global, and cannot be separately tailored for + * each decoder's instantiation. + */ + + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief This is the base class from which all messaging levels are derived + * + * Importantly it defined the base virtual operator() that must be defined + * in all derived classes. + */ + class OJPH_EXPORT message_base { public: - OJPH_EXPORT + /** + * @brief Prints a message and for errors throws an exception. + * All derived classes must override this virtual function. + * + * @param warn_code Message code (integer) for identifications. + * @param file_name The file name where the message originates. + * @param line_num The line number where the message originates. + * @param fmt The format of the message; this is printf format. + * @param ... A variable number of parameters to print. This is + * the parameters you would pass to printf. + */ virtual void operator() (int warn_code, const char* file_name, int line_num, const char *fmt, ...) = 0; }; - //////////////////////////////////////////////////////////////////////////// - class message_info : public message_base + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Derived from message_base to handle info messages + */ + class OJPH_EXPORT message_info : public message_base { public: - OJPH_EXPORT + /** + * @brief See the base message_base::operator() for details about + * parameters + */ virtual void operator() (int info_code, const char* file_name, int line_num, const char* fmt, ...); }; - //////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Replaces the info output file from the default stdout to user + * defined output file. + * + * @param s A pointer to the desired output file; it can be stdout, stderr, + * a log file, or NULL if no info messages are desired. + */ OJPH_EXPORT void set_info_stream(FILE* s); + + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief This overrides the default behaviour of handling info messages. + * + * @param info An object derived from message_info to implement the desired + * behaviour. + */ OJPH_EXPORT void configure_info(message_info* info); + + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Get the info message object, whose operator() member class is + * called for info messages -- See the macros below. + * + * @return message_info* returns the active message_info object, or an object + * of the message_info-derived class if one was set. This object + * handles info messages. This is mainly to be used with the macros + * below. + */ OJPH_EXPORT - message_info& get_info(); + message_info* get_info(); - //////////////////////////////////////////////////////////////////////////// - class message_warning : public message_base + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Derived from message_base to handle warning messages + */ + class OJPH_EXPORT message_warning : public message_base { public: - OJPH_EXPORT + /** + * @brief See the base message_base::operator() for details about + * parameters + */ virtual void operator() (int warn_code, const char* file_name, int line_num, const char* fmt, ...); }; - //////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Replaces the warning output file from the default stdout to user + * defined output file. + * + * @param s A pointer to the desired output file; it can be stdout, stderr, + * a log file, or NULL if no warning messages are desired. + */ OJPH_EXPORT void set_warning_stream(FILE* s); + + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief This overrides the default behaviour of handling warning messages. + * + * @param warn An object derived from message_warning to implement the + * desired behaviour. + */ OJPH_EXPORT void configure_warning(message_warning* warn); + + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Get the warning message object, whose operator() member class is + * called for warning messages -- See the macros below. + * + * @return message_warning* returns the active message_warning object, or an + * object of the message_warning-derived class if one was set. This + * object handles warning messages. This is mainly to be used with + * the macros below. + */ OJPH_EXPORT - message_warning& get_warning(); + message_warning* get_warning(); - //////////////////////////////////////////////////////////////////////////// - class message_error : public message_base + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Derived from message_base to handle error messages + */ + class OJPH_EXPORT message_error : public message_base { public: - OJPH_EXPORT + /** + * @brief See the base message_base::operator() for details about + * parameters + */ virtual void operator() (int warn_code, const char* file_name, int line_num, const char *fmt, ...); }; - //////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Replaces the error output file from the default stderr to user + * defined output file. + * + * @param s A pointer to the desired output file; it can be stdout, stderr, + * a log file, or NULL if no error messages are desired. + */ OJPH_EXPORT - void set_error_stream(FILE *s); + void set_error_stream(FILE *s); + + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief This overrides the default behaviour of handling error messages. + * + * @param error An object derived from message_error to implement the + * desired behaviour. Remember, remember to throw an exception + * at the end. + */ OJPH_EXPORT - void configure_error(message_error* error); + void configure_error(message_error* error); + + ////////////////////////////////////////////////////////////////////////////// + /** + * @brief Get the error message object, whose operator() member class is + * called for error messages -- See the macros below. + * + * @return message_error* returns the active message_error object, or an + * object of the message_error-derived class if one was set. This + * object handles error messages. This is mainly to be used with + * the macros below. + */ OJPH_EXPORT - message_error& get_error(); + message_error* get_error(); } ////////////////////////////////////////////////////////////////////////////// +/** + * @brief MACROS to remove the directory name from the file name + */ #if (defined OJPH_OS_WINDOWS) #define __OJPHFILE__ \ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) @@ -122,14 +266,15 @@ namespace ojph { #endif ////////////////////////////////////////////////////////////////////////////// +/** + * @brief MACROs to insert file and line number for info, warning, and error + */ #define OJPH_INFO(t, ...) \ - { ojph::get_info()(t, __OJPHFILE__, __LINE__, __VA_ARGS__); } -////////////////////////////////////////////////////////////////////////////// + { ojph::get_info()[0](t, __OJPHFILE__, __LINE__, __VA_ARGS__); } #define OJPH_WARN(t, ...) \ - { ojph::get_warning()(t, __OJPHFILE__, __LINE__, __VA_ARGS__); } -////////////////////////////////////////////////////////////////////////////// + { ojph::get_warning()[0](t, __OJPHFILE__, __LINE__, __VA_ARGS__); } #define OJPH_ERROR(t, ...) \ - { ojph::get_error()(t, __OJPHFILE__, __LINE__,__VA_ARGS__); } + { ojph::get_error()[0](t, __OJPHFILE__, __LINE__,__VA_ARGS__); } #endif // !OJPH_MESSAGE_H diff --git a/src/core/common/ojph_version.h b/src/core/common/ojph_version.h index ea8cfe0..c324706 100644 --- a/src/core/common/ojph_version.h +++ b/src/core/common/ojph_version.h @@ -34,5 +34,5 @@ //***************************************************************************/ #define OPENJPH_VERSION_MAJOR 0 -#define OPENJPH_VERSION_MINOR 13 -#define OPENJPH_VERSION_PATCH 3 +#define OPENJPH_VERSION_MINOR 14 +#define OPENJPH_VERSION_PATCH 0 diff --git a/src/core/others/ojph_message.cpp b/src/core/others/ojph_message.cpp index 40134e4..9da0f17 100644 --- a/src/core/others/ojph_message.cpp +++ b/src/core/others/ojph_message.cpp @@ -48,16 +48,16 @@ namespace ojph { //////////////////////////////////////////////////////////////////////////// message_info info; - message_info& local_info = info; + message_info* local_info = &info; //////////////////////////////////////////////////////////////////////////// void configure_info(message_info* info) { - local_info = *info; + local_info = info; } //////////////////////////////////////////////////////////////////////////// - message_info& get_info() + message_info* get_info() { return local_info; } @@ -89,16 +89,16 @@ namespace ojph { //////////////////////////////////////////////////////////////////////////// message_warning warn; - message_warning& local_warn = warn; + message_warning* local_warn = &warn; //////////////////////////////////////////////////////////////////////////// void configure_warning(message_warning* warn) { - local_warn = *warn; + local_warn = warn; } //////////////////////////////////////////////////////////////////////////// - message_warning& get_warning() + message_warning* get_warning() { return local_warn; } @@ -130,16 +130,16 @@ namespace ojph { //////////////////////////////////////////////////////////////////////////// message_error error; - message_error& local_error = error; + message_error* local_error = &error; //////////////////////////////////////////////////////////////////////////// void configure_error(message_error* error) { - local_error = *error; + local_error = error; } //////////////////////////////////////////////////////////////////////////// - message_error& get_error() + message_error* get_error() { return local_error; } @@ -154,18 +154,17 @@ namespace ojph { void message_error::operator()(int error_code, const char* file_name, int line_num, const char *fmt, ...) { - if (error_stream == NULL) - return; - - fprintf(error_stream, "ojph error 0x%08X at %s:%d: ", - error_code, file_name, line_num); - va_list args; - va_start(args, fmt); - vfprintf(error_stream, fmt, args); - fprintf(error_stream, "\n"); - va_end(args); + if (error_stream != NULL) + { + fprintf(error_stream, "ojph error 0x%08X at %s:%d: ", + error_code, file_name, line_num); + va_list args; + va_start(args, fmt); + vfprintf(error_stream, fmt, args); + fprintf(error_stream, "\n"); + va_end(args); + } throw std::runtime_error("ojph error"); } - }