diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 8461d5d86..4c1b7ec89 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -196,6 +196,13 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), } mImpl = j2cimpl_create_func(); + + // Clear data size table + for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++) + { // Array size is MAX_DISCARD_LEVEL+1 + mDataSizes[i] = 0; + } + } // virtual @@ -371,9 +378,44 @@ S32 LLImageJ2C::calcHeaderSize() return calcHeaderSizeJ2C(); } +// calcDataSize() returns how many bytes to read +// to load discard_level (including header and higher discard levels) S32 LLImageJ2C::calcDataSize(S32 discard_level) { - return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate); + discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); + + if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth()) + || mDataSizes[0] == 0) + { + mAreaUsedForDataSizeCalcs = getHeight() * getWidth(); + + S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard + while ( level >= 0 ) + { + mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); + level--; + } + + /* This is technically a more correct way to calculate the size required + for each discard level, since they should include the size needed for + lower levels. Unfortunately, this doesn't work well and will lead to + download stalls. The true correct way is to parse the header. This will + all go away with http textures at some point. + + // Calculate the size for each discard level. Lower levels (higher quality) + // contain the cumulative size of higher levels + S32 total_size = calcHeaderSizeJ2C(); + + S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard + while ( level >= 0 ) + { // Add in this discard level and all before it + total_size += calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); + mDataSizes[level] = total_size; + level--; + } + */ + } + return mDataSizes[discard_level]; } S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 23f6ef5fd..56782fbf0 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -87,6 +87,8 @@ protected: void updateRawDiscardLevel(); S32 mMaxBytes; // Maximum number of bytes of data to use... + S32 mDataSizes[MAX_DISCARD_LEVEL+1]; // Size of data required to reach a given level + U32 mAreaUsedForDataSizeCalcs; // Height * width used to calculate mDataSizes S8 mRawDiscardLevel; F32 mRate; BOOL mReversible; diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 455cd48ff..23f67919f 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -151,13 +151,8 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod /* open a byte stream */ cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); - /* decode the stream and fill the image structure, also fill in an additional - structure to get the decoding result. This structure is a bit unusual in that - it is not received through opj, but still has some dynamically allocated fields - that need to be cleared up at the end by calling a destroy function. */ - opj_codestream_info_t cinfo; - memset(&cinfo, 0, sizeof(opj_codestream_info_t)); - image = opj_decode_with_info(dinfo, cio, &cinfo); + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); /* close the byte stream */ opj_cio_close(cio); @@ -171,70 +166,45 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod // 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) + if(!image || !image->numcomps) { - LL_DEBUGS("Openjpeg") << "ERROR -> decodeImpl: failed to decode image - no image" << LL_ENDL; - return TRUE; // done - } - - S32 img_components = image->numcomps; - - if( !img_components ) // < 1 ||img_components > 4 ) - { - LL_DEBUGS("Openjpeg") << "ERROR -> decodeImpl: failed to decode image wrong number of components: " << img_components << LL_ENDL; + llwarns << "ERROR -> decodeImpl: failed to decode image!" << llendl; if (image) { - opj_destroy_cstr_info(&cinfo); opj_image_destroy(image); } + base.decodeFailed(); return TRUE; // done } // sometimes we get bad data out of the cache - check to see if the decode succeeded - int decompdifference = 0; - if (cinfo.numdecompos) // sanity + for (S32 i = 0; i < image->numcomps; i++) { - for (int comp = 0; comp < image->numcomps; comp++) - { /* get maximum decomposition level difference, first field is from the COD header and the second - is what is actually met in the codestream, NB: if everything was ok, this calculation will - return what was set in the cp_reduce value! */ - decompdifference = llmax(decompdifference, cinfo.numdecompos[comp] - image->comps[comp].resno_decoded); - } - if (decompdifference < 0) // sanity + if (image->comps[i].factor != base.getRawDiscardLevel()) { - decompdifference = 0; + // if we didn't get the discard level we're expecting, fail + opj_image_destroy(image); + base.decodeFailed(); + return TRUE; } } - - /* if OpenJPEG failed to decode all requested decomposition levels - the difference will be greater than this level */ - if (decompdifference > base.getRawDiscardLevel()) + if(image->numcomps <= first_channel) { - llwarns << "not enough data for requested discard level, setting mDecoding to FALSE, difference: " << (decompdifference - base.getRawDiscardLevel()) << llendl; - opj_destroy_cstr_info(&cinfo); - opj_image_destroy(image); - base.mDecoding = FALSE; - return TRUE; - } - - if(img_components <= first_channel) - { - // sanity - LL_DEBUGS("Openjpeg") << "trying to decode more channels than are present in image: numcomps: " << img_components << " first_channel: " << first_channel << LL_ENDL; + llwarns << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << llendl; if (image) { - opj_destroy_cstr_info(&cinfo); opj_image_destroy(image); } - + + base.decodeFailed(); return TRUE; } // Copy image data into our raw image format (instead of the separate channel format - + S32 img_components = image->numcomps; S32 channels = img_components - first_channel; if( channels > max_channel_count ) channels = max_channel_count; @@ -274,19 +244,15 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod else // Some rare OpenJPEG versions have this bug. { llwarns << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << llendl; - opj_destroy_cstr_info(&cinfo); opj_image_destroy(image); - + + base.decodeFailed(); return TRUE; // done } } - /* free opj data structures */ - if (image) - { - opj_destroy_cstr_info(&cinfo); - opj_image_destroy(image); - } + /* free image data structure */ + opj_image_destroy(image); return TRUE; // done } @@ -349,7 +315,7 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con OPJ_COLOR_SPACE color_space = CLRSPC_SRGB; opj_image_cmptparm_t cmptparm[MAX_COMPS]; opj_image_t * image = NULL; - S32 numcomps = llmin((S32)raw_image.getComponents(),(S32)MAX_COMPS); + S32 numcomps = llmin((S32)raw_image.getComponents(), MAX_COMPS); S32 width = raw_image.getWidth(); S32 height = raw_image.getHeight(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a75e4162c..2fc5e99bd 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -75,6 +75,7 @@ #include "llfirstuse.h" #include "llrender.h" #include "llfont.h" +#include "llimagej2c.h" #include "llweb.h" #include "llsecondlifeurls.h" diff --git a/indra/newview/llfloaterexport.cpp b/indra/newview/llfloaterexport.cpp index ded17cdf0..70d229f1a 100644 --- a/indra/newview/llfloaterexport.cpp +++ b/indra/newview/llfloaterexport.cpp @@ -22,6 +22,7 @@ #include "lltexturecache.h" #include "llimage.h" #include "llappviewer.h" +#include "llimagej2c.h" std::vector LLFloaterExport::instances; diff --git a/indra/newview/llfloaterpostcard.h b/indra/newview/llfloaterpostcard.h index 087649f15..d294cfca5 100644 --- a/indra/newview/llfloaterpostcard.h +++ b/indra/newview/llfloaterpostcard.h @@ -38,6 +38,7 @@ #include "llmemory.h" #include "llimagegl.h" +#include "llimagejpeg.h" class LLTextEditor; class LLLineEditor; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 71f54ff0f..cc5101a10 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -43,6 +43,7 @@ #include "llfontgl.h" #include "llgl.h" // for renderer #include "llinventory.h" +#include "llimagej2c.h" #include "llstring.h" #include "llsys.h" #include "llversionviewer.h" diff --git a/indra/newview/llfloatervfs.cpp b/indra/newview/llfloatervfs.cpp index e0b3f1b63..18ee463cb 100644 --- a/indra/newview/llfloatervfs.cpp +++ b/indra/newview/llfloatervfs.cpp @@ -10,6 +10,7 @@ #include "llassetconverter.h" #include "llviewerimagelist.h" #include "llviewerimage.h" +#include "llimagej2c.h" LLFloaterVFS* LLFloaterVFS::sInstance; std::list LLFloaterVFS::mFiles; diff --git a/indra/newview/llimportobject.cpp b/indra/newview/llimportobject.cpp index 99f874c46..2378ee160 100644 --- a/indra/newview/llimportobject.cpp +++ b/indra/newview/llimportobject.cpp @@ -24,6 +24,7 @@ #include "llfloaterperms.h" #include "llviewerregion.h" #include "llviewerobjectlist.h" +#include "llimagej2c.h" // static vars bool LLXmlImport::sImportInProgress = false; diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp index 70a411be7..5f59c6b6b 100644 --- a/indra/newview/llinventorybackup.cpp +++ b/indra/newview/llinventorybackup.cpp @@ -13,6 +13,7 @@ #include "llfloater.h" #include "lluictrlfactory.h" #include "llscrolllistctrl.h" +#include "llimagetga.h" std::list LLFloaterInventoryBackup::sInstances; diff --git a/indra/newview/llviewerimagelist.h b/indra/newview/llviewerimagelist.h index 561e8e5f4..a6c26fa38 100644 --- a/indra/newview/llviewerimagelist.h +++ b/indra/newview/llviewerimagelist.h @@ -56,6 +56,7 @@ const BOOL IMMEDIATE_NO = FALSE; class LLMessageSystem; class LLViewerImage; class LLTextureView; +class LLImageJ2C; typedef void (*LLImageCallback)(BOOL success, LLViewerImage *src_vi, diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 75ff06845..596dee9e9 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -81,6 +81,10 @@ #include "lluuid.h" #include "llvorbisencode.h" +#include "llimagejpeg.h" +#include "llimagepng.h" +#include "llimagebmp.h" + // system libraries #include diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index f98c7c242..2921dd583 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -114,13 +114,13 @@ // Library includes from llimage //#include "llblockdata.h" -#include "llimage.h" -#include "llimagebmp.h" -#include "llimagepng.h" -#include "llimagej2c.h" -#include "llimagejpeg.h" -#include "llimagetga.h" -#include "llmapimagetype.h" +//#include "llimage.h" +//#include "llimagebmp.h" +//#include "llimagepng.h" +//#include "llimagej2c.h" +//#include "llimagejpeg.h" +//#include "llimagetga.h" +//#include "llmapimagetype.h" // Library includes from llmath project //#include "camera.h"