summaryrefslogtreecommitdiff
path: root/indra/llimage/llimagej2c.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llimage/llimagej2c.cpp')
-rw-r--r--indra/llimage/llimagej2c.cpp249
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()