diff options
Diffstat (limited to '')
3 files changed, 919 insertions, 919 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs index ac6a1fa..97e6bbe 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | |||
@@ -1,664 +1,664 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSim Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using OpenMetaverse; | 30 | using OpenMetaverse; |
31 | using OpenSim.Framework; | 31 | using OpenSim.Framework; |
32 | using OpenSim.Region.Environment.Interfaces; | 32 | using OpenSim.Region.Environment.Interfaces; |
33 | using C5; | 33 | using C5; |
34 | using OpenSim.Framework.Communications.Cache; | 34 | using OpenSim.Framework.Communications.Cache; |
35 | using OpenMetaverse.Imaging; | 35 | using OpenMetaverse.Imaging; |
36 | 36 | ||
37 | 37 | ||
38 | namespace OpenSim.Region.ClientStack.LindenUDP | 38 | namespace OpenSim.Region.ClientStack.LindenUDP |
39 | { | 39 | { |
40 | 40 | ||
41 | /// <summary> | 41 | /// <summary> |
42 | /// Client image priority + discardlevel sender/manager | 42 | /// Client image priority + discardlevel sender/manager |
43 | /// </summary> | 43 | /// </summary> |
44 | public class LLImageManager | 44 | public class LLImageManager |
45 | { | 45 | { |
46 | /// <summary> | 46 | /// <summary> |
47 | /// Priority Queue for images. Contains lots of data | 47 | /// Priority Queue for images. Contains lots of data |
48 | /// </summary> | 48 | /// </summary> |
49 | private readonly IPriorityQueue<Prio<J2KImage>> pq = new IntervalHeap<Prio<J2KImage>>(); | 49 | private readonly IPriorityQueue<Prio<J2KImage>> pq = new IntervalHeap<Prio<J2KImage>>(); |
50 | 50 | ||
51 | /// <summary> | 51 | /// <summary> |
52 | /// Dictionary of PriorityQueue handles by AssetId | 52 | /// Dictionary of PriorityQueue handles by AssetId |
53 | /// </summary> | 53 | /// </summary> |
54 | private readonly Dictionary<UUID, IPriorityQueueHandle<Prio<J2KImage>>> PQHandles = | 54 | private readonly Dictionary<UUID, IPriorityQueueHandle<Prio<J2KImage>>> PQHandles = |
55 | new Dictionary<UUID, IPriorityQueueHandle<Prio<J2KImage>>>(); | 55 | new Dictionary<UUID, IPriorityQueueHandle<Prio<J2KImage>>>(); |
56 | 56 | ||
57 | private LLClientView m_client; | 57 | private LLClientView m_client; |
58 | private readonly AssetCache m_assetCache; | 58 | private readonly AssetCache m_assetCache; |
59 | private bool m_shuttingdown = false; | 59 | private bool m_shuttingdown = false; |
60 | private readonly IJ2KDecoder m_j2kDecodeModule; | 60 | private readonly IJ2KDecoder m_j2kDecodeModule; |
61 | 61 | ||
62 | private readonly AssetBase MissingSubstitute; | 62 | private readonly AssetBase MissingSubstitute; |
63 | 63 | ||
64 | /// <summary> | 64 | /// <summary> |
65 | /// Client image priority + discardlevel sender/manager | 65 | /// Client image priority + discardlevel sender/manager |
66 | /// </summary> | 66 | /// </summary> |
67 | /// <param name="client">LLClientView of client</param> | 67 | /// <param name="client">LLClientView of client</param> |
68 | /// <param name="pAssetCache">The Asset retrieval system</param> | 68 | /// <param name="pAssetCache">The Asset retrieval system</param> |
69 | /// <param name="pJ2kDecodeModule">The Jpeg2000 Decoder</param> | 69 | /// <param name="pJ2kDecodeModule">The Jpeg2000 Decoder</param> |
70 | public LLImageManager(LLClientView client, AssetCache pAssetCache, IJ2KDecoder pJ2kDecodeModule) | 70 | public LLImageManager(LLClientView client, AssetCache pAssetCache, IJ2KDecoder pJ2kDecodeModule) |
71 | { | 71 | { |
72 | m_client = client; | 72 | m_client = client; |
73 | m_assetCache = pAssetCache; | 73 | m_assetCache = pAssetCache; |
74 | if (pAssetCache != null) | 74 | if (pAssetCache != null) |
75 | MissingSubstitute = pAssetCache.GetAsset(UUID.Parse("5748decc-f629-461c-9a36-a35a221fe21f"), true); | 75 | MissingSubstitute = pAssetCache.GetAsset(UUID.Parse("5748decc-f629-461c-9a36-a35a221fe21f"), true); |
76 | m_j2kDecodeModule = pJ2kDecodeModule; | 76 | m_j2kDecodeModule = pJ2kDecodeModule; |
77 | } | 77 | } |
78 | 78 | ||
79 | /// <summary> | 79 | /// <summary> |
80 | /// Enqueues a texture request | 80 | /// Enqueues a texture request |
81 | /// </summary> | 81 | /// </summary> |
82 | /// <param name="req">Request from the client to get a texture</param> | 82 | /// <param name="req">Request from the client to get a texture</param> |
83 | public void EnqueueReq(TextureRequestArgs req) | 83 | public void EnqueueReq(TextureRequestArgs req) |
84 | { | 84 | { |
85 | if (m_shuttingdown) | 85 | if (m_shuttingdown) |
86 | return; | 86 | return; |
87 | 87 | ||
88 | //if (req.RequestType == 1) // avatar body texture! | 88 | //if (req.RequestType == 1) // avatar body texture! |
89 | // return; | 89 | // return; |
90 | 90 | ||
91 | AddQueueItem(req.RequestedAssetID, (int)req.Priority + 100000); | 91 | AddQueueItem(req.RequestedAssetID, (int)req.Priority + 100000); |
92 | //if (pq[PQHandles[req.RequestedAssetID]].data.Missing) | 92 | //if (pq[PQHandles[req.RequestedAssetID]].data.Missing) |
93 | //{ | 93 | //{ |
94 | // pq[PQHandles[req.RequestedAssetID]] -= 900000; | 94 | // pq[PQHandles[req.RequestedAssetID]] -= 900000; |
95 | //} | 95 | //} |
96 | // | 96 | // |
97 | //if (pq[PQHandles[req.RequestedAssetID]].data.HasData && pq[PQHandles[req.RequestedAssetID]].data.Layers.Length > 0) | 97 | //if (pq[PQHandles[req.RequestedAssetID]].data.HasData && pq[PQHandles[req.RequestedAssetID]].data.Layers.Length > 0) |
98 | //{ | 98 | //{ |
99 | 99 | ||
100 | //} | 100 | //} |
101 | 101 | ||
102 | pq[PQHandles[req.RequestedAssetID]].data.requestedUUID = req.RequestedAssetID; | 102 | pq[PQHandles[req.RequestedAssetID]].data.requestedUUID = req.RequestedAssetID; |
103 | pq[PQHandles[req.RequestedAssetID]].data.Priority = (int)req.Priority; | 103 | pq[PQHandles[req.RequestedAssetID]].data.Priority = (int)req.Priority; |
104 | 104 | ||
105 | lock (pq[PQHandles[req.RequestedAssetID]].data) | 105 | lock (pq[PQHandles[req.RequestedAssetID]].data) |
106 | pq[PQHandles[req.RequestedAssetID]].data.Update(req.DiscardLevel, (int)req.PacketNumber); | 106 | pq[PQHandles[req.RequestedAssetID]].data.Update(req.DiscardLevel, (int)req.PacketNumber); |
107 | } | 107 | } |
108 | 108 | ||
109 | 109 | ||
110 | /// <summary> | 110 | /// <summary> |
111 | /// Callback for the asset system | 111 | /// Callback for the asset system |
112 | /// </summary> | 112 | /// </summary> |
113 | /// <param name="assetID">UUID of the asset that we have received</param> | 113 | /// <param name="assetID">UUID of the asset that we have received</param> |
114 | /// <param name="asset">AssetBase of the asset that we've received</param> | 114 | /// <param name="asset">AssetBase of the asset that we've received</param> |
115 | public void AssetDataCallback(UUID assetID, AssetBase asset) | 115 | public void AssetDataCallback(UUID assetID, AssetBase asset) |
116 | { | 116 | { |
117 | if (m_shuttingdown) | 117 | if (m_shuttingdown) |
118 | return; | 118 | return; |
119 | 119 | ||
120 | //Console.WriteLine("AssetCallback for assetId" + assetID); | 120 | //Console.WriteLine("AssetCallback for assetId" + assetID); |
121 | 121 | ||
122 | if (asset == null || asset.Data == null) | 122 | if (asset == null || asset.Data == null) |
123 | { | 123 | { |
124 | lock (pq) | 124 | lock (pq) |
125 | { | 125 | { |
126 | //pq[PQHandles[assetID]].data.Missing = true; | 126 | //pq[PQHandles[assetID]].data.Missing = true; |
127 | pq[PQHandles[assetID]].data.asset = MissingSubstitute; | 127 | pq[PQHandles[assetID]].data.asset = MissingSubstitute; |
128 | pq[PQHandles[assetID]].data.Missing = false; | 128 | pq[PQHandles[assetID]].data.Missing = false; |
129 | } | 129 | } |
130 | } | 130 | } |
131 | //else | 131 | //else |
132 | 132 | ||
133 | 133 | ||
134 | pq[PQHandles[assetID]].data.asset = asset; | 134 | pq[PQHandles[assetID]].data.asset = asset; |
135 | 135 | ||
136 | lock (pq[PQHandles[assetID]].data) | 136 | lock (pq[PQHandles[assetID]].data) |
137 | pq[PQHandles[assetID]].data.Update((int)pq[PQHandles[assetID]].data.Priority, (int)pq[PQHandles[assetID]].data.CurrentPacket); | 137 | pq[PQHandles[assetID]].data.Update((int)pq[PQHandles[assetID]].data.Priority, (int)pq[PQHandles[assetID]].data.CurrentPacket); |
138 | 138 | ||
139 | 139 | ||
140 | 140 | ||
141 | } | 141 | } |
142 | 142 | ||
143 | /// <summary> | 143 | /// <summary> |
144 | /// Processes the image queue. Pops count elements off and processes them | 144 | /// Processes the image queue. Pops count elements off and processes them |
145 | /// </summary> | 145 | /// </summary> |
146 | /// <param name="count">number of images to peek off the queue</param> | 146 | /// <param name="count">number of images to peek off the queue</param> |
147 | public void ProcessImageQueue(int count) | 147 | public void ProcessImageQueue(int count) |
148 | { | 148 | { |
149 | if (m_shuttingdown) | 149 | if (m_shuttingdown) |
150 | return; | 150 | return; |
151 | 151 | ||
152 | 152 | ||
153 | IPriorityQueueHandle<Prio<J2KImage>> h = null; | 153 | IPriorityQueueHandle<Prio<J2KImage>> h = null; |
154 | for (int j = 0; j < count; j++) | 154 | for (int j = 0; j < count; j++) |
155 | { | 155 | { |
156 | 156 | ||
157 | lock (pq) | 157 | lock (pq) |
158 | { | 158 | { |
159 | if (!pq.IsEmpty) | 159 | if (!pq.IsEmpty) |
160 | { | 160 | { |
161 | //peek off the top | 161 | //peek off the top |
162 | Prio<J2KImage> process = pq.FindMax(out h); | 162 | Prio<J2KImage> process = pq.FindMax(out h); |
163 | 163 | ||
164 | // Do we have the Asset Data? | 164 | // Do we have the Asset Data? |
165 | if (!process.data.HasData) | 165 | if (!process.data.HasData) |
166 | { | 166 | { |
167 | // Did we request the asset data? | 167 | // Did we request the asset data? |
168 | if (!process.data.dataRequested) | 168 | if (!process.data.dataRequested) |
169 | { | 169 | { |
170 | m_assetCache.GetAsset(process.data.requestedUUID, AssetDataCallback, true); | 170 | m_assetCache.GetAsset(process.data.requestedUUID, AssetDataCallback, true); |
171 | pq[h].data.dataRequested = true; | 171 | pq[h].data.dataRequested = true; |
172 | } | 172 | } |
173 | 173 | ||
174 | // Is the asset missing? | 174 | // Is the asset missing? |
175 | if (process.data.Missing) | 175 | if (process.data.Missing) |
176 | { | 176 | { |
177 | 177 | ||
178 | //m_client.sendtextur | 178 | //m_client.sendtextur |
179 | pq[h] -= 90000; | 179 | pq[h] -= 90000; |
180 | /* | 180 | /* |
181 | { | 181 | { |
182 | OpenMetaverse.Packets.ImageNotInDatabasePacket imdback = | 182 | OpenMetaverse.Packets.ImageNotInDatabasePacket imdback = |
183 | new OpenMetaverse.Packets.ImageNotInDatabasePacket(); | 183 | new OpenMetaverse.Packets.ImageNotInDatabasePacket(); |
184 | imdback.ImageID = | 184 | imdback.ImageID = |
185 | new OpenMetaverse.Packets.ImageNotInDatabasePacket.ImageIDBlock(); | 185 | new OpenMetaverse.Packets.ImageNotInDatabasePacket.ImageIDBlock(); |
186 | imdback.ImageID.ID = process.data.requestedUUID; | 186 | imdback.ImageID.ID = process.data.requestedUUID; |
187 | m_client.OutPacket(imdback, ThrottleOutPacketType.Texture); | 187 | m_client.OutPacket(imdback, ThrottleOutPacketType.Texture); |
188 | } | 188 | } |
189 | */ | 189 | */ |
190 | 190 | ||
191 | // Substitute a blank image | 191 | // Substitute a blank image |
192 | process.data.asset = MissingSubstitute; | 192 | process.data.asset = MissingSubstitute; |
193 | process.data.Missing = false; | 193 | process.data.Missing = false; |
194 | 194 | ||
195 | // If the priority is less then -4billion, the client has forgotten about it. | 195 | // If the priority is less then -4billion, the client has forgotten about it. |
196 | if (pq[h] < -400000000) | 196 | if (pq[h] < -400000000) |
197 | { | 197 | { |
198 | RemoveItemFromQueue(pq[h].data.requestedUUID); | 198 | RemoveItemFromQueue(pq[h].data.requestedUUID); |
199 | continue; | 199 | continue; |
200 | } | 200 | } |
201 | } | 201 | } |
202 | // Lower the priority to give the next image a chance | 202 | // Lower the priority to give the next image a chance |
203 | pq[h] -= 100000; | 203 | pq[h] -= 100000; |
204 | } | 204 | } |
205 | else if (process.data.HasData) | 205 | else if (process.data.HasData) |
206 | { | 206 | { |
207 | // okay, we've got the data | 207 | // okay, we've got the data |
208 | lock (process.data) | 208 | lock (process.data) |
209 | { | 209 | { |
210 | if (!process.data.J2KDecode && !process.data.J2KDecodeWaiting) | 210 | if (!process.data.J2KDecode && !process.data.J2KDecodeWaiting) |
211 | { | 211 | { |
212 | process.data.J2KDecodeWaiting = true; | 212 | process.data.J2KDecodeWaiting = true; |
213 | 213 | ||
214 | // Do we have a jpeg decoder? | 214 | // Do we have a jpeg decoder? |
215 | if (m_j2kDecodeModule != null) | 215 | if (m_j2kDecodeModule != null) |
216 | { | 216 | { |
217 | // Send it off to the jpeg decoder | 217 | // Send it off to the jpeg decoder |
218 | m_j2kDecodeModule.decode(process.data.requestedUUID, process.data.Data, | 218 | m_j2kDecodeModule.decode(process.data.requestedUUID, process.data.Data, |
219 | j2kDecodedCallback); | 219 | j2kDecodedCallback); |
220 | } | 220 | } |
221 | else | 221 | else |
222 | { | 222 | { |
223 | // no module, no layers, full resolution only | 223 | // no module, no layers, full resolution only |
224 | j2kDecodedCallback(process.data.AssetId, new OpenJPEG.J2KLayerInfo[0]); | 224 | j2kDecodedCallback(process.data.AssetId, new OpenJPEG.J2KLayerInfo[0]); |
225 | } | 225 | } |
226 | 226 | ||
227 | 227 | ||
228 | 228 | ||
229 | } // Are we waiting? | 229 | } // Are we waiting? |
230 | else if (!process.data.J2KDecodeWaiting) | 230 | else if (!process.data.J2KDecodeWaiting) |
231 | { | 231 | { |
232 | // Send more data at a time for higher discard levels | 232 | // Send more data at a time for higher discard levels |
233 | for (int i = 0; i < (2*(5 - process.data.DiscardLevel) + 1)*2; i++) | 233 | for (int i = 0; i < (2*(5 - process.data.DiscardLevel) + 1)*2; i++) |
234 | if (!process.data.SendPacket(m_client)) | 234 | if (!process.data.SendPacket(m_client)) |
235 | { | 235 | { |
236 | pq[h] -= (500000*i); | 236 | pq[h] -= (500000*i); |
237 | break; | 237 | break; |
238 | } | 238 | } |
239 | } | 239 | } |
240 | // If the priority is less then -4 billion, the client has forgotten about it, pop it off | 240 | // If the priority is less then -4 billion, the client has forgotten about it, pop it off |
241 | if (pq[h] < -400000000) | 241 | if (pq[h] < -400000000) |
242 | { | 242 | { |
243 | RemoveItemFromQueue(pq[h].data.requestedUUID); | 243 | RemoveItemFromQueue(pq[h].data.requestedUUID); |
244 | continue; | 244 | continue; |
245 | } | 245 | } |
246 | } | 246 | } |
247 | 247 | ||
248 | //pq[h] = process; | 248 | //pq[h] = process; |
249 | } | 249 | } |
250 | 250 | ||
251 | // uncomment the following line to see the upper most asset and the priority | 251 | // uncomment the following line to see the upper most asset and the priority |
252 | //Console.WriteLine(process.ToString()); | 252 | //Console.WriteLine(process.ToString()); |
253 | 253 | ||
254 | // Lower priority to give the next image a chance to bubble up | 254 | // Lower priority to give the next image a chance to bubble up |
255 | pq[h] -= 50000; | 255 | pq[h] -= 50000; |
256 | } | 256 | } |
257 | } | 257 | } |
258 | } | 258 | } |
259 | 259 | ||
260 | } | 260 | } |
261 | 261 | ||
262 | 262 | ||
263 | /// <summary> | 263 | /// <summary> |
264 | /// Callback for when the image has been decoded | 264 | /// Callback for when the image has been decoded |
265 | /// </summary> | 265 | /// </summary> |
266 | /// <param name="AssetId">The UUID of the Asset</param> | 266 | /// <param name="AssetId">The UUID of the Asset</param> |
267 | /// <param name="layers">The Jpeg2000 discard level Layer start and end byte offsets Array. 0 elements for failed or no decoder</param> | 267 | /// <param name="layers">The Jpeg2000 discard level Layer start and end byte offsets Array. 0 elements for failed or no decoder</param> |
268 | public void j2kDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers) | 268 | public void j2kDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers) |
269 | { | 269 | { |
270 | // are we shutting down? if so, end. | 270 | // are we shutting down? if so, end. |
271 | if (m_shuttingdown) | 271 | if (m_shuttingdown) |
272 | return; | 272 | return; |
273 | 273 | ||
274 | 274 | ||
275 | lock (PQHandles) | 275 | lock (PQHandles) |
276 | { | 276 | { |
277 | // Update our asset data | 277 | // Update our asset data |
278 | if (PQHandles.ContainsKey(AssetId)) | 278 | if (PQHandles.ContainsKey(AssetId)) |
279 | { | 279 | { |
280 | pq[PQHandles[AssetId]].data.Layers = layers; | 280 | pq[PQHandles[AssetId]].data.Layers = layers; |
281 | pq[PQHandles[AssetId]].data.J2KDecode = true; | 281 | pq[PQHandles[AssetId]].data.J2KDecode = true; |
282 | pq[PQHandles[AssetId]].data.J2KDecodeWaiting = false; | 282 | pq[PQHandles[AssetId]].data.J2KDecodeWaiting = false; |
283 | lock (pq[PQHandles[AssetId]].data) | 283 | lock (pq[PQHandles[AssetId]].data) |
284 | pq[PQHandles[AssetId]].data.Update((int)pq[PQHandles[AssetId]].data.Priority, (int)pq[PQHandles[AssetId]].data.CurrentPacket); | 284 | pq[PQHandles[AssetId]].data.Update((int)pq[PQHandles[AssetId]].data.Priority, (int)pq[PQHandles[AssetId]].data.CurrentPacket); |
285 | 285 | ||
286 | // Send the first packet | 286 | // Send the first packet |
287 | pq[PQHandles[AssetId]].data.SendPacket(m_client); | 287 | pq[PQHandles[AssetId]].data.SendPacket(m_client); |
288 | } | 288 | } |
289 | } | 289 | } |
290 | } | 290 | } |
291 | 291 | ||
292 | 292 | ||
293 | /// <summary> | 293 | /// <summary> |
294 | /// This image has had a good life. It's now expired. Remove it off the queue | 294 | /// This image has had a good life. It's now expired. Remove it off the queue |
295 | /// </summary> | 295 | /// </summary> |
296 | /// <param name="AssetId">UUID of asset to remove off the queue</param> | 296 | /// <param name="AssetId">UUID of asset to remove off the queue</param> |
297 | private void RemoveItemFromQueue(UUID AssetId) | 297 | private void RemoveItemFromQueue(UUID AssetId) |
298 | { | 298 | { |
299 | lock (PQHandles) | 299 | lock (PQHandles) |
300 | { | 300 | { |
301 | if (PQHandles.ContainsKey(AssetId)) | 301 | if (PQHandles.ContainsKey(AssetId)) |
302 | { | 302 | { |
303 | IPriorityQueueHandle<Prio<J2KImage>> h = PQHandles[AssetId]; | 303 | IPriorityQueueHandle<Prio<J2KImage>> h = PQHandles[AssetId]; |
304 | PQHandles.Remove(AssetId); | 304 | PQHandles.Remove(AssetId); |
305 | pq.Delete(h); | 305 | pq.Delete(h); |
306 | } | 306 | } |
307 | } | 307 | } |
308 | } | 308 | } |
309 | 309 | ||
310 | 310 | ||
311 | /// <summary> | 311 | /// <summary> |
312 | /// Adds an image to the queue and update priority | 312 | /// Adds an image to the queue and update priority |
313 | /// if the item is already in the queue, just update the priority | 313 | /// if the item is already in the queue, just update the priority |
314 | /// </summary> | 314 | /// </summary> |
315 | /// <param name="AssetId">UUID of the asset</param> | 315 | /// <param name="AssetId">UUID of the asset</param> |
316 | /// <param name="priority">Priority to set</param> | 316 | /// <param name="priority">Priority to set</param> |
317 | private void AddQueueItem(UUID AssetId, int priority) | 317 | private void AddQueueItem(UUID AssetId, int priority) |
318 | { | 318 | { |
319 | IPriorityQueueHandle<Prio<J2KImage>> h = null; | 319 | IPriorityQueueHandle<Prio<J2KImage>> h = null; |
320 | 320 | ||
321 | lock (PQHandles) | 321 | lock (PQHandles) |
322 | { | 322 | { |
323 | if (PQHandles.ContainsKey(AssetId)) | 323 | if (PQHandles.ContainsKey(AssetId)) |
324 | { | 324 | { |
325 | h = PQHandles[AssetId]; | 325 | h = PQHandles[AssetId]; |
326 | pq[h] = pq[h].SetPriority(priority); | 326 | pq[h] = pq[h].SetPriority(priority); |
327 | 327 | ||
328 | } | 328 | } |
329 | else | 329 | else |
330 | { | 330 | { |
331 | J2KImage newreq = new J2KImage(); | 331 | J2KImage newreq = new J2KImage(); |
332 | newreq.requestedUUID = AssetId; | 332 | newreq.requestedUUID = AssetId; |
333 | pq.Add(ref h, new Prio<J2KImage>(newreq, priority)); | 333 | pq.Add(ref h, new Prio<J2KImage>(newreq, priority)); |
334 | PQHandles.Add(AssetId, h); | 334 | PQHandles.Add(AssetId, h); |
335 | } | 335 | } |
336 | } | 336 | } |
337 | } | 337 | } |
338 | 338 | ||
339 | /// <summary> | 339 | /// <summary> |
340 | /// Okay, we're ending. Clean up on isle 9 | 340 | /// Okay, we're ending. Clean up on isle 9 |
341 | /// </summary> | 341 | /// </summary> |
342 | public void Close() | 342 | public void Close() |
343 | { | 343 | { |
344 | m_shuttingdown = true; | 344 | m_shuttingdown = true; |
345 | 345 | ||
346 | lock (pq) | 346 | lock (pq) |
347 | { | 347 | { |
348 | while (!pq.IsEmpty) | 348 | while (!pq.IsEmpty) |
349 | { | 349 | { |
350 | pq.DeleteMin(); | 350 | pq.DeleteMin(); |
351 | } | 351 | } |
352 | } | 352 | } |
353 | 353 | ||
354 | 354 | ||
355 | lock (PQHandles) | 355 | lock (PQHandles) |
356 | PQHandles.Clear(); | 356 | PQHandles.Clear(); |
357 | m_client = null; | 357 | m_client = null; |
358 | } | 358 | } |
359 | 359 | ||
360 | } | 360 | } |
361 | 361 | ||
362 | /// <summary> | 362 | /// <summary> |
363 | /// Image Data for this send | 363 | /// Image Data for this send |
364 | /// Encapsulates the image sending data and method | 364 | /// Encapsulates the image sending data and method |
365 | /// </summary> | 365 | /// </summary> |
366 | public class J2KImage | 366 | public class J2KImage |
367 | { | 367 | { |
368 | private AssetBase m_asset_ref = null; | 368 | private AssetBase m_asset_ref = null; |
369 | public volatile int LastPacketNum = 0; | 369 | public volatile int LastPacketNum = 0; |
370 | public volatile int DiscardLimit = 0; | 370 | public volatile int DiscardLimit = 0; |
371 | public volatile bool dataRequested = false; | 371 | public volatile bool dataRequested = false; |
372 | public OpenJPEG.J2KLayerInfo[] Layers = new OpenJPEG.J2KLayerInfo[0]; | 372 | public OpenJPEG.J2KLayerInfo[] Layers = new OpenJPEG.J2KLayerInfo[0]; |
373 | 373 | ||
374 | public const int FIRST_IMAGE_PACKET_SIZE = 600; | 374 | public const int FIRST_IMAGE_PACKET_SIZE = 600; |
375 | public const int IMAGE_PACKET_SIZE = 1000; | 375 | public const int IMAGE_PACKET_SIZE = 1000; |
376 | 376 | ||
377 | public volatile int DiscardLevel; | 377 | public volatile int DiscardLevel; |
378 | public float Priority; | 378 | public float Priority; |
379 | public volatile int CurrentPacket = 1; | 379 | public volatile int CurrentPacket = 1; |
380 | public volatile int StopPacket; | 380 | public volatile int StopPacket; |
381 | public bool Missing = false; | 381 | public bool Missing = false; |
382 | public bool J2KDecode = false; | 382 | public bool J2KDecode = false; |
383 | public bool J2KDecodeWaiting = false; | 383 | public bool J2KDecodeWaiting = false; |
384 | 384 | ||
385 | private volatile bool sendFirstPacket = true; | 385 | private volatile bool sendFirstPacket = true; |
386 | 386 | ||
387 | // Having this *AND* the AssetId allows us to remap asset data to AssetIds as necessary. | 387 | // Having this *AND* the AssetId allows us to remap asset data to AssetIds as necessary. |
388 | public UUID requestedUUID = UUID.Zero; | 388 | public UUID requestedUUID = UUID.Zero; |
389 | 389 | ||
390 | public J2KImage(AssetBase asset) | 390 | public J2KImage(AssetBase asset) |
391 | { | 391 | { |
392 | m_asset_ref = asset; | 392 | m_asset_ref = asset; |
393 | } | 393 | } |
394 | 394 | ||
395 | public J2KImage() | 395 | public J2KImage() |
396 | { | 396 | { |
397 | 397 | ||
398 | } | 398 | } |
399 | 399 | ||
400 | public AssetBase asset | 400 | public AssetBase asset |
401 | { | 401 | { |
402 | set { m_asset_ref = value; } | 402 | set { m_asset_ref = value; } |
403 | } | 403 | } |
404 | 404 | ||
405 | // We make the asset a reference so that we don't duplicate the byte[] | 405 | // We make the asset a reference so that we don't duplicate the byte[] |
406 | // it's read only anyway, so no worries here | 406 | // it's read only anyway, so no worries here |
407 | // we want to avoid duplicating the byte[] for the images at all costs to avoid memory bloat! :) | 407 | // we want to avoid duplicating the byte[] for the images at all costs to avoid memory bloat! :) |
408 | 408 | ||
409 | /// <summary> | 409 | /// <summary> |
410 | /// ID of the AssetBase | 410 | /// ID of the AssetBase |
411 | /// </summary> | 411 | /// </summary> |
412 | public UUID AssetId | 412 | public UUID AssetId |
413 | { | 413 | { |
414 | get { return m_asset_ref.FullID; } | 414 | get { return m_asset_ref.FullID; } |
415 | } | 415 | } |
416 | 416 | ||
417 | /// <summary> | 417 | /// <summary> |
418 | /// Asset Data | 418 | /// Asset Data |
419 | /// </summary> | 419 | /// </summary> |
420 | public byte[] Data | 420 | public byte[] Data |
421 | { | 421 | { |
422 | get { return m_asset_ref.Data; } | 422 | get { return m_asset_ref.Data; } |
423 | } | 423 | } |
424 | 424 | ||
425 | /// <summary> | 425 | /// <summary> |
426 | /// Returns true if we have the asset | 426 | /// Returns true if we have the asset |
427 | /// </summary> | 427 | /// </summary> |
428 | public bool HasData | 428 | public bool HasData |
429 | { | 429 | { |
430 | get { return !(m_asset_ref == null); } | 430 | get { return !(m_asset_ref == null); } |
431 | } | 431 | } |
432 | 432 | ||
433 | /// <summary> | 433 | /// <summary> |
434 | /// Called from the PriorityQueue handle .ToString(). Prints data on this asset | 434 | /// Called from the PriorityQueue handle .ToString(). Prints data on this asset |
435 | /// </summary> | 435 | /// </summary> |
436 | /// <returns></returns> | 436 | /// <returns></returns> |
437 | public override string ToString() | 437 | public override string ToString() |
438 | { | 438 | { |
439 | return string.Format("ID:{0}, RD:{1}, CP:{2}", requestedUUID, HasData, CurrentPacket); | 439 | return string.Format("ID:{0}, RD:{1}, CP:{2}", requestedUUID, HasData, CurrentPacket); |
440 | } | 440 | } |
441 | 441 | ||
442 | /// <summary> | 442 | /// <summary> |
443 | /// Returns the total number of packets needed to transfer this texture, | 443 | /// Returns the total number of packets needed to transfer this texture, |
444 | /// including the first packet of size FIRST_IMAGE_PACKET_SIZE | 444 | /// including the first packet of size FIRST_IMAGE_PACKET_SIZE |
445 | /// </summary> | 445 | /// </summary> |
446 | /// <returns>Total number of packets needed to transfer this texture</returns> | 446 | /// <returns>Total number of packets needed to transfer this texture</returns> |
447 | public int TexturePacketCount() | 447 | public int TexturePacketCount() |
448 | { | 448 | { |
449 | if (!HasData) | 449 | if (!HasData) |
450 | return 0; | 450 | return 0; |
451 | return ((m_asset_ref.Data.Length - FIRST_IMAGE_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1; | 451 | return ((m_asset_ref.Data.Length - FIRST_IMAGE_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1; |
452 | } | 452 | } |
453 | 453 | ||
454 | /// <summary> | 454 | /// <summary> |
455 | /// Returns the current byte offset for this transfer, calculated from | 455 | /// Returns the current byte offset for this transfer, calculated from |
456 | /// the CurrentPacket | 456 | /// the CurrentPacket |
457 | /// </summary> | 457 | /// </summary> |
458 | /// <returns>Current byte offset for this transfer</returns> | 458 | /// <returns>Current byte offset for this transfer</returns> |
459 | public int CurrentBytePosition() | 459 | public int CurrentBytePosition() |
460 | { | 460 | { |
461 | if (CurrentPacket == 0) | 461 | if (CurrentPacket == 0) |
462 | return 0; | 462 | return 0; |
463 | if (CurrentPacket == 1) | 463 | if (CurrentPacket == 1) |
464 | return FIRST_IMAGE_PACKET_SIZE; | 464 | return FIRST_IMAGE_PACKET_SIZE; |
465 | 465 | ||
466 | int result = FIRST_IMAGE_PACKET_SIZE + (CurrentPacket - 2) * IMAGE_PACKET_SIZE; | 466 | int result = FIRST_IMAGE_PACKET_SIZE + (CurrentPacket - 2) * IMAGE_PACKET_SIZE; |
467 | if (result < 0) | 467 | if (result < 0) |
468 | { | 468 | { |
469 | result = FIRST_IMAGE_PACKET_SIZE; | 469 | result = FIRST_IMAGE_PACKET_SIZE; |
470 | } | 470 | } |
471 | return result; | 471 | return result; |
472 | } | 472 | } |
473 | 473 | ||
474 | /// <summary> | 474 | /// <summary> |
475 | /// Returns the size, in bytes, of the last packet. This will be somewhere | 475 | /// Returns the size, in bytes, of the last packet. This will be somewhere |
476 | /// between 1 and IMAGE_PACKET_SIZE bytes | 476 | /// between 1 and IMAGE_PACKET_SIZE bytes |
477 | /// </summary> | 477 | /// </summary> |
478 | /// <returns>Size of the last packet in the transfer</returns> | 478 | /// <returns>Size of the last packet in the transfer</returns> |
479 | public int LastPacketSize() | 479 | public int LastPacketSize() |
480 | { | 480 | { |
481 | if (CurrentPacket == 1) | 481 | if (CurrentPacket == 1) |
482 | return m_asset_ref.Data.Length; | 482 | return m_asset_ref.Data.Length; |
483 | return (m_asset_ref.Data.Length - FIRST_IMAGE_PACKET_SIZE) % IMAGE_PACKET_SIZE; // m_asset_ref.Data.Length - (FIRST_IMAGE_PACKET_SIZE + ((TexturePacketCount() - 1) * IMAGE_PACKET_SIZE)); | 483 | return (m_asset_ref.Data.Length - FIRST_IMAGE_PACKET_SIZE) % IMAGE_PACKET_SIZE; // m_asset_ref.Data.Length - (FIRST_IMAGE_PACKET_SIZE + ((TexturePacketCount() - 1) * IMAGE_PACKET_SIZE)); |
484 | } | 484 | } |
485 | 485 | ||
486 | /// <summary> | 486 | /// <summary> |
487 | /// Find the packet number that contains a given byte position | 487 | /// Find the packet number that contains a given byte position |
488 | /// </summary> | 488 | /// </summary> |
489 | /// <param name="bytePosition">Byte position</param> | 489 | /// <param name="bytePosition">Byte position</param> |
490 | /// <returns>Packet number that contains the given byte position</returns> | 490 | /// <returns>Packet number that contains the given byte position</returns> |
491 | int GetPacketForBytePosition(int bytePosition) | 491 | int GetPacketForBytePosition(int bytePosition) |
492 | { | 492 | { |
493 | return ((bytePosition - FIRST_IMAGE_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1; | 493 | return ((bytePosition - FIRST_IMAGE_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1; |
494 | } | 494 | } |
495 | 495 | ||
496 | /// <summary> | 496 | /// <summary> |
497 | /// Updates the Image sending limits based on the discard | 497 | /// Updates the Image sending limits based on the discard |
498 | /// If we don't have any Layers, Send the full texture | 498 | /// If we don't have any Layers, Send the full texture |
499 | /// </summary> | 499 | /// </summary> |
500 | /// <param name="discardLevel">jpeg2000 discard level. 5-0</param> | 500 | /// <param name="discardLevel">jpeg2000 discard level. 5-0</param> |
501 | /// <param name="packet">Which packet to start from</param> | 501 | /// <param name="packet">Which packet to start from</param> |
502 | public void Update(int discardLevel, int packet) | 502 | public void Update(int discardLevel, int packet) |
503 | { | 503 | { |
504 | //Requests for 0 means that the client wants us to resend the whole image | 504 | //Requests for 0 means that the client wants us to resend the whole image |
505 | //Requests for -1 mean 'update priority but don't change discard level' | 505 | //Requests for -1 mean 'update priority but don't change discard level' |
506 | 506 | ||
507 | if (packet == 0 || packet == -1) | 507 | if (packet == 0 || packet == -1) |
508 | return; | 508 | return; |
509 | 509 | ||
510 | // Check if we've got layers | 510 | // Check if we've got layers |
511 | if (Layers.Length > 0) | 511 | if (Layers.Length > 0) |
512 | { | 512 | { |
513 | DiscardLevel = Util.Clamp<int>(discardLevel, 0, Layers.Length - 1); | 513 | DiscardLevel = Util.Clamp<int>(discardLevel, 0, Layers.Length - 1); |
514 | StopPacket = GetPacketForBytePosition(Layers[(Layers.Length - 1) - DiscardLevel].End); | 514 | StopPacket = GetPacketForBytePosition(Layers[(Layers.Length - 1) - DiscardLevel].End); |
515 | CurrentPacket = Util.Clamp<int>(packet, 1, TexturePacketCount() - 1); | 515 | CurrentPacket = Util.Clamp<int>(packet, 1, TexturePacketCount() - 1); |
516 | // sendFirstPacket = true; | 516 | // sendFirstPacket = true; |
517 | } | 517 | } |
518 | else | 518 | else |
519 | { | 519 | { |
520 | // No layers, send full image | 520 | // No layers, send full image |
521 | DiscardLevel = 0; | 521 | DiscardLevel = 0; |
522 | StopPacket = TexturePacketCount() - 1; | 522 | StopPacket = TexturePacketCount() - 1; |
523 | CurrentPacket = Util.Clamp<int>(packet, 1, TexturePacketCount() - 1); | 523 | CurrentPacket = Util.Clamp<int>(packet, 1, TexturePacketCount() - 1); |
524 | 524 | ||
525 | } | 525 | } |
526 | } | 526 | } |
527 | 527 | ||
528 | /// <summary> | 528 | /// <summary> |
529 | /// Sends a texture packet to the client. | 529 | /// Sends a texture packet to the client. |
530 | /// </summary> | 530 | /// </summary> |
531 | /// <param name="client">Client to send texture to</param> | 531 | /// <param name="client">Client to send texture to</param> |
532 | /// <returns>true if a packet was sent, false if not</returns> | 532 | /// <returns>true if a packet was sent, false if not</returns> |
533 | public bool SendPacket(LLClientView client) | 533 | public bool SendPacket(LLClientView client) |
534 | { | 534 | { |
535 | // If we've hit the end of the send or if the client set -1, return false. | 535 | // If we've hit the end of the send or if the client set -1, return false. |
536 | if (CurrentPacket > StopPacket || StopPacket == -1) | 536 | if (CurrentPacket > StopPacket || StopPacket == -1) |
537 | return false; | 537 | return false; |
538 | 538 | ||
539 | // The first packet contains up to 600 bytes and the details of the image. Number of packets, image size in bytes, etc. | 539 | // The first packet contains up to 600 bytes and the details of the image. Number of packets, image size in bytes, etc. |
540 | // This packet only gets sent once unless we're restarting the transfer from 0! | 540 | // This packet only gets sent once unless we're restarting the transfer from 0! |
541 | if (sendFirstPacket) | 541 | if (sendFirstPacket) |
542 | { | 542 | { |
543 | sendFirstPacket = false; | 543 | sendFirstPacket = false; |
544 | 544 | ||
545 | // Do we have less then 1 packet's worth of data? | 545 | // Do we have less then 1 packet's worth of data? |
546 | if (m_asset_ref.Data.Length <= FIRST_IMAGE_PACKET_SIZE) | 546 | if (m_asset_ref.Data.Length <= FIRST_IMAGE_PACKET_SIZE) |
547 | { | 547 | { |
548 | // Send only 1 packet | 548 | // Send only 1 packet |
549 | client.SendImageFirstPart(1, requestedUUID , (uint)m_asset_ref.Data.Length, m_asset_ref.Data, 2); | 549 | client.SendImageFirstPart(1, requestedUUID , (uint)m_asset_ref.Data.Length, m_asset_ref.Data, 2); |
550 | CurrentPacket = 2; // Makes it so we don't come back to SendPacket and error trying to send a second packet | 550 | CurrentPacket = 2; // Makes it so we don't come back to SendPacket and error trying to send a second packet |
551 | return true; | 551 | return true; |
552 | } | 552 | } |
553 | else | 553 | else |
554 | { | 554 | { |
555 | 555 | ||
556 | // Send first packet | 556 | // Send first packet |
557 | byte[] firstImageData = new byte[FIRST_IMAGE_PACKET_SIZE]; | 557 | byte[] firstImageData = new byte[FIRST_IMAGE_PACKET_SIZE]; |
558 | try { Buffer.BlockCopy(m_asset_ref.Data, 0, firstImageData, 0, FIRST_IMAGE_PACKET_SIZE); } | 558 | try { Buffer.BlockCopy(m_asset_ref.Data, 0, firstImageData, 0, FIRST_IMAGE_PACKET_SIZE); } |
559 | catch (Exception) | 559 | catch (Exception) |
560 | { | 560 | { |
561 | Console.WriteLine(String.Format("Err: srcLen:{0}, BytePos:{1}, desLen:{2}, pktsize{3}", m_asset_ref.Data.Length, CurrentBytePosition(), firstImageData.Length, FIRST_IMAGE_PACKET_SIZE)); | 561 | Console.WriteLine(String.Format("Err: srcLen:{0}, BytePos:{1}, desLen:{2}, pktsize{3}", m_asset_ref.Data.Length, CurrentBytePosition(), firstImageData.Length, FIRST_IMAGE_PACKET_SIZE)); |
562 | 562 | ||
563 | //m_log.Error("Texture data copy failed on first packet for " + m_asset_ref.FullID.ToString()); | 563 | //m_log.Error("Texture data copy failed on first packet for " + m_asset_ref.FullID.ToString()); |
564 | //m_cancel = true; | 564 | //m_cancel = true; |
565 | //m_sending = false; | 565 | //m_sending = false; |
566 | return false; | 566 | return false; |
567 | } | 567 | } |
568 | client.SendImageFirstPart((ushort)TexturePacketCount(), requestedUUID, (uint)m_asset_ref.Data.Length, firstImageData, 2); | 568 | client.SendImageFirstPart((ushort)TexturePacketCount(), requestedUUID, (uint)m_asset_ref.Data.Length, firstImageData, 2); |
569 | ++CurrentPacket; // sets CurrentPacket to 1 | 569 | ++CurrentPacket; // sets CurrentPacket to 1 |
570 | } | 570 | } |
571 | } | 571 | } |
572 | 572 | ||
573 | // figure out if we're on the last packet, if so, use the last packet size. If not, use 1000. | 573 | // figure out if we're on the last packet, if so, use the last packet size. If not, use 1000. |
574 | // we know that the total image size is greater then 1000 if we're here | 574 | // we know that the total image size is greater then 1000 if we're here |
575 | int imagePacketSize = (CurrentPacket == (TexturePacketCount() ) ) ? LastPacketSize() : IMAGE_PACKET_SIZE; | 575 | int imagePacketSize = (CurrentPacket == (TexturePacketCount() ) ) ? LastPacketSize() : IMAGE_PACKET_SIZE; |
576 | 576 | ||
577 | //if (imagePacketSize > 0) | 577 | //if (imagePacketSize > 0) |
578 | // imagePacketSize = IMAGE_PACKET_SIZE; | 578 | // imagePacketSize = IMAGE_PACKET_SIZE; |
579 | //if (imagePacketSize != 1000) | 579 | //if (imagePacketSize != 1000) |
580 | // Console.WriteLine("ENdPacket"); | 580 | // Console.WriteLine("ENdPacket"); |
581 | //Console.WriteLine(String.Format("srcLen:{0}, BytePos:{1}, desLen:{2}, pktsize{3}", m_asset_ref.Data.Length, CurrentBytePosition(),0, imagePacketSize)); | 581 | //Console.WriteLine(String.Format("srcLen:{0}, BytePos:{1}, desLen:{2}, pktsize{3}", m_asset_ref.Data.Length, CurrentBytePosition(),0, imagePacketSize)); |
582 | 582 | ||
583 | 583 | ||
584 | byte[] imageData = new byte[imagePacketSize]; | 584 | byte[] imageData = new byte[imagePacketSize]; |
585 | try { Buffer.BlockCopy(m_asset_ref.Data, CurrentBytePosition(), imageData, 0, imagePacketSize); } | 585 | try { Buffer.BlockCopy(m_asset_ref.Data, CurrentBytePosition(), imageData, 0, imagePacketSize); } |
586 | catch (Exception e) | 586 | catch (Exception e) |
587 | { | 587 | { |
588 | Console.WriteLine(String.Format("Err: srcLen:{0}, BytePos:{1}, desLen:{2}, pktsize:{3}, currpak:{4}, stoppak:{5}, totalpak:{6}", m_asset_ref.Data.Length, CurrentBytePosition(), | 588 | Console.WriteLine(String.Format("Err: srcLen:{0}, BytePos:{1}, desLen:{2}, pktsize:{3}, currpak:{4}, stoppak:{5}, totalpak:{6}", m_asset_ref.Data.Length, CurrentBytePosition(), |
589 | imageData.Length, imagePacketSize, CurrentPacket,StopPacket,TexturePacketCount())); | 589 | imageData.Length, imagePacketSize, CurrentPacket,StopPacket,TexturePacketCount())); |
590 | System.Console.WriteLine(e.ToString()); | 590 | System.Console.WriteLine(e.ToString()); |
591 | //m_log.Error("Texture data copy failed for " + m_asset_ref.FullID.ToString()); | 591 | //m_log.Error("Texture data copy failed for " + m_asset_ref.FullID.ToString()); |
592 | //m_cancel = true; | 592 | //m_cancel = true; |
593 | //m_sending = false; | 593 | //m_sending = false; |
594 | return false; | 594 | return false; |
595 | } | 595 | } |
596 | 596 | ||
597 | // Send next packet to the client | 597 | // Send next packet to the client |
598 | client.SendImageNextPart((ushort)(CurrentPacket - 1), requestedUUID, imageData); | 598 | client.SendImageNextPart((ushort)(CurrentPacket - 1), requestedUUID, imageData); |
599 | ++CurrentPacket; | 599 | ++CurrentPacket; |
600 | return true; | 600 | return true; |
601 | } | 601 | } |
602 | 602 | ||
603 | } | 603 | } |
604 | 604 | ||
605 | /// <summary> | 605 | /// <summary> |
606 | /// Generic Priority Queue element | 606 | /// Generic Priority Queue element |
607 | /// Contains a Priority and a Reference type Data Element | 607 | /// Contains a Priority and a Reference type Data Element |
608 | /// </summary> | 608 | /// </summary> |
609 | /// <typeparam name="D">Reference type data element</typeparam> | 609 | /// <typeparam name="D">Reference type data element</typeparam> |
610 | struct Prio<D> : IComparable<Prio<D>> where D : class | 610 | struct Prio<D> : IComparable<Prio<D>> where D : class |
611 | { | 611 | { |
612 | public D data; | 612 | public D data; |
613 | private int priority; | 613 | private int priority; |
614 | 614 | ||
615 | public Prio(D data, int priority) | 615 | public Prio(D data, int priority) |
616 | { | 616 | { |
617 | this.data = data; | 617 | this.data = data; |
618 | this.priority = priority; | 618 | this.priority = priority; |
619 | } | 619 | } |
620 | 620 | ||
621 | public int CompareTo(Prio<D> that) | 621 | public int CompareTo(Prio<D> that) |
622 | { | 622 | { |
623 | return this.priority.CompareTo(that.priority); | 623 | return this.priority.CompareTo(that.priority); |
624 | } | 624 | } |
625 | 625 | ||
626 | public bool Equals(Prio<D> that) | 626 | public bool Equals(Prio<D> that) |
627 | { | 627 | { |
628 | return this.priority == that.priority; | 628 | return this.priority == that.priority; |
629 | } | 629 | } |
630 | 630 | ||
631 | public static Prio<D> operator +(Prio<D> tp, int delta) | 631 | public static Prio<D> operator +(Prio<D> tp, int delta) |
632 | { | 632 | { |
633 | return new Prio<D>(tp.data, tp.priority + delta); | 633 | return new Prio<D>(tp.data, tp.priority + delta); |
634 | } | 634 | } |
635 | 635 | ||
636 | public static bool operator <(Prio<D> tp, int check) | 636 | public static bool operator <(Prio<D> tp, int check) |
637 | { | 637 | { |
638 | return (tp.priority < check); | 638 | return (tp.priority < check); |
639 | } | 639 | } |
640 | 640 | ||
641 | public static bool operator >(Prio<D> tp, int check) | 641 | public static bool operator >(Prio<D> tp, int check) |
642 | { | 642 | { |
643 | return (tp.priority > check); | 643 | return (tp.priority > check); |
644 | } | 644 | } |
645 | 645 | ||
646 | public static Prio<D> operator -(Prio<D> tp, int delta) | 646 | public static Prio<D> operator -(Prio<D> tp, int delta) |
647 | { | 647 | { |
648 | if (tp.priority - delta < 0) | 648 | if (tp.priority - delta < 0) |
649 | return new Prio<D>(tp.data, tp.priority - delta); | 649 | return new Prio<D>(tp.data, tp.priority - delta); |
650 | else | 650 | else |
651 | return new Prio<D>(tp.data, 0); | 651 | return new Prio<D>(tp.data, 0); |
652 | } | 652 | } |
653 | 653 | ||
654 | public override String ToString() | 654 | public override String ToString() |
655 | { | 655 | { |
656 | return String.Format("{0}[{1}]", data, priority); | 656 | return String.Format("{0}[{1}]", data, priority); |
657 | } | 657 | } |
658 | 658 | ||
659 | internal Prio<D> SetPriority(int pPriority) | 659 | internal Prio<D> SetPriority(int pPriority) |
660 | { | 660 | { |
661 | return new Prio<D>(this.data, pPriority); | 661 | return new Prio<D>(this.data, pPriority); |
662 | } | 662 | } |
663 | } | 663 | } |
664 | } | 664 | } |
diff --git a/OpenSim/Region/Environment/Interfaces/IJ2KDecoder.cs b/OpenSim/Region/Environment/Interfaces/IJ2KDecoder.cs index f0e13ba..44b9289 100644 --- a/OpenSim/Region/Environment/Interfaces/IJ2KDecoder.cs +++ b/OpenSim/Region/Environment/Interfaces/IJ2KDecoder.cs | |||
@@ -1,40 +1,40 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSim Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using OpenMetaverse; | 28 | using OpenMetaverse; |
29 | using OpenMetaverse.Imaging; | 29 | using OpenMetaverse.Imaging; |
30 | 30 | ||
31 | namespace OpenSim.Region.Environment.Interfaces | 31 | namespace OpenSim.Region.Environment.Interfaces |
32 | { | 32 | { |
33 | 33 | ||
34 | public delegate void DecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers); | 34 | public delegate void DecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers); |
35 | 35 | ||
36 | public interface IJ2KDecoder | 36 | public interface IJ2KDecoder |
37 | { | 37 | { |
38 | void decode(UUID AssetId, byte[] assetData, DecodedCallback decodedReturn); | 38 | void decode(UUID AssetId, byte[] assetData, DecodedCallback decodedReturn); |
39 | } | 39 | } |
40 | } | 40 | } |
diff --git a/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs index 7c51d68..6b84880 100644 --- a/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs +++ b/OpenSim/Region/Environment/Modules/Agent/TextureSender/J2KDecoderModule.cs | |||
@@ -1,215 +1,215 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSim Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Reflection; | 29 | using System.Reflection; |
30 | using System.Threading; | 30 | using System.Threading; |
31 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
32 | using log4net; | 32 | using log4net; |
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenMetaverse.Imaging; | 35 | using OpenMetaverse.Imaging; |
36 | using OpenSim.Region.Environment.Interfaces; | 36 | using OpenSim.Region.Environment.Interfaces; |
37 | using OpenSim.Region.Environment.Scenes; | 37 | using OpenSim.Region.Environment.Scenes; |
38 | 38 | ||
39 | namespace OpenSim.Region.Environment.Modules.Agent.TextureSender | 39 | namespace OpenSim.Region.Environment.Modules.Agent.TextureSender |
40 | { | 40 | { |
41 | public class J2KDecoderModule : IRegionModule, IJ2KDecoder | 41 | public class J2KDecoderModule : IRegionModule, IJ2KDecoder |
42 | { | 42 | { |
43 | #region IRegionModule Members | 43 | #region IRegionModule Members |
44 | 44 | ||
45 | private static readonly ILog m_log | 45 | private static readonly ILog m_log |
46 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 46 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
47 | 47 | ||
48 | /// <summary> | 48 | /// <summary> |
49 | /// Cached Decoded Layers | 49 | /// Cached Decoded Layers |
50 | /// </summary> | 50 | /// </summary> |
51 | private readonly Dictionary<UUID, OpenJPEG.J2KLayerInfo[]> m_cacheddecode = new Dictionary<UUID, OpenJPEG.J2KLayerInfo[]>(); | 51 | private readonly Dictionary<UUID, OpenJPEG.J2KLayerInfo[]> m_cacheddecode = new Dictionary<UUID, OpenJPEG.J2KLayerInfo[]>(); |
52 | 52 | ||
53 | /// <summary> | 53 | /// <summary> |
54 | /// List of client methods to notify of results of decode | 54 | /// List of client methods to notify of results of decode |
55 | /// </summary> | 55 | /// </summary> |
56 | private readonly Dictionary<UUID, List<DecodedCallback>> m_notifyList = new Dictionary<UUID, List<DecodedCallback>>(); | 56 | private readonly Dictionary<UUID, List<DecodedCallback>> m_notifyList = new Dictionary<UUID, List<DecodedCallback>>(); |
57 | 57 | ||
58 | public void Initialise(Scene scene, IConfigSource source) | 58 | public void Initialise(Scene scene, IConfigSource source) |
59 | { | 59 | { |
60 | scene.RegisterModuleInterface<IJ2KDecoder>(this); | 60 | scene.RegisterModuleInterface<IJ2KDecoder>(this); |
61 | } | 61 | } |
62 | 62 | ||
63 | public void PostInitialise() | 63 | public void PostInitialise() |
64 | { | 64 | { |
65 | 65 | ||
66 | } | 66 | } |
67 | 67 | ||
68 | public void Close() | 68 | public void Close() |
69 | { | 69 | { |
70 | 70 | ||
71 | } | 71 | } |
72 | 72 | ||
73 | public string Name | 73 | public string Name |
74 | { | 74 | { |
75 | get { return "J2KDecoderModule"; } | 75 | get { return "J2KDecoderModule"; } |
76 | } | 76 | } |
77 | 77 | ||
78 | public bool IsSharedModule | 78 | public bool IsSharedModule |
79 | { | 79 | { |
80 | get { return true; } | 80 | get { return true; } |
81 | } | 81 | } |
82 | 82 | ||
83 | #endregion | 83 | #endregion |
84 | 84 | ||
85 | #region IJ2KDecoder Members | 85 | #region IJ2KDecoder Members |
86 | 86 | ||
87 | 87 | ||
88 | public void decode(UUID AssetId, byte[] assetData, DecodedCallback decodedReturn) | 88 | public void decode(UUID AssetId, byte[] assetData, DecodedCallback decodedReturn) |
89 | { | 89 | { |
90 | // Dummy for if decoding fails. | 90 | // Dummy for if decoding fails. |
91 | OpenJPEG.J2KLayerInfo[] result = new OpenJPEG.J2KLayerInfo[0]; | 91 | OpenJPEG.J2KLayerInfo[] result = new OpenJPEG.J2KLayerInfo[0]; |
92 | 92 | ||
93 | // Check if it's cached | 93 | // Check if it's cached |
94 | bool cached = false; | 94 | bool cached = false; |
95 | lock (m_cacheddecode) | 95 | lock (m_cacheddecode) |
96 | { | 96 | { |
97 | if (m_cacheddecode.ContainsKey(AssetId)) | 97 | if (m_cacheddecode.ContainsKey(AssetId)) |
98 | { | 98 | { |
99 | cached = true; | 99 | cached = true; |
100 | result = m_cacheddecode[AssetId]; | 100 | result = m_cacheddecode[AssetId]; |
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | // If it's cached, return the cached results | 104 | // If it's cached, return the cached results |
105 | if (cached) | 105 | if (cached) |
106 | { | 106 | { |
107 | decodedReturn(AssetId, result); | 107 | decodedReturn(AssetId, result); |
108 | } | 108 | } |
109 | else | 109 | else |
110 | { | 110 | { |
111 | // not cached, so we need to decode it | 111 | // not cached, so we need to decode it |
112 | // Add to notify list and start decoding. | 112 | // Add to notify list and start decoding. |
113 | // Next request for this asset while it's decoding will only be added to the notify list | 113 | // Next request for this asset while it's decoding will only be added to the notify list |
114 | // once this is decoded, requests will be served from the cache and all clients in the notifylist will be updated | 114 | // once this is decoded, requests will be served from the cache and all clients in the notifylist will be updated |
115 | bool decode = false; | 115 | bool decode = false; |
116 | lock (m_notifyList) | 116 | lock (m_notifyList) |
117 | { | 117 | { |
118 | if (m_notifyList.ContainsKey(AssetId)) | 118 | if (m_notifyList.ContainsKey(AssetId)) |
119 | { | 119 | { |
120 | m_notifyList[AssetId].Add(decodedReturn); | 120 | m_notifyList[AssetId].Add(decodedReturn); |
121 | } | 121 | } |
122 | else | 122 | else |
123 | { | 123 | { |
124 | List<DecodedCallback> notifylist = new List<DecodedCallback>(); | 124 | List<DecodedCallback> notifylist = new List<DecodedCallback>(); |
125 | notifylist.Add(decodedReturn); | 125 | notifylist.Add(decodedReturn); |
126 | m_notifyList.Add(AssetId, notifylist); | 126 | m_notifyList.Add(AssetId, notifylist); |
127 | decode = true; | 127 | decode = true; |
128 | } | 128 | } |
129 | } | 129 | } |
130 | // Do Decode! | 130 | // Do Decode! |
131 | if (decode) | 131 | if (decode) |
132 | { | 132 | { |
133 | doJ2kDecode(AssetId, assetData); | 133 | doJ2kDecode(AssetId, assetData); |
134 | } | 134 | } |
135 | } | 135 | } |
136 | } | 136 | } |
137 | 137 | ||
138 | #endregion | 138 | #endregion |
139 | 139 | ||
140 | /// <summary> | 140 | /// <summary> |
141 | /// Decode Jpeg2000 Asset Data | 141 | /// Decode Jpeg2000 Asset Data |
142 | /// </summary> | 142 | /// </summary> |
143 | /// <param name="AssetId">UUID of Asset</param> | 143 | /// <param name="AssetId">UUID of Asset</param> |
144 | /// <param name="j2kdata">Byte Array Asset Data </param> | 144 | /// <param name="j2kdata">Byte Array Asset Data </param> |
145 | private void doJ2kDecode(UUID AssetId, byte[] j2kdata) | 145 | private void doJ2kDecode(UUID AssetId, byte[] j2kdata) |
146 | { | 146 | { |
147 | int DecodeTime = 0; | 147 | int DecodeTime = 0; |
148 | DecodeTime = System.Environment.TickCount; | 148 | DecodeTime = System.Environment.TickCount; |
149 | OpenJPEG.J2KLayerInfo[] layers = new OpenJPEG.J2KLayerInfo[0]; // Dummy result for if it fails. Informs that there's only full quality | 149 | OpenJPEG.J2KLayerInfo[] layers = new OpenJPEG.J2KLayerInfo[0]; // Dummy result for if it fails. Informs that there's only full quality |
150 | try | 150 | try |
151 | { | 151 | { |
152 | 152 | ||
153 | AssetTexture texture = new AssetTexture(AssetId, j2kdata); | 153 | AssetTexture texture = new AssetTexture(AssetId, j2kdata); |
154 | if (texture.DecodeLayerBoundaries()) | 154 | if (texture.DecodeLayerBoundaries()) |
155 | { | 155 | { |
156 | bool sane = true; | 156 | bool sane = true; |
157 | 157 | ||
158 | // Sanity check all of the layers | 158 | // Sanity check all of the layers |
159 | for (int i = 0; i < texture.LayerInfo.Length; i++) | 159 | for (int i = 0; i < texture.LayerInfo.Length; i++) |
160 | { | 160 | { |
161 | if (texture.LayerInfo[i].End > texture.AssetData.Length) | 161 | if (texture.LayerInfo[i].End > texture.AssetData.Length) |
162 | { | 162 | { |
163 | sane = false; | 163 | sane = false; |
164 | break; | 164 | break; |
165 | } | 165 | } |
166 | } | 166 | } |
167 | 167 | ||
168 | if (sane) | 168 | if (sane) |
169 | { | 169 | { |
170 | layers = texture.LayerInfo; | 170 | layers = texture.LayerInfo; |
171 | } | 171 | } |
172 | else | 172 | else |
173 | { | 173 | { |
174 | m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding succeeded, but sanity check failed for {0}", | 174 | m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding succeeded, but sanity check failed for {0}", |
175 | AssetId); | 175 | AssetId); |
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | else | 179 | else |
180 | { | 180 | { |
181 | m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding failed for {0}", AssetId); | 181 | m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding failed for {0}", AssetId); |
182 | } | 182 | } |
183 | texture = null; // dereference and dispose of ManagedImage | 183 | texture = null; // dereference and dispose of ManagedImage |
184 | } | 184 | } |
185 | catch (Exception ex) | 185 | catch (Exception ex) |
186 | { | 186 | { |
187 | m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding threw an exception for {0}, {1}", AssetId, ex); | 187 | m_log.WarnFormat("[J2KDecoderModule]: JPEG2000 texture decoding threw an exception for {0}, {1}", AssetId, ex); |
188 | } | 188 | } |
189 | 189 | ||
190 | // Write out decode time | 190 | // Write out decode time |
191 | m_log.InfoFormat("[J2KDecoderModule]: {0} Decode Time: {1}", System.Environment.TickCount - DecodeTime, AssetId); | 191 | m_log.InfoFormat("[J2KDecoderModule]: {0} Decode Time: {1}", System.Environment.TickCount - DecodeTime, AssetId); |
192 | 192 | ||
193 | // Cache Decoded layers | 193 | // Cache Decoded layers |
194 | lock (m_cacheddecode) | 194 | lock (m_cacheddecode) |
195 | { | 195 | { |
196 | m_cacheddecode.Add(AssetId, layers); | 196 | m_cacheddecode.Add(AssetId, layers); |
197 | 197 | ||
198 | } | 198 | } |
199 | 199 | ||
200 | // Notify Interested Parties | 200 | // Notify Interested Parties |
201 | lock (m_notifyList) | 201 | lock (m_notifyList) |
202 | { | 202 | { |
203 | if (m_notifyList.ContainsKey(AssetId)) | 203 | if (m_notifyList.ContainsKey(AssetId)) |
204 | { | 204 | { |
205 | foreach (DecodedCallback d in m_notifyList[AssetId]) | 205 | foreach (DecodedCallback d in m_notifyList[AssetId]) |
206 | { | 206 | { |
207 | if (d != null) | 207 | if (d != null) |
208 | d.DynamicInvoke(AssetId, layers); | 208 | d.DynamicInvoke(AssetId, layers); |
209 | } | 209 | } |
210 | m_notifyList.Remove(AssetId); | 210 | m_notifyList.Remove(AssetId); |
211 | } | 211 | } |
212 | } | 212 | } |
213 | } | 213 | } |
214 | } | 214 | } |
215 | } | 215 | } |