1 : /******************************************************************************
2 : * $Id: ecwdataset.cpp 21486 2011-01-13 17:38:17Z warmerdam $
3 : *
4 : * Project: GDAL
5 : * Purpose: ECWAsyncReader implementation
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_ecw.h"
31 :
32 4029 : CPL_CVSID("$Id: ecwdataset.cpp 21486 2011-01-13 17:38:17Z warmerdam $");
33 :
34 : #if defined(FRMT_ecw) && (ECWSDK_VERSION >= 40)
35 :
36 : /************************************************************************/
37 : /* BeginAsyncReader() */
38 : /************************************************************************/
39 :
40 : GDALAsyncReader*
41 : ECWDataset::BeginAsyncReader( int nXOff, int nYOff, int nXSize, int nYSize,
42 : void *pBuf, int nBufXSize, int nBufYSize,
43 : GDALDataType eBufType,
44 : int nBandCount, int* panBandMap,
45 : int nPixelSpace, int nLineSpace, int nBandSpace,
46 : char **papszOptions)
47 :
48 : {
49 : /* -------------------------------------------------------------------- */
50 : /* Provide default packing if needed. */
51 : /* -------------------------------------------------------------------- */
52 : if( nPixelSpace == 0 )
53 : nPixelSpace = GDALGetDataTypeSize(eBufType) / 8;
54 : if( nLineSpace == 0 )
55 : nLineSpace = nPixelSpace * nBufXSize;
56 : if( nBandSpace == 0 )
57 : nBandSpace = nLineSpace * nBufYSize;
58 :
59 : /* -------------------------------------------------------------------- */
60 : /* We should do a bit of validation first - perhaps add later. */
61 : /* -------------------------------------------------------------------- */
62 :
63 : /* -------------------------------------------------------------------- */
64 : /* Create the corresponding async reader. */
65 : /* -------------------------------------------------------------------- */
66 : ECWAsyncReader *poReader = new ECWAsyncReader();
67 :
68 : poReader->poDS = this;
69 :
70 : poReader->nXOff = nXOff;
71 : poReader->nYOff = nYOff;
72 : poReader->nXSize = nXSize;
73 : poReader->nYSize = nYSize;
74 :
75 : poReader->pBuf = pBuf;
76 : poReader->nBufXSize = nBufXSize;
77 : poReader->nBufYSize = nBufYSize;
78 : poReader->eBufType = eBufType;
79 : poReader->nBandCount = nBandCount;
80 : poReader->panBandMap = (int *) CPLCalloc(sizeof(int),nBandCount);
81 : memcpy( poReader->panBandMap, panBandMap, sizeof(int) * nBandCount );
82 :
83 : poReader->nPixelSpace = nPixelSpace;
84 : poReader->nLineSpace = nLineSpace;
85 : poReader->nBandSpace = nBandSpace;
86 :
87 : /* -------------------------------------------------------------------- */
88 : /* Create a new view for this request. */
89 : /* -------------------------------------------------------------------- */
90 : poReader->poFileView = OpenFileView( GetDescription(), true,
91 : poReader->bUsingCustomStream );
92 :
93 : if( poReader->poFileView == NULL )
94 : {
95 : delete poReader;
96 : return NULL;
97 : }
98 :
99 : poReader->poFileView->SetClientData( poReader );
100 : poReader->poFileView->SetRefreshCallback( ECWAsyncReader::RefreshCB );
101 :
102 : /* -------------------------------------------------------------------- */
103 : /* Issue a corresponding SetView command. */
104 : /* -------------------------------------------------------------------- */
105 : std::vector<UINT32> anBandIndices;
106 : int i;
107 : NCSError eNCSErr;
108 : CNCSError oErr;
109 :
110 : for( i = 0; i < nBandCount; i++ )
111 : anBandIndices.push_back( panBandMap[i] - 1 );
112 :
113 : oErr = poReader->poFileView->SetView( nBandCount, &(anBandIndices[0]),
114 : nXOff, nYOff,
115 : nXOff + nXSize - 1,
116 : nYOff + nYSize - 1,
117 : nBufXSize, nBufYSize );
118 : eNCSErr = oErr.GetErrorNumber();
119 :
120 : if( eNCSErr != NCS_SUCCESS )
121 : {
122 : delete poReader;
123 : CPLError( CE_Failure, CPLE_AppDefined,
124 : "%s", NCSGetErrorText(eNCSErr) );
125 :
126 : return NULL;
127 : }
128 :
129 : return poReader;
130 : }
131 :
132 : /************************************************************************/
133 : /* EndAsyncReader() */
134 : /************************************************************************/
135 : void ECWDataset::EndAsyncReader(GDALAsyncReader *poReader)
136 :
137 : {
138 : delete poReader;
139 : }
140 :
141 : /************************************************************************/
142 : /* ECWAsyncReader() */
143 : /************************************************************************/
144 :
145 : ECWAsyncReader::ECWAsyncReader()
146 :
147 : {
148 : hMutex = CPLCreateMutex();
149 : CPLReleaseMutex( hMutex );
150 :
151 : poFileView = NULL;
152 : bUpdateReady = FALSE;
153 : bComplete = FALSE;
154 : }
155 :
156 : /************************************************************************/
157 : /* ~ECWAsyncReader() */
158 : /************************************************************************/
159 :
160 : ECWAsyncReader::~ECWAsyncReader()
161 :
162 : {
163 : {
164 : CPLMutexHolderD( &hMutex );
165 :
166 : // cancel?
167 :
168 : delete poFileView;
169 : // we should also consider cleaning up the io stream if needed.
170 : }
171 :
172 : CPLDestroyMutex( hMutex );
173 : hMutex = NULL;
174 : }
175 :
176 : /************************************************************************/
177 : /* RefreshCB() */
178 : /* */
179 : /* This static method is called by the ECW SDK to notify us */
180 : /* that there is new data ready to refresh from. We just mark */
181 : /* the async reader as ready for an update. We fetch the data */
182 : /* and push into into the buffer the application uses. We lock */
183 : /* this async reader's mutex for this whole operation to avoid */
184 : /* a conflict with the main application. */
185 : /************************************************************************/
186 :
187 : NCSEcwReadStatus ECWAsyncReader::RefreshCB( NCSFileView *pFileView )
188 :
189 : {
190 : NCSFileViewSetInfo *psVSI = NULL;
191 :
192 : NCScbmGetViewInfo( pFileView, &psVSI );
193 : if( psVSI != NULL )
194 : {
195 : CPLDebug( "ECW", "RefreshCB(): BlockCounts=%d/%d/%d/%d",
196 : psVSI->nBlocksAvailableAtSetView,
197 : psVSI->nBlocksAvailable,
198 : psVSI->nMissedBlocksDuringRead,
199 : psVSI->nBlocksInView );
200 : }
201 :
202 : /* -------------------------------------------------------------------- */
203 : /* Identify the reader we are responding on behalf of. */
204 : /* -------------------------------------------------------------------- */
205 : CNCSJP2FileView *poFileView = (CNCSJP2FileView *) pFileView;
206 : ECWAsyncReader *poReader = (ECWAsyncReader *)poFileView->GetClientData();
207 :
208 : /* -------------------------------------------------------------------- */
209 : /* Acquire the async reader mutex. Currently we make no */
210 : /* arrangements for failure to acquire it. */
211 : /* -------------------------------------------------------------------- */
212 : CPLMutexHolderD( &(poReader->hMutex) );
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Mark the buffer as updated unless we are already complete. */
216 : /* It seems the Update callback keeps getting called even when */
217 : /* no new data has arrived after completion so we don't want to */
218 : /* trigger new work elsewhere in that case. */
219 : /* */
220 : /* Also record whether we are now complete. */
221 : /* -------------------------------------------------------------------- */
222 : if( !poReader->bComplete )
223 : poReader->bUpdateReady = TRUE;
224 :
225 : if( psVSI->nBlocksAvailable == psVSI->nBlocksInView )
226 : poReader->bComplete = TRUE;
227 :
228 : return NCSECW_READ_OK;
229 : }
230 :
231 : /************************************************************************/
232 : /* ReadToBuffer() */
233 : /************************************************************************/
234 : NCSEcwReadStatus ECWAsyncReader::ReadToBuffer()
235 : {
236 : /* -------------------------------------------------------------------- */
237 : /* Setup working scanline, and the pointers into it. */
238 : /* */
239 : /* Should we try and optimize some cases that we could read */
240 : /* directly into the application buffer? Perhaps in the */
241 : /* future. */
242 : /* -------------------------------------------------------------------- */
243 : ECWDataset *poECWDS = (ECWDataset *) poDS;
244 : int i;
245 : int nDataTypeSize = (GDALGetDataTypeSize(poECWDS->eRasterDataType) / 8);
246 : GByte *pabyBILScanline = (GByte *)
247 : CPLMalloc(nBufXSize * nDataTypeSize * nBandCount);
248 : GByte **papabyBIL = (GByte**)CPLMalloc(nBandCount*sizeof(void*));
249 :
250 : for( i = 0; i < nBandCount; i++ )
251 : papabyBIL[i] = pabyBILScanline
252 : + i * nBufXSize * nDataTypeSize;
253 :
254 : /* -------------------------------------------------------------------- */
255 : /* Read back the imagery into the buffer. */
256 : /* -------------------------------------------------------------------- */
257 : for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
258 : {
259 : NCSEcwReadStatus eRStatus;
260 :
261 : eRStatus =
262 : poFileView->ReadLineBIL( poECWDS->eNCSRequestDataType,
263 : (UINT16) nBandCount,
264 : (void **) papabyBIL );
265 : if( eRStatus != NCSECW_READ_OK )
266 : {
267 : CPLFree( papabyBIL );
268 : CPLFree( pabyBILScanline );
269 : CPLError( CE_Failure, CPLE_AppDefined,
270 : "NCScbmReadViewLineBIL failed." );
271 : return eRStatus;
272 : }
273 :
274 : for( i = 0; i < nBandCount; i++ )
275 : {
276 : GDALCopyWords(
277 : pabyBILScanline + i * nDataTypeSize * nBufXSize,
278 : poECWDS->eRasterDataType, nDataTypeSize,
279 : ((GByte *) pBuf)
280 : + nLineSpace * iScanline
281 : + nBandSpace * i,
282 : eBufType,
283 : nPixelSpace,
284 : nBufXSize );
285 : }
286 : }
287 :
288 : CPLFree( pabyBILScanline );
289 : CPLFree( papabyBIL );
290 :
291 : return NCSECW_READ_OK;
292 : }
293 :
294 : /************************************************************************/
295 : /* GetNextUpdatedRegion() */
296 : /************************************************************************/
297 :
298 : GDALAsyncStatusType
299 : ECWAsyncReader::GetNextUpdatedRegion( double dfTimeout,
300 : int* pnXBufOff, int* pnYBufOff,
301 : int* pnXBufSize, int* pnYBufSize )
302 :
303 : {
304 : CPLDebug( "ECW", "GetNextUpdatedRegion()" );
305 :
306 : /* -------------------------------------------------------------------- */
307 : /* We always mark the whole raster as updated since the ECW SDK */
308 : /* does not have a concept of partial update notifications. */
309 : /* -------------------------------------------------------------------- */
310 : *pnXBufOff = 0;
311 : *pnYBufOff = 0;
312 : *pnXBufSize = nBufXSize;
313 : *pnYBufSize = nBufYSize;
314 :
315 : if( bComplete && !bUpdateReady )
316 : {
317 : CPLDebug( "ECW", "return GARIO_COMPLETE" );
318 : return GARIO_COMPLETE;
319 : }
320 :
321 : /* -------------------------------------------------------------------- */
322 : /* Wait till our timeout, or until we are notified there is */
323 : /* data ready. We are trusting the CPLSleep() to be pretty */
324 : /* accurate instead of keeping track of time elapsed ourselves */
325 : /* - this is not necessarily a good approach. */
326 : /* -------------------------------------------------------------------- */
327 : if( dfTimeout < 0.0 )
328 : dfTimeout = 100000.0;
329 :
330 : while( !bUpdateReady && dfTimeout > 0.0 )
331 : {
332 : CPLSleep( MIN(0.1, dfTimeout) );
333 : dfTimeout -= 0.1;
334 : CPLDebug( "ECW", "wait..." );
335 : }
336 :
337 : if( !bUpdateReady )
338 : {
339 : CPLDebug( "ECW", "return GARIO_PENDING" );
340 : return GARIO_PENDING;
341 : }
342 :
343 : bUpdateReady = FALSE;
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Acquire Mutex */
347 : /* -------------------------------------------------------------------- */
348 : if( !CPLAcquireMutex( hMutex, dfTimeout ) )
349 : {
350 : CPLDebug( "ECW", "return GARIO_PENDING" );
351 : return GARIO_PENDING;
352 : }
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Actually decode the imagery into our buffer. */
356 : /* -------------------------------------------------------------------- */
357 : NCSEcwReadStatus eRStatus = ReadToBuffer();
358 :
359 : if( eRStatus != NCSECW_READ_OK )
360 : {
361 : CPLReleaseMutex( hMutex );
362 : return GARIO_ERROR;
363 : }
364 :
365 : /* -------------------------------------------------------------------- */
366 : /* Return indication of complete or just buffer updateded. */
367 : /* -------------------------------------------------------------------- */
368 :
369 : if( bComplete && !bUpdateReady )
370 : {
371 : CPLReleaseMutex( hMutex );
372 : CPLDebug( "ECW", "return GARIO_COMPLETE" );
373 : return GARIO_COMPLETE;
374 : }
375 : else
376 : {
377 : CPLReleaseMutex( hMutex );
378 : CPLDebug( "ECW", "return GARIO_UPDATE" );
379 : return GARIO_UPDATE;
380 : }
381 : }
382 :
383 : #endif /* def FRMT_ecw */
|