mmserv/thumbnailengine/TneAPISrc/HXTNEVideoClipInfoImp.cpp
changeset 0 71ca22bcf22a
child 43 9894ed580e4a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/thumbnailengine/TneAPISrc/HXTNEVideoClipInfoImp.cpp	Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,747 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:   TNE Video Clip Implementation
+*
+*/
+
+
+
+
+#include "HXTNEVideoClipInfoImp.h"
+#include <e32base.h>
+
+
+#include <fbs.h>
+#include <coemain.h>
+#include <ecom/ecom.h>
+
+
+#include "yuv2rgb12.h"
+#include "yuv2rgb16.h"
+#include "yuv2rgb24.h"
+
+#include <flogger.h>
+
+// PRINT macro
+#ifdef _DEBUG
+#include <e32svr.h>
+#define PRINT(x) RDebug::Print x
+#else
+#define PRINT(x)
+#endif
+
+#ifdef _DEBUG
+#define ENABLE_S60_TNE_LOGGING 1
+#endif
+
+//implementation
+#ifdef ENABLE_S60_TNE_LOGGING
+#define FLOG FileLog
+inline static void FileLog(TRefByValue<const TDesC16> aFmt,...)
+{
+    VA_LIST  args;
+    VA_START (args, aFmt);
+    RFileLogger::WriteFormat(_L("tne"), _L("S60tne.log"), 
+                        EFileLoggingModeAppend, aFmt, args);
+}
+
+#else // logging is disabled
+#define FLOG LogFNull
+inline static void LogFNull(TRefByValue<const TDesC16> aFmt,...){}
+
+#endif // enable logging
+
+//server details
+const TUint kDefaultMessageSlots=4;
+
+
+
+// -----------------------------------------------------------------------------
+// CTNEVideoClipInfo::NewL
+// API exposed by TNE to 
+// TNEVideoClipInfo using RFile handle
+// -----------------------------------------------------------------------------
+EXPORT_C CTNEVideoClipInfo* CTNEVideoClipInfo::NewL(const RFile& aFileHandle,
+                                                    MTNEVideoClipInfoObserver& aObserver)
+{
+    FLOG(_L("CTNEVideoClipInfo::NewL"));
+
+     CHXTNEVideoClipInfoImp* self = ( CHXTNEVideoClipInfoImp*)NewLC(aFileHandle, aObserver);
+
+
+    FLOG(_L("CTNEVideoClipInfo::NewL out"));
+    return self;
+}
+
+// -----------------------------------------------------------------------------
+// CTNEVideoClipInfo::NewL
+// API exposed by TNE to create TNEVideoClipInfo using file name
+// -----------------------------------------------------------------------------
+EXPORT_C CTNEVideoClipInfo* CTNEVideoClipInfo::NewL(const TDesC& aFileName,
+                                                    MTNEVideoClipInfoObserver& aObserver)
+{
+    FLOG(_L("CTNEVideoClipInfo::NewL"));
+
+     CHXTNEVideoClipInfoImp* self = ( CHXTNEVideoClipInfoImp*)NewLC(aFileName, aObserver);
+
+
+    FLOG(_L("CTNEVideoClipInfo::NewL out"));
+    return self;
+}
+
+EXPORT_C CTNEVideoClipInfo* CTNEVideoClipInfo::NewLC(const RFile& aFileHandle,
+                                                     MTNEVideoClipInfoObserver& aObserver)
+{
+     	
+    CHXTNEVideoClipInfoImp* self = new (ELeave)  CHXTNEVideoClipInfoImp();
+    CleanupStack::PushL(self);
+    self->ConstructL(aFileHandle, aObserver);   
+    CleanupStack::Pop();
+    return self;
+}
+
+    
+EXPORT_C CTNEVideoClipInfo* CTNEVideoClipInfo::NewLC(const TDesC& aFileName,
+                                                     MTNEVideoClipInfoObserver& aObserver)
+{
+    
+     CHXTNEVideoClipInfoImp* self = new (ELeave)  CHXTNEVideoClipInfoImp();
+    CleanupStack::PushL(self);
+    self->ConstructL(aFileName, aObserver);   
+     CleanupStack::Pop();
+    return self;
+}
+
+
+
+
+CTNEVideoClipInfo*  CHXTNEVideoClipInfoImp::NewL(const RFile& aFileHandle, 
+                                              MTNEVideoClipInfoObserver& aObserver)
+{
+     CHXTNEVideoClipInfoImp* self = new (ELeave)  CHXTNEVideoClipInfoImp();
+    CleanupStack::PushL(self);
+    self->ConstructL(aFileHandle, aObserver);
+    CleanupStack::Pop(self);
+    return self;
+}
+
+//constructor
+
+ CHXTNEVideoClipInfoImp::CHXTNEVideoClipInfoImp()
+ {
+ 	//empty constructor
+ 
+ }
+
+
+//destructor
+
+
+ CHXTNEVideoClipInfoImp::~CHXTNEVideoClipInfoImp()
+{
+    FLOG(_L("CTNEVideoClipInfo::~ CHXTNEVideoClipInfoImp in"));
+    
+        
+    
+    RSessionBase::Close();
+    iServerThread.Close(); 
+   
+    if (iServerName)
+   {
+    	delete iServerName;
+    	iServerName = NULL;
+    }
+    if (iObserver)
+    {
+        delete iObserver;
+        iObserver = NULL;
+    }
+    
+    if (iCloseHandle)
+    {    	
+        iCloseHandle = EFalse;
+    	iFileHandle.Close();	
+    }
+        		           		    
+    if (iOutBitmap)
+    {
+        delete iOutBitmap;
+        iOutBitmap = 0;
+    }
+            
+    
+    if(iFs)
+    {
+	    iFs->Close();
+	    delete iFs;
+	    iFs = NULL;
+    }
+    
+    if (iEnhancer)
+    {
+        delete iEnhancer;
+        iEnhancer = NULL;
+    }
+    
+    FLOG(_L("CTNEVideoClipInfo::~ CHXTNEVideoClipInfoImp out"));    
+}
+
+void  CHXTNEVideoClipInfoImp::ConstructL(const RFile& aFileHandle,
+                                      MTNEVideoClipInfoObserver& aObserver)
+{
+    FLOG(_L("CTNEVideoClipInfo::ConstructL in this=%x"), this);
+    iObserver = CTNEClientObserver::NewL(this);
+	iClipInfoObserver = &aObserver;
+
+		
+	User::LeaveIfError(CreateServer());
+	iFileHandle.Duplicate(aFileHandle);
+	iCloseHandle = ETrue;
+	User::LeaveIfError(OpenFile(iFileHandle, 0));
+    
+    FLOG(_L("CTNEVideoClipInfo::ConstructL out this=%x"), this);
+    
+ }
+
+void  CHXTNEVideoClipInfoImp::ConstructL(const TDesC& aFileName,
+                                      MTNEVideoClipInfoObserver& aObserver)
+{
+    FLOG(_L("CTNEVideoClipInfo::ConstructL in this=%x"), this);
+    iObserver = CTNEClientObserver::NewL(this);
+   	iClipInfoObserver = &aObserver;
+   	iFileName.Copy(aFileName);
+   
+    User::LeaveIfError(CreateServer());
+	
+    User::LeaveIfError(OpenFile(0));
+   
+    
+    FLOG(_L("CTNEVideoClipInfo::ConstructL out this=%x"), this);
+}
+
+TInt  CHXTNEVideoClipInfoImp::CreateServer()
+{
+	TInt err = KErrNoMemory;	
+	FLOG(_L("CHXTNEVideoClipInfoImp::CreateServer in"));    
+	 TRAP(err,iServerName = HBufC::NewL(KMaxFileName));
+	
+	if (iServerName && err == KErrNone)
+	{ 
+		 TPtr ptr = iServerName->Des();
+    ptr.Copy(KTneServerName);
+    ptr.AppendNum(Math::Random(), EHex);
+	
+		err = StartThread(iServerThread, iServerName);
+	}		
+	
+    if ( err == KErrNone)
+    {
+       //server name FIXME
+       err = CreateSession(*iServerName, Version(), kDefaultMessageSlots);
+    }
+                     
+    FLOG(_L("CHXTNEVideoClipInfoImp::CreateServer out err=%d"), err);   
+    return(err); 
+  
+}
+
+TVersion CHXTNEVideoClipInfoImp::Version(void) const
+    {
+    return(TVersion(KTNEServMajorVersionNumber,KTNEServMinorVersionNumber,KTNEServBuildVersionNumber));
+    }
+
+
+//SendRecieve() commands to server
+
+TInt CHXTNEVideoClipInfoImp::OpenFile(const RFile& aFileHandle, TInt aPosition)
+
+{
+   FLOG(_L("CHXTNEVideoClipInfoImp::OpenFile in"));
+   c_State = EStartGettingMetadata;
+   iObserver->Activate();
+   SendReceive(EOpenFileRFmsg,TIpcArgs(&aFileHandle,aPosition), iObserver->iStatus);    
+   FLOG(_L("CHXTNEVideoClipInfoImp::OpenFile out"));
+   return KErrNone;
+ }
+
+TInt CHXTNEVideoClipInfoImp::OpenFile(TInt aPosition)
+
+{
+   FLOG(_L("CHXTNEVideoClipInfoImp::OpenFile in"));
+   c_State = EStartGettingMetadata;
+   iObserver->Activate();
+   SendReceive(EOpenFIleNamemsg,TIpcArgs(&iFileName,aPosition), iObserver->iStatus);    
+   FLOG(_L("CHXTNEVideoClipInfoImp::OpenFile out"));
+   return KErrNone;
+ }
+
+void CHXTNEVideoClipInfoImp::GetThumbL(MTNEVideoClipThumbObserver& aObserver, 
+                                     TInt aIndex,
+                                     TSize* const aResolution,
+                                     TDisplayMode aDisplayMode,
+                                     TBool aEnhance,
+                                     TInt aPriority)
+                                     
+{
+        FLOG(_L("CHXTNEVideoClipInfoImp::GetThumbL in"));
+        
+        iThumbObserver               = &aObserver;
+        iThumbIndex                    = aIndex;
+        iThumbEnhance               = aEnhance;	
+        iThumbDisplayMode         = aDisplayMode; 
+        iPriority                            = aPriority;                
+        iThumbRequestData.iIndex =  aIndex;
+        
+        if (aResolution)
+        {    	    
+            iOutputThumbResolution = *aResolution;
+        }
+        else
+        {    	                            	
+            iOutputThumbResolution.iHeight = iMetaData.iHeight;
+            iOutputThumbResolution.iWidth = iMetaData.iWidth;         
+        }
+        
+        iThumbRequestData.iYUVBuffer = NULL;                
+        c_State = EStartGettingThumbNail;
+        iObserver->Activate();
+        SendReceive(EGetThumbmsg, TIpcArgs(&iThumbRequestData), iObserver->iStatus);    
+        FLOG(_L("CHXTNEVideoClipInfoImp::GetThumbL out"));
+ }
+  
+
+void CHXTNEVideoClipInfoImp::CancelThumb()
+{
+    FLOG(_L("CHXTNEVideoClipInfoImp::CancelThumb in"));
+    c_State = ECancelling;
+    SendReceive(ECancelThumbmsg);    
+    FLOG(_L("CHXTNEVideoClipInfoImp::CancelThumb out"));
+}
+  
+  TPtrC CHXTNEVideoClipInfoImp::FileName() const
+{
+    TFileName fileName;
+	if (iCloseHandle)
+	{
+		iFileHandle.FullName(fileName);
+	}
+
+    return fileName;
+}
+
+TInt CHXTNEVideoClipInfoImp::VideoFrameCount() const
+{
+	return (TInt)iMetaData.iFrameCount ;
+
+}
+  
+
+// Called from Observer after a Complete() from Server
+
+void  CHXTNEVideoClipInfoImp::ServiceCompleted(TInt aError)
+{
+	FLOG(_L("CHXTNEVideoClipInfoImp::ServiceCompleted in aError=%d c_State=%d"),
+	            aError, c_State);
+    switch(c_State)
+    {
+        case EStartGettingMetadata:			                        
+            FetchAndSendMetaData(aError);            
+            break;
+        case EStartGettingThumbNail:
+            if (aError == KErrNone)
+            {
+                GenerateThumbNail();
+            }
+            else
+            {
+                if (iOutBitmap)
+                {
+                    delete iOutBitmap;
+                    iOutBitmap = NULL;
+                }
+                m_LastError = aError;
+            }
+            
+			NotifyIfGetThumbPending(m_LastError, iOutBitmap);
+			break;
+		case ECancelling:
+        default:
+            break;
+    }
+    
+    FLOG(_L("CHXTNEVideoClipInfoImp::ServiceCompleted out"));
+    
+}
+
+void CHXTNEVideoClipInfoImp::FetchAndSendMetaData(TInt aError)
+{
+    FLOG(_L("CHXTNEVideoClipInfoImp::FetchAndSendMetaData in"));
+    if (aError == KErrNone)
+    {
+        aError = SendReceive(EGetMetaDatamsg, TIpcArgs(&iMetaData));
+    }
+    if(c_State== EStartGettingMetadata)
+    {
+    CTNEVideoClipInfo *pInfo = (CTNEVideoClipInfo *) this;
+    iClipInfoObserver->NotifyVideoClipInfoReady(*pInfo, aError);  
+    }
+    FLOG(_L("CHXTNEVideoClipInfoImp::FetchAndSendMetaData out and state = %d"), c_State);
+
+}
+
+// ownership of pBitMap will be passed to Observer
+void CHXTNEVideoClipInfoImp::NotifyIfGetThumbPending(TInt aError, CFbsBitmap *&pBitMap) 
+{
+    FLOG(_L("CHXTNEVideoClipInfoImp::NotifyIfGetThumbPending in"));
+	if (iThumbObserver)
+	{				
+        CFbsBitmap* pTmpBitmap = pBitMap;
+        pBitMap = NULL;
+		iThumbObserver->NotifyVideoClipThumbCompleted(*this, aError, pTmpBitmap);
+	}
+	FLOG(_L("CHXTNEVideoClipInfoImp::NotifyIfGetThumbPending out"));
+}
+
+void CHXTNEVideoClipInfoImp::GenerateThumbNail()
+{
+	FLOG(_L("CHXTNEVideoClipInfoImp::GenerateThumbNail in"));
+    TInt bytesPerPixel = 0;           
+    TInt error = KErrNone;
+    
+    if ( !iRgbBuf )
+    {
+        TSize inputFrameResolution(iMetaData.iWidth,iMetaData.iHeight);
+                       
+        // rgb specs
+        TUint thumbLength = iMetaData.iWidth * iMetaData.iHeight; 
+        TUint thumbUVLength = thumbLength>>2;	
+        
+       // VPASSERT(iYuvBuf);
+        // assign yuv pointers 
+        TUint8* yBuf = iThumbRequestData.iYUVBuffer;
+        TUint8* uBuf = yBuf + thumbLength;
+        TUint8* vBuf = uBuf + thumbUVLength;	
+      
+  	   // convert to no enhabnce if 64K is selected as thumb display mode
+  	 	if(iThumbDisplayMode == EColor64K)
+  	    iThumbEnhance = EFalse;
+  	   
+        // check validity of thumbnail and associated operation
+        if(iThumbEnhance)		// for saving to file
+        {			
+                iThumbDisplayMode = EColor16M;				// 24-bit color image for enhancement
+          
+            // no enhancements if clip is too small.
+            if (iOutputThumbResolution.iWidth < 16 || iOutputThumbResolution.iHeight < 16)
+            {
+            	iThumbEnhance = EFalse;            	
+            }
+        }
+        else								// for screen display
+        {
+            if(iThumbDisplayMode == ENone)					// if no preference
+                iThumbDisplayMode = EColor64K;				// 16-bit image
+        }
+        
+        // determine proper bit depth for the bitmap
+        if(iThumbDisplayMode == EColor16M)
+            bytesPerPixel = 3; // 24-bit rgb takes 3 bytes, stored as bbbbbbbb gggggggg rrrrrrrr
+        else if(iThumbDisplayMode == EColor64K || iThumbDisplayMode == EColor4K)
+            bytesPerPixel = 2; // 12-bit rgb takes 2 bytes, stored as ggggbbbb xxxxrrrr                            
+        else
+        {
+            HandleThumbnailError(KErrNotSupported);
+            return;					// support for 12-, 16- and 24-bit color images only
+        }
+        
+        // create output rgb buffer
+        TRAP(error, iRgbBuf = (TUint8*) User::AllocL(thumbLength * bytesPerPixel));
+        if (HandleThumbnailError(error))
+            return;                                
+        
+        TInt scanLineLength;
+        
+        // convert yuv to rgb
+        switch (iThumbDisplayMode)
+        {
+            
+        case EColor4K:
+            {
+                TInt error;
+                CYuv2Rgb12* yuvConverter = NULL; 
+                TRAP(error, yuvConverter = new(ELeave) CYuv2Rgb12);
+                if (HandleThumbnailError(error))
+                    return;
+                scanLineLength = inputFrameResolution.iWidth * bytesPerPixel;                 
+                TRAP(error, yuvConverter->ConstructL(inputFrameResolution.iWidth, inputFrameResolution.iHeight, inputFrameResolution.iWidth, inputFrameResolution.iHeight));
+                if (HandleThumbnailError(error))
+                    return;
+                yuvConverter->Convert(yBuf, uBuf, vBuf, inputFrameResolution.iWidth, inputFrameResolution.iHeight, iRgbBuf, scanLineLength);                
+                delete yuvConverter;		
+                yuvConverter=0;         
+            }
+            break;
+            
+        default:
+        case EColor64K:
+            {
+                TInt error;
+                CYuv2Rgb16* yuvConverter = NULL; 
+                TRAP(error, yuvConverter = new(ELeave) CYuv2Rgb16);
+                if (HandleThumbnailError(error))
+                    return;                
+                scanLineLength = inputFrameResolution.iWidth * bytesPerPixel; 
+                TRAP(error, yuvConverter->ConstructL(inputFrameResolution.iWidth, inputFrameResolution.iHeight, inputFrameResolution.iWidth, inputFrameResolution.iHeight);)
+                if (HandleThumbnailError(error))
+                    return;
+                yuvConverter->Convert(yBuf, uBuf, vBuf, inputFrameResolution.iWidth, inputFrameResolution.iHeight, iRgbBuf, scanLineLength);                
+                delete yuvConverter;		
+                yuvConverter=0; 
+            }
+            break;
+            
+        case EColor16M:
+            {
+                TInt error;
+                CYuv2Rgb24* yuvConverter = NULL; 
+                TRAP(error, yuvConverter = new(ELeave) CYuv2Rgb24);
+                if (HandleThumbnailError(error))
+                    return;                                
+                scanLineLength = inputFrameResolution.iWidth * bytesPerPixel;                 
+                TRAP(error, yuvConverter->ConstructL(inputFrameResolution.iWidth, inputFrameResolution.iHeight, inputFrameResolution.iWidth, inputFrameResolution.iHeight))
+                if (HandleThumbnailError(error))
+                    return;                
+                yuvConverter->Convert(yBuf, uBuf, vBuf, inputFrameResolution.iWidth, inputFrameResolution.iHeight, iRgbBuf, scanLineLength);                
+                delete yuvConverter;		
+                yuvConverter=0; 
+            }
+            break;
+        }        
+    }
+
+	if(!iThumbEnhance)
+	{
+        TSize inputFrameResolution(iMetaData.iWidth,iMetaData.iHeight);
+		    
+		/* Pre-calculate pixel indices for horizontal scaling. */
+		// inputFrameResolution is the resolution of the image read from video clip.
+		// iOutputThumbResolution is the final resolution desired by the caller.
+		
+		TInt OutW = (iOutputThumbResolution.iWidth + 3 )/4 * 4;
+		TInt OutH = (iOutputThumbResolution.iHeight + 3 )/4 * 4;
+		
+		TSize roundedsize = TSize (OutW,OutH);
+		
+		TInt xIncrement = inputFrameResolution.iWidth * OutW;
+		TInt xBoundary =  OutW * OutW;
+		
+		TInt* xIndices = 0;
+		TRAPD(xIndicesErr, xIndices = new (ELeave) TInt[OutW]);
+		if (xIndicesErr == KErrNone)
+		{
+			TInt xDecision = xIncrement / bytesPerPixel; // looks like they changed here - orig was /2
+			TInt sourceIndex = 0;
+			for (TInt x = 0; x < OutW; x++)
+			{
+				while (xDecision > xBoundary)
+				{
+					xDecision -= xBoundary;
+					sourceIndex += bytesPerPixel;
+				}
+				
+				xIndices[x] = sourceIndex;
+				xDecision += xIncrement;
+			}
+		}
+		else
+		{		    
+		    HandleThumbnailError(xIndicesErr);
+		    return;
+		}
+		
+		/* Initialize bitmap. */
+		TRAPD(bitmapErr, iOutBitmap = new (ELeave) CFbsBitmap);
+		if ((xIndicesErr == KErrNone) && (bitmapErr == KErrNone))
+		{
+			bitmapErr = iOutBitmap->Create(roundedsize, iThumbDisplayMode/*EColor64K*/);
+			if (bitmapErr == KErrNone)
+			{
+                // Lock the heap to prevent the FBS server from invalidating the address
+                iOutBitmap->LockHeap();
+
+				/* Scale to desired iOutputThumbResolution and copy to bitmap. */
+				TUint8* dataAddress = (TUint8*)iOutBitmap->DataAddress(); // fix
+				
+				TInt yIncrement = inputFrameResolution.iHeight * OutH;
+				TInt yBoundary =  OutH * OutH;
+				
+				TInt targetIndex = 0;
+				TInt sourceRowIndex = 0;
+				TInt yDecision = yIncrement / 2; 
+				for (TInt y = 0; y < OutH; y++)
+				{
+					while (yDecision > yBoundary)
+					{
+						yDecision -= yBoundary;
+						sourceRowIndex += (inputFrameResolution.iWidth * bytesPerPixel); 
+					}
+					yDecision += yIncrement;
+
+
+					for (TInt x = 0; x < OutW; x++)					
+					{
+                        for (TInt i = 0; i < bytesPerPixel; ++i)
+                        {
+                            const TInt firstPixelSourceIndex = sourceRowIndex + xIndices[x] + i;
+                            dataAddress[targetIndex] = iRgbBuf[firstPixelSourceIndex];
+                            targetIndex++;
+                        }
+                    }
+				}
+                iOutBitmap->UnlockHeap();
+                
+                // resing to original if odd values were input
+               if(roundedsize != iOutputThumbResolution)
+               {
+               
+               	TInt err ;
+               	err = iOutBitmap->Resize(iOutputThumbResolution);
+               	if(err!= KErrNone)
+               		HandleThumbnailError(err);	
+               	
+               }
+                
+			} 
+			
+			else
+			{			    
+				delete iOutBitmap; iOutBitmap = 0;
+				HandleThumbnailError(bitmapErr);
+				return;
+			}
+		}
+		else
+		{
+		    HandleThumbnailError(bitmapErr);
+		    delete[] xIndices; xIndices = 0;
+		    return;
+		}
+		
+		delete[] xIndices;
+		xIndices = 0;
+	}
+	else		// enhance
+	{
+		TInt i,j;
+		// create input bitmap and buffer
+		CFbsBitmap* inBitmap = 0;
+		TRAPD(inBitmapErr, inBitmap = new (ELeave) CFbsBitmap);
+		if( inBitmapErr == KErrNone )
+        {
+		    // create bitmaps
+		    TSize originalResolution(iMetaData.iWidth, iMetaData.iHeight);
+		    inBitmapErr = inBitmap->Create(originalResolution, iThumbDisplayMode/*EColor16M*/); 
+		
+            if( inBitmapErr == KErrNone )
+            {
+		        // fill image from rgb buffer to input bitmap buffer 
+		        TPtr8 linePtr(0,0); 
+        		TInt lineLength = inBitmap->ScanLineLength(originalResolution.iWidth, iThumbDisplayMode); 
+		        for(j=0, i=0; j<originalResolution.iHeight; j++, i+=lineLength)
+		        {
+        			linePtr.Set(iRgbBuf+i, lineLength, lineLength);
+		        	inBitmap->SetScanLine((TDes8&)linePtr,j); 
+		        }
+		
+        		// create output bitmap 
+		        TRAPD(outBitmapErr, iOutBitmap = new (ELeave) CFbsBitmap);
+                if( outBitmapErr == KErrNone )
+                {
+		            outBitmapErr = iOutBitmap->Create(iOutputThumbResolution, iThumbDisplayMode/*EColor16M*/); // same size as input frame
+		
+                    if( outBitmapErr == KErrNone )
+                    {
+		                // post-processing enhancement 
+		                TRAP(outBitmapErr, EnhanceThumbnailL((const CFbsBitmap*)inBitmap, (CFbsBitmap*)iOutBitmap));
+
+                    }
+                    else
+                    {
+                        delete inBitmap; inBitmap = 0;   
+                        delete iOutBitmap; iOutBitmap = 0;
+                        HandleThumbnailError(outBitmapErr);
+                        return;
+                    }
+                }
+                else
+                {
+                     delete inBitmap; inBitmap = 0;
+                     HandleThumbnailError(outBitmapErr);
+                     return;
+                }
+            }
+            else
+            {
+                delete inBitmap; inBitmap = 0;
+                HandleThumbnailError(inBitmapErr);
+                return;                
+            }
+		
+		    // delete input bitmap 
+		    delete inBitmap;
+		    inBitmap = 0;
+        }
+        else
+        {
+            HandleThumbnailError(inBitmapErr);
+            return;
+        }
+	}
+
+    delete iRgbBuf;
+    iRgbBuf = 0;
+    FLOG(_L("CHXTNEVideoClipInfoImp::GenerateThumbNail out"));
+}
+
+
+TBool CHXTNEVideoClipInfoImp::HandleThumbnailError(TInt aError)
+{
+    if (aError != KErrNone)
+    {
+    	m_LastError = aError;
+   
+        return ETrue;
+    }
+       
+    return EFalse;    
+}
+
+
+void CHXTNEVideoClipInfoImp::EnhanceThumbnailL(const CFbsBitmap* aInBitmap, 
+											CFbsBitmap* aTargetBitmap) 
+{
+    FLOG(_L("CHXTNEVideoClipInfoImp::EnhanceThumbnailL in"));
+  // create enhancement object
+	if(!iEnhancer)
+    iEnhancer = (CDisplayChain*) CDisplayChain::NewL();
+
+	// enhance image
+	iEnhancer->ProcessL(aInBitmap, aTargetBitmap); 
+
+	// clear enhancement object
+	delete iEnhancer;
+	iEnhancer=0;
+	FLOG(_L("CHXTNEVideoClipInfoImp::EnhanceThumbnailL out"));
+
+}