--- /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 <flogger.h>
+#include <f32file64.h>
+static const TInt kDefaultStack = 0x4000;
+
+
+
+// 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
+
+
+
+
+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; i<lCount; i++)
+ {
+ HBufC *pDes = NULL;
+ HXMetaDataKeys::EHXMetaDataId id;
+ iUtil->GetMetaDataAt(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<ySize; i+=pixelSkips, aYUVDataPtr+=pixelSkips, numberOfSamples++)
+ {
+
+
+ runningSum += *aYUVDataPtr;
+ if(*aYUVDataPtr > 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);
+ }
+}