diff -r 000000000000 -r 71ca22bcf22a mmserv/thumbnailengine/TneAPISrc/HXTneserver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmserv/thumbnailengine/TneAPISrc/HXTneserver.cpp Tue Feb 02 01:08:46 2010 +0200 @@ -0,0 +1,800 @@ +/* +* 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 server +* +*/ + + + +#include"HXTneserver.h" +#include"HXTneclientservercommon.h" +#include +#include +static const TInt kDefaultStack = 0x4000; + + + +// 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 + + + + +const TInt KMaxPacketToDecode = 32; + +//////////////Server/////////////// + + +CTneServer::CTneServer(CActive::TPriority aActiveObjectPriority) + : CServer2(aActiveObjectPriority) + { + } + + + +CSession2* CTneServer::NewSessionL(const TVersion& /* aVersion */,const RMessage2& +/*aMessage*/) const + +{ + return new (ELeave) CTneSession; + } + + + +GLDEF_C TInt CTneServer::ThreadFunction(TAny* aName) +{ + HBufC *pServerName = (HBufC *) aName; + CTrapCleanup* cleanup = NULL; + CActiveScheduler *pA = NULL; + CTneServer *pS = NULL; + TInt err = KErrNoMemory; + + FLOG(_L("CTneServer::ThreadFunction ServerName=%S"), pServerName); + // get clean-up stack + if (pServerName) + { + cleanup =CTrapCleanup::New(); + pA = new CActiveScheduler; + pS = new CTneServer(EPriorityStandard); + + } + + + if (cleanup && pA && pS ) + { + // OK + CActiveScheduler::Install(pA); + // Start the server + err = pS->Start(*pServerName); + } + + RThread::Rendezvous(err); + + CActiveScheduler::Start(); + + // Tidy up... + delete pS; + delete pA; + delete cleanup; + + + return(err); +} + + +//global function + +TInt StartThread(RThread& aServerThread, HBufC *pServerName) + { + TInt res=KErrNone; + + + res=aServerThread.Create(*pServerName, + CTneServer::ThreadFunction, + kDefaultStack, &User::Heap(), + (TAny *)pServerName ); + + // The thread has been created OK so get it started - however + // we need to make sure that it has started before we continue. + if (res==KErrNone) + { + TRequestStatus rendezvousStatus; + + aServerThread.SetPriority(EPriorityNormal); + aServerThread.Rendezvous(rendezvousStatus); + aServerThread.Resume(); + User::WaitForRequest(rendezvousStatus); + res = rendezvousStatus.Int(); + } + + // The thread has not been created - clearly there's been a problem. + else + { + aServerThread.Close(); + } + + return res; + } + + + + + + ////////////////////////ServerSession////////////////////////////// + + +CTneSession::CTneSession(): + iWidth(0), + iHeight(0) , + iDuration(0) , + iFrameCount(0) , + m_LastError(KErrNone), + m_uPacketsReceived(0) , + m_bDone(EFalse), + iFs(NULL), + iYUVBuffer(NULL), + iClientYUVBufferPtrPtr(NULL), + m_bOpenFileLPending(EFalse), + iGetThumbPending(EFalse), + iCloseHandle(EFalse), + ibOpenFilePending(EFalse), + iThumbIndex(0), + iUtil(NULL), + m_State( ENotReady), + m_bMetaDataReady(EFalse) + { + FLOG(_L("CTneSession::CTneSession()in this=%x"), this); + FLOG(_L("CTneSession::CTneSession()out this=%x"), this); + } + + + + CTneSession::~CTneSession() +{ + FLOG(_L("CTneSession::~CTneSession()in this=%x"), this); + if(iYUVBuffer) + { + User::Free(iYUVBuffer); + iYUVBuffer = NULL; + } + + if (iCloseHandle) + { + iFileHandle.Close(); + } + if (iUtil) + { + delete iUtil; + iUtil = NULL; + } + if(iFs) + { + iFs->Close(); + delete iFs; + iFs = NULL; + } + CompleteRequest(KErrCancel); + CompleteCancelRequest(); + CActiveScheduler::Stop(); + + FLOG(_L("CTneSession::~CTneSession()out this=%x"), this); +} + + + /** +Services a client request. +*/ +void CTneSession::ServiceL(const RMessage2& aMessage) + { + DispatchMessageL(aMessage); + } + + +void CTneSession::DispatchMessageL(const RMessage2& aMessage) + { + + TBool bCompleteRequest = EFalse; + TInt lError = KErrNone; + RFile* pFileHandle; + TFileName *pFileName; + TInt aPosition; + TNEMetaData* pMetaData; + TNEThumbRequest *pThumbRequestData; + RFile64 aFilehandle; + + FLOG(_L("CTneSession::DispatchMessageL in type=%d"), aMessage.Function()); + + switch (aMessage.Function()) + { + case EOpenFileRFmsg: + m_State = EStartGettingMetadata; + bCompleteRequest = ETrue; + iClientRequest = aMessage; + pFileHandle = ( RFile* ) aMessage.Ptr0(); // Handle to read Message data + aPosition = (TInt ) aMessage.Ptr1(); + + lError = iFileHandle.Duplicate(*pFileHandle); + if (lError == KErrNone) + { + iCloseHandle = ETrue; + lError = DoOpenFile(iFileHandle, aPosition); + } + + if( m_State == EStartGettingThumbNailWithIndex) + { + lError = ReOpenFile(iFileHandle); + } + + CompleteCancelRequest(); // it will check also if cancel needs to be done. + + break; + +//fix me - Avoid duplicate code -common func (Future Work) + case EOpenFIleNamemsg: + iFs = NULL; + m_State = EStartGettingMetadata; + iClientRequest = aMessage; + pFileName = (TFileName* ) aMessage.Ptr0(); + aPosition = (TInt ) aMessage.Ptr1(); + + iFs = new RFs; + if(iFs == NULL) + { + lError = KErrNoMemory; + bCompleteRequest = ETrue; + } + else if ( (lError = iFs->Connect())!= KErrNone) + { + bCompleteRequest = ETrue; + } + else if ((lError = aFilehandle.Open(*iFs,*pFileName, EFileShareReadersOnly | EFileStream | EFileRead))!= KErrNone) + { + bCompleteRequest = ETrue; + } + else if ((lError = iFileHandle.Duplicate(aFilehandle))!= KErrNone) + { + bCompleteRequest = ETrue; + aFilehandle.Close(); + + } + else if ( (lError = DoOpenFile(iFileHandle, aPosition)) != KErrNone ) + { + bCompleteRequest = ETrue; + aFilehandle.Close(); + iCloseHandle = ETrue; + } + else + { + bCompleteRequest = ETrue; + aFilehandle.Close(); + iCloseHandle = ETrue; + } + + + if( m_State == EStartGettingThumbNailWithIndex) + { + lError = ReOpenFile(iFileHandle); + } + + CompleteCancelRequest(); // it will check also if cancel needs to be done. + + if (lError != KErrNone) + { + bCompleteRequest = ETrue; + } + + break; + case EGetMetaDatamsg: + iClientRequest = aMessage; + pMetaData = ( TNEMetaData* ) aMessage.Ptr0(); + pMetaData->iWidth = iWidth; + pMetaData->iHeight = iHeight; + pMetaData->iFrameCount = iFrameCount; + bCompleteRequest = ETrue; + + break; + + case EGetThumbmsg: + + iClientRequest = aMessage; + pThumbRequestData = ( TNEThumbRequest * ) aMessage.Ptr0(); + // store thumb request parameters + iClientYUVBufferPtrPtr = &(pThumbRequestData->iYUVBuffer); + iThumbIndex = pThumbRequestData->iIndex; + if (iThumbIndex == KBestThumbIndex || iThumbIndex <= 1) + { + m_State = EStartGettingThumbNail; + DoGetThumb(); + } + else + { + m_State = EStartGettingThumbNailWithIndex; + if (!ibOpenFilePending) + { + lError = ReOpenFile(iFileHandle); + } + } + break; + case ECancelThumbmsg: + iGetThumbPending = EFalse; + iCancelRequest = aMessage; + m_State = ECancelling; + if(iUtil) + { + iUtil->CancelThumb(); + } + // cancel any pending getthumb or openfile request. + lError = KErrCancel; + CompleteRequest(lError); + + if (!ibOpenFilePending) + { + CompleteCancelRequest(); + } + break; + + default: + // PanicClient(aMessage,EBadRequest); + return; + + } + + if (bCompleteRequest) + { + CompleteRequest(lError); + } + + FLOG(_L("CTneSession::DispatchMessageL out type=%d"), aMessage.Function()); +} + + + +TInt CTneSession::DoOpenFile(RFile &aFileHandle, TUint uStartTime) +{ + FLOG(_L(" CTneSession::DoOpenFile in")); + + MHXThumbnailUtilityImplObserver* pObserver = + (MHXThumbnailUtilityImplObserver *) this; + + ibOpenFilePending = ETrue; + TFileName aFilename; + aFileHandle.FullName(aFilename); + FLOG(_L("aFilename=%S"),&aFilename ); + TRAPD(err, iUtil = CHXThumbnailUtility::NewL(*pObserver)); + m_bDone = EFalse; + m_uPacketsReceived = 0; + if (err == KErrNone) + { + TRAP(err, iUtil->OpenFileL(aFileHandle, uStartTime)); + } + FLOG(_L(" CTneSession::DoOpenFile out err = %d"),err); + ibOpenFilePending = EFalse; + return err; +} + +TInt CTneSession::ReOpenFile(RFile &aFileHandle) +{ + iGetThumbPending = ETrue; + TInt lError = KErrNone; + TUint uStartingTime = 0; + lError = GetStartingTime(uStartingTime); + if (lError == KErrNone) + { + if (iUtil) + { + iUtil->CancelThumb(); + delete iUtil; + iUtil = NULL; + } + + lError = DoOpenFile(aFileHandle, uStartingTime); + } + + return lError; +} + + + +void CTneSession::FetchBasicMetaData() +{ + TUint lCount = 0; + TUint i=0; + TUint lFrameRateinSec = 0; + + iUtil->GetMetaDataCount(lCount); + + TBool bGotFrameSize = EFalse, bGotDuration = EFalse, bGotFrameRate = EFalse; + + for (i=0; iGetMetaDataAt(i, id, pDes); + + if (id == HXMetaDataKeys::EHXFrameSize && pDes) + { + TPtr pFrameSizePtr = pDes->Des(); + _LIT(KChar_x, "x"); + TInt xLoc = pFrameSizePtr.Find(KChar_x); + if (xLoc != KErrNotFound) + { + TLex lexWidth(pFrameSizePtr.Mid(0, xLoc)); + TLex lexHeight(pFrameSizePtr.Mid(xLoc+1)); + lexWidth.Val(iWidth); // Storing into local iWidth variable + lexHeight.Val(iHeight); // Storing into local iHeight variable + bGotFrameSize = ETrue; + FLOG(_L(" iWidth=%d,iHeight=%d"), iWidth,iHeight); + } + } + else if (id == HXMetaDataKeys::EHXDuration && pDes) + { + TLex lexDuration(pDes->Des()); + lexDuration.Val(iDuration); + bGotDuration = ETrue; + } + else if (id == HXMetaDataKeys::EHXFramesPerSecond && pDes) + { + TLex lexFramesPerSecond(pDes->Des()); + lexFramesPerSecond.Val(lFrameRateinSec); + bGotFrameRate = ETrue; + } + + if (bGotDuration && bGotFrameRate && bGotFrameSize) + { + break; + } + + } // end of for + + if (bGotDuration && bGotFrameRate) + { + // approximate frame count + // iDuration is in msec. + iFrameCount = ( (iDuration+500)/1000 ) * lFrameRateinSec; + } + + else + { + iFrameCount = ( (iDuration+500)/1000 ) * 10; + } + + +} + + +void CTneSession::DoGetThumb() +{ + iGetThumbPending = ETrue; + if(m_bDone) + { + if (m_LastError != KErrNone) + { + if (iYUVBuffer) + { + User::Free(iYUVBuffer); + iYUVBuffer = NULL; + } + } + + NotifyIfGetThumbPending(m_LastError, iYUVBuffer); + } +} + +void CTneSession::MetaDataReady(TInt aError) +{ + + FLOG(_L("CTneSession::MetaDataReady in callbacks from Utility aError=%d"), aError); + if ( m_State == EStartGettingMetadata) + { + // extract some minimum metadata to be used for thumbnail generation + if (aError == KErrNone) + { + FetchBasicMetaData(); + if(iYUVBuffer) + { + User::Free(iYUVBuffer); + iYUVBuffer = NULL; + } + + // Allocate memory for iYUVBuffer + if( iWidth > 4 && iHeight > 4 ) // for all frame sizes + { + TInt length = iWidth * iHeight; + length += (length>>1); + iYUVBuffer = (TUint8*)User::Alloc(length); + + if (!iYUVBuffer) + { + FLOG(_L("CTneSession::MetaDataReady Error No memory for iYUVBuffer")); + aError = KErrNoMemory; + } + } + else + { + FLOG(_L("CTneSession::MetaDataReady Error Width/Height not found")); + aError = KErrNotSupported; + + } + } + m_LastError = aError; + + // only complete the request if there is any error. If the request is not completed here then + // it will be completed after the DoOpenFile() returns. + if (aError != KErrNone) + { + CompleteRequest(aError); + } + + } + FLOG(_L("CTneSession::MetaDataReady out aError=%d"), aError); + m_bMetaDataReady = ETrue; + +} + + +void CTneSession::PacketReady(TInt aError, + void *pData, TUint32 aDataSize) +{ + FLOG(_L("CTneSession::PacketReady aError=%d m_State=%d aDataSize=%d"), aError, m_State, aDataSize); + if(aDataSize > (iWidth*iHeight*3/2 )) + { + aDataSize = iWidth*iHeight*3/2 ; //restore back to values coming from header if they differ + + } + if (m_State == ECancelling) + { + FLOG(_L("CTneSession::PacketReady no op")); + return; + } + if(aDataSize < (iWidth*iHeight*3/2 )) // check to avoid getting very low size + { + if(m_uPacketsReceived == 0) + { + m_LastError = KErrNotSupported ; // if this is the first packet then only send KErrNotSupported + } + + m_bDone = ETrue; + } + + if (m_LastError != KErrNone || aError != KErrNone || pData == NULL) + { + FLOG(_L("CTneSession::PacketReady aError=%d m_State=%d pData=%x"), aError, m_State, pData); + // MetadataReady might set m_LastError + m_bDone = ETrue; + + if (m_LastError == KErrNone) + { + if (aError == KErrNone) + { + m_LastError = KErrNotSupported; + } + else + { + m_LastError = aError; + } + } + } + else + { + m_uPacketsReceived++; + if ( IsGoodFrame((TUint8*)pData ) && !m_bDone ) + { + m_bDone = ETrue; + m_LastError = KErrNone; + Mem::Copy(iYUVBuffer, pData, aDataSize); + } + else if (m_uPacketsReceived == 1) // we copy the first packet + { + Mem::Copy(iYUVBuffer, pData, aDataSize); + } + else if (m_uPacketsReceived >= KMaxPacketToDecode) + { + // we decoded upto KMaxPacketToDecode and haven't found + // a good frame yet. + FLOG(_L("CHXTNEVideoClipInfoImp::PacketReady max count reached %d"), + m_uPacketsReceived); + Mem::Copy(iYUVBuffer, pData, aDataSize); // we copy and use the last frame + m_bDone = ETrue; + m_LastError = KErrNone; + } + } + + + // we are done. Tell the TNUtil that no more packets are needed. + if (m_bDone) + { + iUtil->CancelThumb(); + } + + if (iGetThumbPending) + { + + // we are done either success or failure. + if(m_bDone) + { + if (m_LastError != KErrNone) + { + if (iYUVBuffer) + { + User::Free(iYUVBuffer); + iYUVBuffer = NULL; + } + } + + NotifyIfGetThumbPending(m_LastError, iYUVBuffer); + } + } + + +} + +void CTneSession::EndOfPackets() +{ + if (!m_bDone) + { + if(m_uPacketsReceived >= 1) + { + NotifyIfGetThumbPending(KErrNone, iYUVBuffer); + } + else + { + TUint8* pYUVBuffer = NULL; + NotifyIfGetThumbPending(KErrNotFound, pYUVBuffer); + } + // If end of packet has been received then thumbnailengine should be done + m_bDone = ETrue; + } + + if(!m_bMetaDataReady) + { + MetaDataReady(KErrCompletion); + } +} + +TBool CTneSession::IsGoodFrame(TUint8* aYUVDataPtr) +{ + + TInt i; + TInt minValue = 255; + TInt maxValue = 0; + TBool goodFrame = ETrue; + TInt runningSum=0; + TInt averageValue=0; + TInt pixelSkips = 4; + TInt numberOfSamples=0; + TInt minMaxDeltaThreshold = 20; + TInt extremeRegionThreshold = 20; + TInt ySize = iWidth*iHeight; + + // gather image statistics + for(i=0, numberOfSamples=0; i maxValue) + maxValue = *aYUVDataPtr; + if(*aYUVDataPtr < minValue) + minValue = *aYUVDataPtr; + } + //VDASSERT(numberOfSamples,10); + if (numberOfSamples == 0) + { + FLOG(_L("CTneSession::IsGoodFrame numberOfSamples is zero")); + } + else + { + averageValue = runningSum/numberOfSamples; + } + + // make decision based statistics + if((maxValue - minValue) < minMaxDeltaThreshold) + goodFrame = EFalse; + else + { + if(averageValue < (minValue + extremeRegionThreshold) || + averageValue > (maxValue - extremeRegionThreshold)) + goodFrame = EFalse; + } + return goodFrame; +} + +TInt CTneSession::GetStartingTime(TUint &uStartingTime) +{ + TInt err = KErrNone; + + if (iThumbIndex <= iFrameCount) + { + TReal tempDuration = iDuration; + uStartingTime = (tempDuration/iFrameCount) * iThumbIndex; + // thumbnail beyond the clip duration. + if (uStartingTime >= iDuration) + { + uStartingTime = 0; + } + } + else + { + err = KErrNotSupported; + } + FLOG(_L("CTNEVideoClipInfo::GetStartingTime StartingTime=%d iDuration=%d iFrameCount=l:%d h:%d iThumbIndex=%d err=%d"), + uStartingTime, iDuration, I64LOW(iFrameCount),I64HIGH(iFrameCount), iThumbIndex, err); + return err; +} + + + +void CTneSession::CompleteRequest(TInt aError) +{ + if(!iClientRequest.IsNull()) + { + iClientRequest.Complete(aError); + } +} + + + + +// ownership of pBitMap will be passed to Observer +void CTneSession::NotifyIfGetThumbPending(TInt aError, TUint8 *&pYUVBuffer) +{ + if (iGetThumbPending && !iClientRequest.IsNull()) + { + iGetThumbPending = EFalse; + *iClientYUVBufferPtrPtr = pYUVBuffer; + iClientRequest.Complete(aError); + + } +} + +void CTneSession::CompleteCancelRequest() +{ + + if (!iCancelRequest.IsNull()) + { + + if (iUtil) + { + delete iUtil; + iUtil = NULL; + } + iCancelRequest.Complete(KErrNone); + } +}