aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs
diff options
context:
space:
mode:
authorTeravus Ovares2009-01-22 01:33:46 +0000
committerTeravus Ovares2009-01-22 01:33:46 +0000
commitc6154c89873da5d9fa017c75cbfad8e5f50da8f0 (patch)
treeb4bebda4fce471815a7880837b475271a3c47ec8 /OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs
parent* refactor: Extract caps related code from scene and put into a region module (diff)
downloadopensim-SC-c6154c89873da5d9fa017c75cbfad8e5f50da8f0.zip
opensim-SC-c6154c89873da5d9fa017c75cbfad8e5f50da8f0.tar.gz
opensim-SC-c6154c89873da5d9fa017c75cbfad8e5f50da8f0.tar.bz2
opensim-SC-c6154c89873da5d9fa017c75cbfad8e5f50da8f0.tar.xz
* Add File cache for j2k layer decodes. This will make it so that the server will decode the j2k stream once and cache it to disk so that the cache is saved across sim restarts.
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs342
1 files changed, 304 insertions, 38 deletions
diff --git a/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs
index dc46dc6..518766e 100644
--- a/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs
+++ b/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs
@@ -26,13 +26,16 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.IO;
29using System.Reflection; 30using System.Reflection;
31using System.Text;
30using System.Threading; 32using System.Threading;
31using System.Collections.Generic; 33using System.Collections.Generic;
32using log4net; 34using log4net;
33using Nini.Config; 35using Nini.Config;
34using OpenMetaverse; 36using OpenMetaverse;
35using OpenMetaverse.Imaging; 37using OpenMetaverse.Imaging;
38using OpenSim.Framework;
36using OpenSim.Region.Environment.Interfaces; 39using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Region.Environment.Scenes; 40using OpenSim.Region.Environment.Scenes;
38 41
@@ -50,12 +53,19 @@ namespace OpenSim.Region.Environment.Modules.Agent.TextureSender
50 /// </summary> 53 /// </summary>
51 private readonly Dictionary<UUID, OpenJPEG.J2KLayerInfo[]> m_cacheddecode = new Dictionary<UUID, OpenJPEG.J2KLayerInfo[]>(); 54 private readonly Dictionary<UUID, OpenJPEG.J2KLayerInfo[]> m_cacheddecode = new Dictionary<UUID, OpenJPEG.J2KLayerInfo[]>();
52 private bool OpenJpegFail = false; 55 private bool OpenJpegFail = false;
56 private readonly string CacheFolder = Util.dataDir() + "/j2kDecodeCache";
57 private readonly J2KDecodeFileCache fCache;
53 58
54 /// <summary> 59 /// <summary>
55 /// List of client methods to notify of results of decode 60 /// List of client methods to notify of results of decode
56 /// </summary> 61 /// </summary>
57 private readonly Dictionary<UUID, List<DecodedCallback>> m_notifyList = new Dictionary<UUID, List<DecodedCallback>>(); 62 private readonly Dictionary<UUID, List<DecodedCallback>> m_notifyList = new Dictionary<UUID, List<DecodedCallback>>();
58 63
64 public J2KDecoderModule()
65 {
66 fCache = new J2KDecodeFileCache(CacheFolder);
67 }
68
59 public void Initialise(Scene scene, IConfigSource source) 69 public void Initialise(Scene scene, IConfigSource source)
60 { 70 {
61 scene.RegisterModuleInterface<IJ2KDecoder>(this); 71 scene.RegisterModuleInterface<IJ2KDecoder>(this);
@@ -151,61 +161,68 @@ namespace OpenSim.Region.Environment.Modules.Agent.TextureSender
151 161
152 if (!OpenJpegFail) 162 if (!OpenJpegFail)
153 { 163 {
154 try 164 if (!fCache.TryLoadCacheForAsset(AssetId, out layers))
155 { 165 {
156 166 try
157 AssetTexture texture = new AssetTexture(AssetId, j2kdata);
158 if (texture.DecodeLayerBoundaries())
159 { 167 {
160 bool sane = true;
161 168
162 // Sanity check all of the layers 169 AssetTexture texture = new AssetTexture(AssetId, j2kdata);
163 for (int i = 0; i < texture.LayerInfo.Length; i++) 170 if (texture.DecodeLayerBoundaries())
164 { 171 {
165 if (texture.LayerInfo[i].End > texture.AssetData.Length) 172 bool sane = true;
173
174 // Sanity check all of the layers
175 for (int i = 0; i < texture.LayerInfo.Length; i++)
166 { 176 {
167 sane = false; 177 if (texture.LayerInfo[i].End > texture.AssetData.Length)
168 break; 178 {
179 sane = false;
180 break;
181 }
169 } 182 }
170 }
171 183
172 if (sane) 184 if (sane)
173 { 185 {
174 layers = texture.LayerInfo; 186 layers = texture.LayerInfo;
187 fCache.SaveFileCacheForAsset(AssetId, layers);
188
189
190 // Write out decode time
191 m_log.InfoFormat("[J2KDecoderModule]: {0} Decode Time: {1}", System.Environment.TickCount - DecodeTime,
192 AssetId);
193
194 }
195 else
196 {
197 m_log.WarnFormat(
198 "[J2KDecoderModule]: JPEG2000 texture decoding succeeded, but sanity check failed for {0}",
199 AssetId);
200 }
175 } 201 }
202
176 else 203 else
177 { 204 {
178 m_log.WarnFormat( 205 m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding failed for {0}", AssetId);
179 "[J2KDecoderModule]: JPEG2000 texture decoding succeeded, but sanity check failed for {0}",
180 AssetId);
181 } 206 }
207 texture = null; // dereference and dispose of ManagedImage
182 } 208 }
183 209 catch (DllNotFoundException)
184 else
185 { 210 {
186 m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding failed for {0}", AssetId); 211 m_log.Error(
212 "[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!");
213 OpenJpegFail = true;
214 }
215 catch (Exception ex)
216 {
217 m_log.WarnFormat(
218 "[J2KDecoderModule]: JPEG2000 texture decoding threw an exception for {0}, {1}",
219 AssetId, ex);
187 } 220 }
188 texture = null; // dereference and dispose of ManagedImage
189 }
190 catch (DllNotFoundException)
191 {
192 m_log.Error(
193 "[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!");
194 OpenJpegFail = true;
195 }
196 catch (Exception ex)
197 {
198 m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding threw an exception for {0}, {1}",
199 AssetId, ex);
200 } 221 }
222
201 } 223 }
202 224
203 if (!OpenJpegFail) 225
204 {
205 // Write out decode time
206 m_log.InfoFormat("[J2KDecoderModule]: {0} Decode Time: {1}", System.Environment.TickCount - DecodeTime,
207 AssetId);
208 }
209 // Cache Decoded layers 226 // Cache Decoded layers
210 lock (m_cacheddecode) 227 lock (m_cacheddecode)
211 { 228 {
@@ -213,6 +230,8 @@ namespace OpenSim.Region.Environment.Modules.Agent.TextureSender
213 230
214 } 231 }
215 232
233
234
216 // Notify Interested Parties 235 // Notify Interested Parties
217 lock (m_notifyList) 236 lock (m_notifyList)
218 { 237 {
@@ -228,4 +247,251 @@ namespace OpenSim.Region.Environment.Modules.Agent.TextureSender
228 } 247 }
229 } 248 }
230 } 249 }
250
251 public class J2KDecodeFileCache
252 {
253 private readonly string m_cacheDecodeFolder;
254 private bool enabled = true;
255
256 private static readonly ILog m_log
257 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
258
259 public J2KDecodeFileCache(string pFolder)
260 {
261 m_cacheDecodeFolder = pFolder;
262 if (!Directory.Exists(pFolder))
263 {
264 Createj2KCacheFolder(pFolder);
265 }
266
267 }
268
269 public bool SaveFileCacheForAsset(UUID AssetId, OpenJPEG.J2KLayerInfo[] Layers)
270 {
271 if (Layers.Length > 0 && enabled)
272 {
273 FileStream fsCache =
274 new FileStream(String.Format("{0}/{1}", m_cacheDecodeFolder, FileNameFromAssetId(AssetId)),
275 FileMode.Create);
276 StreamWriter fsSWCache = new StreamWriter(fsCache);
277 StringBuilder stringResult = new StringBuilder();
278 string strEnd = "\n";
279 for (int i = 0; i < Layers.Length; i++)
280 {
281 if (i == (Layers.Length - 1))
282 strEnd = "";
283
284 stringResult.AppendFormat("{0}|{1}|{2}{3}", Layers[i].Start, Layers[i].End, Layers[i].Size, strEnd);
285 }
286 fsSWCache.Write(stringResult.ToString());
287 fsSWCache.Close();
288 fsSWCache.Dispose();
289 fsCache.Dispose();
290 return true;
291 }
292
293
294 return false;
295 }
296
297
298
299 public bool TryLoadCacheForAsset(UUID AssetId, out OpenJPEG.J2KLayerInfo[] Layers)
300 {
301 string filename = String.Format("{0}/{1}", m_cacheDecodeFolder, FileNameFromAssetId(AssetId));
302 Layers = new OpenJPEG.J2KLayerInfo[0];
303
304 if (!File.Exists(filename))
305 return false;
306
307 if (!enabled)
308 {
309 return false;
310 }
311
312 string readResult = string.Empty;
313
314 try
315 {
316 FileStream fsCachefile =
317 new FileStream(filename,
318 FileMode.Open);
319
320 StreamReader sr = new StreamReader(fsCachefile);
321 readResult = sr.ReadToEnd();
322
323 sr.Close();
324 sr.Dispose();
325 fsCachefile.Dispose();
326
327 }
328 catch (IOException ioe)
329 {
330 if (ioe is PathTooLongException)
331 {
332 m_log.Error(
333 "[J2KDecodeCache]: Cache Read failed. Path is too long.");
334 }
335 else if (ioe is DirectoryNotFoundException)
336 {
337 m_log.Error(
338 "[J2KDecodeCache]: Cache Read failed. Cache Directory does not exist!");
339 enabled = false;
340 }
341 else
342 {
343 m_log.Error(
344 "[J2KDecodeCache]: Cache Read failed. IO Exception.");
345 }
346 return false;
347
348 }
349 catch (UnauthorizedAccessException)
350 {
351 m_log.Error(
352 "[J2KDecodeCache]: Cache Read failed. UnauthorizedAccessException Exception. Do you have the proper permissions on this file?");
353 return false;
354 }
355 catch (ArgumentException ae)
356 {
357 if (ae is ArgumentNullException)
358 {
359 m_log.Error(
360 "[J2KDecodeCache]: Cache Read failed. No Filename provided");
361 }
362 else
363 {
364 m_log.Error(
365 "[J2KDecodeCache]: Cache Read failed. Filname was invalid");
366 }
367 return false;
368 }
369 catch (NotSupportedException)
370 {
371 m_log.Error(
372 "[J2KDecodeCache]: Cache Read failed, not supported. Cache disabled!");
373 enabled = false;
374
375 return false;
376 }
377 catch (Exception e)
378 {
379 m_log.ErrorFormat(
380 "[J2KDecodeCache]: Cache Read failed, unknown exception. Error: {0}",
381 e.ToString());
382 return false;
383 }
384
385 string[] lines = readResult.Split('\n');
386
387 if (lines.Length <= 0)
388 return false;
389
390 Layers = new OpenJPEG.J2KLayerInfo[lines.Length];
391
392 for (int i = 0; i < lines.Length; i++)
393 {
394 string[] elements = lines[i].Split('|');
395 if (elements.Length == 3)
396 {
397 int element1, element2;
398
399 try
400 {
401 element1 = Convert.ToInt32(elements[0]);
402 element2 = Convert.ToInt32(elements[1]);
403 }
404 catch (FormatException)
405 {
406 m_log.WarnFormat("[J2KDecodeCache]: Cache Read failed with ErrorConvert for {0}", AssetId);
407 Layers = new OpenJPEG.J2KLayerInfo[0];
408 return false;
409 }
410
411 Layers[i] = new OpenJPEG.J2KLayerInfo();
412 Layers[i].Start = element1;
413 Layers[i].End = element2;
414
415 }
416 else
417 {
418 // reading failed
419 m_log.WarnFormat("[J2KDecodeCache]: Cache Read failed for {0}", AssetId);
420 Layers = new OpenJPEG.J2KLayerInfo[0];
421 return false;
422 }
423 }
424
425
426
427
428 return true;
429 }
430
431 public string FileNameFromAssetId(UUID AssetId)
432 {
433 return String.Format("j2kCache_{0}.cache", AssetId);
434 }
435
436 public void Createj2KCacheFolder(string pFolder)
437 {
438 try
439 {
440 Directory.CreateDirectory(pFolder);
441 }
442 catch (IOException ioe)
443 {
444 if (ioe is PathTooLongException)
445 {
446 m_log.Error(
447 "[J2KDecodeCache]: Cache Directory does not exist and create failed because the path to the cache folder is too long. Cache disabled!");
448 }
449 else if (ioe is DirectoryNotFoundException)
450 {
451 m_log.Error(
452 "[J2KDecodeCache]: Cache Directory does not exist and create failed because the supplied base of the directory folder does not exist. Cache disabled!");
453 }
454 else
455 {
456 m_log.Error(
457 "[J2KDecodeCache]: Cache Directory does not exist and create failed because of an IO Exception. Cache disabled!");
458 }
459 enabled = false;
460
461 }
462 catch (UnauthorizedAccessException)
463 {
464 m_log.Error(
465 "[J2KDecodeCache]: Cache Directory does not exist and create failed because of an UnauthorizedAccessException Exception. Cache disabled!");
466 enabled = false;
467 }
468 catch (ArgumentException ae)
469 {
470 if (ae is ArgumentNullException)
471 {
472 m_log.Error(
473 "[J2KDecodeCache]: Cache Directory does not exist and create failed because the folder provided is invalid! Cache disabled!");
474 }
475 else
476 {
477 m_log.Error(
478 "[J2KDecodeCache]: Cache Directory does not exist and create failed because no cache folder was provided! Cache disabled!");
479 }
480 enabled = false;
481 }
482 catch (NotSupportedException)
483 {
484 m_log.Error(
485 "[J2KDecodeCache]: Cache Directory does not exist and create failed because it's not supported. Cache disabled!");
486 enabled = false;
487 }
488 catch (Exception e)
489 {
490 m_log.ErrorFormat(
491 "[J2KDecodeCache]: Cache Directory does not exist and create failed because of an unknown exception. Cache disabled! Error: {0}",
492 e.ToString());
493 enabled = false;
494 }
495 }
496 }
231} 497}