1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Utility for creating bitmaps from video files |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 /** |
|
21 * @internal reviewed 31/07/2007 by Simon Brooks |
|
22 */ |
|
23 |
|
24 #include "glxtnimageutility.h" |
|
25 |
|
26 #include <MIHLScaler.h> // MIHLScaler |
|
27 #include <fbs.h> |
|
28 #include <glxtracer.h> |
|
29 #include <glxpanic.h> |
|
30 #include <glxthumbnail.h> |
|
31 #include <imageconversion.h> |
|
32 |
|
33 #include "glxtnimagedecoderfactory.h" |
|
34 |
|
35 // ----------------------------------------------------------------------------- |
|
36 // Constructor |
|
37 // ----------------------------------------------------------------------------- |
|
38 // |
|
39 CGlxtnImageUtility::CGlxtnImageUtility(RFs& aFs) : iFs(aFs) |
|
40 { |
|
41 TRACER("CGlxtnImageUtility::CGlxtnImageUtility()"); |
|
42 } |
|
43 |
|
44 // ----------------------------------------------------------------------------- |
|
45 // Destructor |
|
46 // ----------------------------------------------------------------------------- |
|
47 // |
|
48 CGlxtnImageUtility::~CGlxtnImageUtility() |
|
49 { |
|
50 TRACER("CGlxtnImageUtility::~CGlxtnImageUtility()"); |
|
51 delete iDecoder; |
|
52 delete iScaler; |
|
53 delete iBitGc; |
|
54 } |
|
55 |
|
56 // ----------------------------------------------------------------------------- |
|
57 // Cancel |
|
58 // ----------------------------------------------------------------------------- |
|
59 // |
|
60 void CGlxtnImageUtility::Cancel() |
|
61 { |
|
62 TRACER("void CGlxtnImageUtility::Cancel()"); |
|
63 if ( iDecoder ) |
|
64 { |
|
65 iDecoder->Cancel(); |
|
66 } |
|
67 if ( iScaler && iScaler->IsBusy()) |
|
68 { |
|
69 iScaler->CancelProcess(); |
|
70 } |
|
71 } |
|
72 |
|
73 // ----------------------------------------------------------------------------- |
|
74 // AdjustSize |
|
75 // ----------------------------------------------------------------------------- |
|
76 // |
|
77 void CGlxtnImageUtility::AdjustSize(TSize& aTargetSize, const TSize& aSourceSize) |
|
78 { |
|
79 TRACER("void CGlxtnImageUtility::AdjustSize()"); |
|
80 if ( aTargetSize.iHeight * aSourceSize.iWidth |
|
81 < aTargetSize.iWidth * aSourceSize.iHeight ) |
|
82 { |
|
83 // Source has taller aspect than target so reduce target width |
|
84 aTargetSize.iWidth = ( ( aTargetSize.iHeight * aSourceSize.iWidth ) |
|
85 / ( aSourceSize.iHeight ) ); |
|
86 } |
|
87 else |
|
88 { |
|
89 // Source has wider aspect than target so reduce target height |
|
90 aTargetSize.iHeight = (aTargetSize.iWidth * aSourceSize.iHeight) |
|
91 / aSourceSize.iWidth; |
|
92 } |
|
93 } |
|
94 |
|
95 // ----------------------------------------------------------------------------- |
|
96 // DecodeImageL |
|
97 // ----------------------------------------------------------------------------- |
|
98 // |
|
99 CFbsBitmap* CGlxtnImageUtility::DecodeImageL(TRequestStatus& aStatus, |
|
100 const TDesC& aFileName, RArray<TSize>& aTargetSizes, TDisplayMode aMode) |
|
101 { |
|
102 TRACER("CFbsBitmap* CGlxtnImageUtility::DecodeImageL()"); |
|
103 delete iDecoder; |
|
104 iDecoder = NULL; |
|
105 iDecoder = GlxtnImageDecoderFactory::NewL( iFs, aFileName ); |
|
106 |
|
107 iOriginalSize = iDecoder->FrameInfo().iOverallSizeInPixels; |
|
108 if ( 0 == iOriginalSize.iWidth || 0 == iOriginalSize.iHeight ) |
|
109 { |
|
110 User::Leave(KErrCorrupt); |
|
111 } |
|
112 |
|
113 TInt count = aTargetSizes.Count(); |
|
114 TSize testSize; |
|
115 TSize targetSize; |
|
116 for ( TInt i = 0 ; i < count ; i++ ) |
|
117 { |
|
118 testSize = aTargetSizes[i]; |
|
119 AdjustSize(testSize, iOriginalSize); |
|
120 if( ( testSize.iWidth > targetSize.iWidth ) || ( testSize.iHeight > targetSize.iHeight ) ) |
|
121 { |
|
122 targetSize = testSize; |
|
123 } |
|
124 } |
|
125 |
|
126 // Find max scaling factor which won't make image smaller than target size |
|
127 TInt shift = 3; |
|
128 while ( shift |
|
129 && ((iOriginalSize.iWidth >> shift) < targetSize.iWidth |
|
130 || (iOriginalSize.iHeight >> shift) < targetSize.iHeight ) ) |
|
131 { |
|
132 shift--; |
|
133 } |
|
134 TInt roundUp = (1 << shift) - 1; |
|
135 TSize loadSize((iOriginalSize.iWidth + roundUp) >> shift, |
|
136 (iOriginalSize.iHeight + roundUp) >> shift); |
|
137 |
|
138 CFbsBitmap* image = new (ELeave) CFbsBitmap; |
|
139 CleanupStack::PushL(image); |
|
140 User::LeaveIfError(image->Create(loadSize, aMode)); |
|
141 |
|
142 iDecoder->Convert(&aStatus, *image); |
|
143 |
|
144 CleanupStack::Pop(image); |
|
145 return image; |
|
146 } |
|
147 |
|
148 // ----------------------------------------------------------------------------- |
|
149 // FreeDecoder |
|
150 // ----------------------------------------------------------------------------- |
|
151 // |
|
152 void CGlxtnImageUtility::FreeDecoder() |
|
153 { |
|
154 TRACER("void CGlxtnImageUtility::FreeDecoder()"); |
|
155 delete iDecoder; |
|
156 iDecoder = NULL; |
|
157 } |
|
158 |
|
159 // ----------------------------------------------------------------------------- |
|
160 // OriginalSize |
|
161 // ----------------------------------------------------------------------------- |
|
162 // |
|
163 const TSize& CGlxtnImageUtility::OriginalSize() const |
|
164 { |
|
165 TRACER("TSize& CGlxtnImageUtility::OriginalSize()"); |
|
166 return iOriginalSize; |
|
167 } |
|
168 |
|
169 //--------------------------------------------------------------------------- |
|
170 /** |
|
171 K-Nearest neighbour scaling for EColor64K. |
|
172 Code originally inherited from t_display.cpp by Toni Hemminki. |
|
173 Added windowing and further optimized by Jarmo Nikula 2006-2007. |
|
174 |
|
175 @param aSrc Source buffer pointer |
|
176 @param aSrcStride Source buffer stride in bytes |
|
177 @param aSrcCols Source columns |
|
178 @param aSrcRows Source rows |
|
179 @param aX Source window top-left X-coordinate |
|
180 @param aY Source window top-left Y-coordinate |
|
181 @param aW Source window width |
|
182 @param aH Source window height |
|
183 @param aDst Destination buffer pointer |
|
184 @param aDstStride Destination buffer stride in bytes |
|
185 @param aDstCols Destination columns, must be even |
|
186 @param aDstRows Destination rows |
|
187 */ |
|
188 // OPTION's for MMP file: |
|
189 // Interleave assembly code with C, output can be found on txt-files on some BUILD directory: |
|
190 // OPTION ARMCC --asm --interleave |
|
191 // Modify optimization for ARM insturcion set and for maximum speed |
|
192 // OPTION_REPLACE ARMCC --arm -Otime |
|
193 /* aSource->LockHeap(); |
|
194 TUint16* sourceAddress = (TUint16*)aSource->DataAddress(); |
|
195 aSource->UnlockHeap(); |
|
196 aTarget->LockHeap(); |
|
197 TUint16* targetAddress = (TUint16*)aTarget->DataAddress(); |
|
198 aTarget->UnlockHeap(); |
|
199 ScaleColor64K(sourceAddress, aSource->DataStride(), |
|
200 sourceSize.iWidth, sourceSize.iHeight, 0, 0, sourceSize.iWidth, sourceSize.iHeight, |
|
201 targetAddress, aTarget->DataStride(), |
|
202 targetSize.iWidth, targetSize.iHeight); |
|
203 */ |
|
204 |
|
205 void CGlxtnImageUtility::FilterImageL(TRequestStatus* aStatus, CFbsBitmap* aSource, CFbsBitmap*& aFilteredSource, CFbsBitmap* aTarget) |
|
206 { |
|
207 TRACER("void CGlxtnImageUtility::FilterImageL()"); |
|
208 TSize sourceSize(aSource->SizeInPixels()); |
|
209 TSize targetSize(aTarget->SizeInPixels()); |
|
210 TInt scalePercent = ((100*sourceSize.iWidth)/targetSize.iWidth) - 100; |
|
211 |
|
212 // no need to filter if close enough or smaller |
|
213 if ( scalePercent >= 2 && ( aTarget->DisplayMode() == EColor64K ) ) |
|
214 { |
|
215 FilterL(aSource, aFilteredSource, scalePercent); |
|
216 } |
|
217 |
|
218 *aStatus = KRequestPending; |
|
219 User::RequestComplete(aStatus, KErrNone); |
|
220 } |
|
221 |
|
222 // ----------------------------------------------------------------------------- |
|
223 // ScaleImageL |
|
224 // ----------------------------------------------------------------------------- |
|
225 // |
|
226 void CGlxtnImageUtility::ScaleImageL(TRequestStatus& aStatus, CFbsBitmap& aSrcBitmap, |
|
227 const TRect& aSrcRect, CFbsBitmap& aDstBitmap, |
|
228 const TRect& aDstRect) |
|
229 { |
|
230 TRACER("void CGlxtnImageUtility::ScaleImageL(IHL)"); |
|
231 if (!iScaler) |
|
232 { |
|
233 TInt option = MIHLScaler::EOptionUseBilinearInterpolation; |
|
234 |
|
235 iScaler = IHLScaler::CreateL(option); |
|
236 } |
|
237 User::LeaveIfError(iScaler->Scale(aStatus, aSrcBitmap, aSrcRect, aDstBitmap, aDstRect)); |
|
238 } |
|
239 |
|
240 void CGlxtnImageUtility::ScaleImage64kL(TRequestStatus* aStatus, CFbsBitmap* aSource, CFbsBitmap* aFilteredSource, CFbsBitmap* aTarget) |
|
241 { |
|
242 TRACER("void CGlxtnImageUtility::ScaleImage64kL()"); |
|
243 TSize sourceSize(aSource->SizeInPixels()); |
|
244 TSize targetSize(aTarget->SizeInPixels()); |
|
245 TInt scalePercent = ((100*sourceSize.iWidth)/targetSize.iWidth) - 100; |
|
246 TRect targetRect(targetSize); |
|
247 TRect sourceRect(sourceSize); |
|
248 |
|
249 CFbsBitmap* sourceImage = aFilteredSource; |
|
250 if ( !aFilteredSource ) |
|
251 { |
|
252 sourceImage = aSource; |
|
253 } |
|
254 if ( scalePercent < 2 ) |
|
255 { |
|
256 if ( scalePercent > 0 ) |
|
257 { |
|
258 sourceRect = targetRect; |
|
259 } |
|
260 sourceImage = aSource; |
|
261 } |
|
262 sourceImage->LockHeap(); |
|
263 TUint16* sourceAddress = (TUint16*)sourceImage->DataAddress(); |
|
264 sourceImage->UnlockHeap(); |
|
265 aTarget->LockHeap(); |
|
266 TUint16* targetAddress = (TUint16*)aTarget->DataAddress(); |
|
267 aTarget->UnlockHeap(); |
|
268 ScaleColor64K(sourceAddress, sourceImage->DataStride(), |
|
269 sourceImage->SizeInPixels().iWidth, sourceImage->SizeInPixels().iHeight, 0, 0, sourceImage->SizeInPixels().iWidth, sourceImage->SizeInPixels().iHeight, |
|
270 targetAddress, aTarget->DataStride(), |
|
271 targetSize.iWidth, targetSize.iHeight); |
|
272 |
|
273 /* if ( !iBitGc ) |
|
274 { |
|
275 iBitGc = CFbsBitGc::NewL(); |
|
276 } |
|
277 CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(aTarget); |
|
278 CleanupStack::PushL(bitmapDevice); |
|
279 iBitGc->Activate(bitmapDevice); |
|
280 iBitGc->DrawBitmap(targetRect, sourceImage, sourceRect); |
|
281 CleanupStack::PopAndDestroy(bitmapDevice); |
|
282 */ |
|
283 *aStatus = KRequestPending; |
|
284 User::RequestComplete(aStatus, KErrNone); |
|
285 } |
|
286 |
|
287 void CGlxtnImageUtility::ScaleColor64K( TUint16* aSrc, TInt aSrcStride, TInt /*aSrcCols*/, TInt /*aSrcRows*/, |
|
288 TInt aX, TInt aY, TInt aW, TInt aH, |
|
289 TUint16* aDst, TInt aDstStride, TInt aDstCols, TInt aDstRows ) |
|
290 { |
|
291 TRACER("void CGlxtnImageUtility::ScaleColor64K()"); |
|
292 const TUint KPrecision = 16; |
|
293 TUint hInc = ( aW<< KPrecision ) / aDstCols; |
|
294 TUint vInc = ( aH << KPrecision ) / aDstRows; |
|
295 TUint v = 0; |
|
296 for ( TUint row = aDstRows; row > 0; --row ) |
|
297 { |
|
298 TInt h = hInc * (aDstCols - 1); |
|
299 TUint linestart = aSrcStride * ( aY + ( v >> KPrecision ) ) / sizeof(TUint16) + aX; |
|
300 TUint16* src = &aSrc[ linestart ]; |
|
301 TUint32* dst = (TUint32*)aDst + aDstCols / 2; |
|
302 TUint32 pxl2x; |
|
303 // This loop generates 11 assembly instructions per round |
|
304 // when using "--arm --Otime" options. Since two pixels are handled per round, |
|
305 // it means 5.5 instructions per pixel on average. |
|
306 do { |
|
307 pxl2x = src[ h >> KPrecision ]<<16; |
|
308 h -= hInc; |
|
309 pxl2x |= src[ h >> KPrecision ]; |
|
310 *--dst = pxl2x; |
|
311 // Compiler eliminates CMP instruction when substraction |
|
312 // is done inside the while () statement. |
|
313 } while ( ( h -= hInc ) >= 0 ); |
|
314 v += vInc; |
|
315 aDst += aDstStride / sizeof(TUint16); |
|
316 } |
|
317 } |
|
318 |
|
319 void CGlxtnImageUtility::FilterL( CFbsBitmap* aSource, CFbsBitmap*& aFilteredSource, TInt aFilterPercent ) |
|
320 { |
|
321 TRACER("void CGlxtnImageUtility::FilterL()"); |
|
322 if ( !aFilteredSource ) |
|
323 { |
|
324 TSize imageSize = aSource->SizeInPixels(); |
|
325 aFilteredSource = new (ELeave) CFbsBitmap; |
|
326 aFilteredSource->Create(imageSize, aSource->DisplayMode()); |
|
327 |
|
328 CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(aFilteredSource); |
|
329 if ( !iBitGc ) |
|
330 { |
|
331 iBitGc = CFbsBitGc::NewL(); |
|
332 } |
|
333 iBitGc->Activate(bitmapDevice); |
|
334 iBitGc->BitBlt(TPoint(), aSource, imageSize); |
|
335 delete bitmapDevice; |
|
336 } |
|
337 |
|
338 TSize imageSize = aFilteredSource->SizeInPixels(); |
|
339 aFilteredSource->LockHeap(); |
|
340 TUint16* sourceAddress = (TUint16*)aFilteredSource->DataAddress(); |
|
341 aFilteredSource->UnlockHeap(); |
|
342 const TInt KGlxScalingNeeds4Filtering = 80; // if scaling more than 1.8 need to filter by 4 |
|
343 const TInt KGlxScalingNeeds8Filtering = 260; // if scaling more than 3.6 need to filter by 8 |
|
344 if ( KGlxScalingNeeds8Filtering < aFilterPercent ) |
|
345 { |
|
346 FIRFiltering8( |
|
347 sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16), |
|
348 imageSize.iWidth, imageSize.iHeight ); |
|
349 } |
|
350 else if ( KGlxScalingNeeds4Filtering < aFilterPercent ) |
|
351 { |
|
352 FIRFiltering4( |
|
353 sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16), |
|
354 imageSize.iWidth, imageSize.iHeight ); |
|
355 } |
|
356 else |
|
357 { |
|
358 FIRFiltering( |
|
359 sourceAddress, aFilteredSource->DataStride() / sizeof(TUint16), |
|
360 imageSize.iWidth, imageSize.iHeight ); |
|
361 } |
|
362 } |
|
363 |
|
364 #define rmask565 0xf800 |
|
365 #define gmask565 0x07e0 |
|
366 #define bmask565 0x001f |
|
367 #define rbmask565 (rmask565|bmask565) |
|
368 #define rm565( rgb ) ((rgb) & rmask565) |
|
369 #define gm565( rgb ) ((rgb) & gmask565) |
|
370 #define bm565( rgb ) ((rgb) & bmask565) |
|
371 #define rbm565( rgb ) ((rgb) & rbmask565) |
|
372 #define r565( rgb ) ((rgb)>>11) |
|
373 #define g565( rgb ) (gm565(rgb)>>5) |
|
374 #define b565( rgb ) (bm565(rgb)) |
|
375 #define rgb565( r, g, b ) (((r)<<11)|((g)<<5)|(b)) |
|
376 |
|
377 #define mask32gbr655 0x07e0f81f |
|
378 |
|
379 // Keep below three defs in sync with each other! |
|
380 #define KFIRLen 2 |
|
381 #define KFIRCen (KFIRLen / 2) |
|
382 #define incFIRIndex( i ) i = (i + 1) & (KFIRLen - 1) |
|
383 // Keep above three defs in sync with each other! |
|
384 |
|
385 void CGlxtnImageUtility::FIRFiltering( |
|
386 TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows ) |
|
387 { |
|
388 TRACER("void CGlxtnImageUtility::FIRFiltering( )"); |
|
389 TUint firFifo[ KFIRLen ]; |
|
390 TUint i; // index for fifo in&out |
|
391 TUint16 *p; |
|
392 TUint32 px; |
|
393 TInt row, col; |
|
394 TUint FIRsum; |
|
395 // Horizontal scan. |
|
396 p = aDst; |
|
397 for ( row = aDstRows - 1; row >= 0; row-- ) |
|
398 { |
|
399 // read for cache |
|
400 //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ]; |
|
401 // Fill in the FIR first. |
|
402 // TODO: Fill in with extrapolated values at edges! |
|
403 FIRsum = ((KFIRLen / 2)<<21) | ((KFIRLen / 2)<<11) | (KFIRLen / 2); // for correct rounding |
|
404 i = 0; |
|
405 TUint32 mask1 = mask32gbr655; |
|
406 for ( col = 0; col < KFIRLen; col++ ) |
|
407 { |
|
408 px = p[ col ]; |
|
409 px = ((px<<16) | px) & mask1; |
|
410 firFifo[ i ] = px; |
|
411 FIRsum += px; |
|
412 incFIRIndex( i ); |
|
413 } |
|
414 TUint32 ave; |
|
415 for ( ; col < aDstCols; col++ ) |
|
416 { |
|
417 ave = ( FIRsum / KFIRLen ) & mask1; |
|
418 p[ col - KFIRCen ] = TUint16( ave | (ave>>16) ); |
|
419 FIRsum -= firFifo[ i ]; |
|
420 px = p[ col ]; |
|
421 px = ((px<<16) | px) & mask1; |
|
422 firFifo[ i ] = px; |
|
423 FIRsum += px; |
|
424 incFIRIndex( i ); |
|
425 } |
|
426 p += aDstStridep; |
|
427 } |
|
428 // Vertical scan. |
|
429 for ( col = aDstCols - 1; col >= 0; col-- ) |
|
430 { |
|
431 // Fill in the FIR first. |
|
432 FIRsum = ((KFIRLen / 2)<<21) | ((KFIRLen / 2)<<11) | (KFIRLen / 2); // for correct rounding |
|
433 TUint32 mask1 = mask32gbr655; |
|
434 i = 0; |
|
435 p = aDst + col; |
|
436 for ( row = 0; row < KFIRLen; row++ ) |
|
437 { |
|
438 px = *p; |
|
439 px = ((px<<16) | px) & mask1; |
|
440 firFifo[ i ] = px; |
|
441 FIRsum += px; |
|
442 incFIRIndex( i ); |
|
443 p += aDstStridep; |
|
444 } |
|
445 TUint32 ave; |
|
446 p -= aDstStridep * KFIRCen; |
|
447 for ( ; row < aDstRows; row++ ) |
|
448 { |
|
449 ave = ( FIRsum / KFIRLen ) & mask1; |
|
450 p[0] = TUint16( ave | (ave>>16) ); |
|
451 FIRsum -= firFifo[ i ]; |
|
452 px = p[ aDstStridep * KFIRCen ]; |
|
453 px = ((px<<16) | px) & mask1; |
|
454 firFifo[ i ] = px; |
|
455 FIRsum += px; |
|
456 incFIRIndex( i ); |
|
457 p += aDstStridep; |
|
458 } |
|
459 } |
|
460 } |
|
461 // |
|
462 // Keep below three defs in sync with each other! |
|
463 #define KFIRLen4 4 |
|
464 #define KFIRCen4 (KFIRLen4 / 2) |
|
465 #define incFIRIndex4( i ) i = (i + 1) & (KFIRLen4 - 1) |
|
466 // Keep above three defs in sync with each other! |
|
467 |
|
468 void CGlxtnImageUtility::FIRFiltering4( |
|
469 TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows ) |
|
470 { |
|
471 TRACER("void CGlxtnImageUtility::FIRFiltering4()"); |
|
472 TUint firFifo[ KFIRLen4 ]; |
|
473 TUint i; // index for fifo in&out |
|
474 TUint16 *p; |
|
475 TUint32 px; |
|
476 TInt row, col; |
|
477 TUint FIRsum; |
|
478 // Horizontal scan. |
|
479 p = aDst; |
|
480 for ( row = aDstRows - 1; row >= 0; row-- ) |
|
481 { |
|
482 // read for cache |
|
483 //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ]; |
|
484 // Fill in the FIR first. |
|
485 // TODO: Fill in with extrapolated values at edges! |
|
486 FIRsum = ((KFIRLen4 / 2)<<21) | ((KFIRLen4 / 2)<<11) | (KFIRLen4 / 2); // for correct rounding |
|
487 i = 0; |
|
488 TUint32 mask1 = mask32gbr655; |
|
489 for ( col = 0; col < KFIRLen4; col++ ) |
|
490 { |
|
491 px = p[ col ]; |
|
492 px = ((px<<16) | px) & mask1; |
|
493 firFifo[ i ] = px; |
|
494 FIRsum += px; |
|
495 incFIRIndex4( i ); |
|
496 } |
|
497 TUint32 ave; |
|
498 for ( ; col < aDstCols; col++ ) |
|
499 { |
|
500 ave = ( FIRsum / KFIRLen4 ) & mask1; |
|
501 p[ col - KFIRCen4 ] = TUint16( ave | (ave>>16) ); |
|
502 FIRsum -= firFifo[ i ]; |
|
503 px = p[ col ]; |
|
504 px = ((px<<16) | px) & mask1; |
|
505 firFifo[ i ] = px; |
|
506 FIRsum += px; |
|
507 incFIRIndex4( i ); |
|
508 } |
|
509 p += aDstStridep; |
|
510 } |
|
511 // Vertical scan. |
|
512 for ( col = aDstCols - 1; col >= 0; col-- ) |
|
513 { |
|
514 // Fill in the FIR first. |
|
515 FIRsum = ((KFIRLen4 / 2)<<21) | ((KFIRLen4 / 2)<<11) | (KFIRLen4 / 2); // for correct rounding |
|
516 TUint32 mask1 = mask32gbr655; |
|
517 i = 0; |
|
518 p = aDst + col; |
|
519 for ( row = 0; row < KFIRLen4; row++ ) |
|
520 { |
|
521 px = *p; |
|
522 px = ((px<<16) | px) & mask1; |
|
523 firFifo[ i ] = px; |
|
524 FIRsum += px; |
|
525 incFIRIndex4( i ); |
|
526 p += aDstStridep; |
|
527 } |
|
528 TUint32 ave; |
|
529 p -= aDstStridep * KFIRCen4; |
|
530 for ( ; row < aDstRows; row++ ) |
|
531 { |
|
532 ave = ( FIRsum / KFIRLen4 ) & mask1; |
|
533 p[0] = TUint16( ave | (ave>>16) ); |
|
534 FIRsum -= firFifo[ i ]; |
|
535 px = p[ aDstStridep * KFIRCen4 ]; |
|
536 px = ((px<<16) | px) & mask1; |
|
537 firFifo[ i ] = px; |
|
538 FIRsum += px; |
|
539 incFIRIndex4( i ); |
|
540 p += aDstStridep; |
|
541 } |
|
542 } |
|
543 } |
|
544 |
|
545 // Keep below three defs in sync with each other! |
|
546 #define KFIRLen8 8 |
|
547 #define KFIRCen8 (KFIRLen8 / 2) |
|
548 #define incFIRIndex8( i ) i = (i + 1) & (KFIRLen8 - 1) |
|
549 // Keep above three defs in sync with each other! |
|
550 |
|
551 void CGlxtnImageUtility::FIRFiltering8( |
|
552 TUint16* aDst, TUint aDstStridep, TUint aDstCols, TUint aDstRows ) |
|
553 { |
|
554 TRACER("void CGlxtnImageUtility::FIRFiltering8()"); |
|
555 TUint firFifo[ KFIRLen8 ]; |
|
556 TUint i; // index for fifo in&out |
|
557 TUint16 *p; |
|
558 TUint32 px; |
|
559 TInt row, col; |
|
560 TUint FIRsum; |
|
561 // Horizontal scan. |
|
562 p = aDst; |
|
563 for ( row = aDstRows - 1; row >= 0; row-- ) |
|
564 { |
|
565 // read for cache |
|
566 //for ( col = aDstCols - 1; col >= 0; col-- ) TInt temp = p[ col ]; |
|
567 // Fill in the FIR first. |
|
568 // TODO: Fill in with extrapolated values at edges! |
|
569 FIRsum = ((KFIRLen8 / 2)<<21) | ((KFIRLen8 / 2)<<11) | (KFIRLen8 / 2); // for correct rounding |
|
570 i = 0; |
|
571 TUint32 mask1 = mask32gbr655; |
|
572 for ( col = 0; col < KFIRLen8; col++ ) |
|
573 { |
|
574 px = p[ col ]; |
|
575 px = ((px<<16) | px) & mask1; |
|
576 firFifo[ i ] = px; |
|
577 FIRsum += px; |
|
578 incFIRIndex8( i ); |
|
579 } |
|
580 TUint32 ave; |
|
581 for ( ; col < aDstCols; col++ ) |
|
582 { |
|
583 ave = ( FIRsum / KFIRLen8 ) & mask1; |
|
584 p[ col - KFIRCen8 ] = TUint16( ave | (ave>>16) ); |
|
585 FIRsum -= firFifo[ i ]; |
|
586 px = p[ col ]; |
|
587 px = ((px<<16) | px) & mask1; |
|
588 firFifo[ i ] = px; |
|
589 FIRsum += px; |
|
590 incFIRIndex8( i ); |
|
591 } |
|
592 p += aDstStridep; |
|
593 } |
|
594 // Vertical scan. |
|
595 for ( col = aDstCols - 1; col >= 0; col-- ) |
|
596 { |
|
597 // Fill in the FIR first. |
|
598 FIRsum = ((KFIRLen8 / 2)<<21) | ((KFIRLen8 / 2)<<11) | (KFIRLen8 / 2); // for correct rounding |
|
599 TUint32 mask1 = mask32gbr655; |
|
600 i = 0; |
|
601 p = aDst + col; |
|
602 for ( row = 0; row < KFIRLen8; row++ ) |
|
603 { |
|
604 px = *p; |
|
605 px = ((px<<16) | px) & mask1; |
|
606 firFifo[ i ] = px; |
|
607 FIRsum += px; |
|
608 incFIRIndex8( i ); |
|
609 p += aDstStridep; |
|
610 } |
|
611 TUint32 ave; |
|
612 p -= aDstStridep * KFIRCen8; |
|
613 for ( ; row < aDstRows; row++ ) |
|
614 { |
|
615 ave = ( FIRsum / KFIRLen8 ) & mask1; |
|
616 p[0] = TUint16( ave | (ave>>16) ); |
|
617 FIRsum -= firFifo[ i ]; |
|
618 px = p[ aDstStridep * KFIRCen8 ]; |
|
619 px = ((px<<16) | px) & mask1; |
|
620 firFifo[ i ] = px; |
|
621 FIRsum += px; |
|
622 incFIRIndex8( i ); |
|
623 p += aDstStridep; |
|
624 } |
|
625 } |
|
626 } |
|