videoeditorengine/vedtranscoder/src/Ctrscaler.cpp
branchRCL_3
changeset 3 e0b5df5c0969
parent 0 951a5db380a0
child 5 4c409de21d23
equal deleted inserted replaced
0:951a5db380a0 3:e0b5df5c0969
     1 /*
       
     2 * Copyright (c) 2010 Ixonos Plc.
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the "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 * Ixonos Plc
       
    14 *
       
    15 * Description:  
       
    16 * Resampling framework for YUV 4.2.0.
       
    17 *
       
    18 */
       
    19 
       
    20 
       
    21 
       
    22 // INCLUDES
       
    23 #include "ctrscaler.h"
       
    24 #include "ctrsettings.h"
       
    25 #include "ctrhwsettings.h"
       
    26 #include <e32math.h>
       
    27 
       
    28 
       
    29 // Debug print macro
       
    30 #ifdef _DEBUG
       
    31     #include <e32svr.h>
       
    32     #define PRINT(x) RDebug::Print x;
       
    33 #else
       
    34     #define PRINT(x)
       
    35 #endif
       
    36 
       
    37 
       
    38 // An assertion macro wrapper to clean up the code a bit
       
    39 #define VPASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CTRScaler"), KErrAbort))
       
    40 
       
    41 
       
    42 // Macros for fixed point math
       
    43 #define FP_BITS         15      // Number of bits to use for FP decimals
       
    44 #define FP_FP(x)        (static_cast<TInt>((x) * 32768.0))
       
    45 #define FP_ONE          (1 << FP_BITS)
       
    46 #define FP_MUL(x,y)     (((x) * (y)) >> FP_BITS)
       
    47 #define FP_FRAC(x)      ((x) & (FP_ONE - 1))
       
    48 #define FP_INT(x)       ((x) >> FP_BITS)
       
    49 
       
    50 
       
    51 // ============================ MEMBER FUNCTIONS ===============================
       
    52 
       
    53 // -----------------------------------------------------------------------------
       
    54 // CTRScaler::NewL
       
    55 // Two-phased constructor.
       
    56 // -----------------------------------------------------------------------------
       
    57 //
       
    58 CTRScaler* CTRScaler::NewL()
       
    59     {
       
    60     // Standard two phase construction
       
    61     CTRScaler* self = new (ELeave) CTRScaler();
       
    62     CleanupStack::PushL(self);
       
    63     self->ConstructL();
       
    64     CleanupStack::Pop();
       
    65 
       
    66     return self;
       
    67     }
       
    68 
       
    69 
       
    70 // -----------------------------------------------------------------------------
       
    71 // CTRScaler::ConstructL
       
    72 // Symbian 2nd phase constructor can leave.
       
    73 // -----------------------------------------------------------------------------
       
    74 //
       
    75 void CTRScaler::ConstructL()
       
    76     {
       
    77     }
       
    78 
       
    79 
       
    80 // -----------------------------------------------------------------------------
       
    81 // CTRScaler::CTRScaler
       
    82 // C++ default constructor can NOT contain any code, that
       
    83 // might leave.
       
    84 // -----------------------------------------------------------------------------
       
    85 CTRScaler::CTRScaler()
       
    86     {
       
    87     // Scaler does not perform any operation before initializing
       
    88     iOperation = EOperationNone;
       
    89     iTrgBuffer = NULL;
       
    90     }
       
    91 
       
    92 
       
    93 // ---------------------------------------------------------
       
    94 // CTRScaler::~CTRScaler()
       
    95 // Destructor
       
    96 // ---------------------------------------------------------
       
    97 //
       
    98 CTRScaler::~CTRScaler()
       
    99     {
       
   100     }
       
   101 
       
   102 // ---------------------------------------------------------
       
   103 // CTRScaler::IsWideAspectRatio()
       
   104 // Checks if aspect ratio is wide
       
   105 // ---------------------------------------------------------
       
   106 //
       
   107 TBool CTRScaler::IsWideAspectRatio(TSize aSize)
       
   108     {
       
   109     return ( TReal(aSize.iWidth) / TReal(aSize.iHeight) ) > KTRWideThreshold;
       
   110     }
       
   111 
       
   112 // -----------------------------------------------------------------------------
       
   113 // CTRScaler::SetupScalerL
       
   114 // Sets the scaler options (src buffer, dest buffer (could be the same as a src), src resolution, trg resolution)
       
   115 // (other items were commented in a header).
       
   116 // -----------------------------------------------------------------------------
       
   117 //
       
   118 void CTRScaler::SetScalerOptionsL(TPtr8& aSrc, TPtr8& aTrg, TSize& aSrcSize, TSize& aTrgSize )
       
   119     {
       
   120     
       
   121     
       
   122     PRINT((_L("CTRScaler::SetScalerOptionsL, src = (%d, %d), trg = (%d, %d)"), 
       
   123         aSrcSize.iWidth, aSrcSize.iHeight, aTrgSize.iWidth, aTrgSize.iHeight));
       
   124     
       
   125     // Check settings
       
   126     if ( ( !aSrc.Ptr() ) || ( !aTrg.Ptr() ) || 
       
   127        ( aSrcSize.iWidth == 0) || ( aSrcSize.iHeight == 0 )   || 
       
   128        ( aTrgSize.iWidth == 0) || ( aTrgSize.iHeight == 0 )   ||
       
   129        ( aSrc.MaxLength() < ( aSrcSize.iWidth * aSrcSize.iHeight * 3 / 2 ) ) || 
       
   130        ( aTrg.MaxLength() < ( aTrgSize.iWidth * aTrgSize.iHeight * 3 / 2 ) )
       
   131         )
       
   132         {
       
   133         PRINT((_L("CTRScaler::SetupScalerL(), Given options are not supported")))
       
   134         User::Leave(KErrNotSupported);
       
   135         }
       
   136     else
       
   137         {
       
   138         TReal remainder = 0.0;
       
   139         iTrgBuffer = NULL;
       
   140 
       
   141         // We don't support non-multiple output yet
       
   142         Math::Mod( remainder, static_cast<TReal>(aTrgSize.iWidth), 4.0 );
       
   143 
       
   144         if ( remainder == 0.0 )
       
   145             {
       
   146             Math::Mod( remainder, static_cast<TReal>(aTrgSize.iHeight), 4.0 );
       
   147             }
       
   148 
       
   149         if ( remainder != 0.0 )
       
   150             {
       
   151             PRINT((_L("CTRScaler::SetupScalerL(), Scaler does not support output resolution that is not multiple by 4")))
       
   152             User::Leave(KErrNotSupported);
       
   153             }
       
   154             
       
   155         TSize targetSize = aTrgSize;
       
   156         // check if black boxing is needed
       
   157         TBool srcWide = IsWideAspectRatio(aSrcSize);
       
   158         TBool dstWide = IsWideAspectRatio(aTrgSize);
       
   159         
       
   160         iBlackBoxing = TSize(0,0);
       
   161         
       
   162         TBool doScaling = ETrue;
       
   163         if (srcWide != dstWide)
       
   164             {
       
   165                 TSize resolution(0,0);
       
   166             
       
   167                 doScaling = GetIntermediateResolution(aSrcSize, aTrgSize, resolution, iBlackBoxing);
       
   168             
       
   169                 // Set the whole image to black
       
   170                 TUint yLength = aTrgSize.iWidth * aTrgSize.iHeight;
       
   171 		        TUint uvLength = yLength >> 1;
       
   172                 
       
   173                 // Y
       
   174         		TInt data = 0;
       
   175         		TPtr8 tempPtr(0,0);        		
       
   176         		tempPtr.Set(const_cast<TUint8*>(aTrg.Ptr()), yLength, yLength);        		
       
   177         		tempPtr.Fill((TChar)data, yLength);
       
   178 
       
   179         		// U,V        		
       
   180         		data = 127;
       
   181         		tempPtr.Set(const_cast<TUint8*>(aTrg.Ptr()) + yLength, uvLength, uvLength); 
       
   182         		tempPtr.Fill((TChar)data, uvLength);                
       
   183 
       
   184                 aTrgSize = resolution;
       
   185                 PRINT((_L("CTRScaler::SetScalerOptionsL, blackboxing width = %d, height = %d"), iBlackBoxing.iWidth, iBlackBoxing.iHeight));
       
   186             }
       
   187          
       
   188         if ( !doScaling )
       
   189             {
       
   190             // No need to perform resampling operation, copy data with black boxing
       
   191             iOperation = EOperationCopyWithBB;
       
   192             }        
       
   193         
       
   194         else if ( (aTrgSize.iWidth == aSrcSize.iWidth) && (aTrgSize.iHeight == aSrcSize.iHeight) )
       
   195             {
       
   196             // No need to perform resampling operation, just copy data
       
   197             iOperation = EOperationCopy;
       
   198             }
       
   199         else if ( (aTrgSize.iWidth == aSrcSize.iWidth * 2) && (aTrgSize.iHeight == aSrcSize.iHeight * 2) )
       
   200             {
       
   201             // Resolution is doubled
       
   202             iOperation = EDoubleSize;
       
   203             }
       
   204         else if ( (aTrgSize.iWidth * 2 == aSrcSize.iWidth) && (aTrgSize.iHeight * 2 == aSrcSize.iHeight) )
       
   205             {
       
   206             // Resolution is halved
       
   207             iOperation = EHalveSize;
       
   208             }
       
   209         else if ( (aTrgSize.iWidth > aSrcSize.iWidth) && (aTrgSize.iHeight > aSrcSize.iHeight) )
       
   210             {
       
   211             // Resolution is increased
       
   212             iOperation = EUpSampling;
       
   213             }
       
   214         else if ( (aTrgSize.iWidth < aSrcSize.iWidth) && (aTrgSize.iHeight < aSrcSize.iHeight) )
       
   215             {
       
   216             // Resolution is decreased
       
   217             iOperation = EDownSampling;
       
   218             }
       
   219         else
       
   220             {
       
   221             // The image is streched ie. vertical resolution increases and horizontal decreases or vice versa
       
   222             iOperation = EUpDownSampling;
       
   223             }
       
   224 
       
   225         // Set given settings
       
   226         iSrc = const_cast<TUint8*>( aSrc.Ptr() );
       
   227         iTrg = const_cast<TUint8*>( aTrg.Ptr() );
       
   228         iSrcSize = aSrcSize;
       
   229         iTrgSize = aTrgSize;
       
   230         iSrcInit = iSrc;
       
   231         iTrgInit = iTrg;
       
   232         aTrgSize = targetSize;  // recover target size since it's a reference
       
   233         iTrgDataSize = aTrgSize.iWidth * aTrgSize.iHeight * 3 / 2;
       
   234         iTrgBuffer = &aTrg;
       
   235         }
       
   236     }
       
   237     
       
   238 // ---------------------------------------------------------
       
   239 // CTRScaler::GetIntermediateResolution()
       
   240 // Calculates intermediate resolution for use with black boxing
       
   241 // ---------------------------------------------------------
       
   242 //
       
   243 TBool CTRScaler::GetIntermediateResolution(TSize aSrcSize, TSize aTrgSize, 
       
   244                                            TSize& aTargetResolution, TSize& aBlackBoxing)
       
   245     {
       
   246 
       
   247     TSize resolution;
       
   248     TBool doScaling = ETrue;
       
   249        
       
   250     TBool srcWide = IsWideAspectRatio(aSrcSize);
       
   251     TBool dstWide = IsWideAspectRatio(aTrgSize);
       
   252     
       
   253     VPASSERT(srcWide != dstWide);
       
   254     
       
   255     if (dstWide)
       
   256         {
       
   257         // Pillarboxing
       
   258         
       
   259         // scale height to destination
       
   260         TReal factor = TReal(aTrgSize.iHeight) / TReal(aSrcSize.iHeight);
       
   261         
       
   262         resolution.iWidth = TInt( aSrcSize.iWidth * factor );
       
   263         
       
   264         if (resolution.iWidth & 0x1 > 0)
       
   265             resolution.iWidth++;
       
   266         
       
   267         resolution.iHeight = aTrgSize.iHeight;
       
   268         
       
   269         while ( (aTrgSize.iWidth - resolution.iWidth) % 4 != 0 )
       
   270         {
       
   271             resolution.iWidth += 2;
       
   272         }
       
   273 
       
   274         aBlackBoxing.iWidth = (aTrgSize.iWidth - resolution.iWidth) / 2;
       
   275         
       
   276         if ( factor == 1.0 )
       
   277             {
       
   278             // source and destination heights are the same, 
       
   279             // meaning source width is smaller and we don't
       
   280             // have to scale, just do pillarboxing
       
   281             doScaling = EFalse;
       
   282 
       
   283             // set target width
       
   284             resolution.iWidth = aTrgSize.iWidth;
       
   285             }
       
   286                         
       
   287         }
       
   288     else
       
   289         {
       
   290         // Letterboxing
       
   291     
       
   292         // scale width to destination
       
   293         TReal factor = TReal(aTrgSize.iWidth) / TReal(aSrcSize.iWidth);                                
       
   294                     
       
   295         resolution.iHeight = TInt( aSrcSize.iHeight * factor );                
       
   296 
       
   297         if (resolution.iHeight & 0x1 > 0)
       
   298             resolution.iHeight++;
       
   299         
       
   300         resolution.iWidth = aTrgSize.iWidth;
       
   301         
       
   302         while ( (aTrgSize.iHeight - resolution.iHeight) % 4 != 0 )
       
   303             {
       
   304             resolution.iHeight += 2;
       
   305             }                                    
       
   306         
       
   307         aBlackBoxing.iHeight = (aTrgSize.iHeight - resolution.iHeight) / 2;
       
   308         
       
   309         if ( factor == 1.0 )
       
   310             {
       
   311             // source and destination widths are the same, 
       
   312             // meaning source height is smaller and we don't
       
   313             // have to scale, just do letterboxing
       
   314             doScaling = EFalse;
       
   315 
       
   316             // set target height
       
   317             resolution.iHeight = aTrgSize.iHeight;
       
   318             }
       
   319         }
       
   320 
       
   321     PRINT((_L("CTRScaler::GetIntermediateResolution, resolution = (%d, %d), bb = (%d, %d)"), 
       
   322         resolution.iWidth, resolution.iHeight, aBlackBoxing.iWidth, aBlackBoxing.iHeight));
       
   323 
       
   324     aTargetResolution = resolution;
       
   325     
       
   326     return doScaling;
       
   327     
       
   328 
       
   329 }
       
   330 
       
   331 
       
   332 // -----------------------------------------------------------------------------
       
   333 // CTRScaler::Scale()
       
   334 // Scale the image
       
   335 // (other items were commented in a header).
       
   336 // -----------------------------------------------------------------------------
       
   337 //
       
   338 void CTRScaler::Scale()
       
   339     {
       
   340     TSize srcSizeUV = TSize( iSrcSize.iWidth / 2, iSrcSize.iHeight / 2 );
       
   341     TSize trgSizeUV = TSize( iTrgSize.iWidth / 2, iTrgSize.iHeight / 2 );
       
   342     TSize blackBoxingUV = TSize( iBlackBoxing.iWidth / 2, iBlackBoxing.iHeight / 2 );
       
   343     
       
   344     switch( iOperation )
       
   345         {
       
   346         case EOperationCopy:
       
   347             {
       
   348             // Src / Trg resolutions are the same, no needs to perform resampling
       
   349             if ( iSrc != iTrg )
       
   350                 {
       
   351                     // Copy data, if different memory areas are specified
       
   352                     Mem::Copy( iTrg, iSrc, iTrgDataSize );            
       
   353                 }
       
   354             else
       
   355                 {
       
   356                 // The same memory fragment is specified for the output; Keep it without changes;
       
   357                 }
       
   358             }
       
   359             break;
       
   360             
       
   361         case EOperationCopyWithBB:
       
   362             {                
       
   363             // Copy with black boxing
       
   364             CopyWithBlackBoxing(iSrcSize, iTrgSize, iBlackBoxing);
       
   365             CopyWithBlackBoxing(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   366             CopyWithBlackBoxing(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   367             }
       
   368             break;
       
   369 
       
   370         case EDownSampling:
       
   371             {
       
   372             TInt error = KErrNoMemory;
       
   373             
       
   374             // If scaling to less than 50% of the source size
       
   375             if ( (iTrgSize.iWidth * 2 < iSrcSize.iWidth) && (iTrgSize.iHeight * 2 < iSrcSize.iHeight) )
       
   376                 {
       
   377                 // Try to do the scaling in two steps
       
   378                 TRAP( error, DoHalveAndBilinearResampleL() );
       
   379                 }
       
   380                
       
   381             // If the above failed or scaling to 51% or higher        
       
   382             if ( error != KErrNone )
       
   383                 {
       
   384                 // Resample the Y, U & V components
       
   385                 ResampleBilinear(iSrcSize, iTrgSize, iBlackBoxing);
       
   386                 ResampleBilinear(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   387                 ResampleBilinear(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   388                 }
       
   389             }
       
   390             break;
       
   391             
       
   392         case EUpSampling:
       
   393         case EUpDownSampling:
       
   394             {            
       
   395             // Resample the Y, U & V components
       
   396             ResampleBilinear(iSrcSize, iTrgSize, iBlackBoxing);
       
   397             ResampleBilinear(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   398             ResampleBilinear(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   399             }
       
   400             break;
       
   401             
       
   402         case EDoubleSize:
       
   403             {
       
   404             // Resample the Y, U & V components to double size
       
   405             ResampleDouble(iSrcSize, iTrgSize);
       
   406             ResampleDouble(srcSizeUV, trgSizeUV);
       
   407             ResampleDouble(srcSizeUV, trgSizeUV);
       
   408             }
       
   409             break;
       
   410             
       
   411         case EHalveSize:
       
   412             {
       
   413             // Resample the Y, U & V components to half size
       
   414             ResampleHalve(iSrcSize, iTrgSize, iBlackBoxing);
       
   415             ResampleHalve(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   416             ResampleHalve(srcSizeUV, trgSizeUV, blackBoxingUV);
       
   417             }
       
   418             break;
       
   419 
       
   420         case EOperationNone:
       
   421             {
       
   422             PRINT((_L("CTRScaler::Scale(), Scaler was not initialized yet to perform any operation")))
       
   423             return;
       
   424             }
       
   425 //            break;
       
   426 
       
   427         default:
       
   428             {
       
   429             }
       
   430         }
       
   431         
       
   432     // Recover source and target data pointers
       
   433     iSrc = iSrcInit;
       
   434     iTrg = iTrgInit;
       
   435     
       
   436     // Set Dsc length
       
   437     if (iTrgBuffer)
       
   438         {
       
   439         iTrgBuffer->SetLength(iTrgDataSize);
       
   440         }
       
   441     }
       
   442 
       
   443 // -----------------------------------------------------------------------------
       
   444 // CTRScaler::CopyWithBlackBoxing()
       
   445 // Copies frame to target buffer applying black borders
       
   446 // -----------------------------------------------------------------------------
       
   447 //       
       
   448 void CTRScaler::CopyWithBlackBoxing(TSize& aSrcSize, TSize& aTrgSize, TSize& aBlackBoxing)
       
   449 {
       
   450 
       
   451     if (aBlackBoxing.iHeight != 0)
       
   452         {
       
   453         
       
   454         TInt copyLength = aSrcSize.iWidth * aSrcSize.iHeight;
       
   455         
       
   456         iTrg += aBlackBoxing.iHeight * aTrgSize.iWidth;
       
   457         Mem::Copy(iTrg, iSrc, copyLength);
       
   458         
       
   459         iTrg += copyLength;
       
   460         iTrg += aBlackBoxing.iHeight * aTrgSize.iWidth;                                        
       
   461         iSrc += copyLength;
       
   462         
       
   463         } 
       
   464                     
       
   465     else if (aBlackBoxing.iWidth != 0)
       
   466         {
       
   467                                                 
       
   468         TInt i;
       
   469         iTrg += aBlackBoxing.iWidth;
       
   470         
       
   471         for (i = 0; i < iTrgSize.iHeight; i++)
       
   472             {
       
   473             // copy one row
       
   474             Mem::Copy(iTrg, iSrc, aSrcSize.iWidth);
       
   475             iSrc += aSrcSize.iWidth;
       
   476             iTrg += aSrcSize.iWidth;
       
   477             iTrg += aBlackBoxing.iWidth * 2;
       
   478             }
       
   479             
       
   480         // subtract the width of one pillar
       
   481         iTrg -= aBlackBoxing.iWidth;
       
   482             
       
   483         }
       
   484 }
       
   485 
       
   486 
       
   487 // -----------------------------------------------------------------------------
       
   488 // CTRScaler::DoHalveAndBilinearResampleL()
       
   489 // First resamples an image to half size and then uses bilinear resample to
       
   490 // scale it to requested size.
       
   491 // -----------------------------------------------------------------------------
       
   492 //    
       
   493 void CTRScaler::DoHalveAndBilinearResampleL()
       
   494     {
       
   495     // Make sure the scale factor is correct
       
   496     VPASSERT( (iTrgSize.iWidth * 2 < iSrcSize.iWidth) &&
       
   497               (iTrgSize.iHeight * 2 < iSrcSize.iHeight) );
       
   498     
       
   499     TSize srcSizeUV = TSize( iSrcSize.iWidth / 2, iSrcSize.iHeight / 2 );
       
   500     TSize trgSizeUV = TSize( iTrgSize.iWidth / 2, iTrgSize.iHeight / 2 );
       
   501     TSize blackBoxingUV = TSize( iBlackBoxing.iWidth / 2, iBlackBoxing.iHeight / 2 );
       
   502     
       
   503     // Calculate the size for the temporary image where we store the intermediate result         
       
   504     TSize tempSize = TSize( iSrcSize.iWidth / 2, iSrcSize.iHeight / 2 );
       
   505     TSize tempSizeUV = TSize( tempSize.iWidth / 2, tempSize.iHeight / 2 );
       
   506     
       
   507     // Allocate memory for the temporary image
       
   508     TUint8* tempBuffer = (TUint8*) User::AllocLC(tempSize.iWidth * tempSize.iHeight * 3 / 2);
       
   509     
       
   510     // Set the temporary image as the target
       
   511     iTrg = tempBuffer;
       
   512 
       
   513     TSize zeroBlackBox = TSize(0,0);
       
   514     // Resample the Y, U & V components to half size
       
   515     ResampleHalve(iSrcSize, tempSize, zeroBlackBox);
       
   516     ResampleHalve(srcSizeUV, tempSizeUV, zeroBlackBox);
       
   517     ResampleHalve(srcSizeUV, tempSizeUV, zeroBlackBox);
       
   518     
       
   519     // Set the temporary image as the source and recover the original target
       
   520     iSrc = tempBuffer;
       
   521     iTrg = iTrgInit;
       
   522     
       
   523     // Resample the Y, U & V components
       
   524     ResampleBilinear(tempSize, iTrgSize, iBlackBoxing);
       
   525     ResampleBilinear(tempSizeUV, trgSizeUV, blackBoxingUV);
       
   526     ResampleBilinear(tempSizeUV, trgSizeUV, blackBoxingUV);
       
   527     
       
   528     // Release the temporary buffer
       
   529     CleanupStack::PopAndDestroy(tempBuffer);
       
   530     }
       
   531 
       
   532 // -----------------------------------------------------------------------------
       
   533 // CTRScaler::ResampleBilinear()
       
   534 // Resamples an image with bilinear filtering. The target pixel is generated by
       
   535 // linearly interpolating the four nearest source pixels in x- and y-directions.
       
   536 // -----------------------------------------------------------------------------
       
   537 //    
       
   538 void CTRScaler::ResampleBilinear(TSize& aSrcSize, TSize& aTrgSize, TSize& aBlackBoxing)
       
   539     {
       
   540     TInt i = 0, j = 0;
       
   541     TInt x = 0, y = 0;
       
   542     TInt fx = 0, fy = 0;
       
   543     TInt weightFactor = 0;
       
   544     
       
   545     // Pointers to the source memory
       
   546     TUint8* srcRowPosition = 0;
       
   547     TUint8* srcPixelPosition = 0;
       
   548     
       
   549     // Calculate the scale factor using the max indices of the source and target images
       
   550     TReal scaleX = TReal(aSrcSize.iWidth - 1) / TReal(aTrgSize.iWidth - 1);
       
   551     TReal scaleY = TReal(aSrcSize.iHeight - 1) / TReal(aTrgSize.iHeight - 1);
       
   552     
       
   553     // Convert the scale factor to fixed point
       
   554     iScaleXInt = FP_FP(scaleX) - 1;     // subtract 1 so we don't go outside the source image
       
   555     iScaleYInt = FP_FP(scaleY) - 1;
       
   556         
       
   557     if ( aBlackBoxing.iWidth != 0 )
       
   558         {
       
   559         // increment target pointer over first 'pillar'
       
   560         iTrg += aBlackBoxing.iWidth;
       
   561         }
       
   562     else if ( aBlackBoxing.iHeight != 0 )
       
   563         {
       
   564         // increment target pointer over top letterboxed area
       
   565         iTrg += aTrgSize.iWidth * aBlackBoxing.iHeight;
       
   566         }
       
   567 
       
   568     // Loop target rows
       
   569     for( i = 0, y = 0; i < aTrgSize.iHeight; i++ )
       
   570         {
       
   571         // Calculate the row position of the source        
       
   572         srcRowPosition = iSrc + FP_INT(y) * aSrcSize.iWidth;
       
   573         
       
   574         fy = FP_FRAC(y);    // Fractational part of the row position
       
   575          
       
   576         // Loop target columns
       
   577         for( j = 0, x = 0; j < aTrgSize.iWidth; j++ )
       
   578             {
       
   579             // Calculate the pixel position in the source            
       
   580             srcPixelPosition = srcRowPosition + FP_INT(x);
       
   581             
       
   582             // Calculate the weight factor for blending
       
   583             fx = FP_FRAC(x); 
       
   584             weightFactor = FP_MUL(fx, fy);
       
   585             
       
   586             // Blend using the four nearest pixels
       
   587             *(iTrg) = FP_INT(
       
   588                 *(srcPixelPosition) * (weightFactor + FP_ONE - fx - fy) + 
       
   589                 *(srcPixelPosition + 1) * (fx - weightFactor) + 
       
   590                 *(srcPixelPosition + aSrcSize.iWidth) * (fy - weightFactor) +
       
   591                 *(srcPixelPosition + 1 + aSrcSize.iWidth) * weightFactor );
       
   592             
       
   593             iTrg++;             // Move on to the next target pixel
       
   594             x += iScaleXInt;    // Calculate the column for the next source pixel
       
   595             }
       
   596 
       
   597         y += iScaleYInt;        // Calculate the row for the next source pixels
       
   598         
       
   599         if ( aBlackBoxing.iWidth != 0 )
       
   600             {
       
   601             // increment target pointer over two pillars, one at the end of this row, 
       
   602             // other one at the beginning of the next row
       
   603             iTrg += aBlackBoxing.iWidth * 2;
       
   604             }
       
   605         }
       
   606 
       
   607     // Update pointers 
       
   608     iSrc += aSrcSize.iWidth * aSrcSize.iHeight;
       
   609     
       
   610     if ( aBlackBoxing.iWidth != 0 )
       
   611         {
       
   612         // subtract the width of one pillar
       
   613         iTrg -= aBlackBoxing.iWidth;
       
   614         }
       
   615     else if ( aBlackBoxing.iHeight != 0 )
       
   616         {
       
   617         // increment over bottom letterboxed area
       
   618         iTrg += aBlackBoxing.iHeight * aTrgSize.iWidth;
       
   619         }
       
   620         
       
   621     }
       
   622 
       
   623 // -----------------------------------------------------------------------------
       
   624 // CTRScaler::ResampleHalve()
       
   625 // Resamples an image to half size. For each target pixel a 2x2 pixel area is
       
   626 // read from the source and blended together to produce the target color.
       
   627 // -----------------------------------------------------------------------------
       
   628 //    
       
   629 void CTRScaler::ResampleHalve(TSize& aSrcSize, TSize& aTrgSize, TSize& aBlackBoxing)
       
   630     {
       
   631     TInt i = 0, j = 0;
       
   632     
       
   633     // Make sure the scale factor is correct
       
   634     VPASSERT( (aTrgSize.iWidth * 2 == aSrcSize.iWidth) &&
       
   635               (aTrgSize.iHeight * 2 == aSrcSize.iHeight) );
       
   636               
       
   637     if ( aBlackBoxing.iHeight != 0 )
       
   638         {
       
   639         // increment target pointer over top letterboxed area
       
   640         iTrg += aTrgSize.iWidth * aBlackBoxing.iHeight;
       
   641         }          
       
   642 
       
   643     // Loop target rows
       
   644     for( i = 0; i < aTrgSize.iHeight; i++ )
       
   645         {
       
   646         // Loop target columns    
       
   647         for( j = 0; j < aTrgSize.iWidth; j++ )
       
   648             {
       
   649             // Calculate the target pixel by blending the 4 nearest source pixels          
       
   650             *(iTrg) = (
       
   651                 *(iSrc) +
       
   652                 *(iSrc + 1) +
       
   653                 *(iSrc + aSrcSize.iWidth) +
       
   654                 *(iSrc + 1 + aSrcSize.iWidth)
       
   655                 ) >> 2;  // divide by 4
       
   656                 
       
   657             iTrg++;     // Move on to the next target pixel
       
   658             iSrc += 2;  // Sample every second column from the source
       
   659             }
       
   660             
       
   661         iSrc += aSrcSize.iWidth;    // Sample every second row from the source
       
   662         }
       
   663         
       
   664     if ( aBlackBoxing.iHeight != 0 )
       
   665         {
       
   666         // increment over bottom letterboxed area
       
   667         iTrg += aBlackBoxing.iHeight * aTrgSize.iWidth;
       
   668         }
       
   669     }
       
   670 
       
   671 // -----------------------------------------------------------------------------
       
   672 // CTRScaler::ResampleDouble()
       
   673 // Resamples an image to double size. A 2x2 pixel area is generated using
       
   674 // the four nearest pixels from the source and written to the target image.
       
   675 // -----------------------------------------------------------------------------
       
   676 //      
       
   677 void CTRScaler::ResampleDouble(TSize& aSrcSize, TSize& aTrgSize)
       
   678     {
       
   679     TInt i = 0, j = 0;
       
   680     
       
   681     // Make sure the scale factor is correct
       
   682     VPASSERT( (aTrgSize.iWidth == aSrcSize.iWidth * 2) &&
       
   683               (aTrgSize.iHeight == aSrcSize.iHeight * 2) );
       
   684 
       
   685     // Generate 2x2 target pixels in each loop
       
   686     
       
   687     // Loop every second target row
       
   688     for( i = 0; i < aTrgSize.iHeight - 2; i += 2 )
       
   689         {
       
   690         // Loop every second target column      
       
   691         for( j = 0; j < aTrgSize.iWidth - 2; j += 2 )
       
   692             {
       
   693             // Top-left pixel: Copy as it is
       
   694             *(iTrg) = *(iSrc);
       
   695             
       
   696             // Top-right pixel: Blend the pixels on the left and right
       
   697             *(iTrg + 1) = (*(iSrc) + *(iSrc + 1)) >> 1; 
       
   698              
       
   699             // Bottom-left pixel: Blend the above and below pixels
       
   700             *(iTrg + aTrgSize.iWidth) = (*(iSrc) + *(iSrc + aSrcSize.iWidth)) >> 1;
       
   701                
       
   702             // Bottom-right pixel: Blend the four nearest pixels
       
   703             *(iTrg + 1 + aTrgSize.iWidth) = (
       
   704                 *(iSrc) +
       
   705                 *(iSrc + 1) +
       
   706                 *(iSrc + aSrcSize.iWidth) +
       
   707                 *(iSrc + 1 + aSrcSize.iWidth)
       
   708                 ) >> 2;
       
   709                 
       
   710             iTrg += 2;      // Move on to the next 2x2 group of pixels
       
   711             iSrc++;         // Sample the next pixel from source       
       
   712             }
       
   713             
       
   714         // The last 2x2 pixels on this row need to be handled separately
       
   715         
       
   716         // Top-left and top-right pixels: Copy as it is
       
   717         *(iTrg) = *(iTrg + 1) = *(iSrc);
       
   718         
       
   719         // Bottom-left and bottom-right pixels: Blend the above and below pixels
       
   720         *(iTrg + aTrgSize.iWidth) = *(iTrg + 1 + aTrgSize.iWidth) = (
       
   721             *(iSrc) +
       
   722             *(iSrc + aSrcSize.iWidth)
       
   723             ) >> 1;
       
   724             
       
   725         iTrg += 2 + aTrgSize.iWidth;        // Move on to the beginning of the next row
       
   726         iSrc++;                             // Sample the next pixel from source   
       
   727         }
       
   728         
       
   729     // Handle the last row    
       
   730     for( j = 0; j < aTrgSize.iWidth - 2; j += 2 )
       
   731         {
       
   732         // Top-left and bottom-left pixels: Copy as it is
       
   733         *(iTrg) = *(iTrg + aTrgSize.iWidth) = *(iSrc);
       
   734         
       
   735         // Top-right and bottom-right pixels: Blend the pixels on the left and right
       
   736         *(iTrg + 1) = *(iTrg + 1 + aTrgSize.iWidth) = (
       
   737             *(iSrc) +
       
   738             *(iSrc + 1)
       
   739             ) >> 1;
       
   740             
       
   741         iTrg += 2;      // Move on to the next 2x2 group of pixels
       
   742         iSrc++;         // Sample the next pixel from source               
       
   743         }
       
   744     
       
   745     // Handle the last 2x2 group of pixels  
       
   746     
       
   747     // Copy all four pixels
       
   748     *(iTrg) = *(iTrg + 1) = *(iTrg + aTrgSize.iWidth) = *(iTrg + 1 + aTrgSize.iWidth) = *(iSrc);
       
   749     
       
   750     // Update pointers to the beginning of the next image
       
   751     iTrg += 2 + aTrgSize.iWidth;
       
   752     iSrc++;
       
   753     }
       
   754 
       
   755 // -----------------------------------------------------------------------------
       
   756 // CTRScaler::EstimateResampleFrameTime
       
   757 // Returns a time estimate of how long it takes to resample a frame
       
   758 // (other items were commented in a header).
       
   759 // -----------------------------------------------------------------------------
       
   760 //    
       
   761 TReal CTRScaler::EstimateResampleFrameTime(const TTRVideoFormat& aInput, const TTRVideoFormat& aOutput)
       
   762     {
       
   763     // Assume bilinear filtering is used by default
       
   764     TReal time = KTRResampleTimeFactorBilinear;
       
   765     
       
   766     if ( (aOutput.iSize.iWidth == aInput.iSize.iWidth) && (aOutput.iSize.iHeight == aInput.iSize.iHeight) )
       
   767         {
       
   768         // No need for resampling
       
   769         return 0.0;
       
   770         }
       
   771     else if ( (aOutput.iSize.iWidth == aInput.iSize.iWidth * 2) && (aOutput.iSize.iHeight == aInput.iSize.iHeight * 2) )
       
   772         {
       
   773         // Resolution is doubled
       
   774         time = KTRResampleTimeFactorDouble;
       
   775         }
       
   776     else if ( (aOutput.iSize.iWidth * 2 == aInput.iSize.iWidth) && (aOutput.iSize.iHeight * 2 == aInput.iSize.iHeight) )
       
   777         {
       
   778         // Resolution is halved
       
   779         time = KTRResampleTimeFactorHalve;
       
   780         }
       
   781     
       
   782     // Multiply the time by the resolution of the output frame
       
   783     time *= static_cast<TReal>(aOutput.iSize.iWidth + aOutput.iSize.iHeight) * KTRTimeFactorScale;
       
   784     
       
   785     PRINT((_L("CTRScaler::EstimateResampleFrameTime(), resample frame time: %.2f"), time))
       
   786     
       
   787     return time;
       
   788     }
       
   789 
       
   790 
       
   791 // End of file