diff options
Diffstat (limited to 'indra/llimage/llimagej2c.cpp')
-rw-r--r-- | indra/llimage/llimagej2c.cpp | 249 |
1 files changed, 174 insertions, 75 deletions
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 0911c43674..c8c866b7f2 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -1,36 +1,31 @@ /** * @file llimagej2c.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ #include "linden_common.h" -#include <apr-1/apr_pools.h> -#include <apr-1/apr_dso.h> +#include "apr_pools.h" +#include "apr_dso.h" #include "lldir.h" #include "llimagej2c.h" @@ -177,8 +172,8 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mMaxBytes(0), mRawDiscardLevel(-1), mRate(0.0f), - mReversible(FALSE) - + mReversible(FALSE), + mAreaUsedForDataSizeCalcs(0) { //We assume here that if we wanted to create via //a dynamic library that the approriate open calls were made @@ -194,6 +189,12 @@ 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 @@ -219,59 +220,86 @@ LLImageJ2C::~LLImageJ2C() } // virtual +void LLImageJ2C::resetLastError() +{ + mLastError.clear(); +} + +//virtual +void LLImageJ2C::setLastError(const std::string& message, const std::string& filename) +{ + mLastError = message; + if (!filename.empty()) + mLastError += std::string(" FILE: ") + filename; +} + +// virtual S8 LLImageJ2C::getRawDiscardLevel() { return mRawDiscardLevel; } BOOL LLImageJ2C::updateData() -{ +{ + BOOL res = TRUE; resetLastError(); // Check to make sure that this instance has been initialized with data if (!getData() || (getDataSize() < 16)) { setLastError("LLImageJ2C uninitialized"); - return FALSE; + res = FALSE; + } + else + { + res = mImpl->getMetadata(*this); } - if (!mImpl->getMetadata(*this)) + if (res) { - return FALSE; + // SJB: override discard based on mMaxBytes elsewhere + S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize(); + S32 discard = calcDiscardLevelBytes(max_bytes); + setDiscardLevel(discard); } - // SJB: override discard based on mMaxBytes elsewhere - S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize(); - S32 discard = calcDiscardLevelBytes(max_bytes); - setDiscardLevel(discard); - return TRUE; + if (!mLastError.empty()) + { + LLImage::setLastError(mLastError); + } + return res; } BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time) { - return decode(raw_imagep, decode_time, 0, 4); + return decodeChannels(raw_imagep, decode_time, 0, 4); } -BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) +// Returns TRUE to mean done, whether successful or not. +BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); + BOOL res = TRUE; + resetLastError(); // Check to make sure that this instance has been initialized with data if (!getData() || (getDataSize() < 16)) { setLastError("LLImageJ2C uninitialized"); - return FALSE; + res = TRUE; // done } - - // Update the raw discard level - updateRawDiscardLevel(); - - mDecoding = TRUE; - BOOL res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + else + { + // Update the raw discard level + updateRawDiscardLevel(); + mDecoding = TRUE; + res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + } + if (res) { if (!mDecoding) @@ -283,9 +311,14 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_chann { mDecoding = FALSE; } - return TRUE; // done } - return FALSE; + + if (!mLastError.empty()) + { + LLImage::setLastError(mLastError); + } + + return res; } @@ -297,14 +330,20 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time) BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time) { - LLMemType mt1((LLMemType::EMemType)mMemType); - return mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible); + LLMemType mt1(mMemType); + resetLastError(); + BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible); + if (!mLastError.empty()) + { + LLImage::setLastError(mLastError); + } + return res; } //static S32 LLImageJ2C::calcHeaderSizeJ2C() { - return 600; //2048; // ??? hack... just needs to be >= actual header size... + return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size... } //static @@ -329,9 +368,45 @@ 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) @@ -374,58 +449,82 @@ void LLImageJ2C::setReversible(const BOOL reversible) } -BOOL LLImageJ2C::loadAndValidate(const LLString &filename) +BOOL LLImageJ2C::loadAndValidate(const std::string &filename) { + BOOL res = TRUE; + resetLastError(); S32 file_size = 0; - apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size); + LLAPRFile infile ; + infile.open(filename, LL_APR_RB, NULL, &file_size); + apr_file_t* apr_file = infile.getFileHandle() ; if (!apr_file) { setLastError("Unable to open file for reading", filename); - return FALSE; + res = FALSE; } - if (file_size == 0) + else if (file_size == 0) { setLastError("File is empty",filename); - apr_file_close(apr_file); - return FALSE; + res = FALSE; + } + else + { + U8 *data = new U8[file_size]; + apr_size_t bytes_read = file_size; + apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read + infile.close() ; + + if (s != APR_SUCCESS || (S32)bytes_read != file_size) + { + delete[] data; + setLastError("Unable to read entire file"); + res = FALSE; + } + else + { + res = validate(data, file_size); + } } - U8 *data = new U8[file_size]; - apr_size_t bytes_read = file_size; - apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read - if (s != APR_SUCCESS || (S32)bytes_read != file_size) + if (!mLastError.empty()) { - delete[] data; - setLastError("Unable to read entire file"); - return FALSE; + LLImage::setLastError(mLastError); } - apr_file_close(apr_file); - - return validate(data, file_size); + + return res; } BOOL LLImageJ2C::validate(U8 *data, U32 file_size) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); + resetLastError(); + setData(data, file_size); + BOOL res = updateData(); - if ( !res ) + if ( res ) { - return FALSE; + // Check to make sure that this instance has been initialized with data + if (!getData() || (0 == getDataSize())) + { + setLastError("LLImageJ2C uninitialized"); + res = FALSE; + } + else + { + res = mImpl->getMetadata(*this); + } } - - // Check to make sure that this instance has been initialized with data - if (!getData() || (0 == getDataSize())) + + if (!mLastError.empty()) { - setLastError("LLImageJ2C uninitialized"); - return FALSE; + LLImage::setLastError(mLastError); } - - return mImpl->getMetadata(*this); + return res; } void LLImageJ2C::decodeFailed() |