aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs455
1 files changed, 230 insertions, 225 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
index 638c765..5f549b5 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
@@ -38,40 +38,37 @@ using System.Reflection;
38namespace OpenSim.Region.ClientStack.LindenUDP 38namespace OpenSim.Region.ClientStack.LindenUDP
39{ 39{
40 /// <summary> 40 /// <summary>
41 /// We use this class to store image data and associated request data and attributes 41 /// Stores information about a current texture download and a reference to the texture asset
42 /// </summary> 42 /// </summary>
43 public class J2KImage 43 public class J2KImage
44 { 44 {
45 private const int IMAGE_PACKET_SIZE = 1000;
46 private const int FIRST_PACKET_SIZE = 600;
47
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 49
47 public double m_designatedPriorityKey; 50 public uint m_lastSequence;
48 public double m_requestedPriority = 0.0d; 51 public float m_requestedPriority;
49 public uint m_lastSequence = 0;
50 public uint m_requestedPacketNumber; 52 public uint m_requestedPacketNumber;
51 public sbyte m_requestedDiscardLevel; 53 public sbyte m_requestedDiscardLevel;
52 public UUID m_requestedUUID; 54 public UUID m_requestedUUID;
53 public IJ2KDecoder m_j2kDecodeModule; 55 public IJ2KDecoder m_j2kDecodeModule;
54 public IAssetService m_assetCache; 56 public IAssetService m_assetCache;
55 public OpenJPEG.J2KLayerInfo[] Layers = new OpenJPEG.J2KLayerInfo[0]; 57 public OpenJPEG.J2KLayerInfo[] m_layers;
56 public AssetBase m_MissingSubstitute = null; 58 public bool m_decoded;
57 public bool m_decoded = false; 59 public bool m_hasasset;
58 public bool m_completedSendAtCurrentDiscardLevel; 60 public C5.IPriorityQueueHandle<J2KImage> m_priorityQueueHandle;
59 61
60 private sbyte m_discardLevel=-1;
61 private uint m_packetNumber; 62 private uint m_packetNumber;
62 private bool m_decoderequested = false; 63 private bool m_decoderequested;
63 private bool m_hasasset = false; 64 private bool m_asset_requested;
64 private bool m_asset_requested = false; 65 private bool m_sentinfo;
65 private bool m_sentinfo = false; 66 private uint m_stopPacket;
66 private uint m_stopPacket = 0; 67 private AssetBase m_asset;
67 private const int cImagePacketSize = 1000; 68 private int m_assetDataLength;
68 private const int cFirstPacketSize = 600; 69 private LLImageManager m_imageManager;
69 private AssetBase m_asset = null; 70
70 private LLImageManager m_image; 71 #region Properties
71 public J2KImage(LLImageManager image)
72 {
73 m_image = image;
74 }
75 72
76 public uint m_pPacketNumber 73 public uint m_pPacketNumber
77 { 74 {
@@ -84,10 +81,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
84 81
85 public byte[] Data 82 public byte[] Data
86 { 83 {
87 get 84 get
88 { 85 {
89 if (m_asset != null) 86 if (m_asset != null)
90 return m_asset.Data; 87 return m_asset.Data;
91 else 88 else
92 return null; 89 return null;
93 } 90 }
@@ -97,9 +94,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
97 { 94 {
98 if (!m_decoded) 95 if (!m_decoded)
99 return 0; 96 return 0;
97
100 try 98 try
101 { 99 {
102 return (ushort)(((m_asset.Data.Length - cFirstPacketSize + cImagePacketSize - 1) / cImagePacketSize) + 1); 100 return (ushort)(((m_assetDataLength - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1);
103 } 101 }
104 catch (Exception) 102 catch (Exception)
105 { 103 {
@@ -110,119 +108,154 @@ namespace OpenSim.Region.ClientStack.LindenUDP
110 } 108 }
111 } 109 }
112 110
113 public void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers) 111 #endregion Properties
114 {
115 m_image.m_outstandingtextures++;
116 Layers = layers;
117 m_decoded = true;
118 RunUpdate();
119 }
120 112
121 public void AssetDataCallback(UUID AssetID, AssetBase asset) 113 public J2KImage(LLImageManager imageManager)
122 { 114 {
123 m_hasasset = true; 115 m_imageManager = imageManager;
124 if (asset == null || asset.Data == null)
125 {
126 m_asset = m_MissingSubstitute;
127 }
128 else
129 {
130 m_asset = asset;
131 }
132 RunUpdate();
133 } 116 }
134 117
135 protected void AssetReceived(string id, Object sender, AssetBase asset) 118 public bool SendPackets(LLClientView client, int maxpack)
136 { 119 {
137 UUID assetID = UUID.Zero; 120 if (m_packetNumber <= m_stopPacket)
138 if (asset != null) 121 {
139 assetID = asset.FullID; 122 bool SendMore = true;
140 123 if (!m_sentinfo || (m_packetNumber == 0))
141 AssetDataCallback(assetID, asset); 124 {
142 125 if (SendFirstPacket(client))
143 } 126 {
127 SendMore = false;
128 }
129 m_sentinfo = true;
130 m_packetNumber++;
131 }
132 // bool ignoreStop = false;
133 if (m_packetNumber < 2)
134 {
135 m_packetNumber = 2;
136 }
144 137
145 private int GetPacketForBytePosition(int bytePosition) 138 int count = 0;
146 { 139 while (SendMore && count < maxpack && m_packetNumber <= m_stopPacket)
147 return ((bytePosition - cFirstPacketSize + cImagePacketSize - 1) / cImagePacketSize) + 1; 140 {
148 } 141 count++;
142 SendMore = SendPacket(client);
143 m_packetNumber++;
144 }
149 145
150 public int LastPacketSize() 146 if (m_packetNumber > m_stopPacket)
151 { 147 return true;
152 if (m_packetNumber == 1)
153 return m_asset.Data.Length;
154 int lastsize = (m_asset.Data.Length - cFirstPacketSize) % cImagePacketSize;
155 //If the last packet size is zero, it's really cImagePacketSize, it sits on the boundary
156 if (lastsize == 0)
157 {
158 lastsize = cImagePacketSize;
159 } 148 }
160 return lastsize;
161 }
162
163 public int CurrentBytePosition()
164 {
165 if (m_packetNumber == 0)
166 return 0;
167 if (m_packetNumber == 1)
168 return cFirstPacketSize;
169 149
170 int result = cFirstPacketSize + ((int)m_packetNumber - 2) * cImagePacketSize; 150 return false;
171 if (result < 0)
172 {
173 result = cFirstPacketSize;
174 }
175 return result;
176 } 151 }
177 152
178 public bool SendFirstPacket(LLClientView client) 153 public void RunUpdate()
179 { 154 {
180 // this means we don't have 155 //This is where we decide what we need to update
181 if (Data == null) 156 //and assign the real discardLevel and packetNumber
182 { 157 //assuming of course that the connected client might be bonkers
183 client.SendImageNotFound(m_requestedUUID); 158
184 m_log.WarnFormat("[TEXTURE]: Got null Data element on a asset {0}.. and the missing image Data property is al", m_requestedUUID); 159 if (!m_hasasset)
185 return true;
186 }
187 // Do we have less then 1 packet's worth of data?
188 else if (m_asset.Data.Length <= cFirstPacketSize)
189 { 160 {
190 // Send only 1 packet 161 if (!m_asset_requested)
191 client.SendImageFirstPart(1, m_requestedUUID, (uint)m_asset.Data.Length, m_asset.Data, 2); 162 {
192 m_stopPacket = 0; 163 m_asset_requested = true;
193 return true; 164 m_assetCache.Get(m_requestedUUID.ToString(), this, AssetReceived);
165 }
194 } 166 }
195 else 167 else
196 { 168 {
197 byte[] firstImageData = new byte[cFirstPacketSize]; 169 if (!m_decoded)
198 try 170 {
199 { 171 //We need to decode the requested image first
200 Buffer.BlockCopy(m_asset.Data, 0, firstImageData, 0, (int)cFirstPacketSize); 172 if (!m_decoderequested)
201 client.SendImageFirstPart(TexturePacketCount(), m_requestedUUID, (uint)m_asset.Data.Length, firstImageData, 2); 173 {
174 //Request decode
175 m_decoderequested = true;
176 // Do we have a jpeg decoder?
177 if (m_j2kDecodeModule != null)
178 {
179 if (Data == null)
180 {
181 J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]);
182 }
183 else
184 {
185 // Send it off to the jpeg decoder
186 m_j2kDecodeModule.BeginDecode(m_requestedUUID, Data, J2KDecodedCallback);
187 }
188
189 }
190 else
191 {
192 J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]);
193 }
194 }
202 } 195 }
203 catch (Exception) 196 else
204 { 197 {
205 m_log.Error("Texture block copy failed. Possibly out of memory?"); 198 // Check for missing image asset data
206 return true; 199 if (m_asset == null || m_asset.Data == null)
200 {
201 // FIXME:
202 m_packetNumber = m_stopPacket;
203 return;
204 }
205
206 if (m_requestedDiscardLevel >= 0 || m_stopPacket == 0)
207 {
208 int maxDiscardLevel = Math.Max(0, m_layers.Length - 1);
209
210 // Treat initial texture downloads with a DiscardLevel of -1 a request for the highest DiscardLevel
211 if (m_requestedDiscardLevel < 0 && m_stopPacket == 0)
212 m_requestedDiscardLevel = (sbyte)maxDiscardLevel;
213
214 // Clamp at the highest discard level
215 m_requestedDiscardLevel = (sbyte)Math.Min(m_requestedDiscardLevel, maxDiscardLevel);
216
217 //Calculate the m_stopPacket
218 if (m_layers.Length > 0)
219 {
220 m_stopPacket = (uint)GetPacketForBytePosition(m_layers[(m_layers.Length - 1) - m_requestedDiscardLevel].End);
221 //I don't know why, but the viewer seems to expect the final packet if the file
222 //is just one packet bigger.
223 if (TexturePacketCount() == m_stopPacket + 1)
224 {
225 m_stopPacket = TexturePacketCount();
226 }
227 }
228 else
229 {
230 m_stopPacket = TexturePacketCount();
231 }
232
233 m_packetNumber = m_requestedPacketNumber;
234 }
235
236 if (m_imageManager.Client.PacketHandler.GetQueueCount(ThrottleOutPacketType.Texture) == 0)
237 {
238 //m_log.Debug("No textures queued, sending one packet to kickstart it");
239 SendPacket(m_imageManager.Client);
240 }
207 } 241 }
208 } 242 }
209 return false;
210 } 243 }
211 244
212 private bool SendPacket(LLClientView client) 245 private bool SendPacket(LLClientView client)
213 { 246 {
214 bool complete = false; 247 bool complete = false;
215 int imagePacketSize = ((int)m_packetNumber == (TexturePacketCount())) ? LastPacketSize() : cImagePacketSize; 248 int imagePacketSize = ((int)m_packetNumber == (TexturePacketCount())) ? LastPacketSize() : IMAGE_PACKET_SIZE;
216 249
217 try 250 try
218 { 251 {
219 if ((CurrentBytePosition() + cImagePacketSize) > m_asset.Data.Length) 252 if ((CurrentBytePosition() + IMAGE_PACKET_SIZE) > m_assetDataLength)
220 { 253 {
221 imagePacketSize = LastPacketSize(); 254 imagePacketSize = LastPacketSize();
222 complete=true; 255 complete = true;
223 if ((CurrentBytePosition() + imagePacketSize) > m_asset.Data.Length) 256 if ((CurrentBytePosition() + imagePacketSize) > m_assetDataLength)
224 { 257 {
225 imagePacketSize = m_asset.Data.Length - CurrentBytePosition(); 258 imagePacketSize = m_assetDataLength - CurrentBytePosition();
226 complete = true; 259 complete = true;
227 } 260 }
228 } 261 }
@@ -244,7 +277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
244 } 277 }
245 278
246 //Send the packet 279 //Send the packet
247 client.SendImageNextPart((ushort)(m_packetNumber-1), m_requestedUUID, imageData); 280 client.SendImageNextPart((ushort)(m_packetNumber - 1), m_requestedUUID, imageData);
248 } 281 }
249 if (complete) 282 if (complete)
250 { 283 {
@@ -260,143 +293,115 @@ namespace OpenSim.Region.ClientStack.LindenUDP
260 return false; 293 return false;
261 } 294 }
262 } 295 }
263 public bool SendPackets(LLClientView client, int maxpack) 296
297 private int GetPacketForBytePosition(int bytePosition)
264 { 298 {
299 return ((bytePosition - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1;
300 }
265 301
266 if (!m_completedSendAtCurrentDiscardLevel) 302 private int LastPacketSize()
303 {
304 if (m_packetNumber == 1)
305 return m_assetDataLength;
306 int lastsize = (m_assetDataLength - FIRST_PACKET_SIZE) % IMAGE_PACKET_SIZE;
307 //If the last packet size is zero, it's really cImagePacketSize, it sits on the boundary
308 if (lastsize == 0)
267 { 309 {
268 if (m_packetNumber <= m_stopPacket) 310 lastsize = IMAGE_PACKET_SIZE;
269 { 311 }
270 bool SendMore = true; 312 return lastsize;
271 if (!m_sentinfo || (m_packetNumber == 0)) 313 }
272 {
273 if (SendFirstPacket(client))
274 {
275 SendMore = false;
276 }
277 m_sentinfo = true;
278 m_packetNumber++;
279 }
280 // bool ignoreStop = false;
281 if (m_packetNumber < 2)
282 {
283 m_packetNumber = 2;
284 }
285 314
286 int count = 0; 315 private int CurrentBytePosition()
287 while (SendMore && count < maxpack && m_packetNumber <= m_stopPacket) 316 {
288 { 317 if (m_packetNumber == 0)
289 count++; 318 return 0;
290 SendMore = SendPacket(client); 319 if (m_packetNumber == 1)
291 m_packetNumber++; 320 return FIRST_PACKET_SIZE;
292 }
293 321
294 if (m_packetNumber > m_stopPacket) 322 int result = FIRST_PACKET_SIZE + ((int)m_packetNumber - 2) * IMAGE_PACKET_SIZE;
295 { 323 if (result < 0)
296 return true; 324 {
297 } 325 result = FIRST_PACKET_SIZE;
326 }
327 return result;
328 }
329
330 private bool SendFirstPacket(LLClientView client)
331 {
332 // this means we don't have
333 if (Data == null)
334 {
335 client.SendImageNotFound(m_requestedUUID);
336 m_log.WarnFormat("[TEXTURE]: Got null Data element on a asset {0}.. and the missing image Data property is also null", m_requestedUUID);
337 return true;
338 }
339 // Do we have less then 1 packet's worth of data?
340 else if (m_assetDataLength <= FIRST_PACKET_SIZE)
341 {
342 // Send only 1 packet
343 client.SendImageFirstPart(1, m_requestedUUID, (uint)m_assetDataLength, m_asset.Data, 2);
344 m_stopPacket = 0;
345 return true;
346 }
347 else
348 {
349 byte[] firstImageData = new byte[FIRST_PACKET_SIZE];
350 try
351 {
352 Buffer.BlockCopy(m_asset.Data, 0, firstImageData, 0, (int)FIRST_PACKET_SIZE);
353 client.SendImageFirstPart(TexturePacketCount(), m_requestedUUID, (uint)m_assetDataLength, firstImageData, 2);
354 }
355 catch (Exception)
356 {
357 m_log.Error("Texture block copy failed. Possibly out of memory?");
358 return true;
298 } 359 }
299 } 360 }
300 return false; 361 return false;
301 } 362 }
302 363
303 public void RunUpdate() 364 private void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers)
304 { 365 {
305 //This is where we decide what we need to update 366 m_layers = layers;
306 //and assign the real discardLevel and packetNumber 367 m_decoded = true;
307 //assuming of course that the connected client might be bonkers 368 RunUpdate();
369 }
308 370
309 if (!m_hasasset) 371 private void AssetDataCallback(UUID AssetID, AssetBase asset)
310 { 372 {
373 m_hasasset = true;
311 374
312 if (!m_asset_requested) 375 if (asset == null || asset.Data == null)
376 {
377 if (m_imageManager.MissingImage != null)
313 { 378 {
314 m_asset_requested = true; 379 m_asset = m_imageManager.MissingImage;
315 m_assetCache.Get(m_requestedUUID.ToString(), this, AssetReceived); 380 m_assetDataLength = m_asset.Data.Length;
316 381 }
382 else
383 {
384 m_asset = null;
385 m_decoded = true;
317 } 386 }
318
319 } 387 }
320 else 388 else
321 { 389 {
390 m_asset = asset;
391 m_assetDataLength = m_asset.Data.Length;
392 }
322 393
394 RunUpdate();
395 }
323 396
324 if (!m_decoded) 397 private void AssetReceived(string id, Object sender, AssetBase asset)
325 { 398 {
326 //We need to decode the requested image first 399 UUID assetID = UUID.Zero;
327 if (!m_decoderequested) 400 if (asset != null)
328 { 401 assetID = asset.FullID;
329 //Request decode
330 m_decoderequested = true;
331 // Do we have a jpeg decoder?
332 if (m_j2kDecodeModule != null)
333 {
334 if (Data == null)
335 {
336 J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]);
337 }
338 // Send it off to the jpeg decoder
339 m_j2kDecodeModule.decode(m_requestedUUID, Data, J2KDecodedCallback);
340
341 }
342 else
343 {
344 J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]);
345 }
346 }
347
348 }
349 else
350 {
351 //discardLevel of -1 means just update the priority
352 if (m_requestedDiscardLevel != -1)
353 {
354 //Evaluate the discard level
355 //First, is it positive?
356 if (m_requestedDiscardLevel >= 0)
357 {
358 if (m_requestedDiscardLevel > Layers.Length - 1)
359 {
360 m_discardLevel = (sbyte)(Layers.Length - 1);
361 }
362 else
363 {
364 m_discardLevel = m_requestedDiscardLevel;
365 }
366 402
367 //Calculate the m_stopPacket 403 AssetDataCallback(assetID, asset);
368 if (Layers.Length > 0)
369 {
370 m_stopPacket = (uint)GetPacketForBytePosition(Layers[(Layers.Length - 1) - m_discardLevel].End);
371 //I don't know why, but the viewer seems to expect the final packet if the file
372 //is just one packet bigger.
373 if (TexturePacketCount() == m_stopPacket + 1)
374 {
375 m_stopPacket = TexturePacketCount();
376 }
377 }
378 else
379 {
380 m_stopPacket = TexturePacketCount();
381 }
382 //Don't reset packet number unless we're waiting or it's ahead of us
383 if (m_completedSendAtCurrentDiscardLevel || m_requestedPacketNumber>m_packetNumber)
384 {
385 m_packetNumber = m_requestedPacketNumber;
386 }
387 404
388 if (m_packetNumber <= m_stopPacket)
389 {
390 m_completedSendAtCurrentDiscardLevel = false;
391 }
392 }
393 }
394 else
395 {
396 m_packetNumber = m_stopPacket;
397 }
398 }
399 }
400 } 405 }
401 } 406 }
402} 407}