diff --git a/autobuild.xml b/autobuild.xml index de34be725d84528c6b50435cf19d078df496749b..355ce178b3fbd32603d25f8b8a26f297e36a4117 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2112,7 +2112,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>openjpeg</key> <map> <key>copyright</key> - <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> + <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> <key>description</key> <string>The OpenJPEG library is an open-source JPEG 2000 codec written in C language.</string> <key>license</key> @@ -2142,11 +2142,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>60a1ca9b97ad74a8e3a33d33caf503cdb5e7f1684d6316ed484471c02124d603878c8526f7166a16064cd7c88b9905db</string> + <string>80c7062c95c45e6851ddbdf19f61885280728ec40a5dfdcfbdaea9c4eed0bfe7dcbfb71b7e7e6d01fff4eb357f7c02ae</string> <key>hash_algorithm</key> <string>sha3_384</string> <key>url</key> - <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg-641/1.5.1/openjpeg-1.5.1-linux64-641.tar.xz</string> + <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg-753/2.4.0/openjpeg-2.4.0-linux64-753.tar.xz</string> </map> <key>name</key> <string>linux64</string> @@ -2156,11 +2156,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>474913320ea038660a73810b6563d0b2174cef5a9445f3454fb6e8d9efac89fddb9fb0be007001a434ec3c8125917f6d</string> + <string>d6984ea9ff046e2e541071182833365cc0d15edfcad59c4ded1f15c3d1ba88f3627c784f5c0f789a003244a816788cde</string> <key>hash_algorithm</key> <string>sha3_384</string> <key>url</key> - <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg-641/1.5.1/openjpeg-1.5.1-windows-641.tar.xz</string> + <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg-753/2.4.0/openjpeg-2.4.0-windows-753.tar.xz</string> </map> <key>name</key> <string>windows</string> @@ -2170,18 +2170,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>044b5655aecdc9e22f013509ec3a0a8297955cfc993465256e182d519876d55bc3b33df56b861f587a8086e79b8aa090</string> + <string>993058a8a028842c7e65c49612c893fcf3e6961eb13b9be88a2080f6f5b4b782791bd5bb3eed79d05ca3734b26b0102e</string> <key>hash_algorithm</key> <string>sha3_384</string> <key>url</key> - <string>https://git.alchemyviewer.org/api/v4/projects/105/packages/generic/openjpeg-641/1.5.1/openjpeg-1.5.1-windows64-641.tar.xz</string> + <string>https://git.alchemyviewer.org/api/v4/projects/147/packages/generic/openjpeg-753/2.4.0/openjpeg-2.4.0-windows64-753.tar.xz</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>1.5.1</string> + <string>2.4.0</string> </map> <key>openssl</key> <map> diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 8b7ac2f71b2d3eae0237305fda7b429c287e58f7..0dd49e1a31f37bfc2685ec8c4feb9254731b718d 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -81,7 +81,7 @@ if(WINDOWS) libxml2.dll minizip.dll nghttp2.dll - openjpeg.dll + openjp2.dll ssleay32.dll uriparser.dll xmlrpc-epi.dll diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake index dc92cdb4110592a734aaafd8bf8474833f9a7bbd..46dac7ec0f565538dfd214e9911371e1213fdf62 100644 --- a/indra/cmake/OpenJPEG.cmake +++ b/indra/cmake/OpenJPEG.cmake @@ -10,13 +10,10 @@ else (USESYSTEMLIBS) use_prebuilt_binary(openjpeg) if(WINDOWS) - # Windows has differently named release and debug openjpeg(d) libs. - set(OPENJPEG_LIBRARIES - debug openjpegd - optimized openjpeg) + set(OPENJPEG_LIBRARIES openjp2) else(WINDOWS) - set(OPENJPEG_LIBRARIES openjpeg) + set(OPENJPEG_LIBRARIES openjp2) endif(WINDOWS) - set(OPENJPEG_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/openjpeg-1.5) + set(OPENJPEG_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/openjpeg) endif (USESYSTEMLIBS) diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index d7706e73b24ed6033609482a852323aaf077b04b..3957ede77f01d49af6eabc3cd7d389c223c4d8d8 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -99,14 +99,14 @@ if (WINDOWS) # Copy over OpenJPEG.dll # *NOTE: On Windows with VS2005, only the first comment prints set(OPENJPEG_RELEASE - "${ARCH_PREBUILT_DIRS_RELEASE}/openjpeg.dll") + "${ARCH_PREBUILT_DIRS_RELEASE}/openjp2.dll") add_custom_command( TARGET llui_libtest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${OPENJPEG_RELEASE} ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Copying OpenJPEG DLLs to binary directory" ) set(OPENJPEG_DEBUG - "${ARCH_PREBUILT_DIRS_DEBUG}/openjpegd.dll") + "${ARCH_PREBUILT_DIRS_DEBUG}/openjp2.dll") add_custom_command( TARGET llui_libtest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${OPENJPEG_DEBUG} ${CMAKE_CURRENT_BINARY_DIR} diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 6e5e9d3b5b3a66370542e49066e647cf2b215e87..4db064c21ee9222186f33eb359703d6531e7edc6 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -29,9 +29,134 @@ // this is defined so that we get static linking. #include "openjpeg.h" +#include "cio.h" +#include "event.h" #include "lltimer.h" -//#include "llmemory.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; +}; // Factory function: see declaration in llimagej2c.cpp LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() @@ -41,11 +166,10 @@ LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() std::string LLImageJ2COJ::getEngineInfo() const { -#ifdef OPENJPEG_VERSION - return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ") - + opj_version(); +#ifdef OPJ_PACKAGE_VERSION + return std::string("OpenJPEG: " OPJ_PACKAGE_VERSION ", Runtime: ") + opj_version(); #else - return std::string("OpenJPEG runtime: ") + opj_version(); + return std::string("OpenJPEG Runtime: ") + opj_version(); #endif } @@ -70,21 +194,21 @@ sample error callback expecting a LLFILE* client object */ void error_callback(const char* msg, void*) { - LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; + LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } /** sample warning callback expecting a LLFILE* client object */ void warning_callback(const char* msg, void*) { - LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; + LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } /** sample debug callback expecting no client object */ void info_callback(const char* msg, void*) { - LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; + LL_INFOS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } // Divide a by 2 to the power of b and round upwards @@ -93,13 +217,11 @@ 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) { // No specific implementation for this method in the OpenJpeg case @@ -114,26 +236,10 @@ bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int block 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; opj_dparameters_t parameters; /* decompression parameters */ - 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 + opj_image_t *image = NULL; /* set decoding parameters to default values */ opj_set_default_decoder_parameters(¶meters); @@ -146,37 +252,57 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod /* JPEG-2000 codestream */ /* get a decoder handle */ - dinfo = opj_create_decompress(CODEC_J2K); + opj_codec_t* opj_decoder_p = opj_create_decompress(OPJ_CODEC_J2K); + if (!opj_decoder_p) + { + LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to create decoder!" << LL_ENDL; + base.decodeFailed(); + return true; // done + } +#ifdef SHOW_DEBUG /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + 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 /* setup the decoder decoding parameters using user parameters */ - opj_setup_decoder(dinfo, ¶meters); + if (!opj_setup_decoder(opj_decoder_p, ¶meters)) + { + LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; + opj_destroy_codec(opj_decoder_p); + base.decodeFailed(); + return true; // done + } /* open a byte stream */ - cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); + 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()); /* decode the stream and fill the image structure */ - image = opj_decode(dinfo, cio); + 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); /* close the byte stream */ - opj_cio_close(cio); + opj_stream_destroy(opj_stream_p); /* free remaining structures */ - if(dinfo) - { - opj_destroy_decompress(dinfo); - } + opj_destroy_codec(opj_decoder_p); + // 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(!image || !image->numcomps) + if (!success || !image || !image->numcomps) { -#if SHOW_DEBUG LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; -#endif if (image) { opj_image_destroy(image); @@ -185,23 +311,15 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod return true; // done } - // sometimes we get bad data out of the cache - check to see if the decode succeeded - for (S32 i = 0; i < image->numcomps; i++) + if(image->numcomps <= first_channel) { - if (image->comps[i].factor != base.getRawDiscardLevel()) + LL_WARNS() << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL; + if (image) { - // if we didn't get the discard level we're expecting, fail opj_image_destroy(image); - base.decodeFailed(); - return true; } - } - - 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; } @@ -273,16 +391,6 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con { 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); @@ -322,9 +430,9 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con // // Fill in the source image from our raw image // - OPJ_COLOR_SPACE color_space = CLRSPC_SRGB; + OPJ_COLOR_SPACE color_space = OPJ_CLRSPC_SRGB; opj_image_cmptparm_t cmptparm[MAX_COMPS]; - opj_image_t * image = nullptr; + opj_image_t * image = NULL; S32 numcomps = raw_image.getComponents(); S32 width = raw_image.getWidth(); S32 height = raw_image.getHeight(); @@ -362,52 +470,61 @@ 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_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + opj_codec_t* opj_encoder_p = opj_create_compress(OPJ_CODEC_J2K); +#ifdef SHOW_DEBUG /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + 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 /* setup the encoder parameters using the current image and using user parameters */ - opj_setup_encoder(cinfo, ¶meters, image); + 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; + } /* open a byte stream for writing */ /* allocate memory for all tiles */ - cio = opj_cio_open((opj_common_ptr)cinfo, nullptr, 0); + 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()); /* encode the image */ - bool bSuccess = opj_encode(cinfo, cio, image, nullptr); - if (!bSuccess) + 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)) { - opj_cio_close(cio); + opj_stream_destroy(opj_stream_p); + opj_destroy_codec(opj_encoder_p); + opj_image_destroy(image); 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_cio_close(cio); + opj_stream_destroy(opj_stream_p); /* free remaining compression structures */ - opj_destroy_compress(cinfo); - - - /* free user parameters structure */ - if(parameters.cp_matrice) free(parameters.cp_matrice); + opj_destroy_codec(opj_encoder_p); /* free image data */ opj_image_destroy(image); + return true; } @@ -490,54 +607,69 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) // Do it the old and slow way, decode the image with openjpeg opj_dparameters_t parameters; /* decompression parameters */ - 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; + opj_codec_t *opj_decoder = nullptr; /* handle to a decompressor */ /* 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 */ - dinfo = opj_create_decompress(CODEC_J2K); + opj_decoder = opj_create_decompress(OPJ_CODEC_J2K); + if (opj_decoder) + { + LL_WARNS() << "ERROR -> getMetadata: failed to create decoder!" << LL_ENDL; + return false; + } +#ifdef SHOW_DEBUG /* catch events using our callbacks and give a local context */ - opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + 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 /* setup the decoder decoding parameters using user parameters */ - opj_setup_decoder(dinfo, ¶meters); + if (!opj_setup_decoder(opj_decoder, ¶meters)) + { + LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL; + opj_destroy_codec(opj_decoder); + return false; + } /* open a byte stream */ - cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); + 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()); /* decode the stream and fill the image structure */ - image = opj_decode(dinfo, cio); + 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; + } /* close the byte stream */ - opj_cio_close(cio); + opj_stream_destroy(decode_stream); /* free remaining structures */ - if(dinfo) - { - opj_destroy_decompress(dinfo); - } + opj_destroy_codec(opj_decoder); if(!image) { @@ -546,7 +678,6 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) } // 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 d8451407390a89287077f78d504b616be538655f..25579a0c929e252941955da545b5c4dc2468eb64 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1890,8 +1890,8 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom23.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom23.dll #${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom23-d.dll - ${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll + ${SHARED_LIB_STAGING_DIR}/Release/openjp2.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjp2.dll #${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll ${SHARED_LIB_STAGING_DIR}/Release/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 14a4017ab796afee413015adf0a33e8cd93bb09d..2878dc510a25a6e75e683384ad2a5a6557565742 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -531,7 +531,7 @@ def construct(self): self.path("jpeg8.dll") self.path("libpng16*.dll") self.path("libwebp.dll") - self.path("openjpeg.dll") + self.path("openjp2.dll") # For OpenGL extensions self.path("epoxy-0.dll") @@ -933,7 +933,7 @@ def construct(self): 'libhunspell-*.dylib', 'libndofdev.dylib', 'libogg.*.dylib', - 'libopenjpeg.*.dylib', + 'libopenjp2.*.dylib', 'liburiparser.*.dylib', 'libvorbis.*.dylib', 'libvorbisenc.*.dylib', @@ -1474,7 +1474,7 @@ def construct(self): self.path("libexpat.so.*") self.path("libGLOD.so") self.path("libSDL2*.so*") - self.path("libopenjpeg.so*") + self.path("libopenjp2.*so*") self.path("libepoxy.so") self.path("libepoxy.so.0") self.path("libepoxy.so.0.0.0") @@ -1516,7 +1516,7 @@ def construct(self): self.path("libexpat.so.*") self.path("libGLOD.so") self.path("libSDL2*.so*") - self.path("libopenjpeg.so*") + self.path("libopenjp2.*so*") self.path("libepoxy.so") self.path("libepoxy.so.0") self.path("libepoxy.so.0.0.0")