diff -r 000000000000 -r 71ca22bcf22a mmserv/thumbnailengine/TneAPISrc/HXTNEVideoClipInfoImp.cpp --- /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 + + +#include +#include +#include + + +#include "yuv2rgb12.h" +#include "yuv2rgb16.h" +#include "yuv2rgb24.h" + +#include + +// PRINT macro +#ifdef _DEBUG +#include +#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 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 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; jSetScanLine((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")); + +}