00001
00030 #include "linden_common.h"
00031
00032 #include <apr-1/apr_pools.h>
00033 #include <apr-1/apr_dso.h>
00034
00035 #include "lldir.h"
00036 #include "llimagej2c.h"
00037 #include "llmemtype.h"
00038
00039 typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)();
00040 typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*);
00041 typedef const char* (*EngineInfoLLImageJ2CFunction)();
00042
00043
00044
00045 CreateLLImageJ2CFunction j2cimpl_create_func;
00046 DestroyLLImageJ2CFunction j2cimpl_destroy_func;
00047 EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func;
00048 apr_pool_t *j2cimpl_dso_memory_pool;
00049 apr_dso_handle_t *j2cimpl_dso_handle;
00050
00051
00052
00053
00054
00055 LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl();
00056 void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl);
00057 const char* fallbackEngineInfoLLImageJ2CImpl();
00058
00059
00060
00061 void LLImageJ2C::openDSO()
00062 {
00063
00064 std::string dso_name;
00065 std::string dso_path;
00066
00067 bool all_functions_loaded = false;
00068 apr_status_t rv;
00069
00070 #if LL_WINDOWS
00071 dso_name = "llkdu.dll";
00072 #elif LL_DARWIN
00073 dso_name = "libllkdu.dylib";
00074 #else
00075 dso_name = "libllkdu.so";
00076 #endif
00077
00078 dso_path = gDirUtilp->findFile(dso_name,
00079 gDirUtilp->getAppRODataDir(),
00080 gDirUtilp->getExecutableDir());
00081
00082 j2cimpl_dso_handle = NULL;
00083 j2cimpl_dso_memory_pool = NULL;
00084
00085
00086 apr_pool_create(&j2cimpl_dso_memory_pool, NULL);
00087 rv = apr_dso_load(&j2cimpl_dso_handle,
00088 dso_path.c_str(),
00089 j2cimpl_dso_memory_pool);
00090
00091
00092 if ( rv == APR_SUCCESS )
00093 {
00094
00095
00096 CreateLLImageJ2CFunction create_func = NULL;
00097 DestroyLLImageJ2CFunction dest_func = NULL;
00098 EngineInfoLLImageJ2CFunction engineinfo_func = NULL;
00099
00100 rv = apr_dso_sym((apr_dso_handle_sym_t*)&create_func,
00101 j2cimpl_dso_handle,
00102 "createLLImageJ2CKDU");
00103 if ( rv == APR_SUCCESS )
00104 {
00105
00106
00107
00108 rv = apr_dso_sym((apr_dso_handle_sym_t*)&dest_func,
00109 j2cimpl_dso_handle,
00110 "destroyLLImageJ2CKDU");
00111 if ( rv == APR_SUCCESS )
00112 {
00113
00114 rv = apr_dso_sym((apr_dso_handle_sym_t*)&engineinfo_func,
00115 j2cimpl_dso_handle,
00116 "engineInfoLLImageJ2CKDU");
00117 if ( rv == APR_SUCCESS )
00118 {
00119
00120 j2cimpl_create_func = create_func;
00121 j2cimpl_destroy_func = dest_func;
00122 j2cimpl_engineinfo_func = engineinfo_func;
00123 all_functions_loaded = true;
00124 }
00125 }
00126 }
00127 }
00128
00129 if ( !all_functions_loaded )
00130 {
00131
00132
00133
00134 #if 0
00135
00136
00137 char errbuf[256];
00138 fprintf(stderr, "failed to load syms from DSO %s (%s)\n",
00139 dso_name.c_str(), dso_path.c_str());
00140 apr_strerror(rv, errbuf, sizeof(errbuf));
00141 fprintf(stderr, "error: %d, %s\n", rv, errbuf);
00142 apr_dso_error(j2cimpl_dso_handle, errbuf, sizeof(errbuf));
00143 fprintf(stderr, "dso-error: %d, %s\n", rv, errbuf);
00144 #endif
00145
00146 if ( j2cimpl_dso_handle )
00147 {
00148 apr_dso_unload(j2cimpl_dso_handle);
00149 j2cimpl_dso_handle = NULL;
00150 }
00151
00152 if ( j2cimpl_dso_memory_pool )
00153 {
00154 apr_pool_destroy(j2cimpl_dso_memory_pool);
00155 j2cimpl_dso_memory_pool = NULL;
00156 }
00157 }
00158 }
00159
00160
00161 void LLImageJ2C::closeDSO()
00162 {
00163 if ( j2cimpl_dso_handle ) apr_dso_unload(j2cimpl_dso_handle);
00164 if (j2cimpl_dso_memory_pool) apr_pool_destroy(j2cimpl_dso_memory_pool);
00165 }
00166
00167
00168 std::string LLImageJ2C::getEngineInfo()
00169 {
00170 if (!j2cimpl_engineinfo_func)
00171 j2cimpl_engineinfo_func = fallbackEngineInfoLLImageJ2CImpl;
00172
00173 return j2cimpl_engineinfo_func();
00174 }
00175
00176 LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
00177 mMaxBytes(0),
00178 mRawDiscardLevel(-1),
00179 mRate(0.0f),
00180 mReversible(FALSE)
00181
00182 {
00183
00184
00185
00186
00187
00188
00189
00190
00191 if ( !j2cimpl_create_func )
00192 {
00193 j2cimpl_create_func = fallbackCreateLLImageJ2CImpl;
00194 }
00195
00196 mImpl = j2cimpl_create_func();
00197 }
00198
00199
00200 LLImageJ2C::~LLImageJ2C()
00201 {
00202
00203
00204
00205
00206
00207
00208
00209
00210 if ( !j2cimpl_destroy_func )
00211 {
00212 j2cimpl_destroy_func = fallbackDestroyLLImageJ2CImpl;
00213 }
00214
00215 if ( mImpl )
00216 {
00217 j2cimpl_destroy_func(mImpl);
00218 }
00219 }
00220
00221
00222 S8 LLImageJ2C::getRawDiscardLevel()
00223 {
00224 return mRawDiscardLevel;
00225 }
00226
00227 BOOL LLImageJ2C::updateData()
00228 {
00229 resetLastError();
00230
00231
00232 if (!getData() || (getDataSize() < 16))
00233 {
00234 setLastError("LLImageJ2C uninitialized");
00235 return FALSE;
00236 }
00237
00238 if (!mImpl->getMetadata(*this))
00239 {
00240 return FALSE;
00241 }
00242
00243 S32 max_bytes = getDataSize();
00244 S32 discard = calcDiscardLevelBytes(max_bytes);
00245 setDiscardLevel(discard);
00246
00247 return TRUE;
00248 }
00249
00250
00251 BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
00252 {
00253 return decode(raw_imagep, decode_time, 0, 4);
00254 }
00255
00256
00257 BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
00258 {
00259 LLMemType mt1((LLMemType::EMemType)mMemType);
00260
00261 resetLastError();
00262
00263
00264 if (!getData() || (getDataSize() < 16))
00265 {
00266 setLastError("LLImageJ2C uninitialized");
00267 return FALSE;
00268 }
00269
00270
00271 updateRawDiscardLevel();
00272
00273 mDecoding = TRUE;
00274 BOOL res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count);
00275 if (res)
00276 {
00277 if (!mDecoding)
00278 {
00279
00280 raw_imagep->deleteData();
00281 }
00282 else
00283 {
00284 mDecoding = FALSE;
00285 }
00286 return TRUE;
00287 }
00288 return FALSE;
00289 }
00290
00291
00292 BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
00293 {
00294 return encode(raw_imagep, NULL, encode_time);
00295 }
00296
00297
00298 BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
00299 {
00300 LLMemType mt1((LLMemType::EMemType)mMemType);
00301 return mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
00302 }
00303
00304
00305 S32 LLImageJ2C::calcHeaderSizeJ2C()
00306 {
00307 return 600;
00308 }
00309
00310
00311 S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
00312 {
00313 if (rate <= 0.f) rate = .125f;
00314 while (discard_level > 0)
00315 {
00316 if (w < 1 || h < 1)
00317 break;
00318 w >>= 1;
00319 h >>= 1;
00320 discard_level--;
00321 }
00322 S32 bytes = (S32)((F32)(w*h*comp)*rate);
00323 bytes = llmax(bytes, calcHeaderSizeJ2C());
00324 return bytes;
00325 }
00326
00327 S32 LLImageJ2C::calcHeaderSize()
00328 {
00329 return calcHeaderSizeJ2C();
00330 }
00331
00332 S32 LLImageJ2C::calcDataSize(S32 discard_level)
00333 {
00334 return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate);
00335 }
00336
00337 S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes)
00338 {
00339 llassert(bytes >= 0);
00340 S32 discard_level = 0;
00341 if (bytes == 0)
00342 {
00343 return MAX_DISCARD_LEVEL;
00344 }
00345 while (1)
00346 {
00347 S32 bytes_needed = calcDataSize(discard_level);
00348 if (bytes >= bytes_needed - (bytes_needed>>2))
00349 {
00350 break;
00351 }
00352 discard_level++;
00353 if (discard_level >= MAX_DISCARD_LEVEL)
00354 {
00355 break;
00356 }
00357 }
00358 return discard_level;
00359 }
00360
00361 void LLImageJ2C::setRate(F32 rate)
00362 {
00363 mRate = rate;
00364 }
00365
00366 void LLImageJ2C::setMaxBytes(S32 max_bytes)
00367 {
00368 mMaxBytes = max_bytes;
00369 }
00370
00371 void LLImageJ2C::setReversible(const BOOL reversible)
00372 {
00373 mReversible = reversible;
00374 }
00375
00376
00377 BOOL LLImageJ2C::loadAndValidate(const LLString &filename)
00378 {
00379 resetLastError();
00380
00381 S32 file_size = 0;
00382 apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size);
00383 if (!apr_file)
00384 {
00385 setLastError("Unable to open file for reading", filename);
00386 return FALSE;
00387 }
00388 if (file_size == 0)
00389 {
00390 setLastError("File is empty",filename);
00391 apr_file_close(apr_file);
00392 return FALSE;
00393 }
00394
00395 U8 *data = new U8[file_size];
00396 apr_size_t bytes_read = file_size;
00397 apr_status_t s = apr_file_read(apr_file, data, &bytes_read);
00398 if (s != APR_SUCCESS || (S32)bytes_read != file_size)
00399 {
00400 delete[] data;
00401 setLastError("Unable to read entire file");
00402 return FALSE;
00403 }
00404 apr_file_close(apr_file);
00405
00406 return validate(data, file_size);
00407 }
00408
00409
00410 BOOL LLImageJ2C::validate(U8 *data, U32 file_size)
00411 {
00412 LLMemType mt1((LLMemType::EMemType)mMemType);
00413
00414 setData(data, file_size);
00415 BOOL res = updateData();
00416 if ( !res )
00417 {
00418 return FALSE;
00419 }
00420
00421
00422 if (!getData() || (0 == getDataSize()))
00423 {
00424 setLastError("LLImageJ2C uninitialized");
00425 return FALSE;
00426 }
00427
00428 return mImpl->getMetadata(*this);
00429 }
00430
00431 void LLImageJ2C::decodeFailed()
00432 {
00433 mDecoding = FALSE;
00434 }
00435
00436 void LLImageJ2C::updateRawDiscardLevel()
00437 {
00438 mRawDiscardLevel = mMaxBytes ? calcDiscardLevelBytes(mMaxBytes) : mDiscardLevel;
00439 }
00440
00441 LLImageJ2CImpl::~LLImageJ2CImpl()
00442 {
00443 }