29 using System.Collections.Generic;
31 using OpenMetaverse.Imaging;
32 using OpenSim.Framework;
33 using OpenSim.Region.Framework.Interfaces;
34 using OpenSim.Services.Interfaces;
36 using System.Reflection;
38 namespace OpenSim.
Region.ClientStack.LindenUDP
45 private const int IMAGE_PACKET_SIZE = 1000;
46 private const int FIRST_PACKET_SIZE = 600;
55 private const int ASSET_REQUEST_TIMEOUT = 100000000;
57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68 private OpenJPEG.J2KLayerInfo[] m_layers;
73 public bool IsDecoded {
get;
private set; }
78 public bool HasAsset {
get;
private set; }
83 public long AssetRequestTime {
get;
private set; }
87 private uint m_currentPacket;
88 private bool m_decodeRequested;
89 private bool m_assetRequested;
90 private bool m_sentInfo;
91 private uint m_stopPacket;
92 private byte[] m_asset;
97 m_imageManager = imageManager;
112 if (m_currentPacket <= m_stopPacket)
114 bool sendMore =
true;
116 if (!m_sentInfo || (m_currentPacket == 0))
118 sendMore = !SendFirstPacket(client);
124 if (m_currentPacket < 2)
129 while (sendMore && packetsSent < packetsToSend && m_currentPacket <= m_stopPacket)
131 sendMore = SendPacket(client);
137 return (m_currentPacket > m_stopPacket);
149 if (!m_assetRequested || DateTime.UtcNow.Ticks > AssetRequestTime + ASSET_REQUEST_TIMEOUT)
155 m_assetRequested =
true;
156 AssetRequestTime = DateTime.UtcNow.Ticks;
158 AssetService.Get(TextureID.ToString(),
this, AssetReceived);
166 if (!m_decodeRequested)
169 m_decodeRequested =
true;
174 if (J2KDecoder != null)
178 J2KDecodedCallback(TextureID,
new OpenJPEG.J2KLayerInfo[0]);
183 J2KDecoder.BeginDecode(TextureID, m_asset, J2KDecodedCallback);
188 J2KDecodedCallback(TextureID,
new OpenJPEG.J2KLayerInfo[0]);
197 m_log.Warn(
"[J2KIMAGE]: RunUpdate() called with missing asset data (no missing image texture?). Canceling texture transfer");
198 m_currentPacket = m_stopPacket;
202 if (DiscardLevel >= 0 || m_stopPacket == 0)
205 if (m_layers == null)
207 m_log.Warn(
"[J2KIMAGE]: RunUpdate() called with missing Layers. Canceling texture transfer");
208 m_currentPacket = m_stopPacket;
212 int maxDiscardLevel = Math.Max(0, m_layers.Length - 1);
215 if (DiscardLevel < 0 && m_stopPacket == 0)
216 DiscardLevel = (sbyte)maxDiscardLevel;
219 DiscardLevel = (sbyte)Math.Min(DiscardLevel, maxDiscardLevel);
222 if (m_layers.Length > 0)
224 m_stopPacket = (uint)GetPacketForBytePosition(m_layers[(m_layers.Length - 1) - DiscardLevel].End);
227 if (TexturePacketCount() == m_stopPacket + 1)
229 m_stopPacket = TexturePacketCount();
234 m_stopPacket = TexturePacketCount();
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
240 m_currentPacket = StartPacket;
246 private bool SendFirstPacket(
IClientAPI client)
253 m_log.Warn(
"[J2KIMAGE]: Sending ImageNotInDatabase for texture " + TextureID);
254 client.SendImageNotFound(TextureID);
257 else if (m_asset.Length <= FIRST_PACKET_SIZE)
260 client.SendImageFirstPart(1, TextureID, (uint)m_asset.Length, m_asset, 2);
267 byte[] firstImageData =
new byte[FIRST_PACKET_SIZE];
269 try { Buffer.BlockCopy(m_asset, 0, firstImageData, 0, FIRST_PACKET_SIZE); }
272 m_log.ErrorFormat(
"[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}", TextureID, m_asset.Length);
276 client.SendImageFirstPart(TexturePacketCount(), TextureID, (uint)m_asset.Length, firstImageData, (byte)ImageCodec.J2C);
286 bool complete =
false;
287 int imagePacketSize = ((int)m_currentPacket == (TexturePacketCount())) ? LastPacketSize() : IMAGE_PACKET_SIZE;
291 if ((CurrentBytePosition() + IMAGE_PACKET_SIZE) > m_asset.Length)
293 imagePacketSize = LastPacketSize();
295 if ((CurrentBytePosition() + imagePacketSize) > m_asset.Length)
297 imagePacketSize = m_asset.Length - CurrentBytePosition();
305 if (imagePacketSize > 0)
307 byte[] imageData =
new byte[imagePacketSize];
308 int currentPosition = CurrentBytePosition();
310 try { Buffer.BlockCopy(m_asset, currentPosition, imageData, 0, imagePacketSize); }
313 m_log.ErrorFormat(
"[J2KIMAGE]: Texture block copy for the first packet failed. textureid={0}, assetlength={1}, currentposition={2}, imagepacketsize={3}, exception={4}",
314 TextureID, m_asset.Length, currentPosition, imagePacketSize, e.Message);
319 client.SendImageNextPart((ushort)(m_currentPacket - 1), TextureID, imageData);
330 private ushort TexturePacketCount()
338 if (m_asset.Length <= FIRST_PACKET_SIZE)
341 return (ushort)(((m_asset.Length - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1);
344 private int GetPacketForBytePosition(
int bytePosition)
346 return ((bytePosition - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1;
349 private int LastPacketSize()
351 if (m_currentPacket == 1)
352 return m_asset.Length;
353 int lastsize = (m_asset.Length - FIRST_PACKET_SIZE) % IMAGE_PACKET_SIZE;
357 lastsize = IMAGE_PACKET_SIZE;
362 private int CurrentBytePosition()
364 if (m_currentPacket == 0)
367 if (m_currentPacket == 1)
368 return FIRST_PACKET_SIZE;
370 int result = FIRST_PACKET_SIZE + ((int)m_currentPacket - 2) * IMAGE_PACKET_SIZE;
373 result = FIRST_PACKET_SIZE;
378 private void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers)
385 private void AssetDataCallback(UUID AssetID,
AssetBase asset)
389 if (asset == null || asset.
Data == null)
391 if (m_imageManager.MissingImage != null)
393 m_asset = m_imageManager.MissingImage.Data;
403 m_asset = asset.Data;
409 private void AssetReceived(
string id, Object sender,
AssetBase asset)
414 UUID assetID = UUID.Zero;
417 assetID = asset.FullID;
419 else if ((InventoryAccessModule != null) && (sender != InventoryAccessModule))
426 string assetServerURL = string.Empty;
427 if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
429 if (!assetServerURL.EndsWith(
"/") && !assetServerURL.EndsWith(
"="))
430 assetServerURL = assetServerURL +
"/";
433 AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
438 AssetDataCallback(assetID, asset);
C5.IPriorityQueueHandle< J2KImage > PriorityQueueHandle
void RunUpdate()
This is where we decide what we need to update and assign the real discardLevel and packetNumber assu...
bool SendPackets(IClientAPI client, int packetsToSend, out int packetsSent)
Sends packets for this texture to a client until packetsToSend is hit or the transfer completes ...
Asset class. All Assets are reference by this class or a class derived from this class ...
Stores information about a current texture download and a reference to the texture asset ...
IAssetService AssetService
IInventoryAccessModule InventoryAccessModule
J2KImage(LLImageManager imageManager)
This class handles UDP texture requests.