aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
diff options
context:
space:
mode:
authorMelanie2009-09-30 19:26:26 +0100
committerMelanie2009-09-30 19:26:26 +0100
commitf908e32f620272a63c6a338fddfa3214ce95627b (patch)
treee04c53d2514551986b6bc6b1ae825f437b3ccebf /OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
parentRemove more tests that don't apply to this build (diff)
downloadopensim-SC-f908e32f620272a63c6a338fddfa3214ce95627b.zip
opensim-SC-f908e32f620272a63c6a338fddfa3214ce95627b.tar.gz
opensim-SC-f908e32f620272a63c6a338fddfa3214ce95627b.tar.bz2
opensim-SC-f908e32f620272a63c6a338fddfa3214ce95627b.tar.xz
Revert "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"
This reverts commit 22cc31135e2989df28e0756eb3b03f85530d5555.
Diffstat (limited to 'OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs236
1 files changed, 168 insertions, 68 deletions
diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
index aa29947..937f76b 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;
37using OpenMetaverse.Imaging; 38using 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,58 +195,174 @@ 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 = null; 198 OpenJPEG.J2KLayerInfo[] layers = new OpenJPEG.J2KLayerInfo[0]; // Dummy result for if it fails. Informs that there's only full quality
199 199
200 if (!fCache.TryLoadCacheForAsset(AssetId, out layers)) 200 if (!OpenJpegFail)
201 { 201 {
202 try 202 if (!fCache.TryLoadCacheForAsset(AssetId, out layers))
203 { 203 {
204 List<int> layerStarts = CSJ2K.J2kImage.GetLayerBoundaries(new MemoryStream(j2kdata)); 204 try
205
206 if (layerStarts != null && layerStarts.Count > 0)
207 { 205 {
208 layers = new OpenJPEG.J2KLayerInfo[layerStarts.Count];
209 206
210 for (int i = 0; i < layerStarts.Count; i++) 207 AssetTexture texture = new AssetTexture(AssetId, j2kdata);
208 if (texture.DecodeLayerBoundaries())
211 { 209 {
212 OpenJPEG.J2KLayerInfo layer = new OpenJPEG.J2KLayerInfo(); 210 bool sane = true;
213 int start = layerStarts[i]; 211
214 212 // Sanity check all of the layers
215 if (i == 0) 213 for (int i = 0; i < texture.LayerInfo.Length; i++)
216 layer.Start = 0; 214 {
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 }
217 else 233 else
218 layer.Start = layerStarts[i]; 234 {
235 m_log.WarnFormat(
236 "[J2KDecoderModule]: JPEG2000 texture decoding succeeded, but sanity check failed for {0}",
237 AssetId);
238 }
239 }
219 240
220 if (i == layerStarts.Count - 1) 241 else
221 layer.End = j2kdata.Length; 242 {
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 }
222 else 334 else
223 layer.End = layerStarts[i + 1] - 1; 335 {
224 336 m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding failed for {0}. Is this a texture? is it J2K?", AssetId);
225 layers[i] = layer; 337 }
226 } 338 }
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);
227 } 352 }
228 } 353 }
229 catch (Exception ex) 354
230 { 355 }
231 m_log.Warn("[J2KDecoderModule]: CSJ2K threw an exception decoding texture " + AssetId + ": " + ex.ToString());
232 }
233 356
234 if (layers.Length == 0) 357 // Cache Decoded layers
235 { 358 lock (m_cacheddecode)
236 m_log.Warn("[J2KDecoderModule]: OpenJPEG failed to decode any layer data for texture " + AssetId + ", guessing sane defaults"); 359 {
237 // Layer decoding completely failed. Guess at sane defaults for the layer boundaries 360 if (m_cacheddecode.ContainsKey(AssetId))
238 layers = CreateDefaultLayers(j2kdata.Length); 361 m_cacheddecode.Remove(AssetId);
239 } 362 m_cacheddecode.Add(AssetId, layers);
363
364 }
240 365
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
250 // Notify Interested Parties 366 // Notify Interested Parties
251 lock (m_notifyList) 367 lock (m_notifyList)
252 { 368 {
@@ -261,31 +377,6 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
261 } 377 }
262 } 378 }
263 } 379 }
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 }
289 380
290 private void CleanCache() 381 private void CleanCache()
291 { 382 {
@@ -327,9 +418,10 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
327 { 418 {
328 m_cacheDecodeFolder = pFolder; 419 m_cacheDecodeFolder = pFolder;
329 m_cacheTimeout = timeout; 420 m_cacheTimeout = timeout;
330
331 if (!Directory.Exists(pFolder)) 421 if (!Directory.Exists(pFolder))
422 {
332 Createj2KCacheFolder(pFolder); 423 Createj2KCacheFolder(pFolder);
424 }
333 } 425 }
334 426
335 /// <summary> 427 /// <summary>
@@ -355,15 +447,14 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
355 447
356 stringResult.AppendFormat("{0}|{1}|{2}{3}", Layers[i].Start, Layers[i].End, Layers[i].End - Layers[i].Start, strEnd); 448 stringResult.AppendFormat("{0}|{1}|{2}{3}", Layers[i].Start, Layers[i].End, Layers[i].End - Layers[i].Start, strEnd);
357 } 449 }
358
359 fsSWCache.Write(stringResult.ToString()); 450 fsSWCache.Write(stringResult.ToString());
360 fsSWCache.Close(); 451 fsSWCache.Close();
361 fsSWCache.Dispose(); 452 fsSWCache.Dispose();
362 fsCache.Dispose(); 453 fsCache.Dispose();
363
364 return true; 454 return true;
365 } 455 }
366 456
457
367 return false; 458 return false;
368 } 459 }
369 460
@@ -384,9 +475,11 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
384 return false; 475 return false;
385 476
386 if (!enabled) 477 if (!enabled)
478 {
387 return false; 479 return false;
480 }
388 481
389 string readResult = String.Empty; 482 string readResult = string.Empty;
390 483
391 try 484 try
392 { 485 {
@@ -400,6 +493,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
400 sr.Close(); 493 sr.Close();
401 sr.Dispose(); 494 sr.Dispose();
402 fsCachefile.Dispose(); 495 fsCachefile.Dispose();
496
403 } 497 }
404 catch (IOException ioe) 498 catch (IOException ioe)
405 { 499 {
@@ -420,6 +514,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
420 "[J2KDecodeCache]: Cache Read failed. IO Exception."); 514 "[J2KDecodeCache]: Cache Read failed. IO Exception.");
421 } 515 }
422 return false; 516 return false;
517
423 } 518 }
424 catch (UnauthorizedAccessException) 519 catch (UnauthorizedAccessException)
425 { 520 {
@@ -446,6 +541,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
446 m_log.Error( 541 m_log.Error(
447 "[J2KDecodeCache]: Cache Read failed, not supported. Cache disabled!"); 542 "[J2KDecodeCache]: Cache Read failed, not supported. Cache disabled!");
448 enabled = false; 543 enabled = false;
544
449 return false; 545 return false;
450 } 546 }
451 catch (Exception e) 547 catch (Exception e)
@@ -485,6 +581,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
485 Layers[i] = new OpenJPEG.J2KLayerInfo(); 581 Layers[i] = new OpenJPEG.J2KLayerInfo();
486 Layers[i].Start = element1; 582 Layers[i].Start = element1;
487 Layers[i].End = element2; 583 Layers[i].End = element2;
584
488 } 585 }
489 else 586 else
490 { 587 {
@@ -495,6 +592,9 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
495 } 592 }
496 } 593 }
497 594
595
596
597
498 return true; 598 return true;
499 } 599 }
500 600