diff --git a/autobuild.xml b/autobuild.xml index e32857f6b7a4c993db404a12900fac1e526fffb2..ca7874423d1ff429f2dcfe90b03d4e05aa71648d 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1902,11 +1902,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>666ad5a7dd4bede7745cbe2846e2516b47510720824c57fa976bf8424b4f7745b8adbc209e65410ad0e03d3f78f8146d841fb81bbf23fc05358be11ffef60900</string> + <string>4261f3c8510252c4767c422f309d6f5c462f3069dbe5d943bc72444d6ba56b796ed1c4e3b65c2c6ff12e37379445a6b172226bc56e3557e2bd698bf8d86ec322</string> <key>hash_algorithm</key> <string>blake2b</string> <key>url</key> - <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg/2.4.0.2371/openjpeg-2.4.0-darwin64-2371.tar.zst</string> + <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg/1.5.1.2451/openjpeg-1.5.1-darwin64-2451.tar.zst</string> </map> <key>name</key> <string>darwin64</string> @@ -1916,11 +1916,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>331d224c638d9ee50c519d8714ad48b8e1c7802ee18ff7b64c77c1905d48cee1a4f0d0c1f23c546dc298464817e4fd39a61b066537ea0a1cbcc90f059ae1747f</string> + <string>bfadf99f079161d6f2cef1ce1c4d2623a1aa8f02ba87ff71697af048261d4ea3ca2cbe3e95d627abe985c10bd80edd16b18ef124c7af57246a4ad7887de985d9</string> <key>hash_algorithm</key> <string>blake2b</string> <key>url</key> - <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg/2.4.0.2371/openjpeg-2.4.0-linux64-2371.tar.zst</string> + <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg/1.5.1.2451/openjpeg-1.5.1-linux64-2451.tar.zst</string> </map> <key>name</key> <string>linux64</string> @@ -1930,11 +1930,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>4bc3980bf4bf9b5d933fcca1949bd2890a5fb2e3a22675e524ea6989150a77211e30f3bc81999272f23387f3aefcd2d894dca7f5bea6f79fcb6b8aea6a02ebcb</string> + <string>d10bc74430b0ee657cb9c6bafec81860974547c1890c038e4223b6e50665cf352a0b8c7dd2db81b21c086a15c6a55ba545d087f88dedddf599fd743e515564c9</string> <key>hash_algorithm</key> <string>blake2b</string> <key>url</key> - <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg/2.4.0.2371/openjpeg-2.4.0-windows64-2371.tar.zst</string> + <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg/1.5.1.2451/openjpeg-1.5.1-windows64-2451.tar.zst</string> </map> <key>name</key> <string>windows64</string> @@ -1945,9 +1945,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>license_file</key> <string>LICENSES/openjpeg.txt</string> <key>copyright</key> - <string>Copyright (c) 2002-2014, Universite catholique de Louvain, Belgium, Copyright (c) 2002-2012, Professor Benoit Macq, Copyright (c) 2003-2012, Antonin Descampe, Copyright (c) 2003-2009, Francois-Olivier Devaux, Copyright (c) 2005, Herve Drolon, FreeImage Team, Copyright (c) 2002-2003, Yannick Verschueren, Copyright (c) 2001-2003, David Janssens</string> + <string>Copyright (c) 2002-2012, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium, Copyright (c) 2002-2012, Professor Benoit Macq, Copyright (c) 2003-2012, Antonin Descampe, Copyright (c) 2003-2009, Francois-Olivier Devaux, Copyright (c) 2005, Herve Drolon, FreeImage Team, Copyright (c) 2002-2003, Yannick Verschueren, Copyright (c) 2001-2003, David Janssens</string> <key>version</key> - <string>2.4.0</string> + <string>1.5.1</string> <key>name</key> <string>openjpeg</string> <key>description</key> diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index ecb2eda9014623449ac480e5bdfc8059516ec683..8f8322d8c47de220aa150eb10c45768177d0f054 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -58,12 +58,12 @@ if(WINDOWS) set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}") set(debug_files - openjp2.dll + openjpeg.dll ) set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") set(release_files - openjp2.dll + openjpeg.dll ) # ICU4C (same filenames for 32 and 64 bit builds) diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake index 32739d5786de349b03e602cd7e38ec4ed77b01c5..5d4abf57afd8aa39c73230a993bb1464e8320c82 100644 --- a/indra/cmake/OpenJPEG.cmake +++ b/indra/cmake/OpenJPEG.cmake @@ -9,9 +9,9 @@ use_prebuilt_binary(openjpeg) if(WINDOWS) target_link_libraries(ll::openjpeg INTERFACE - debug ${ARCH_PREBUILT_DIRS_DEBUG}/openjp2.lib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/openjp2.lib) + debug ${ARCH_PREBUILT_DIRS_DEBUG}/openjpeg.lib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/openjpeg.lib) else () - target_link_libraries(ll::openjpeg INTERFACE openjp2 ) + target_link_libraries(ll::openjpeg INTERFACE openjpeg ) endif () -target_include_directories( ll::openjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/openjpeg) +target_include_directories( ll::openjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/openjpeg-1.5) diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index aafb2e228670f1081561ae316712fac1063e7a46..ce7035de4fb4a7e0cfa7c549e742ad25efac110a 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llimagej2coj.cpp * @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,134 +27,11 @@ #include "linden_common.h" #include "llimagej2coj.h" -// this is defined so that we get static linking. + // this is defined so that we get static linking. #include "openjpeg.h" #include "lltimer.h" - -struct LLJp2StreamReader -{ - LLJp2StreamReader(LLImageJ2C* pImage) : m_pImage(pImage), m_Position(0) { } - - static OPJ_SIZE_T readStream(void* pBufferOut, OPJ_SIZE_T szBufferOut, void* pUserData) - { - LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData); - if (!pBufferOut || !pStream || !pStream->m_pImage) - return (OPJ_SIZE_T)-1; - - OPJ_SIZE_T szBufferRead = llmin(szBufferOut, pStream->m_pImage->getDataSize() - pStream->m_Position); - if (!szBufferRead) - return (OPJ_SIZE_T)-1; - - memcpy(pBufferOut, pStream->m_pImage->getData() + pStream->m_Position, szBufferRead); - pStream->m_Position += szBufferRead; - return szBufferRead; - } - - static OPJ_OFF_T skipStream(OPJ_OFF_T bufferOffset, void* pUserData) - { - LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData); - if (!pStream || !pStream->m_pImage) - return (OPJ_OFF_T)-1; - - if (bufferOffset < 0) - { - // Skipping backward - if (pStream->m_Position == 0) - return (OPJ_OFF_T)-1; // Already at the start of the stream - else if (pStream->m_Position + bufferOffset < 0) - bufferOffset = -(OPJ_OFF_T)pStream->m_Position; // Don't underflow - } - else - { - // Skipping forward - OPJ_SIZE_T szRemaining = pStream->m_pImage->getDataSize() - pStream->m_Position; - if (!szRemaining) - return (OPJ_OFF_T)-1; // Already at the end of the stream - else if (bufferOffset > szRemaining) - bufferOffset = szRemaining; // Don't overflow - } - pStream->m_Position += bufferOffset; - - return bufferOffset; - } - - static OPJ_BOOL seekStream(OPJ_OFF_T bufferOffset, void* pUserData) - { - LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData); - if (!pStream || !pStream->m_pImage) - return OPJ_FALSE; - - if (bufferOffset < 0 || bufferOffset > pStream->m_pImage->getDataSize()) - return OPJ_FALSE; - - pStream->m_Position = bufferOffset; - return OPJ_TRUE; - } - - LLImageJ2C* m_pImage = nullptr; - OPJ_SIZE_T m_Position = 0; -}; - -struct LLJp2StreamWriter -{ - LLJp2StreamWriter(LLImageJ2C* pImage) : m_pImage(pImage), m_Position(0) { } - - static OPJ_SIZE_T writeStream(void* pBufferIn, OPJ_SIZE_T szBufferIn, void* pUserData) - { - LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData); - if (!pBufferIn || !pStream || !pStream->m_pImage) - return (OPJ_SIZE_T)-1; - - if (pStream->m_Position + szBufferIn > pStream->m_pImage->getDataSize()) - pStream->m_pImage->reallocateData(pStream->m_Position + szBufferIn); - - memcpy(pStream->m_pImage->getData() + pStream->m_Position, pBufferIn, szBufferIn); - pStream->m_Position += szBufferIn; - return szBufferIn; - } - - static OPJ_OFF_T skipStream(OPJ_OFF_T bufferOffset, void* pUserData) - { - LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData); - if (!pStream || !pStream->m_pImage) - return -1; - - if (bufferOffset < 0) - { - // Skipping backward - if (pStream->m_Position == 0) - return -1; // Already at the start of the stream - else if (pStream->m_Position + bufferOffset < 0) - bufferOffset = -(OPJ_OFF_T)pStream->m_Position; // Don't underflow - } - else - { - // Skipping forward - if (pStream->m_Position + bufferOffset > pStream->m_pImage->getDataSize()) - return -1; // Don't allow skipping past the end of the stream - } - - pStream->m_Position += bufferOffset; - return bufferOffset; - } - - static OPJ_BOOL seekStream(OPJ_OFF_T bufferOffset, void* pUserData) - { - LLJp2StreamReader* pStream = static_cast<LLJp2StreamReader*>(pUserData); - if (!pStream || !pStream->m_pImage) - return OPJ_FALSE; - - if (bufferOffset < 0 || bufferOffset > pStream->m_pImage->getDataSize()) - return OPJ_FALSE; - - pStream->m_Position = bufferOffset; - return OPJ_TRUE; - } - - LLImageJ2C* m_pImage = nullptr; - OPJ_OFF_T m_Position = 0; -}; +//#include "llmemory.h" // Factory function: see declaration in llimagej2c.cpp LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() @@ -164,10 +41,11 @@ LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() std::string LLImageJ2COJ::getEngineInfo() const { -#ifdef OPJ_PACKAGE_VERSION - return std::string("OpenJPEG: " OPJ_PACKAGE_VERSION ", Runtime: ") + opj_version(); +#ifdef OPENJPEG_VERSION + return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ") + + opj_version(); #else - return std::string("OpenJPEG Runtime: ") + opj_version(); + return std::string("OpenJPEG runtime: ") + opj_version(); #endif } @@ -181,7 +59,7 @@ static std::string chomp(const char* msg) size_t last = message.size() - 1; if (message[last] == '\n') { - message.resize( last ); + message.resize(last); } } return message; @@ -192,21 +70,21 @@ sample error callback expecting a LLFILE* client object */ void error_callback(const char* msg, void*) { - LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; + LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } /** sample warning callback expecting a LLFILE* client object */ void warning_callback(const char* msg, void*) { - LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; + LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } /** sample debug callback expecting no client object */ void info_callback(const char* msg, void*) { - LL_INFOS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; + LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } // Divide a by 2 to the power of b and round upwards @@ -215,70 +93,47 @@ int ceildivpow2(int a, int b) return (a + (1 << b) - 1) >> b; } + LLImageJ2COJ::LLImageJ2COJ() : LLImageJ2CImpl() { } -bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region) + +bool LLImageJ2COJ::initDecode(LLImageJ2C& base, LLImageRaw& raw_image, int discard_level, int* region) { // No specific implementation for this method in the OpenJpeg case return false; } -bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels) +bool LLImageJ2COJ::initEncode(LLImageJ2C& base, LLImageRaw& raw_image, int blocks_size, int precincts_size, int levels) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // No specific implementation for this method in the OpenJpeg case return false; } -bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) +bool LLImageJ2COJ::decodeImpl(LLImageJ2C& base, LLImageRaw& raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) { + // + // FIXME: Get the comment field out of the texture + // + LLTimer decode_timer; - /* Extract metadata */ - /* ---------------- */ - U8* c_data = base.getData(); - size_t c_size = base.getDataSize(); - size_t position = 0; - - while (position < 1024 && position < (c_size - 7)) // the comment field should be in the first 1024 bytes. - { - if (c_data[position] == 0xff && c_data[position + 1] == 0x64) - { - U8 high_byte = c_data[position + 2]; - U8 low_byte = c_data[position + 3]; - S32 c_length = (high_byte * 256) + low_byte; // This size also counts the markers, 00 01 and itself - if (c_length > 200) // sanity check - { - // While comments can be very long, anything longer then 200 is suspect. - break; - } - - if (position + 2 + c_length > c_size) - { - // comment extends past end of data, corruption, or all data not retrived yet. - break; - } - - // if the comment block does not end at the end of data, check to see if the next - // block starts with 0xFF - if (position + 2 + c_length < c_size && c_data[position + 2 + c_length] != 0xff) - { - // invalied comment block - break; - } - - // extract the comment minus the markers, 00 01 - raw_image.mComment.assign((char*)c_data + position + 6, c_length - 4); - break; - } - ++position; - } - opj_dparameters_t parameters; /* decompression parameters */ - opj_image_t *image = NULL; + opj_event_mgr_t event_mgr = { }; /* event manager */ + opj_image_t* image = nullptr; + + opj_dinfo_t* dinfo = nullptr; /* handle to a decompressor */ + opj_cio_t* cio = nullptr; + + +#if SHOW_DEBUG + /* configure the event callbacks (not required) */ + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; +#endif /* set decoding parameters to default values */ opj_set_default_decoder_parameters(¶meters); @@ -291,63 +146,35 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod /* JPEG-2000 codestream */ /* get a decoder handle */ - opj_codec_t* opj_decoder_p = opj_create_decompress(OPJ_CODEC_J2K); - if (!opj_decoder_p) - { -#ifdef SHOW_DEBUG - LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to create decoder!" << LL_ENDL; -#endif - base.decodeFailed(); - return true; // done - } + dinfo = opj_create_decompress(CODEC_J2K); -#if 0 /* catch events using our callbacks and give a local context */ - opj_set_error_handler(opj_decoder_p, error_callback, nullptr); - opj_set_warning_handler(opj_decoder_p, warning_callback, nullptr); - opj_set_info_handler(opj_decoder_p, info_callback, nullptr); -#endif + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); /* setup the decoder decoding parameters using user parameters */ - if (!opj_setup_decoder(opj_decoder_p, ¶meters)) - { -#ifdef SHOW_DEBUG - LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; -#endif - opj_destroy_codec(opj_decoder_p); - base.decodeFailed(); - return true; // done - } - - //opj_decoder_set_strict_mode(opj_decoder_p, OPJ_FALSE); + opj_setup_decoder(dinfo, ¶meters); /* open a byte stream */ - LLJp2StreamReader streamReader(&base); - opj_stream_t* opj_stream_p = opj_stream_default_create(OPJ_STREAM_READ); - opj_stream_set_read_function(opj_stream_p, LLJp2StreamReader::readStream); - opj_stream_set_skip_function(opj_stream_p, LLJp2StreamReader::skipStream); - opj_stream_set_seek_function(opj_stream_p, LLJp2StreamReader::seekStream); - opj_stream_set_user_data(opj_stream_p, &streamReader, nullptr); - opj_stream_set_user_data_length(opj_stream_p, base.getDataSize()); + cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); /* decode the stream and fill the image structure */ - bool success = opj_read_header(opj_stream_p, opj_decoder_p, &image) && - opj_decode(opj_decoder_p, opj_stream_p, image) && - opj_end_decompress(opj_decoder_p, opj_stream_p); + image = opj_decode(dinfo, cio); /* close the byte stream */ - opj_stream_destroy(opj_stream_p); + opj_cio_close(cio); /* free remaining structures */ - opj_destroy_codec(opj_decoder_p); - + if (dinfo) + { + opj_destroy_decompress(dinfo); + } // The image decode failed if the return was NULL or the component // count was zero. The latter is just a sanity check before we // dereference the array. - if (!success || !image || !image->numcomps) + if (!image || !image->numcomps) { -#ifdef SHOW_DEBUG +#if SHOW_DEBUG LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; #endif if (image) @@ -358,15 +185,23 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod return true; // done } - if(image->numcomps <= first_channel) + // sometimes we get bad data out of the cache - check to see if the decode succeeded + for (S32 i = 0; i < image->numcomps; i++) { - LL_WARNS() << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL; - if (image) + if (image->comps[i].factor != base.getRawDiscardLevel()) { + // if we didn't get the discard level we're expecting, fail opj_image_destroy(image); + base.decodeFailed(); + return true; } - base.decodeFailed(); + } + if (image->numcomps <= first_channel) + { + LL_WARNS() << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL; + opj_image_destroy(image); + base.decodeFailed(); return true; } @@ -374,7 +209,7 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod S32 img_components = image->numcomps; S32 channels = img_components - first_channel; - if( channels > max_channel_count ) + if (channels > max_channel_count) channels = max_channel_count; // Component buffers are allocated in an image width by height buffer. @@ -385,11 +220,11 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod // (Assuming all the components have the same width, height and // factor.) S32 comp_width = image->comps[0].w; - S32 f=image->comps[0].factor; + S32 f = image->comps[0].factor; S32 width = ceildivpow2(image->x1 - image->x0, f); S32 height = ceildivpow2(image->y1 - image->y0, f); raw_image.resize(width, height, channels); - U8 *rawp = raw_image.getData(); + U8* rawp = raw_image.getData(); if (!rawp) { opj_image_destroy(image); @@ -401,7 +236,7 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod // first_channel is what channel to start copying from // dest is what channel to copy to. first_channel comes from the // argument, dest always starts writing at channel zero. - for (S32 comp = first_channel, dest=0; comp < first_channel + channels; + for (S32 comp = first_channel, dest = 0; comp < first_channel + channels; comp++, dest++) { if (image->comps[comp].data) @@ -411,14 +246,14 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod { for (S32 x = 0; x < width; x++) { - rawp[offset] = image->comps[comp].data[y*comp_width + x]; + rawp[offset] = image->comps[comp].data[y * comp_width + x]; offset += channels; } } } else // Some rare OpenJPEG versions have this bug. { -#ifdef SHOW_DEBUG +#if SHOW_DEBUG LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << LL_ENDL; #endif opj_image_destroy(image); @@ -434,10 +269,20 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod } -bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible) +bool LLImageJ2COJ::encodeImpl(LLImageJ2C& base, const LLImageRaw& raw_image, const char* comment_text, F32 encode_time, bool reversible) { const S32 MAX_COMPS = 5; opj_cparameters_t parameters; /* compression parameters */ + opj_event_mgr_t event_mgr = { }; /* event manager */ + + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; /* set encoding parameters to default values */ opj_set_default_encoder_parameters(¶meters); @@ -452,10 +297,10 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con else { parameters.tcp_numlayers = 5; - parameters.tcp_rates[0] = 1920.0f; - parameters.tcp_rates[1] = 480.0f; - parameters.tcp_rates[2] = 120.0f; - parameters.tcp_rates[3] = 30.0f; + parameters.tcp_rates[0] = 1920.0f; + parameters.tcp_rates[1] = 480.0f; + parameters.tcp_rates[2] = 120.0f; + parameters.tcp_rates[3] = 30.0f; parameters.tcp_rates[4] = 10.0f; parameters.irreversible = 1; if (raw_image.getComponents() >= 3) @@ -466,26 +311,26 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con if (!comment_text) { - parameters.cp_comment = (char *) ""; + parameters.cp_comment = (char*)""; } else { // Awful hacky cast, too lazy to copy right now. - parameters.cp_comment = (char *) comment_text; + parameters.cp_comment = (char*)comment_text; } // // Fill in the source image from our raw image // - OPJ_COLOR_SPACE color_space = OPJ_CLRSPC_SRGB; + OPJ_COLOR_SPACE color_space = CLRSPC_SRGB; opj_image_cmptparm_t cmptparm[MAX_COMPS]; - opj_image_t * image = NULL; + opj_image_t* image = nullptr; S32 numcomps = raw_image.getComponents(); S32 width = raw_image.getWidth(); S32 height = raw_image.getHeight(); memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t)); - for(S32 c = 0; c < numcomps; c++) { + for (S32 c = 0; c < numcomps; c++) { cmptparm[c].prec = 8; cmptparm[c].bpp = 8; cmptparm[c].sgnd = 0; @@ -502,12 +347,12 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con image->y1 = height; S32 i = 0; - const U8 *src_datap = raw_image.getData(); + const U8* src_datap = raw_image.getData(); for (S32 y = height - 1; y >= 0; y--) { for (S32 x = 0; x < width; x++) { - const U8 *pixel = src_datap + (y*width + x) * numcomps; + const U8* pixel = src_datap + (y * width + x) * numcomps; for (S32 c = 0; c < numcomps; c++) { image->comps[c].data[i] = *pixel; @@ -517,113 +362,104 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con } } + + /* encode the destination image */ /* ---------------------------- */ + int codestream_length; + opj_cio_t* cio = nullptr; + /* get a J2K compressor handle */ - opj_codec_t* opj_encoder_p = opj_create_compress(OPJ_CODEC_J2K); + opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); -#ifdef SHOW_DEBUG /* catch events using our callbacks and give a local context */ - opj_set_error_handler(opj_encoder_p, error_callback, nullptr); - opj_set_warning_handler(opj_encoder_p, warning_callback, nullptr); - opj_set_info_handler(opj_encoder_p, info_callback, nullptr); -#endif + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); /* setup the encoder parameters using the current image and using user parameters */ - if (!opj_setup_encoder(opj_encoder_p, ¶meters, image)) - { - opj_destroy_codec(opj_encoder_p); - opj_image_destroy(image); - LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL; - return false; - } + opj_setup_encoder(cinfo, ¶meters, image); /* open a byte stream for writing */ /* allocate memory for all tiles */ - LLJp2StreamWriter streamWriter(&base); - opj_stream_t* opj_stream_p = opj_stream_default_create(OPJ_STREAM_WRITE); - opj_stream_set_write_function(opj_stream_p, LLJp2StreamWriter::writeStream); - opj_stream_set_skip_function(opj_stream_p, LLJp2StreamWriter::skipStream); - opj_stream_set_seek_function(opj_stream_p, LLJp2StreamWriter::seekStream); - opj_stream_set_user_data(opj_stream_p, &streamWriter, nullptr); - opj_stream_set_user_data_length(opj_stream_p, raw_image.getDataSize()); + cio = opj_cio_open((opj_common_ptr)cinfo, nullptr, 0); /* encode the image */ - if (!opj_start_compress(opj_encoder_p, image, opj_stream_p) || - !opj_encode(opj_encoder_p, opj_stream_p) || - !opj_end_compress(opj_encoder_p, opj_stream_p)) + bool bSuccess = opj_encode(cinfo, cio, image, nullptr); + if (!bSuccess) { - opj_stream_destroy(opj_stream_p); - opj_destroy_codec(opj_encoder_p); - opj_image_destroy(image); + opj_cio_close(cio); LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL; return false; } + codestream_length = cio_tell(cio); + base.copyData(cio->buffer, codestream_length); base.updateData(); // set width, height /* close and free the byte stream */ - opj_stream_destroy(opj_stream_p); + opj_cio_close(cio); /* free remaining compression structures */ - opj_destroy_codec(opj_encoder_p); + opj_destroy_compress(cinfo); + + + /* free user parameters structure */ + if (parameters.cp_matrice) free(parameters.cp_matrice); /* free image data */ opj_image_destroy(image); - return true; } -inline S32 extractLong4( U8 const *aBuffer, int nOffset ) +inline S32 extractLong4(U8 const* aBuffer, int nOffset) { - S32 ret = aBuffer[ nOffset ] << 24; - ret += aBuffer[ nOffset + 1 ] << 16; - ret += aBuffer[ nOffset + 2 ] << 8; - ret += aBuffer[ nOffset + 3 ]; + S32 ret = aBuffer[nOffset] << 24; + ret += aBuffer[nOffset + 1] << 16; + ret += aBuffer[nOffset + 2] << 8; + ret += aBuffer[nOffset + 3]; return ret; } -inline S32 extractShort2( U8 const *aBuffer, int nOffset ) +inline S32 extractShort2(U8 const* aBuffer, int nOffset) { - S32 ret = aBuffer[ nOffset ] << 8; - ret += aBuffer[ nOffset + 1 ]; + S32 ret = aBuffer[nOffset] << 8; + ret += aBuffer[nOffset + 1]; return ret; } -inline bool isSOC( U8 const *aBuffer ) +inline bool isSOC(U8 const* aBuffer) { - return aBuffer[ 0 ] == 0xFF && aBuffer[ 1 ] == 0x4F; + return aBuffer[0] == 0xFF && aBuffer[1] == 0x4F; } -inline bool isSIZ( U8 const *aBuffer ) +inline bool isSIZ(U8 const* aBuffer) { - return aBuffer[ 0 ] == 0xFF && aBuffer[ 1 ] == 0x51; + return aBuffer[0] == 0xFF && aBuffer[1] == 0x51; } -bool getMetadataFast( LLImageJ2C &aImage, S32 &aW, S32 &aH, S32 &aComps ) +bool getMetadataFast(LLImageJ2C& aImage, S32& aW, S32& aH, S32& aComps) { - const int J2K_HDR_LEN( 42 ); - const int J2K_HDR_X1( 8 ); - const int J2K_HDR_Y1( 12 ); - const int J2K_HDR_X0( 16 ); - const int J2K_HDR_Y0( 20 ); - const int J2K_HDR_NUMCOMPS( 40 ); - - if( aImage.getDataSize() < J2K_HDR_LEN ) + const int J2K_HDR_LEN(42); + const int J2K_HDR_X1(8); + const int J2K_HDR_Y1(12); + const int J2K_HDR_X0(16); + const int J2K_HDR_Y0(20); + const int J2K_HDR_NUMCOMPS(40); + + if (aImage.getDataSize() < J2K_HDR_LEN) return false; U8 const* pBuffer = aImage.getData(); - if( !isSOC( pBuffer ) || !isSIZ( pBuffer+2 ) ) + if (!isSOC(pBuffer) || !isSIZ(pBuffer + 2)) return false; - S32 x1 = extractLong4( pBuffer, J2K_HDR_X1 ); - S32 y1 = extractLong4( pBuffer, J2K_HDR_Y1 ); - S32 x0 = extractLong4( pBuffer, J2K_HDR_X0 ); - S32 y0 = extractLong4( pBuffer, J2K_HDR_Y0 ); - S32 numComps = extractShort2( pBuffer, J2K_HDR_NUMCOMPS ); + S32 x1 = extractLong4(pBuffer, J2K_HDR_X1); + S32 y1 = extractLong4(pBuffer, J2K_HDR_Y1); + S32 x0 = extractLong4(pBuffer, J2K_HDR_X0); + S32 y0 = extractLong4(pBuffer, J2K_HDR_Y0); + S32 numComps = extractShort2(pBuffer, J2K_HDR_NUMCOMPS); aComps = numComps; aW = x1 - x0; @@ -632,7 +468,7 @@ bool getMetadataFast( LLImageJ2C &aImage, S32 &aW, S32 &aH, S32 &aComps ) return true; } -bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) +bool LLImageJ2COJ::getMetadata(LLImageJ2C& base) { // // FIXME: We get metadata by decoding the ENTIRE image. @@ -645,7 +481,7 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) S32 height(0); S32 img_components(0); - if ( getMetadataFast( base, width, height, img_components ) ) + if (getMetadataFast(base, width, height, img_components)) { base.setSize(width, height, img_components); return true; @@ -654,77 +490,63 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) // Do it the old and slow way, decode the image with openjpeg opj_dparameters_t parameters; /* decompression parameters */ - opj_image_t *image = nullptr; - opj_codec_t *opj_decoder = nullptr; /* handle to a decompressor */ + opj_event_mgr_t event_mgr = { }; /* event manager */ + opj_image_t* image = nullptr; + + opj_dinfo_t* dinfo = nullptr; /* handle to a decompressor */ + opj_cio_t* cio = nullptr; + + + /* configure the event callbacks (not required) */ + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; /* set decoding parameters to default values */ opj_set_default_decoder_parameters(¶meters); + // Only decode what's required to get the size data. + parameters.cp_limit_decoding = LIMIT_TO_MAIN_HEADER; + + //parameters.cp_reduce = mRawDiscardLevel; + /* decode the code-stream */ /* ---------------------- */ /* JPEG-2000 codestream */ /* get a decoder handle */ - opj_decoder = opj_create_decompress(OPJ_CODEC_J2K); - if (opj_decoder) - { - LL_WARNS() << "ERROR -> getMetadata: failed to create decoder!" << LL_ENDL; - return false; - } + dinfo = opj_create_decompress(CODEC_J2K); -#ifdef SHOW_DEBUG /* catch events using our callbacks and give a local context */ - opj_set_error_handler(opj_decoder, error_callback, nullptr); - opj_set_warning_handler(opj_decoder, warning_callback, nullptr); - opj_set_info_handler(opj_decoder, info_callback, nullptr); -#endif + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); /* setup the decoder decoding parameters using user parameters */ - if (!opj_setup_decoder(opj_decoder, ¶meters)) - { - LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL; - opj_destroy_codec(opj_decoder); - return false; - } + opj_setup_decoder(dinfo, ¶meters); /* open a byte stream */ - LLJp2StreamReader streamReader(&base); - opj_stream_t* decode_stream = opj_stream_default_create(OPJ_STREAM_READ); - opj_stream_set_read_function(decode_stream, LLJp2StreamReader::readStream); - opj_stream_set_skip_function(decode_stream, LLJp2StreamReader::skipStream); - opj_stream_set_seek_function(decode_stream, LLJp2StreamReader::seekStream); - opj_stream_set_user_data(decode_stream, &streamReader, nullptr); - opj_stream_set_user_data_length(decode_stream, base.getDataSize()); + cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); /* decode the stream and fill the image structure */ - if (!opj_read_header(decode_stream, opj_decoder, &image)) - { - LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL; - - opj_stream_destroy(decode_stream); - opj_destroy_codec(opj_decoder); - - if (image) - { - opj_image_destroy(image); - } - return false; - } + image = opj_decode(dinfo, cio); /* close the byte stream */ - opj_stream_destroy(decode_stream); + opj_cio_close(cio); /* free remaining structures */ - opj_destroy_codec(opj_decoder); + if (dinfo) + { + opj_destroy_decompress(dinfo); + } - if(!image) + if (!image) { LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL; return false; } // Copy image data into our raw image format (instead of the separate channel format + img_components = image->numcomps; width = image->x1 - image->x0; height = image->y1 - image->y0; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f092c725ab9b8e91121b051cbbc83a06800c21e7..39c77de8a389733daeae6cd74760b0a845a39510 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1936,7 +1936,7 @@ if (WINDOWS) # The following commented dependencies are determined at variably at build time. Can't do this here. ${CMAKE_SOURCE_DIR}/../etc/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg - ${SHARED_LIB_STAGING_DIR}/openjp2.dll + ${SHARED_LIB_STAGING_DIR}/openjpeg.dll #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/libsndfile-1.dll #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/vivoxoal.dll diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index bd962b441cab3a22e3901f2615e0e329f1b14b70..df184fb16aad8d6d4959b24df4c2a64ccc070e19 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -457,7 +457,7 @@ def construct(self): with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', self.args['buildtype'])): # For image support - self.path("openjp2.dll") + self.path("openjpeg.dll") # Get openal dll for audio engine, continue if missing if self.args['openal'] == 'ON' or self.args['openal'] == 'TRUE': @@ -1241,7 +1241,7 @@ def construct(self): with self.prefix(src=relpkgdir, dst="lib"): self.path("libSDL2*.so*") - self.path("libopenjp2.*so*") + self.path("libopenjpeg.*so*") self.path("libjpeg.so*") if self.args['openal'] == 'ON' or self.args['openal'] == 'TRUE': @@ -1279,7 +1279,7 @@ def construct(self): with self.prefix(src=relpkgdir, dst="lib"): self.path("libSDL2*.so*") - self.path("libopenjp2.*so*") + self.path("libopenjpeg.*so*") self.path("libjpeg.so*") self.path("libsdbus-c++.so*")