mmplugins/imagingplugins/codecs/JPEGCodec/jpegwritecodec.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 #include <e32base.h>
       
    21 #include "icl/ImageCodec.h"
       
    22 
       
    23 #include "JpegTypes.h"
       
    24 #include "rgbbufferptr.h"
       
    25 #include "jpgimageframeprocessor.h"
       
    26 
       
    27 #include "jpegwritecodec.h"
       
    28 
       
    29 const TInt KDataUnitSafeBufferSz = sizeof(TDataUnit) + ( sizeof(TDataUnit) >> 1 ); // sizeof(TDataUnit) * 1.5
       
    30 
       
    31 // Encoder tables.
       
    32 static const TUint8 KLuminanceQTableValues[] = {
       
    33 	16,  11,  12,  14,  12,  10,  16,  14,
       
    34 	13,  14,  18,  17,  16,  19,  24,  40,
       
    35 	26,  24,  22,  22,  24,  49,  35,  37,
       
    36 	29,  40,  58,  51,  61,  60,  57,  51,
       
    37 	56,  55,  64,  72,  92,  78,  64,  68,
       
    38 	87,  69,  55,  56,  80,  109, 81,  87,
       
    39 	95,  98,  103, 104, 103, 62,  77,  113,
       
    40 	121, 112, 100, 120, 92,  101, 103, 99 };
       
    41 
       
    42 static const TUint8 KChrominanceQTableValues[] = {
       
    43 	17,  18,  18,  24,  21,  24,  47,  26,
       
    44 	26,  47,  99,  66,  56,  66,  99,  99,
       
    45 	99,  99,  99,  99,  99,  99,  99,  99,
       
    46 	99,  99,  99,  99,  99,  99,  99,  99,
       
    47 	99,  99,  99,  99,  99,  99,  99,  99,
       
    48 	99,  99,  99,  99,  99,  99,  99,  99,
       
    49 	99,  99,  99,  99,  99,  99,  99,  99,
       
    50 	99,  99,  99,  99,  99,  99,  99,  99 };
       
    51 
       
    52 static const TUint8 KLuminanceDCHuffmanValues[] = {
       
    53 // Number of codes per bit-length
       
    54 //  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 
       
    55 	0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
       
    56 // source byte definitions
       
    57 	0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11 };
       
    58 
       
    59 
       
    60 
       
    61 static const TUint8 KChrominanceDCHuffmanValues[] = {
       
    62 // Number of codes per bit-length
       
    63 //  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 
       
    64 	0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
       
    65 // source byte definitions
       
    66 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
       
    67 
       
    68 
       
    69 
       
    70 static const TUint8 KLuminanceACHuffmanValues[] = {
       
    71 // Number of codes per bit-length
       
    72 //  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 
       
    73 	0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d,
       
    74 	0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
       
    75 	0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
       
    76 	0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
       
    77 	0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
       
    78 	0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
       
    79 	0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
       
    80 	0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
       
    81 	0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
       
    82 	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
       
    83 	0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
       
    84 	0xf9, 0xfa };
       
    85 	
       
    86 static const TUint8 KChrominanceACHuffmanValues[] = {
       
    87     // Number of codes per bit-length
       
    88 	0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77,
       
    89 	// Code value definitions
       
    90 	0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
       
    91 	0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
       
    92 	0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
       
    93 	0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
       
    94 	0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
       
    95 	0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
       
    96 	0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
       
    97 	0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
       
    98 	0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
       
    99 	0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
       
   100 	0xf9, 0xfa };
       
   101 
       
   102 #if defined(PROFILE_JPEG_ENCODER)
       
   103 
       
   104 #define PROFILE_START(a)\
       
   105 			TUint a##_Start=User::FastCounter();
       
   106 			
       
   107 #define PROFILE_END(aa) aa += User::FastCounter() - aa##_Start;
       
   108 
       
   109 #define PROFILE_MARK(aa) aa = User::FastCounter() - aa;			
       
   110 			
       
   111 #define PROFILE_REPORT(a)\
       
   112 		RDebug::Printf("--Profile: %s\t%d",#a, a);
       
   113 #else
       
   114 
       
   115 #define PROFILE_START(a)
       
   116 #define PROFILE_END(a)
       
   117 #define PROFILE_REPORT(a)
       
   118 #define PROFILE_MARK(a)
       
   119 #endif
       
   120 
       
   121 
       
   122 // CJpegWriteCodec
       
   123 CJpgWriteCodec::CJpgWriteCodec(const TJpgFrameInfo& aFrameInfo,TInt aQualityFactor,TQTable* aReplacementLumaQTable,TQTable* aReplacementChromaQTable,const RPointerArray<HBufC8>& aComment)
       
   124 	: iQualityFactor(aQualityFactor), iReplacementLumaQTable(aReplacementLumaQTable), iReplacementChromaQTable(aReplacementChromaQTable), iFrameInfo(aFrameInfo), iComment(aComment)
       
   125 	{
       
   126 	iWrittingDUIdx = KJpgMaxNumOfDataUnits;
       
   127 // check that CJpgWriteCodec::TSpecialDataUnit has the right size, as we rely on that
       
   128 // if it doesn't throw a compile-time error
       
   129     ASSERT( ( _FOFF(CJpgWriteCodec::TSpecialDataUnit,iExtraElement) == sizeof(TDataUnit) ) );
       
   130 	}
       
   131 
       
   132 CJpgWriteCodec::~CJpgWriteCodec()
       
   133 	{
       
   134 	iOperationsRequested.Close();
       
   135 	delete iRgbInputBuffer;
       
   136 	delete iDataUnitProcessor;
       
   137 	delete iImageFrameCodecPtr;
       
   138 	}
       
   139 
       
   140 CJpgWriteCodec* CJpgWriteCodec::NewL(const TJpgFrameInfo& aFrameInfo,TInt aQualityFactor,TQTable* aReplacementLumaQTable,TQTable* aReplacementChromaQTable,const RPointerArray<HBufC8>& aComment,RArray<TUint>* aOperationsRequested)
       
   141 	{
       
   142 	CJpgWriteCodec* self = new(ELeave) CJpgWriteCodec(aFrameInfo, aQualityFactor, aReplacementLumaQTable, aReplacementChromaQTable, aComment);
       
   143 	CleanupStack::PushL(self);
       
   144 	self->ConstructL(aOperationsRequested);
       
   145 	CleanupStack::Pop(self); 
       
   146 	return self;
       
   147 	}
       
   148 
       
   149 void CJpgWriteCodec::ConstructL(RArray<TUint>* aOperationsRequested)
       
   150 	{
       
   151 	if(!aOperationsRequested)
       
   152 		{
       
   153 		iOperationsRequested.Reset();		
       
   154 		}
       
   155 	else
       
   156 		{
       
   157 		TInt count = aOperationsRequested->Count();
       
   158 		for (TInt i = 0; i<count; i++)
       
   159 			{
       
   160 			iOperationsRequested.AppendL((*aOperationsRequested)[i]);
       
   161 			}						
       
   162 		}
       
   163 	}
       
   164 
       
   165 void CJpgWriteCodec::SetHighSpeedMode(TBool aHighSpeedMode)
       
   166 	{
       
   167 	iHighSpeedMode = aHighSpeedMode;
       
   168 	}
       
   169 
       
   170 TFrameState CJpgWriteCodec::ProcessFrameL(TBufPtr8& aDst)
       
   171 	{
       
   172 	
       
   173 	TFrameState state;	
       
   174 	TUint8* destStartPtr = const_cast<TUint8*>(aDst.Ptr());
       
   175 	iDestPtr = destStartPtr;
       
   176 	iDestPtrLimit = iDestPtr + aDst.MaxLength() - sizeof(iBitBuffer) * 2; // Subtract four to give a safety buffer
       
   177 			
       
   178 	if(iStreamConfig.iIsFrameComplete)
       
   179 		{
       
   180 		CompleteFrame();
       
   181 		aDst.SetLength(iDestPtr - destStartPtr);
       
   182 		state = EFrameComplete;
       
   183 		if(iStreamConfig.iNumOfMCUsProcessed < ((iFrameInfo.iSizeInPixels.iWidth * iFrameInfo.iSizeInPixels.iHeight) / (iMCUSizeInPixels.iWidth * iMCUSizeInPixels.iHeight)))		
       
   184 			{
       
   185 			User::Leave(KErrUnderflow);
       
   186 			}
       
   187 		return state;
       
   188 		}
       
   189 	
       
   190 	TRAPD(err,DoProcessL());	
       
   191 
       
   192 	if (err != KErrNone)
       
   193 		{
       
   194 		if (err != KErrCompletion)
       
   195 		    {
       
   196 		    User::Leave(err);
       
   197 		    }
       
   198 		}
       
   199 
       
   200 	state = EFrameIncomplete;
       
   201 
       
   202 	if(iIsBlockStreaming)
       
   203 		{
       
   204 		if (iPosProcessor.IsEndOfImage())
       
   205 			{
       
   206 			state = EBlockComplete;
       
   207 			}		
       
   208 		}
       
   209 	else
       
   210 		{
       
   211 		if (iPosProcessor.IsEndOfImage())
       
   212 			{
       
   213 			CompleteFrame();
       
   214 			state = EFrameComplete;
       
   215 			}
       
   216 		}
       
   217 	
       
   218     aDst.SetLength(iDestPtr - destStartPtr);		
       
   219 	return state;
       
   220 	}
       
   221 
       
   222 void CJpgWriteCodec::SetCompleteFrame()
       
   223 	{
       
   224 	iStreamConfig.iIsFrameComplete = ETrue;
       
   225 	}
       
   226 	
       
   227 void CJpgWriteCodec::CompleteFrame()
       
   228 	{
       
   229 	
       
   230 	if (iBitsUsed >= 8)
       
   231 	    {
       
   232 	    do 
       
   233 			{
       
   234 			TUint8 byte = (TUint8)(iBitBuffer >> 24);
       
   235 			iBitBuffer <<= 8;
       
   236         
       
   237 			*iDestPtr++ = byte;
       
   238 			if (byte == 0xff)
       
   239 				{
       
   240 				*iDestPtr++ = 0;
       
   241 				}
       
   242         
       
   243 			iBitsUsed   -= 8;
       
   244 			} while (iBitsUsed >= 8);
       
   245 	    }
       
   246 
       
   247 	if (iBitsUsed > 0)
       
   248 	    {
       
   249 	    iDestPtr[0] = TUint8( iBitBuffer >> 24 );
       
   250 	    ++iDestPtr;
       
   251 	    }
       
   252 	
       
   253 	PROFILE_MARK(iOverallTime);
       
   254 	PROFILE_REPORT(iGetPixelsTime);
       
   255 	PROFILE_REPORT(iImageFrameTime);
       
   256 	PROFILE_REPORT(iDataUnitProcessTime);
       
   257 	PROFILE_REPORT(iTransforTime);
       
   258 	PROFILE_REPORT(iQuantizeTime);
       
   259 	PROFILE_REPORT(iWriteDataUnitTime);
       
   260 	PROFILE_REPORT(iOverallTime);
       
   261 	}
       
   262 
       
   263 #if defined(__ARMCC__)
       
   264 #pragma push
       
   265 #pragma thumb
       
   266 #endif
       
   267 
       
   268 //Bitmap encoding	
       
   269 void CJpgWriteCodec::InitFrameL(TBufPtr8& aDst, const CFbsBitmap& aSource)
       
   270 	{
       
   271 	PROFILE_MARK(iOverallTime);
       
   272 
       
   273 	TUint8* destStartPtr = const_cast<TUint8*>(aDst.Ptr());
       
   274 	iDestPtr = destStartPtr;
       
   275 	iDestPtrLimit = iDestPtr + aDst.MaxLength();
       
   276 
       
   277 	SetSource(&aSource);
       
   278 
       
   279 	iSourceRect = TRect(aSource.SizeInPixels());
       
   280 	iPos.SetXY(0,0);
       
   281 
       
   282 	iFrameInfo.iSizeInPixels = iSourceRect.Size();
       
   283 	iMCUSizeInPixels.SetSize(iFrameInfo.iMaxHorzSampleFactor,iFrameInfo.iMaxVertSampleFactor);
       
   284 	iMCUSizeInPixels.iWidth     *= KJpgDCTBlockWidth;
       
   285 	iMCUSizeInPixels.iHeight    *= KJpgDCTBlockWidth;
       
   286 	
       
   287 	delete iRgbInputBuffer; 
       
   288 	iRgbInputBuffer = NULL;
       
   289 	iRgbInputBuffer = CRgbBufferPtr::NewL(const_cast<CFbsBitmap&>(aSource), iMCUSizeInPixels);
       
   290 	
       
   291     if (iFrameInfo.iNumberOfComponents == 1)
       
   292         {
       
   293         iDataUnitCount = 1;
       
   294         }
       
   295 	else
       
   296 		{
       
   297 		iDataUnitCount = 0;
       
   298 		for (TInt index = 0; index < iFrameInfo.iNumberOfComponents; index++)
       
   299 			{
       
   300 			TJpgFrameInfo::TComponentInfo& component = iFrameInfo.iComponent[index];
       
   301 			iDataUnitCount += component.iHorzSampleFactor * component.iVertSampleFactor;
       
   302 			}
       
   303 		}
       
   304 		
       
   305     ASSERT( iDataUnitCount <= KJpgMaxNumOfDataUnits );
       
   306 
       
   307 	switch (iDataUnitCount)
       
   308 		{
       
   309 	case KJpgMonochromeDataUnitCount: // Monochrome
       
   310 		iDataUnitProcessor = new(ELeave) TMonoProcessor;
       
   311 		break;
       
   312 	case KJpgEColor444DataUnitCount: // 4:4:4
       
   313 		iDataUnitProcessor = new(ELeave) T444Processor;
       
   314 		break;
       
   315 	case KJpgColor422DataUnitCount: // 4:2:2
       
   316 		iDataUnitProcessor = new(ELeave) T422Processor;
       
   317 		break;
       
   318 	case KJpgColor420DataUnitCount: // 4:2:0
       
   319 		iDataUnitProcessor = new(ELeave) T420Processor;
       
   320 		break;
       
   321 	default:
       
   322 		User::Leave(KErrNotSupported);
       
   323 		}
       
   324 		
       
   325     iDataUnitProcessor->SetBufferPtrUtil( *iRgbInputBuffer );
       
   326     
       
   327     InitTransformationL(iPosProcessor, iSourceRect, iMCUSizeInPixels, iFrameInfo, iDataUnitCount);
       
   328        
       
   329     CodecInfoL();
       
   330     InitCompConfig();
       
   331     
       
   332 	aDst.SetLength(iDestPtr - destStartPtr);
       
   333 	}
       
   334 
       
   335 //ImageFrame encoding
       
   336 void CJpgWriteCodec::InitFrameL(TBufPtr8& aDst, const CImageFrame* aFrame, const CFrameImageData* aFrameImageData)
       
   337 	{
       
   338 	TUint8* destStartPtr = const_cast<TUint8*>(aDst.Ptr());
       
   339 	iDestPtr = destStartPtr;
       
   340 	iDestPtrLimit = iDestPtr + aDst.MaxLength();
       
   341 
       
   342 	iSourceRect = TRect(aFrame->FrameSizeInPixels());
       
   343 	iPos.SetXY(0,0);
       
   344 
       
   345 	iFrameInfo.iSizeInPixels = iSourceRect.Size();
       
   346 	
       
   347 	// Create JPEG write codec extension and the appropriate image processor
       
   348 	ASSERT( iImageFrameCodecPtr == NULL );
       
   349 	delete iImageFrameCodecPtr;
       
   350 	iImageFrameCodecPtr = NULL;
       
   351 	iImageFrameCodecPtr = CJpgImageFrameWriteCodec::NewL(aFrame);
       
   352 	iImageFrameCodecPtr->PrepareFrameInfoL(iFrameInfo, aFrameImageData);
       
   353 	iImageFrameCodecPtr->CreateImageProcessorL();
       
   354 
       
   355 	iDataUnitCount = iImageFrameCodecPtr->DataUnitCount();
       
   356 	
       
   357 	iMCUSizeInPixels.SetSize(iFrameInfo.iMaxHorzSampleFactor, iFrameInfo.iMaxVertSampleFactor);
       
   358 	iMCUSizeInPixels.iWidth     *= KJpgDCTBlockWidth;
       
   359 	iMCUSizeInPixels.iHeight    *= KJpgDCTBlockWidth;
       
   360 	
       
   361 	InitTransformationL(iPosProcessor, iSourceRect, iMCUSizeInPixels, iFrameInfo, iDataUnitCount);
       
   362 	
       
   363 	CodecInfoL();
       
   364 	InitCompConfig();
       
   365 	
       
   366 	aDst.SetLength(iDestPtr - destStartPtr);	
       
   367 	}
       
   368 
       
   369 //ImageFrame stream encoding
       
   370 void CJpgWriteCodec::InitFrameL(TBufPtr8& aDst, TUid aFormat, TInt aFrameNumber, const TSize& aFrameSizeInPixels, const TSize& aBlockSizeInPixels, const CFrameImageData* aFrameImageData)
       
   371 	{
       
   372 	TUint8* destStartPtr = const_cast<TUint8*>(aDst.Ptr());
       
   373 	iDestPtr = destStartPtr;
       
   374 	iDestPtrLimit = iDestPtr + aDst.MaxLength();
       
   375 
       
   376 	iSourceRect = TRect(aFrameSizeInPixels);
       
   377 	iPos.SetXY(0,0);
       
   378 
       
   379 	iFrameInfo.iSizeInPixels = iSourceRect.Size();
       
   380 	
       
   381 	// Create JPEG write codec extension and the appropriate image processor
       
   382 	ASSERT( iImageFrameCodecPtr == NULL );
       
   383 	delete iImageFrameCodecPtr;
       
   384 	iImageFrameCodecPtr = NULL;
       
   385 	iImageFrameCodecPtr = CJpgImageFrameWriteCodec::NewL(NULL);
       
   386 	iImageFrameCodecPtr->PrepareFrameImageDataInfoL(iFrameInfo, aFormat, aFrameNumber, aFrameImageData);
       
   387 	
       
   388 	iDataUnitCount = iImageFrameCodecPtr->DataUnitCount();
       
   389 
       
   390 	iMCUSizeInPixels.SetSize(iFrameInfo.iMaxHorzSampleFactor, iFrameInfo.iMaxVertSampleFactor);
       
   391 	iMCUSizeInPixels.iWidth     *= KJpgDCTBlockWidth;
       
   392 	iMCUSizeInPixels.iHeight    *= KJpgDCTBlockWidth;
       
   393 		
       
   394 	InitTransformationL(iPosProcessor, TRect(aBlockSizeInPixels), iMCUSizeInPixels, iFrameInfo, iDataUnitCount);
       
   395 	
       
   396 	iIsBlockStreaming = ETrue;
       
   397 	iStreamConfig.iIsFrameComplete = EFalse;
       
   398 	
       
   399 	CodecInfoL();
       
   400 	InitCompConfig();
       
   401 	
       
   402 	aDst.SetLength(iDestPtr - destStartPtr);	
       
   403 	}
       
   404 
       
   405 void CJpgWriteCodec::AppendFrameBlockL(const CImageFrame& aBlocks, TInt aNumBlocksToAdd)
       
   406 	{	
       
   407 	ValidateBlockSizeL(aBlocks.FrameSizeInPixels(), iMCUSizeInPixels);
       
   408 	
       
   409 	if (aBlocks.FrameSizeInPixels().iHeight != iMCUSizeInPixels.iHeight)
       
   410 		{
       
   411 		User::Leave(KErrNotSupported);
       
   412 		}
       
   413 	
       
   414 	iStreamConfig.iNumOfBlocksToAppend = aNumBlocksToAdd;
       
   415 	iStreamConfig.iNumOfBlocksAppended = 0;
       
   416 	
       
   417 	iImageFrameCodecPtr->AppendImageFrameBlockL(&aBlocks);
       
   418 	
       
   419 	InitTransformationL(iPosProcessor, TRect(aBlocks.FrameSizeInPixels()), iMCUSizeInPixels, iFrameInfo, iDataUnitCount);
       
   420 	}
       
   421 
       
   422 //validates the stream blocks passed and checks that the height is equal to the mcu height.
       
   423 void CJpgWriteCodec::ValidateBlockSizeL(const TSize& aBlockSizeInPixels, const TSize& aRefSizeInPixels)
       
   424 	{
       
   425 	TInt oddPixelsWidth = aBlockSizeInPixels.iWidth % aRefSizeInPixels.iWidth;
       
   426 	TInt oddPixelsHeight = aBlockSizeInPixels.iHeight % aRefSizeInPixels.iHeight;	
       
   427 	
       
   428 	if (oddPixelsWidth != 0 || oddPixelsHeight != 0)
       
   429 		{
       
   430 		User::Leave(KErrNotSupported);
       
   431 		}
       
   432 	}
       
   433 
       
   434 void CJpgWriteCodec::InitTransformationL(TPositionProcessor& aPosProcessor, const TRect& aSourceRect, const TSize& aMCUSize, TJpgFrameInfo& aFrameInfo, const TInt aDataUnitCount)
       
   435 	{
       
   436     InitTransformCoordinates(aPosProcessor, aSourceRect, aMCUSize, iOperationsRequested);
       
   437     
       
   438     InitTransformDataUnitIndex(aDataUnitCount);
       
   439     
       
   440 	if(aPosProcessor.IsTransformNeeded())
       
   441 		{
       
   442 		ValidateBlockSizeL(aFrameInfo.iSizeInPixels, aMCUSize);
       
   443 		
       
   444 		if(aPosProcessor.SwapDimensions())
       
   445 		    {
       
   446 		    TInt tempDimention;
       
   447 			tempDimention = aFrameInfo.iSizeInPixels.iHeight; 
       
   448 			aFrameInfo.iSizeInPixels.iHeight = aFrameInfo.iSizeInPixels.iWidth; // Y
       
   449 			aFrameInfo.iSizeInPixels.iWidth = tempDimention; // X
       
   450 			
       
   451 			if(aDataUnitCount == KJpgColor422DataUnitCount)
       
   452 				{
       
   453 				tempDimention = aFrameInfo.iComponent[0].iHorzSampleFactor;
       
   454 				aFrameInfo.iComponent[0].iHorzSampleFactor = aFrameInfo.iComponent[0].iVertSampleFactor;
       
   455 				aFrameInfo.iComponent[0].iVertSampleFactor = tempDimention;			
       
   456 				}				
       
   457 		    }		
       
   458 		}
       
   459 	
       
   460 	InitTransformDataUnitCoeff(iTransformDUCoeffIdx);	
       
   461 	}
       
   462 
       
   463 
       
   464 void CJpgWriteCodec::InitCompConfig()
       
   465     {
       
   466 	iCompConfig[ KYComp ].iFirstDUIdx = 0;
       
   467 	
       
   468 	switch (iDataUnitCount)
       
   469 		{
       
   470 	case KJpgMonochromeDataUnitCount: // Monochrome
       
   471 		// in fact we don't have these comps for mono, so assign them last index
       
   472 		iCompConfig[ KUComp ].iFirstDUIdx = KJpgMaxNumOfDataUnits - 1;
       
   473 		iCompConfig[ KVComp ].iFirstDUIdx = KJpgMaxNumOfDataUnits - 1;		
       
   474 		break;
       
   475 	case KJpgEColor444DataUnitCount: // 4:4:4
       
   476 		iCompConfig[ KUComp ].iFirstDUIdx = 1;
       
   477 		iCompConfig[ KVComp ].iFirstDUIdx = 2;
       
   478 		break;
       
   479 	case KJpgColor422DataUnitCount: // 4:2:2
       
   480 		iCompConfig[ KUComp ].iFirstDUIdx = 2;
       
   481 		iCompConfig[ KVComp ].iFirstDUIdx = 3;		
       
   482 		break;
       
   483 	case KJpgColor420DataUnitCount: // 4:2:0
       
   484 		iCompConfig[ KUComp ].iFirstDUIdx = 4;
       
   485 		iCompConfig[ KVComp ].iFirstDUIdx = 5;				
       
   486 		break;
       
   487 	default:
       
   488 		ASSERT( EFalse ); // shan't happen
       
   489 		}
       
   490     
       
   491 	iCompConfig[ KYComp ].iDCPredictorIdx = KYComp;
       
   492 	iCompConfig[ KUComp ].iDCPredictorIdx = KUComp;
       
   493 	iCompConfig[ KVComp ].iDCPredictorIdx = KVComp;
       
   494 	
       
   495     TJpgFrameInfo::TComponentInfo& yComp    = iFrameInfo.iComponent[ KYComp ];
       
   496 	iCompConfig[ KYComp ].iDataUnitsCount     = yComp.iHorzSampleFactor * yComp.iVertSampleFactor;
       
   497 
       
   498 	if (iCompConfig[ KYComp ].iDataUnitsCount == 3)
       
   499 		{
       
   500 		TJpgFrameInfo::TComponentInfo& uComp = iFrameInfo.iComponent[ KUComp ];
       
   501 		iCompConfig[ KUComp ].iDataUnitsCount = uComp.iHorzSampleFactor * uComp.iVertSampleFactor;
       
   502 		
       
   503 		TJpgFrameInfo::TComponentInfo& vComp = iFrameInfo.iComponent[ KVComp ];
       
   504 		iCompConfig[ KVComp ].iDataUnitsCount = vComp.iHorzSampleFactor * vComp.iVertSampleFactor;
       
   505 		}
       
   506 	else
       
   507 	    {
       
   508 	    iCompConfig[ KVComp ].iDataUnitsCount = iCompConfig[ KUComp ].iDataUnitsCount = 0;
       
   509 	    }
       
   510 	    
       
   511 	iCompConfig[ KYComp ].iACTable = &iLumaACHuffmanTable;
       
   512 	iCompConfig[ KYComp ].iDCTable = &iLumaDCHuffmanTable;
       
   513 	
       
   514 	// we use the same tables for U and V comps
       
   515 	iCompConfig[ KUComp ].iACTable = &iChromaACHuffmanTable;
       
   516 	iCompConfig[ KUComp ].iDCTable = &iChromaDCHuffmanTable;
       
   517 
       
   518 	iCompConfig[ KVComp ].iACTable = &iChromaACHuffmanTable;
       
   519 	iCompConfig[ KVComp ].iDCTable = &iChromaDCHuffmanTable;
       
   520 	
       
   521 	iCompConfig[ KYComp ].iQTTable = &iLumaQTable;
       
   522 	// we use the same tables for U and V comps
       
   523 	iCompConfig[ KUComp ].iQTTable = &iChromaQTable;
       
   524 	iCompConfig[ KVComp ].iQTTable = &iChromaQTable;
       
   525 	
       
   526 	iBitsUsed = 0;
       
   527     iBitBuffer= 0;    
       
   528     }
       
   529 
       
   530 void CJpgWriteCodec::CodecInfoL()
       
   531 {
       
   532 	iDCT.SetPrecision(8);
       
   533 
       
   534 	if (iReplacementLumaQTable)
       
   535 		iLumaQTable = *iReplacementLumaQTable;
       
   536 	else
       
   537 		iLumaQTable.Set(KLuminanceQTableValues,EFalse);
       
   538 	iLumaQTable.SetQualityFactor(iQualityFactor);
       
   539 
       
   540 	const TUint8* dataPtr = KLuminanceDCHuffmanValues;
       
   541 	const TUint8* dataPtrLimit = dataPtr + sizeof(KLuminanceDCHuffmanValues);
       
   542 	iLumaDCHuffmanTable.SetL(dataPtr,dataPtrLimit);
       
   543 	iLumaDCHuffmanTable.MakeDerivedTableL();
       
   544 
       
   545 	dataPtr = KLuminanceACHuffmanValues;
       
   546 	dataPtrLimit = dataPtr + sizeof(KLuminanceACHuffmanValues);
       
   547 	iLumaACHuffmanTable.SetL(dataPtr,dataPtrLimit);
       
   548 	iLumaACHuffmanTable.MakeDerivedTableL();
       
   549 
       
   550 	if (iFrameInfo.iNumberOfComponents == 3)
       
   551 		{
       
   552 		if (iReplacementChromaQTable)
       
   553 			iChromaQTable = *iReplacementChromaQTable;
       
   554 		else
       
   555 			iChromaQTable.Set(KChrominanceQTableValues,EFalse);
       
   556 		iChromaQTable.SetQualityFactor(iQualityFactor);
       
   557 
       
   558 		dataPtr = KChrominanceDCHuffmanValues;
       
   559 		dataPtrLimit = dataPtr + sizeof(KChrominanceDCHuffmanValues);
       
   560 		iChromaDCHuffmanTable.SetL(dataPtr,dataPtrLimit);
       
   561 		iChromaDCHuffmanTable.MakeDerivedTableL();
       
   562 
       
   563 		dataPtr = KChrominanceACHuffmanValues;
       
   564 		dataPtrLimit = dataPtr + sizeof(KChrominanceACHuffmanValues);
       
   565 		iChromaACHuffmanTable.SetL(dataPtr,dataPtrLimit);
       
   566 		iChromaACHuffmanTable.MakeDerivedTableL();
       
   567 		}
       
   568 
       
   569 	iDCPredictor[0] = 0;
       
   570 	iDCPredictor[1] = 0;
       
   571 	iDCPredictor[2] = 0;
       
   572 
       
   573 	WriteInfoL();
       
   574 }
       
   575 
       
   576 void CJpgWriteCodec::WriteInfoL()
       
   577 	{
       
   578 	for (TInt index = 0; index < iComment.Count(); index++)
       
   579 		{
       
   580 		if (!iComment[index])
       
   581 			continue;
       
   582 
       
   583 		const TInt commentLength = iComment[index]->Length();
       
   584 		WriteBigEndianUint16(iDestPtr,KJpgCommentSignature);
       
   585 		WriteBigEndianUint16(iDestPtr,commentLength + 2);
       
   586 		Mem::Copy(iDestPtr,iComment[index]->Ptr(),commentLength);
       
   587 		iDestPtr += commentLength;
       
   588 		}
       
   589 
       
   590 
       
   591 	if (iFrameInfo.iNumberOfComponents == 1)
       
   592 		{
       
   593 		WriteBigEndianUint16(iDestPtr,KJpgDQTSignature); // Luminance quantization table
       
   594 		WriteBigEndianUint16(iDestPtr,3 + KJpgQTableEntries); // Lq
       
   595 		*iDestPtr++ = 0; // (Pq << 4) | Tq
       
   596 		iDestPtr += iLumaQTable.Get(iDestPtr); // Qk
       
   597 		}
       
   598 	else if (iFrameInfo.iNumberOfComponents == 3)
       
   599 		{
       
   600 		WriteBigEndianUint16(iDestPtr,KJpgDQTSignature); // Luminance and Chrominance quantization tables
       
   601 		WriteBigEndianUint16(iDestPtr,2 + ((KJpgQTableEntries + 1) * 2)); // Lq
       
   602 
       
   603 		*iDestPtr++ = 0; // (Pq << 4) | Tq
       
   604 		iDestPtr += iLumaQTable.Get(iDestPtr); // Qk
       
   605 
       
   606 		*iDestPtr++ = 1; // (Pq << 4) | Tq
       
   607 		iDestPtr += iChromaQTable.Get(iDestPtr); // Qk
       
   608 		}
       
   609 	else
       
   610 		User::Leave(KErrNotSupported);
       
   611 
       
   612 	WriteBigEndianUint16(iDestPtr,KJpgBaselineDCTSOFSignature); // Frame header
       
   613 	WriteBigEndianUint16(iDestPtr,8 + (3 * iFrameInfo.iNumberOfComponents)); // Lf
       
   614 	*iDestPtr++ = 8; // P
       
   615 	WriteBigEndianUint16(iDestPtr,iFrameInfo.iSizeInPixels.iHeight); // Y
       
   616 	WriteBigEndianUint16(iDestPtr,iFrameInfo.iSizeInPixels.iWidth); // X
       
   617 	*iDestPtr++ = TUint8(iFrameInfo.iNumberOfComponents); // Nf
       
   618 
       
   619 	if (iFrameInfo.iNumberOfComponents == 3)
       
   620 		{
       
   621 		for (TInt i = 0; i < iFrameInfo.iNumberOfComponents; i++)
       
   622 			{
       
   623 			*iDestPtr++ = TUint8(i + 1); // Ci
       
   624 			*iDestPtr++ = TUint8((iFrameInfo.iComponent[i].iHorzSampleFactor << 4) | iFrameInfo.iComponent[i].iVertSampleFactor);
       
   625 			*iDestPtr++ = TUint8((i == 0) ? 0 : 1); // Tqi
       
   626 			}
       
   627 		}
       
   628 	else
       
   629 		{
       
   630 		*iDestPtr++ = 1; // Ci
       
   631 		*iDestPtr++ = 0x11; // (Hi << 4) | Vi
       
   632 		*iDestPtr++ = 0; // Tqi
       
   633 		}
       
   634 
       
   635 	if (iFrameInfo.iNumberOfComponents == 1)
       
   636 		{
       
   637 		WriteBigEndianUint16(iDestPtr,KJpgDHTSignature); // Huffman table
       
   638  
       
   639  		TUint8* LhPtr = iDestPtr; // Remember Lh location
       
   640  		WriteBigEndianUint16(iDestPtr,0); // Dummy Lh value
       
   641  
       
   642  		*iDestPtr++ = 0x00; // (Tc << 4) | Th
       
   643  		const TInt lumaDCTableSize = iLumaDCHuffmanTable.GetL(iDestPtr);
       
   644  		iDestPtr += lumaDCTableSize;
       
   645 
       
   646 		*iDestPtr++ = 0x10; // (Tc << 4) | Th
       
   647  		const TInt lumaACTableSize = iLumaACHuffmanTable.GetL(iDestPtr);
       
   648  		iDestPtr += lumaACTableSize;
       
   649 
       
   650 		WriteBigEndianUint16(LhPtr,iDestPtr - LhPtr); // Real Lh value
       
   651 		}
       
   652 	else if (iFrameInfo.iNumberOfComponents == 3)
       
   653 		{
       
   654  		WriteBigEndianUint16(iDestPtr,KJpgDHTSignature); // Huffman tables
       
   655  
       
   656  		TUint8* LhPtr = iDestPtr; // Remember Lh location
       
   657  		WriteBigEndianUint16(iDestPtr,0); // Dummy Lh value
       
   658  
       
   659  		*iDestPtr++ = 0x00; // (Tc << 4) | Th
       
   660  		const TInt lumaDCTableSize = iLumaDCHuffmanTable.GetL(iDestPtr);
       
   661 		iDestPtr += lumaDCTableSize;
       
   662  
       
   663  		*iDestPtr++ = 0x10; // (Tc << 4) | Th
       
   664  		const TInt lumaACTableSize = iLumaACHuffmanTable.GetL(iDestPtr);
       
   665  		iDestPtr += lumaACTableSize;
       
   666  
       
   667    		*iDestPtr++ = 0x01; // (Tc << 4) | Th
       
   668  		const TInt chromaDCTableSize = iChromaDCHuffmanTable.GetL(iDestPtr);
       
   669  		iDestPtr += chromaDCTableSize;
       
   670 
       
   671    		*iDestPtr++ = 0x11; // (Tc << 4) | Th
       
   672  		const TInt chromaACTableSize = iChromaACHuffmanTable.GetL(iDestPtr);
       
   673  		iDestPtr += chromaACTableSize;
       
   674  
       
   675  		WriteBigEndianUint16(LhPtr,iDestPtr - LhPtr); // Real Lh value
       
   676 		}
       
   677 	else
       
   678 		{
       
   679  		User::Leave(KErrNotSupported);
       
   680 		}
       
   681 
       
   682 	WriteBigEndianUint16(iDestPtr,KJpgSOSSignature); // Scan header
       
   683 	WriteBigEndianUint16(iDestPtr,6 + (2 * iFrameInfo.iNumberOfComponents)); // Ls
       
   684 	*iDestPtr++ = TUint8(iFrameInfo.iNumberOfComponents); // Ns
       
   685 	for (TInt j = 0; j < iFrameInfo.iNumberOfComponents; j++)
       
   686 		{
       
   687 		*iDestPtr++ = TUint8(j + 1); // Csj
       
   688 		*iDestPtr++ = TUint8((j == 0) ? 0x00 : 0x11); // (Tdj << 4) | Taj
       
   689 		}
       
   690 	*iDestPtr++ = 0; // Ss
       
   691 	*iDestPtr++ = 63; // Se
       
   692 	*iDestPtr++ = 0; // (Ah << 4) | Al
       
   693 
       
   694 	*iDestPtr = 0; // Initialize first byte of scan data buffer
       
   695 	}
       
   696 
       
   697 #if defined(__ARMCC__)
       
   698 #pragma pop
       
   699 #endif
       
   700 
       
   701 void CJpgWriteCodec::DoProcessL()
       
   702 	{
       
   703 	ASSERT ( iDataUnitCount > 0 );
       
   704 	// only process a maximum of KMaxRgbBufferLines 
       
   705 	// y position is a multiple of iMCUSizeInPixels.iHeight due to the matrix
       
   706 	// way in which pixels are gathered [see GetPixels()].
       
   707 	// KMaxRgbBufferLines * iMCUSizeInPixels.iHeight = no of scanlines
       
   708 	
       
   709                                     // Maximum number of matrix lines to process in one process call
       
   710                                     // we have no limit for CImageFrame since it doesn't lock
       
   711                                     // FBs heap                                    
       
   712     
       
   713 	TComponentConfig* compCfg[KJpgMaxNumOfDataUnits];//no more then 10 data units is supported now
       
   714 	for (TInt dataUnit = 0; dataUnit < iDataUnitCount; ++dataUnit)
       
   715                 {
       
   716                 compCfg[dataUnit] = (dataUnit < iCompConfig[ KUComp ].iFirstDUIdx ? iCompConfig + KYComp:
       
   717                                                (dataUnit < iCompConfig[ KVComp ].iFirstDUIdx ?  iCompConfig + KUComp:
       
   718                                                                iCompConfig + KVComp)
       
   719                                             );
       
   720 				}
       
   721 	
       
   722 	
       
   723 	do
       
   724 		{		
       
   725 		if ( iWrittingDUIdx >= iDataUnitCount) // we have no blocks to write, so start from processing phase
       
   726 		    {
       
   727 		    
       
   728     		TDataUnit* dataUnitPtr = NULL;
       
   729     		
       
   730     		iPosProcessor.GetCurrentPosition(iPos);
       
   731     		
       
   732     		if 	(iImageFrameCodecPtr==NULL)
       
   733     			{
       
   734     			PROFILE_START(iGetPixelsTime);
       
   735     			// get destination scanline
       
   736     			CRgbBufferPtr::TConstRgbBufferPtr bufPtr = GetPixels(iPos);
       
   737     			PROFILE_END(iGetPixelsTime);
       
   738     			
       
   739     			PROFILE_START(iDataUnitProcessTime);
       
   740      			dataUnitPtr = iDataUnitProcessor->Process( bufPtr );
       
   741      			iRgbInputBuffer->UnlockBuffer();
       
   742      			PROFILE_END(iDataUnitProcessTime);
       
   743     			}
       
   744     		else
       
   745     			{
       
   746     			PROFILE_START(iImageFrameTime);
       
   747     			TPoint imageFramePos;
       
   748     			//set position before processing Image Frame Codec
       
   749     			if(iImageFrameCodecPtr->SamplingScheme() == KUidSamplingColor422)
       
   750 	    			{
       
   751 	    			imageFramePos = iPos;
       
   752 	    			//the code below makes it possible to navigate the image in the multiples of 2 blocks. To be removed if the image frame write codec navigate in the multiple of a block.
       
   753 	    			imageFramePos.iX = imageFramePos.iX * 2;
       
   754 	    			}
       
   755 	    		else
       
   756 		    		{
       
   757 	    			imageFramePos = iPos;		    			
       
   758 		    		}
       
   759 	    		iImageFrameCodecPtr->SetPosition(imageFramePos);
       
   760     			dataUnitPtr = iImageFrameCodecPtr->ProcessL();  			    			
       
   761     			PROFILE_END(iImageFrameTime);
       
   762     			if(iIsBlockStreaming)    			
       
   763 	    			{
       
   764 		    		iStreamConfig.iNumOfBlocksAppended++;
       
   765 		    		iStreamConfig.iNumOfMCUsProcessed++;	    			
       
   766 	    			if(iStreamConfig.iNumOfBlocksAppended >= iStreamConfig.iNumOfBlocksToAppend)
       
   767 		    			{
       
   768 		    			iPosProcessor.SetEndOfImage(ETrue);
       
   769 		    			}
       
   770 					
       
   771 					if(iStreamConfig.iNumOfMCUsProcessed > ((iFrameInfo.iSizeInPixels.iWidth * iFrameInfo.iSizeInPixels.iHeight) / (iMCUSizeInPixels.iWidth * iMCUSizeInPixels.iHeight)))
       
   772 						{
       
   773 						User::Leave(KErrOverflow);
       
   774 						}
       
   775 	    			}    				    			
       
   776     			}
       
   777             
       
   778             iWrittingDUIdx = 0;
       
   779             TDataUnit transformedDataUnitCoeff;
       
   780     		TDataUnit transformedDataUnit;
       
   781     		// here we create a special "data unit" and place a non-zero value at the end,
       
   782     		// as that is required by the WriteDataUnitL()
       
   783             TSpecialDataUnit* quantTarget = iQuantizeTarget;
       
   784 			
       
   785             for (TInt dataUnit = 0; dataUnit < iDataUnitCount; ++dataUnit)
       
   786                 {
       
   787                 PROFILE_START(iTransforTime);
       
   788 				if(iPosProcessor.IsTransformNeeded())
       
   789 					{
       
   790 					//Xform Coefficients in DU
       
   791 	    			TransformDataUnitCoeff(transformedDataUnitCoeff, dataUnitPtr[iTransformedDUIdx[dataUnit]]);
       
   792 					
       
   793 					//Xform DCT
       
   794 	    			iDCT.Transform(transformedDataUnit, transformedDataUnitCoeff, iHighSpeedMode);
       
   795 					}
       
   796 				else
       
   797 					{
       
   798 					//Xform DCT
       
   799 	    			iDCT.Transform(transformedDataUnit, dataUnitPtr[iTransformedDUIdx[dataUnit]], iHighSpeedMode);
       
   800 					}
       
   801 				PROFILE_END(iTransforTime);    			
       
   802     			
       
   803     			//Quantize
       
   804     			PROFILE_START(iQuantizeTime);
       
   805     			compCfg[dataUnit]->iQTTable->Quantize(*quantTarget, transformedDataUnit, iHighSpeedMode);
       
   806     			quantTarget->iExtraElement = KErrNotFound; // place a non-zero value at the end
       
   807     			quantTarget++;
       
   808     			PROFILE_END(iQuantizeTime);			
       
   809                 }
       
   810 		    }
       
   811 
       
   812 		TSpecialDataUnit* quantTarget = iQuantizeTarget;
       
   813 		
       
   814 		PROFILE_START(iWriteDataUnitTime);
       
   815 		/*  Coverity may report about overrun of array compCfg. This is false positive.  The value of iDataUnitCount is <= KJpgMaxNumOfDataUnits, 
       
   816 		so the array access is safe. */
       
   817 		for (; iWrittingDUIdx < iDataUnitCount; ++iWrittingDUIdx) 
       
   818 		    {
       
   819 			WriteDataUnitL( *(quantTarget + iWrittingDUIdx), *(compCfg[iWrittingDUIdx]->iDCTable), *(compCfg[iWrittingDUIdx]->iACTable), 
       
   820 			                                                   iDCPredictor[ compCfg[iWrittingDUIdx]->iDCPredictorIdx ]
       
   821                             );
       
   822 		    }
       
   823         PROFILE_END(iWriteDataUnitTime);		    
       
   824         iWrittingDUIdx = KJpgMaxNumOfDataUnits;
       
   825         
       
   826         iPosProcessor.MoveNext();
       
   827 		
       
   828 		} while(!iPosProcessor.IsEndOfImage());
       
   829 
       
   830 	}
       
   831    
       
   832 // CJpgImageFrameWriteCodec
       
   833 CJpgImageFrameWriteCodec::CJpgImageFrameWriteCodec(const CImageFrame* aFrame)
       
   834 	{
       
   835 	iSource = aFrame;
       
   836 	}
       
   837 
       
   838 CJpgImageFrameWriteCodec::~CJpgImageFrameWriteCodec()
       
   839 	{
       
   840 	delete iImageFrameProcessorPtr; 
       
   841 	}
       
   842 	
       
   843 CJpgImageFrameWriteCodec* CJpgImageFrameWriteCodec::NewL(const CImageFrame* aFrame)
       
   844 	{
       
   845 	CJpgImageFrameWriteCodec* self = new(ELeave) CJpgImageFrameWriteCodec(aFrame);
       
   846 	return self;
       
   847 	}
       
   848 
       
   849 void CJpgImageFrameWriteCodec::CreateImageProcessorL()
       
   850 	{	
       
   851 	iImageFrameProcessorPtr = CJpgImageFrameProcessorUtility::NewL(*(const_cast<CImageFrame*>(iSource)));	
       
   852 	}
       
   853 
       
   854 TInt CJpgImageFrameWriteCodec::DataUnitCount() const
       
   855     {
       
   856     ASSERT( iDataUnitCount > 0 );
       
   857     return iDataUnitCount;
       
   858     }
       
   859 
       
   860 TSize  CJpgImageFrameWriteCodec::ImageFrameSize() const
       
   861 	{
       
   862 	return iSource->FrameSizeInPixels();
       
   863 	}
       
   864 	
       
   865 TUid CJpgImageFrameWriteCodec::SamplingScheme() const
       
   866 	{
       
   867 	return iSampleScheme;		
       
   868 	}	
       
   869 
       
   870 void CJpgImageFrameWriteCodec::PrepareFrameInfoL(TJpgFrameInfo& aFrameInfo, const CFrameImageData* aFrameImageData)
       
   871 	{
       
   872 	// First, validate image frame
       
   873 	CImageFrame* aImageFrame = const_cast<CImageFrame*>(iSource);
       
   874 	CJpgImageFrameProcessorUtility::ValidateImageFrameL(*aImageFrame, ETrue);
       
   875 
       
   876 	// If CFrameImageData has been provided aFrameInfo contains some encoder
       
   877 	// parameters already. These need to be the same as the imageFrame parameters.
       
   878 	// Therefore, validate the image frame parameters against the frame image
       
   879 	// data provided by the application if any
       
   880 	TUid aSampling = static_cast<const TFrameFormat&>(iSource->FrameFormat()).Sampling();
       
   881 
       
   882 	TInt count = (aFrameImageData) ? aFrameImageData->ImageDataCount() : 0;
       
   883 
       
   884 	TBool samplingSchemeSet = EFalse;
       
   885 	// look for Frame Image Data
       
   886 	for (TInt index = 0 ; index<count ; index++)
       
   887 		{	
       
   888 		const TImageDataBlock& encoderData = *aFrameImageData->GetImageData(index);
       
   889 		if (encoderData.DataType() == KJPGImageDataUid)
       
   890 			{
       
   891 			const TJpegImageData& jpegImageData = static_cast<const TJpegImageData&>(encoderData);
       
   892 
       
   893 			TJpegImageData::TColorSampling sampleScheme = jpegImageData.iSampleScheme;
       
   894 			CJpgImageFrameProcessorUtility::ValidateFrameImageDataL(sampleScheme, *aImageFrame);
       
   895 			
       
   896         	switch (sampleScheme)
       
   897         		{
       
   898         		case TJpegImageData::EMonochrome:
       
   899         			iDataUnitCount = 1;
       
   900         			break;
       
   901         		case TJpegImageData::EColor420:
       
   902         		    iDataUnitCount = 6;
       
   903         			break;
       
   904         		case TJpegImageData::EColor422:
       
   905         		    iDataUnitCount = 4;
       
   906         			break;				
       
   907         		case TJpegImageData::EColor444:
       
   908         		    iDataUnitCount = 3;
       
   909         			break;					
       
   910         		default:
       
   911         		    iDataUnitCount = 0;
       
   912         			User::Leave(KErrNotSupported);	
       
   913         			break;	
       
   914         		};
       
   915         		
       
   916 			samplingSchemeSet = ETrue;
       
   917 			break;
       
   918 			}
       
   919 		}
       
   920 		
       
   921 	if (!samplingSchemeSet)
       
   922 		{
       
   923 		iSampleScheme = aSampling;
       
   924 		InitFrameCompInfoL(aFrameInfo);
       
   925 		}
       
   926 	}
       
   927 
       
   928 void CJpgImageFrameWriteCodec::Position(TPoint& aPos)
       
   929 	{
       
   930 	iImageFrameProcessorPtr->GetCurrentPosition(aPos);	
       
   931 	}
       
   932 
       
   933 void CJpgImageFrameWriteCodec::SetPosition(TPoint& aPos)
       
   934 	{
       
   935 	iImageFrameProcessorPtr->SetCurrentPosition(aPos);
       
   936 	}
       
   937 
       
   938 TDataUnit* CJpgImageFrameWriteCodec::ProcessL()
       
   939 	{
       
   940 	return (iImageFrameProcessorPtr->ReadBlockL());	
       
   941 	}
       
   942 
       
   943 
       
   944 // for streaming
       
   945 void CJpgImageFrameWriteCodec::AppendImageFrameBlockL(const CImageFrame* aFrame)
       
   946 	{
       
   947 	if(aFrame == NULL)
       
   948 		{
       
   949 		User::Leave(KErrNotSupported);
       
   950 		}
       
   951 	
       
   952 	iSource = aFrame;
       
   953 	
       
   954 	if(iImageFrameProcessorPtr)
       
   955 		{
       
   956 		delete iImageFrameProcessorPtr;
       
   957 		iImageFrameProcessorPtr = NULL;
       
   958 		}
       
   959 	
       
   960 	iImageFrameProcessorPtr = CJpgImageFrameProcessorUtility::NewL(*(const_cast<CImageFrame*>(iSource)));
       
   961 	
       
   962 	// First, validate image frame	
       
   963 	CImageFrame* aImageFrame = const_cast<CImageFrame*>(iSource);
       
   964 	CJpgImageFrameProcessorUtility::ValidateImageFrameL(*aImageFrame, ETrue);
       
   965 	CJpgImageFrameProcessorUtility::ValidateFrameImageDataL(GetColorSamplingL(iSampleScheme), *aImageFrame);
       
   966 	}
       
   967 
       
   968 TJpegImageData::TColorSampling CJpgImageFrameWriteCodec::GetColorSamplingL(TUid aFormat)
       
   969 	{
       
   970 	TJpegImageData::TColorSampling aColorSampling = TJpegImageData::EColor420;
       
   971 	switch (aFormat.iUid)
       
   972 		{
       
   973 		case KSamplingMonochromeUidValue:
       
   974 			aColorSampling = TJpegImageData::EMonochrome;
       
   975 			break;			
       
   976 		case KSamplingColor422UidValue:
       
   977 			aColorSampling = TJpegImageData::EColor422;
       
   978 			break;
       
   979 		case KSamplingColor420UidValue:
       
   980 			aColorSampling = TJpegImageData::EColor420;
       
   981 			break;
       
   982 		default:			
       
   983 			User::Leave(KErrNotSupported);
       
   984 		}
       
   985 	return aColorSampling;
       
   986 	}
       
   987 
       
   988 TUid CJpgImageFrameWriteCodec::GetSamplingSchemeL(TUid aFormat)
       
   989 	{
       
   990 	TUid samplingScheme = KUidSamplingColor420;
       
   991 	switch (aFormat.iUid)
       
   992 		{
       
   993 		case KFormatYUVMonochromeUidValue:
       
   994 			samplingScheme = KUidSamplingMonochrome;
       
   995 			break;			
       
   996 		case KFormatYUV422InterleavedUidValue:
       
   997 			samplingScheme = KUidSamplingColor422;
       
   998 			break;
       
   999 		case KFormatYUV420PlanarReversedUidValue:
       
  1000 		case KFormatYUV420PlanarUidValue:
       
  1001 			samplingScheme = KUidSamplingColor420;
       
  1002 			break;
       
  1003 		default:			
       
  1004 			User::Leave(KErrNotSupported);			
       
  1005 		}
       
  1006 	return samplingScheme;
       
  1007 	}
       
  1008 
       
  1009 void CJpgImageFrameWriteCodec::PrepareFrameImageDataInfoL(TJpgFrameInfo& aFrameInfo, TUid aFormat, TInt /*aFrameNumber*/, const CFrameImageData* /*aFrameImageData*/)
       
  1010 	{
       
  1011 	iSampleScheme = GetSamplingSchemeL(aFormat);
       
  1012 	InitFrameCompInfoL(aFrameInfo);
       
  1013 	}
       
  1014 
       
  1015 void CJpgImageFrameWriteCodec::InitFrameCompInfoL(TJpgFrameInfo& aFrameInfo)
       
  1016 	{
       
  1017 	aFrameInfo.iComponent[0].iQTable = 0;
       
  1018 	if (iSampleScheme == KUidSamplingMonochrome )
       
  1019 		{
       
  1020 		aFrameInfo.iNumberOfComponents = 1;
       
  1021 		aFrameInfo.iComponent[0].iHorzSampleFactor = 1;
       
  1022 		aFrameInfo.iComponent[0].iVertSampleFactor = 1;
       
  1023 		iDataUnitCount = 1;
       
  1024 		}
       
  1025 	else
       
  1026 		{
       
  1027 		aFrameInfo.iNumberOfComponents = 3;
       
  1028 		switch (iSampleScheme.iUid)
       
  1029 			{
       
  1030 			case KSamplingColor420UidValue:
       
  1031 				aFrameInfo.iComponent[0].iHorzSampleFactor = 2;
       
  1032 				aFrameInfo.iComponent[0].iVertSampleFactor = 2;
       
  1033 				aFrameInfo.iComponent[1].iVertSampleFactor = 1;
       
  1034 				aFrameInfo.iComponent[2].iVertSampleFactor = 1;
       
  1035 				iDataUnitCount = 6;
       
  1036 				break;
       
  1037 			case KSamplingColor422UidValue:
       
  1038 				aFrameInfo.iComponent[0].iHorzSampleFactor = 2;
       
  1039 				aFrameInfo.iComponent[0].iVertSampleFactor = 1;
       
  1040 				aFrameInfo.iComponent[1].iVertSampleFactor = 1;
       
  1041 				aFrameInfo.iComponent[2].iVertSampleFactor = 1;
       
  1042 				iDataUnitCount = 4;
       
  1043 				break;
       
  1044 			case KSamplingColor444UidValue:
       
  1045 				aFrameInfo.iComponent[0].iHorzSampleFactor = 1;
       
  1046 				aFrameInfo.iComponent[0].iVertSampleFactor = 1;
       
  1047 				aFrameInfo.iComponent[1].iVertSampleFactor = 1;
       
  1048 				aFrameInfo.iComponent[2].iVertSampleFactor = 1;
       
  1049 				iDataUnitCount = 3;
       
  1050 				break;
       
  1051 			default:
       
  1052 			    iDataUnitCount = 0;
       
  1053 				User::Leave(KErrNotSupported);
       
  1054 			}
       
  1055 
       
  1056 		aFrameInfo.iComponent[1].iHorzSampleFactor = 1;
       
  1057 		aFrameInfo.iComponent[1].iQTable = 1;
       
  1058 		aFrameInfo.iComponent[2].iHorzSampleFactor = 1;
       
  1059 		aFrameInfo.iComponent[2].iQTable = 1;
       
  1060 		}
       
  1061 		
       
  1062 	aFrameInfo.iMaxHorzSampleFactor = aFrameInfo.iComponent[0].iHorzSampleFactor;
       
  1063 	aFrameInfo.iMaxVertSampleFactor = aFrameInfo.iComponent[0].iVertSampleFactor;		
       
  1064 	}
       
  1065 
       
  1066 void CJpgWriteCodec::InitTransformCoordinates(TPositionProcessor& aPosProcessor, const TRect& aSourceRect, const TSize& aMCUSize, const RArray<TUint>& aOperationsRequested)
       
  1067 	{	
       
  1068     
       
  1069     aPosProcessor.SetDimensions(aSourceRect,aMCUSize);
       
  1070     
       
  1071 	TInt count = aOperationsRequested.Count();
       
  1072 	for (TInt i=0; i<count; i++)
       
  1073 		{
       
  1074 		switch(aOperationsRequested[i])
       
  1075 			{
       
  1076 			case KRotation90DegreesClockwise:
       
  1077 				{
       
  1078 				aPosProcessor.RotateCoordinates();
       
  1079 				break;						
       
  1080 				}
       
  1081 			case KRotation180DegreesClockwise:
       
  1082 				{
       
  1083 				aPosProcessor.RotateCoordinates();
       
  1084 				aPosProcessor.RotateCoordinates();
       
  1085 				break;						
       
  1086 				}
       
  1087 			case KRotation270DegreesClockwise:
       
  1088 				{
       
  1089 				aPosProcessor.RotateCoordinates();
       
  1090 				aPosProcessor.RotateCoordinates();
       
  1091 				aPosProcessor.RotateCoordinates();
       
  1092 				break;						
       
  1093 				}
       
  1094 			case KMirrorHorizontalAxis:
       
  1095 				{
       
  1096 				aPosProcessor.HorFlipCoordinates();
       
  1097 				break;						
       
  1098 				}
       
  1099 			case KMirrorVerticalAxis:
       
  1100 				{
       
  1101 				aPosProcessor.VerFlipCoordinates();
       
  1102 				break;						
       
  1103 				}
       
  1104 			default:
       
  1105 				ASSERT( EFalse );
       
  1106 			}
       
  1107 		}
       
  1108 	     
       
  1109     aPosProcessor.MoveFirst();
       
  1110 		 
       
  1111 	}
       
  1112 	
       
  1113 void CJpgWriteCodec::TransformDataUnitCoeff(TDataUnit& aDestination,const TDataUnit& aSource)
       
  1114 	{	
       
  1115 	const TDataUnit::TDataUnitElemType* srcPtr = aSource.iCoeff;
       
  1116 	TDataUnit::TDataUnitElemType* dstPtr = aDestination.iCoeff;	
       
  1117 	TUint8* idxCoeff = iTransformDUCoeffIdx;
       
  1118 	
       
  1119 	TInt count = 0;
       
  1120 	do
       
  1121 		{		
       
  1122 	    TUint32 fourIndeces = *(TUint32 *)(idxCoeff+count);
       
  1123 	    
       
  1124 	    dstPtr[count++] = srcPtr[fourIndeces & 0xFF];
       
  1125 	    fourIndeces >>= 8;
       
  1126 	    
       
  1127 	    dstPtr[count++] = srcPtr[fourIndeces & 0xFF];
       
  1128 	    fourIndeces >>= 8;
       
  1129 	    
       
  1130 	    dstPtr[count++] = srcPtr[fourIndeces & 0xFF];
       
  1131 	    fourIndeces >>= 8;
       
  1132 	    
       
  1133 	    dstPtr[count++] = srcPtr[fourIndeces];						
       
  1134 		} while (count < KJpgDCTBlockSize);
       
  1135 
       
  1136 	/*do
       
  1137 		{		
       
  1138 		dstPtr[count++] = srcPtr[*idxCoeff++];		
       
  1139 		} while (count < KJpgDCTBlockSize);*/
       
  1140 
       
  1141 	}
       
  1142 
       
  1143 void CJpgWriteCodec::InitTransformDataUnitCoeff(TUint8* aDestination) //TODO
       
  1144 	{
       
  1145 	TPositionProcessor posProcess;
       
  1146 	TPoint pos;	
       
  1147 		
       
  1148 	TUint8* dstPtr = aDestination;
       
  1149 	
       
  1150 	InitTransformCoordinates(posProcess, TRect(TPoint(0,0),TPoint(KJpgDCTBlockWidth, KJpgDCTBlockHeight)), TSize(KJpgPixelRatio, KJpgPixelRatio), iOperationsRequested);
       
  1151 	
       
  1152 	do
       
  1153 		{		
       
  1154 		posProcess.GetCurrentPosition(pos);
       
  1155 		TUint8 elementPos = ((pos.iY * KJpgDCTBlockWidth) + pos.iX);		
       
  1156 		*dstPtr++ = elementPos;
       
  1157 		posProcess.MoveNext();		
       
  1158 		} while (!posProcess.IsEndOfImage());		
       
  1159 	}
       
  1160 
       
  1161 void CJpgWriteCodec::InitTransformDataUnitIndex(TInt aDataUnitCount)
       
  1162 	{
       
  1163 	
       
  1164 	TUint8 tempTransformedDUIdx[KJpgMaxNumOfDataUnits];
       
  1165 	TPositionProcessor posProcess;
       
  1166 	TPoint pos;	
       
  1167 	
       
  1168 	TUint8* dstPtr = iTransformedDUIdx;
       
  1169 	for(TInt i = 0; i < aDataUnitCount; i++)
       
  1170 		{
       
  1171 		iTransformedDUIdx[i] = i;
       
  1172 		tempTransformedDUIdx[i] = i;
       
  1173 		}
       
  1174 	
       
  1175 	ASSERT( aDataUnitCount > 0 && aDataUnitCount <= KJpgMaxNumOfDataUnits ); // Defensive programming
       
  1176 	
       
  1177 	switch (aDataUnitCount)
       
  1178 		{
       
  1179 	case KJpgMonochromeDataUnitCount:
       
  1180 		return;		
       
  1181 	case KJpgEColor444DataUnitCount: // 4:4:4 
       
  1182 		return;		
       
  1183 	case KJpgColor422DataUnitCount: // 4:2:2 
       
  1184 		InitTransformCoordinates(posProcess, TRect(TPoint(0,0),TPoint(2,1)), TSize(KJpgPixelRatio, KJpgPixelRatio), iOperationsRequested);
       
  1185 		break;
       
  1186 	case KJpgColor420DataUnitCount: // 4:2:0 
       
  1187 		InitTransformCoordinates(posProcess, TRect(TPoint(0,0),TPoint(2,2)), TSize(KJpgPixelRatio, KJpgPixelRatio), iOperationsRequested);
       
  1188 		break;
       
  1189 	default:
       
  1190 		ASSERT( EFalse );
       
  1191 		}
       
  1192 	do
       
  1193 		{		
       
  1194 		posProcess.GetCurrentPosition(pos);
       
  1195 		TInt elementPos = ((pos.iY * 2) + pos.iX);		
       
  1196 		*dstPtr++ = tempTransformedDUIdx[elementPos];		
       
  1197 		posProcess.MoveNext();		
       
  1198 		} while (!posProcess.IsEndOfImage());	
       
  1199 	}
       
  1200 
       
  1201 //
       
  1202 // this section contains many performance-critical code, so use ARM instruction set for it
       
  1203 //
       
  1204 #ifdef __ARMCC__
       
  1205 #pragma push
       
  1206 #pragma arm 
       
  1207 #pragma O3 
       
  1208 #pragma Otime
       
  1209 #endif
       
  1210 	
       
  1211 inline
       
  1212 CRgbBufferPtr::TConstRgbBufferPtr CJpgWriteCodec::GetPixels(const TPoint& aPos)
       
  1213 	{
       
  1214     CRgbBufferPtr::TConstRgbBufferPtr ptr = iRgbInputBuffer->LockBuffer(aPos);			
       
  1215 	return ptr;
       
  1216 	}
       
  1217 	
       
  1218 #if defined(__ARMCC__) && defined(__MARM_ARMV5__)//armv6 and armv7 should be added later
       
  1219 __asm int count_lz(int reserved, int x) 
       
  1220 	{
       
  1221 	clz r0, r1
       
  1222     bx lr
       
  1223     endp
       
  1224 	}
       
  1225 
       
  1226 inline
       
  1227 TInt MaxPowerOf2(TUint aValue)
       
  1228 	{
       
  1229 	return 32 - count_lz(0, aValue);
       
  1230 	}
       
  1231 #else
       
  1232 const TUint8 KNumBitsTable[64]=
       
  1233 	{
       
  1234 	// 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 
       
  1235 	   0,   1,  2,  2,  3,  3,  3,  3,  4,  4,  4,  4,  4,  4,  4,  4,  5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5
       
  1236 	  ,6,   6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6,   6  
       
  1237 	};
       
  1238 
       
  1239 inline
       
  1240 TInt MaxPowerOf2(TUint aValue)
       
  1241 	{
       
  1242 	register TInt powerOf2 = 0;
       
  1243 	do 
       
  1244 		{
       
  1245 		powerOf2 += (aValue >= 64? 6 : KNumBitsTable[aValue]);
       
  1246 		aValue  >>= 6;
       
  1247 		} while (aValue);
       
  1248 	return powerOf2;
       
  1249 	}
       
  1250 #endif
       
  1251 
       
  1252 void CJpgWriteCodec::WriteDataUnitL(const TDataUnit& aDataUnit,const TEncHuffmanTable<KEncDCHTSize+1>& aDCTable, const TEncHuffmanTable<KEncACHTSize+1>& aACTable, TInt& aDCPredictor)
       
  1253 	{
       
  1254 #   define MASKED_VALUE(a, num_bit) (TUint(a) & ((1 << num_bit) - 1))//TO optimize
       
  1255 
       
  1256     // make sure that we will never exceed the available buffer size
       
  1257     // as we may have all the 0xFF which will result in size doubled 
       
  1258     //
       
  1259 	if ( TUint(iDestPtrLimit - iDestPtr) < KDataUnitSafeBufferSz)
       
  1260 		{
       
  1261 		User::Leave(KErrCompletion);
       
  1262 		}
       
  1263 	TInt value = aDataUnit.iCoeff[0] - aDCPredictor;
       
  1264 	aDCPredictor = aDataUnit.iCoeff[0];
       
  1265 	TInt valueComp = value;
       
  1266 
       
  1267 	if (value < 0)
       
  1268 		{
       
  1269 		value = -value;
       
  1270 		valueComp--;
       
  1271 		}
       
  1272 
       
  1273   
       
  1274 	TInt numBits = MaxPowerOf2(value);
       
  1275 
       
  1276 	TInt size;
       
  1277 	TInt code=aDCTable.GetCode(size,numBits);
       
  1278 	
       
  1279 	register TUint32 bitBuffer = iBitBuffer;
       
  1280 	register TInt bitsUsed = iBitsUsed;
       
  1281 
       
  1282 	bitsUsed = WriteBitsFast(code, size, bitBuffer, bitsUsed);
       
  1283 	bitsUsed = WriteBitsFast(MASKED_VALUE(valueComp, numBits), numBits, bitBuffer, bitsUsed);
       
  1284 
       
  1285 	const TInt16* acPtr = aDataUnit.iCoeff + 1;
       
  1286 	const TInt16* acPtrLimit = aDataUnit.iCoeff + KJpgDCTBlockSize;
       
  1287 	TInt runLength = 0;
       
  1288 
       
  1289 	FOREVER
       
  1290 		{
       
  1291 		do 
       
  1292 			{
       
  1293 			// here we assume that there is always a non-zero value
       
  1294 			// at the end, the caller must do that.
       
  1295 			value = *acPtr++;
       
  1296 			if (value == 0)
       
  1297 				{
       
  1298 				runLength++;
       
  1299 				}
       
  1300 			} while (value == 0);
       
  1301 
       
  1302 		if (acPtr > acPtrLimit)
       
  1303 			{
       
  1304 			break;
       
  1305 			}
       
  1306 
       
  1307 		while (runLength > 15)
       
  1308 			{
       
  1309 			code = aACTable.GetCode(size, KJpgZeroRunValue);
       
  1310 			bitsUsed = WriteBitsFast(code, size, bitBuffer, bitsUsed);
       
  1311 			runLength -= 16;
       
  1312 			}
       
  1313 
       
  1314 		valueComp = value;
       
  1315 		if (value < 0)
       
  1316 			{
       
  1317 			value = -value;
       
  1318 			valueComp--;
       
  1319 			}
       
  1320       
       
  1321 		numBits = MaxPowerOf2( (value | 1) );
       
  1322 
       
  1323 		code = aACTable.GetCode(size,(runLength << 4) | numBits);
       
  1324 		bitsUsed = WriteBitsFast(code, size, bitBuffer, bitsUsed);
       
  1325 		bitsUsed = WriteBitsFast(MASKED_VALUE(valueComp,numBits), numBits, bitBuffer, bitsUsed);
       
  1326 		runLength = 0;
       
  1327 
       
  1328 		}
       
  1329 		
       
  1330 	if (runLength > 0)
       
  1331 		{
       
  1332 		code = aACTable.GetCode(size,0);
       
  1333 		bitsUsed = WriteBitsFast(code, size, bitBuffer, bitsUsed);
       
  1334 		}
       
  1335 
       
  1336 	iBitBuffer = bitBuffer;
       
  1337 	iBitsUsed = bitsUsed;
       
  1338 
       
  1339 	ASSERT( iDestPtr < iDestPtrLimit );
       
  1340 		
       
  1341 #   undef MASKED_VALUE		
       
  1342 	}
       
  1343 	
       
  1344 FORCEDINLINE TUint32 CJpgWriteCodec::WriteBitsFast(TUint32 aValue, TInt aNumBits, TUint32& aBitBuffer, TInt aBitsUsed)
       
  1345     {
       
  1346     if ((aBitsUsed + aNumBits) >  32)
       
  1347 		{
       
  1348 		aNumBits -= (32 - aBitsUsed);
       
  1349 		aBitBuffer |= (aValue >> aNumBits);
       
  1350 		WriteBits(aBitBuffer);
       
  1351 		aBitBuffer = (aValue << (32 - aNumBits));
       
  1352 		return aNumBits;
       
  1353 		}
       
  1354     else 
       
  1355 		{
       
  1356 		aBitsUsed   += aNumBits;
       
  1357 		aBitBuffer  |= (aValue << (32 - aBitsUsed));
       
  1358 		return aBitsUsed;
       
  1359 		}
       
  1360     }
       
  1361 
       
  1362 void CJpgWriteCodec::WriteBits(TUint32 aBitBuffer)
       
  1363     {
       
  1364 	register TUint8* bytePtr = (TUint8*)(&aBitBuffer);
       
  1365 	register TUint8 byte;
       
  1366         
       
  1367 	byte = *(bytePtr+3);
       
  1368 	*iDestPtr++ = byte;
       
  1369 	if (byte == 0xff)
       
  1370 		{
       
  1371 		*iDestPtr++ = 0;
       
  1372 		}
       
  1373 
       
  1374 	byte = *(bytePtr+2);
       
  1375 	*iDestPtr++ = byte;
       
  1376 	if (byte == 0xff)
       
  1377 		{
       
  1378 		*iDestPtr++ = 0;
       
  1379 		}
       
  1380 	
       
  1381 	byte = *(bytePtr+1);
       
  1382 	*iDestPtr++ = byte;
       
  1383 	if (byte == 0xff)
       
  1384 		{
       
  1385 		*iDestPtr++ = 0;
       
  1386 		}
       
  1387 	
       
  1388 	byte = *bytePtr;
       
  1389 	*iDestPtr++ = byte;
       
  1390 	if (byte == 0xff)
       
  1391 		{
       
  1392 		*iDestPtr++ = 0;
       
  1393 		}
       
  1394 	}
       
  1395 
       
  1396 #ifdef __ARMCC__
       
  1397 #pragma pop
       
  1398 #endif