aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorJohn Hurliman2009-09-29 18:15:22 -0700
committerMelanie2009-09-30 18:42:45 +0100
commit22cc31135e2989df28e0756eb3b03f85530d5555 (patch)
treedc24b568ce040a674a830d598994f8efa8866f7d /OpenSim/Region
parentThis releases the texture assets from LLImageManager cache, and re-requests t... (diff)
downloadopensim-SC-22cc31135e2989df28e0756eb3b03f85530d5555.zip
opensim-SC-22cc31135e2989df28e0756eb3b03f85530d5555.tar.gz
opensim-SC-22cc31135e2989df28e0756eb3b03f85530d5555.tar.bz2
opensim-SC-22cc31135e2989df28e0756eb3b03f85530d5555.tar.xz
Attempting to improve the robustness of texture decoding by always ignoring LayerInfo.End values and creating guessed default layer boundaries on failed decodes Changed a noisy J2K decode log message from Info to Debug
Replacing openjpeg-dotnet decoding with managed CSJ2K decoding. Should be much more reliable, faster, and use less memory * Re-added openjpeg-dotnet files since they are used elsewhere in OpenSim * Updated prebuild.xml with a reference to CSJ2K
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs236
1 files changed, 68 insertions, 168 deletions
diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
index 937f76b..aa29947 100644
--- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
+++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
@@ -34,8 +34,8 @@ using System.Threading;
34using log4net; 34using log4net;
35using Nini.Config; 35using Nini.Config;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenMetaverse.Assets;
38using OpenMetaverse.Imaging; 37using OpenMetaverse.Imaging;
38using CSJ2K;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
@@ -195,174 +195,58 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
195 { 195 {
196 int DecodeTime = 0; 196 int DecodeTime = 0;
197 DecodeTime = Environment.TickCount; 197 DecodeTime = Environment.TickCount;
198 OpenJPEG.J2KLayerInfo[] layers = new OpenJPEG.J2KLayerInfo[0]; // Dummy result for if it fails. Informs that there's only full quality 198 OpenJPEG.J2KLayerInfo[] layers = null;
199 199
200 if (!OpenJpegFail) 200 if (!fCache.TryLoadCacheForAsset(AssetId, out layers))
201 { 201 {
202 if (!fCache.TryLoadCacheForAsset(AssetId, out layers)) 202 try
203 { 203 {
204 try 204 List<int> layerStarts = CSJ2K.J2kImage.GetLayerBoundaries(new MemoryStream(j2kdata));
205
206 if (layerStarts != null && layerStarts.Count > 0)
205 { 207 {
208 layers = new OpenJPEG.J2KLayerInfo[layerStarts.Count];
206 209
207 AssetTexture texture = new AssetTexture(AssetId, j2kdata); 210 for (int i = 0; i < layerStarts.Count; i++)
208 if (texture.DecodeLayerBoundaries())
209 { 211 {
210 bool sane = true; 212 OpenJPEG.J2KLayerInfo layer = new OpenJPEG.J2KLayerInfo();
211 213 int start = layerStarts[i];
212 // Sanity check all of the layers 214
213 for (int i = 0; i < texture.LayerInfo.Length; i++) 215 if (i == 0)
214 { 216 layer.Start = 0;
215 if (texture.LayerInfo[i].End > texture.AssetData.Length)
216 {
217 sane = false;
218 break;
219 }
220 }
221
222 if (sane)
223 {
224 layers = texture.LayerInfo;
225 fCache.SaveFileCacheForAsset(AssetId, layers);
226
227
228 // Write out decode time
229 m_log.InfoFormat("[J2KDecoderModule]: {0} Decode Time: {1}", Environment.TickCount - DecodeTime,
230 AssetId);
231
232 }
233 else 217 else
234 { 218 layer.Start = layerStarts[i];
235 m_log.WarnFormat(
236 "[J2KDecoderModule]: JPEG2000 texture decoding succeeded, but sanity check failed for {0}",
237 AssetId);
238 }
239 }
240 219
241 else 220 if (i == layerStarts.Count - 1)
242 { 221 layer.End = j2kdata.Length;
243 /*
244 Random rnd = new Random();
245 // scramble ends for test
246 for (int i = 0; i < texture.LayerInfo.Length; i++)
247 {
248 texture.LayerInfo[i].End = rnd.Next(999999);
249 }
250 */
251
252 // Try to do some heuristics error correction! Yeah.
253 bool sane2Heuristics = true;
254
255
256 if (texture.Image == null)
257 sane2Heuristics = false;
258
259 if (texture.LayerInfo == null)
260 sane2Heuristics = false;
261
262 if (sane2Heuristics)
263 {
264
265
266 if (texture.LayerInfo.Length == 0)
267 sane2Heuristics = false;
268 }
269
270 if (sane2Heuristics)
271 {
272 // Last layer start is less then the end of the file and last layer start is greater then 0
273 if (texture.LayerInfo[texture.LayerInfo.Length - 1].Start < texture.AssetData.Length && texture.LayerInfo[texture.LayerInfo.Length - 1].Start > 0)
274 {
275 }
276 else
277 {
278 sane2Heuristics = false;
279 }
280
281 }
282
283 if (sane2Heuristics)
284 {
285 int start = 0;
286
287 // try to fix it by using consistant data in the start field
288 for (int i = 0; i < texture.LayerInfo.Length; i++)
289 {
290 if (i == 0)
291 start = 0;
292
293 if (i == texture.LayerInfo.Length - 1)
294 texture.LayerInfo[i].End = texture.AssetData.Length;
295 else
296 texture.LayerInfo[i].End = texture.LayerInfo[i + 1].Start - 1;
297
298 // in this case, the end of the next packet is less then the start of the last packet
299 // after we've attempted to fix it which means the start of the last packet is borked
300 // there's no recovery from this
301 if (texture.LayerInfo[i].End < start)
302 {
303 sane2Heuristics = false;
304 break;
305 }
306
307 if (texture.LayerInfo[i].End < 0 || texture.LayerInfo[i].End > texture.AssetData.Length)
308 {
309 sane2Heuristics = false;
310 break;
311 }
312
313 if (texture.LayerInfo[i].Start < 0 || texture.LayerInfo[i].Start > texture.AssetData.Length)
314 {
315 sane2Heuristics = false;
316 break;
317 }
318
319 start = texture.LayerInfo[i].Start;
320 }
321 }
322
323 if (sane2Heuristics)
324 {
325 layers = texture.LayerInfo;
326 fCache.SaveFileCacheForAsset(AssetId, layers);
327
328
329 // Write out decode time
330 m_log.InfoFormat("[J2KDecoderModule]: HEURISTICS SUCCEEDED {0} Decode Time: {1}", Environment.TickCount - DecodeTime,
331 AssetId);
332
333 }
334 else 222 else
335 { 223 layer.End = layerStarts[i + 1] - 1;
336 m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding failed for {0}. Is this a texture? is it J2K?", AssetId); 224
337 } 225 layers[i] = layer;
338 } 226 }
339 texture = null; // dereference and dispose of ManagedImage
340 }
341 catch (DllNotFoundException)
342 {
343 m_log.Error(
344 "[J2KDecoderModule]: OpenJpeg is not installed properly. Decoding disabled! This will slow down texture performance! Often times this is because of an old version of GLIBC. You must have version 2.4 or above!");
345 OpenJpegFail = true;
346 }
347 catch (Exception ex)
348 {
349 m_log.WarnFormat(
350 "[J2KDecoderModule]: JPEG2000 texture decoding threw an exception for {0}, {1}",
351 AssetId, ex);
352 } 227 }
353 } 228 }
354 229 catch (Exception ex)
355 } 230 {
356 231 m_log.Warn("[J2KDecoderModule]: CSJ2K threw an exception decoding texture " + AssetId + ": " + ex.ToString());
357 // Cache Decoded layers 232 }
358 lock (m_cacheddecode)
359 {
360 if (m_cacheddecode.ContainsKey(AssetId))
361 m_cacheddecode.Remove(AssetId);
362 m_cacheddecode.Add(AssetId, layers);
363 233
364 } 234 if (layers.Length == 0)
235 {
236 m_log.Warn("[J2KDecoderModule]: OpenJPEG failed to decode any layer data for texture " + AssetId + ", guessing sane defaults");
237 // Layer decoding completely failed. Guess at sane defaults for the layer boundaries
238 layers = CreateDefaultLayers(j2kdata.Length);
239 }
365 240
241 // Cache Decoded layers
242 lock (m_cacheddecode)
243 {
244 if (m_cacheddecode.ContainsKey(AssetId))
245 m_cacheddecode.Remove(AssetId);
246 m_cacheddecode.Add(AssetId, layers);
247 }
248 }
249
366 // Notify Interested Parties 250 // Notify Interested Parties
367 lock (m_notifyList) 251 lock (m_notifyList)
368 { 252 {
@@ -377,6 +261,31 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
377 } 261 }
378 } 262 }
379 } 263 }
264
265 private OpenJPEG.J2KLayerInfo[] CreateDefaultLayers(int j2kLength)
266 {
267 OpenJPEG.J2KLayerInfo[] layers = new OpenJPEG.J2KLayerInfo[5];
268 layers[0] = new OpenJPEG.J2KLayerInfo();
269
270 for (int i = 0; i < layers.Length; i++)
271 {
272 OpenJPEG.J2KLayerInfo layer = new OpenJPEG.J2KLayerInfo();
273
274 if (i == 0)
275 layer.Start = 0;
276 else
277 layer.Start = layers[i - 1].End + 1;
278
279 // These default layer sizes are based on a small sampling of real-world texture data
280 // with extra padding thrown in for good measure. This is a worst case fallback plan
281 // and will probably not gracefully handle all real world data
282 layer.End = (int)(160d * Math.Exp(1.3d * (double)(i + 1)));
283
284 layers[i] = layer;
285 }
286
287 return layers;
288 }
380 289
381 private void CleanCache() 290 private void CleanCache()
382 { 291 {
@@ -418,10 +327,9 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
418 { 327 {
419 m_cacheDecodeFolder = pFolder; 328 m_cacheDecodeFolder = pFolder;
420 m_cacheTimeout = timeout; 329 m_cacheTimeout = timeout;
330
421 if (!Directory.Exists(pFolder)) 331 if (!Directory.Exists(pFolder))
422 {
423 Createj2KCacheFolder(pFolder); 332 Createj2KCacheFolder(pFolder);
424 }
425 } 333 }
426 334
427 /// <summary> 335 /// <summary>
@@ -447,14 +355,15 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
447 355
448 stringResult.AppendFormat("{0}|{1}|{2}{3}", Layers[i].Start, Layers[i].End, Layers[i].End - Layers[i].Start, strEnd); 356 stringResult.AppendFormat("{0}|{1}|{2}{3}", Layers[i].Start, Layers[i].End, Layers[i].End - Layers[i].Start, strEnd);
449 } 357 }
358
450 fsSWCache.Write(stringResult.ToString()); 359 fsSWCache.Write(stringResult.ToString());
451 fsSWCache.Close(); 360 fsSWCache.Close();
452 fsSWCache.Dispose(); 361 fsSWCache.Dispose();
453 fsCache.Dispose(); 362 fsCache.Dispose();
363
454 return true; 364 return true;
455 } 365 }
456 366
457
458 return false; 367 return false;
459 } 368 }
460 369
@@ -475,11 +384,9 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
475 return false; 384 return false;
476 385
477 if (!enabled) 386 if (!enabled)
478 {
479 return false; 387 return false;
480 }
481 388
482 string readResult = string.Empty; 389 string readResult = String.Empty;
483 390
484 try 391 try
485 { 392 {
@@ -493,7 +400,6 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
493 sr.Close(); 400 sr.Close();
494 sr.Dispose(); 401 sr.Dispose();
495 fsCachefile.Dispose(); 402 fsCachefile.Dispose();
496
497 } 403 }
498 catch (IOException ioe) 404 catch (IOException ioe)
499 { 405 {
@@ -514,7 +420,6 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
514 "[J2KDecodeCache]: Cache Read failed. IO Exception."); 420 "[J2KDecodeCache]: Cache Read failed. IO Exception.");
515 } 421 }
516 return false; 422 return false;
517
518 } 423 }
519 catch (UnauthorizedAccessException) 424 catch (UnauthorizedAccessException)
520 { 425 {
@@ -541,7 +446,6 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
541 m_log.Error( 446 m_log.Error(
542 "[J2KDecodeCache]: Cache Read failed, not supported. Cache disabled!"); 447 "[J2KDecodeCache]: Cache Read failed, not supported. Cache disabled!");
543 enabled = false; 448 enabled = false;
544
545 return false; 449 return false;
546 } 450 }
547 catch (Exception e) 451 catch (Exception e)
@@ -581,7 +485,6 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
581 Layers[i] = new OpenJPEG.J2KLayerInfo(); 485 Layers[i] = new OpenJPEG.J2KLayerInfo();
582 Layers[i].Start = element1; 486 Layers[i].Start = element1;
583 Layers[i].End = element2; 487 Layers[i].End = element2;
584
585 } 488 }
586 else 489 else
587 { 490 {
@@ -592,9 +495,6 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
592 } 495 }
593 } 496 }
594 497
595
596
597
598 return true; 498 return true;
599 } 499 }
600 500