--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/mmapi_qt/animated_gif_notUsed/src/cmmaanimationplayer.cpp Fri May 14 15:47:24 2010 +0300
@@ -0,0 +1,621 @@
+/*
+* Copyright (c) 2002-2009 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: This class is used for playing animated images.
+*
+*/
+
+
+// INCLUDE FILES
+#include <logger.h>
+
+// For Image Handling Library (IHL)
+#include "IHLImageFactory.h"
+#include "MIHLFileImage.h"
+#include "IHLViewerFactory.h"
+#include "MIHLImageViewer.h"
+#include "MIHLBitmap.h"
+#include "IHLBitmapUtil.h"
+
+// MMAPI includes
+#include "mmmadisplay.h"
+
+// Class header
+#include "cmmaanimationplayer.h"
+#include "cmmaanimationwindow.h"
+
+namespace
+{
+const TInt64 KMMATimeUnknown = -1;
+_LIT(KMMAAnimationContentType, "image/gif");
+
+// Approximated minimum showing time of each frame is 0.12s
+// this value basically depends on how fast device can load frames
+// it is not quaranteed anyway that the media time is equal to
+// clock time, so this needed to be only somewhat close
+
+_LIT(KVideoControlName, "VideoControl");
+}
+
+CMMAAnimationPlayer* CMMAAnimationPlayer::NewLC()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::NewLC");
+ CMMAAnimationPlayer* self = new(ELeave) CMMAAnimationPlayer();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+}
+
+CMMAAnimationPlayer* CMMAAnimationPlayer::NewLC(const TDesC& aFileName)
+{
+ CMMAAnimationPlayer* self = NewLC();
+ self->iFileName = aFileName.AllocL();
+ return self;
+}
+
+CMMAAnimationPlayer::~CMMAAnimationPlayer()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::~CMMAAnimationPlayer +");
+ if (iViewer && iViewer->IsPlaying())
+ {
+ iViewer->Stop();
+ }
+ delete iWindow;
+ delete iSnapshotBitmap;
+ delete iViewer;
+ // viewer has reference to iImage,
+ // thus deletion order is important.
+ delete iBitmap;
+ delete iImage;
+
+ delete iFileName;
+
+ iFSession.Close();
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::~CMMAAnimationPlayer -");
+}
+
+CMMAAnimationPlayer::CMMAAnimationPlayer()
+ : iFrameCount(0), iMediaTime(KMMATimeUnknown), iEndReached(EFalse),
+ iSendEndOfMediaOnNextFrame(EFalse)
+{
+}
+
+void CMMAAnimationPlayer::ConstructL()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::ConstructL +");
+ CMMAPlayer::ConstructL();
+ HBufC* contentType = KMMAAnimationContentType().AllocL();
+ SetContentType(contentType);
+
+ // Connect to file session, needed also when playing from data
+ User::LeaveIfError(iFSession.Connect());
+
+ // File session must be share protected for IHL
+ User::LeaveIfError(iFSession.ShareProtected());
+
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::ConstructL -");
+}
+
+void CMMAAnimationPlayer::SetPlayerListenerObjectL(
+ jobject aListenerObject,
+ JNIEnv* aJni,
+ MMMAEventPoster* aEventPoster)
+{
+ CMMAPlayer::SetPlayerListenerObjectL(aListenerObject,
+ aJni,
+ aEventPoster);
+
+ // this method must be called only ones
+ __ASSERT_DEBUG(!iWindow, User::Invariant());
+
+ // create window for animationplayer
+ // event poster is always MMAFunctionServer type.
+ iWindow = CMMAAnimationWindow::NewL(
+ static_cast< MMAFunctionServer* >(iEventPoster));
+}
+
+void CMMAAnimationPlayer::RealizeL()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::RealizeL");
+ // For file locator file must be prefetched here because
+ // FramePositioningControl must know duration of media
+ // in realized state
+ if (iFileName)
+ {
+ TRAPD(err, PrefetchFileL());
+ if (err != KErrNone)
+ {
+ User::Leave(err);
+ }
+ }
+ CMMAPlayer::RealizeL();
+}
+
+void CMMAAnimationPlayer::PrefetchL()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::PrefetchL +");
+ __ASSERT_DEBUG((iSourceStreams.Count() > 0) || iFileName, User::Invariant());
+
+ if (iFileName)
+ {
+ // file data is already fetched in when realizing
+
+ // If initDisplayMode was called before prefetch,
+ // then the display must notified about source size.
+ if (iDisplay)
+ {
+ iDisplay->SourceSizeChanged(iSourceSize);
+ NotifyWithStringEvent(CMMAPlayerEvent::ESizeChanged, KVideoControlName);
+ }
+
+ // ChangeState(EPrefetched);
+ // PostActionCompleted(KErrNone);
+ // we can go to prefetched state immediately
+ PostActionCompletedFile();
+ ChangeState(EPrefetched);
+ }
+ else
+ {
+ // Using TDes -- load the whole animation
+ iSourceStreams[ 0 ]->ReadAllL();
+ }
+
+ // CMMASourceStream will notify with ReadCompleted
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::PrefetchL -");
+}
+
+void CMMAAnimationPlayer::StartL()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::StartL +");
+
+ // If end of media has been reached, then
+ // start from beginning
+ if (iEndReached)
+ {
+ iEndReached = EFalse;
+ iViewer->SetAnimationFrame(0);
+ iMediaTime = 0;
+ }
+ PostLongEvent(CMMAPlayerEvent::EStarted, iMediaTime);
+
+ // process current frame
+ ProcessCurrentFrameL();
+
+ // progress to next frame (start playback) only if rate is not zero
+ if (iCurrentRate > 0)
+ {
+ iViewer->Play();
+ }
+ ChangeState(EStarted);
+ PostActionCompletedStart();
+ // PostActionCompleted(KErrNone); // java start return
+
+
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::StartL -");
+}
+
+void CMMAAnimationPlayer::ProcessCurrentFrameL()
+{
+ if (iSendEndOfMediaOnNextFrame)
+ {
+ iSendEndOfMediaOnNextFrame = EFalse;
+ // we are reached the end
+ if (!iRepeatForever)
+ {
+ iRepeatCount++;
+ if (iRepeatCount >= iRepeatNumberOfTimes)
+ {
+ LOG( EJavaMMAPI, EInfo, "CMMAAnimationPlayer:ProcessCurrentFrameL: Reached repeat count, Stopping");
+ // end looping, do not send stopped event
+ StopL(EFalse);
+ iViewer->SetAnimationFrame(iFrameCount - 1);
+ SetLoopCount(iRepeatNumberOfTimes); // reset loop count
+
+ // Signal that end of media has been reached so on next
+ // start playback will be started from beginning. This is needed
+ // because if user sets media time to end of media, then start
+ // should not start from beginning but just deliver end of media.
+ // After that, the next start should start from beginning.
+ iEndReached = ETrue;
+ }
+ }
+ PostLongEvent(CMMAPlayerEvent::EEndOfMedia, iMediaTime);
+ LOG( EJavaMMAPI, EInfo, "CMMAAnimationPlayer:ProcessCurrentFrameL: sent END_OF_MEDIA");
+
+ // Prevents this frame from being viewed if playback has terminated
+ // (e.g. not looping)
+ if (iEndReached)
+ {
+ return;
+ }
+ }
+
+ // draw current frame to display if we have it
+ if (iDisplay)
+ {
+ const CFbsBitmap& bitmap = iBitmap->Bitmap();
+ iDisplay->DrawFrameL(&bitmap);
+ }
+
+ TInt currentFrame = iViewer->AnimationFrame();
+ if (currentFrame == 0)
+ {
+ LOG( EJavaMMAPI, EInfo, "CMMAAnimationPlayer:ProcessCurrentFrameL: Reset mediatime");
+ // reset media time when looping
+ iMediaTime = 0;
+ }
+ iMediaTime += FrameDuration(currentFrame).Int();
+
+ // Media time has gone over duration if user has
+ // set media time explicitely to duration.
+ if (iMediaTime > iDuration)
+ {
+ iMediaTime = iDuration;
+ }
+
+ if (currentFrame == (iFrameCount - 1))
+ {
+ // End has been reached, so EndOfMedia is sent when
+ // duration of last frame has passed
+ iSendEndOfMediaOnNextFrame = ETrue;
+ }
+
+ // inform observer
+ if (iAnimationObserver)
+ {
+ iAnimationObserver->AnimationAdvancedL(iViewer->AnimationFrame(), iMediaTime);
+ }
+}
+
+void CMMAAnimationPlayer::StopL(TBool aPostEvent)
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::StopL +");
+ iViewer->Stop();
+ // adjust mediatime
+ if (aPostEvent)
+ {
+ PostLongEvent(CMMAPlayerEvent::EStopped, iMediaTime);
+ }
+ ChangeState(EPrefetched);
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::StopL -");
+}
+
+void CMMAAnimationPlayer::DeallocateL()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::DeallocateL +");
+ // If player is in starte state when deallocate is called,
+ // player is stopped from java side -> state is changed to
+ // prefetched.
+ if (iViewer)
+ {
+ if (iViewer->IsPlaying())
+ iViewer->Stop();
+
+ delete iViewer;
+ iViewer = NULL;
+ }
+
+ if (iState == EPrefetched)
+ {
+ ResetSourceStreams();
+ iEndReached = EFalse;
+ iSendEndOfMediaOnNextFrame = EFalse;
+ ChangeState(ERealized);
+ }
+ LOG( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::DeallocateL -");
+}
+
+void CMMAAnimationPlayer::GetDuration(TInt64* aDuration)
+{
+ *aDuration = iDuration;
+}
+
+TInt CMMAAnimationPlayer::FindFrame(TInt64 aTime)
+{
+ __ASSERT_DEBUG(iImage, User::Invariant());
+
+ // if we are out of bounds
+ if (aTime > iDuration)
+ {
+ return KErrNotFound;
+ }
+
+ TInt64 time = 0;
+ TInt fIndex = 0;
+ while ((time < aTime) && (fIndex < iFrameCount))
+ {
+ time += FrameDuration(fIndex++).Int();
+ }
+
+ // adjust to previous frame
+ if (fIndex > 0)
+ {
+ fIndex--;
+ }
+
+ return fIndex;
+}
+
+TInt64 CMMAAnimationPlayer::MediaTimeForFrame(TInt aFrameIndex)
+{
+ __ASSERT_DEBUG((aFrameIndex <= iFrameCount) && (aFrameIndex >= 0),
+ User::Invariant());
+
+ TInt64 time = 0;
+ for (TInt fIndex = 0; fIndex < aFrameIndex; fIndex++)
+ {
+ time += FrameDuration(fIndex).Int();
+ }
+ return time;
+}
+
+TTimeIntervalMicroSeconds32 CMMAAnimationPlayer::FrameDuration(TInt aFrameIndex)
+{
+ __ASSERT_DEBUG(iImage, User::Invariant());
+ TTimeIntervalMicroSeconds32 fDur = iImage->AnimationFrameDelay(aFrameIndex);
+ const TTimeIntervalMicroSeconds32 KMMAMinimumFrameTime = 120000;
+
+ if (fDur < KMMAMinimumFrameTime)
+ {
+ fDur = KMMAMinimumFrameTime;
+ }
+ return fDur;
+}
+
+void CMMAAnimationPlayer::SetMediaTimeL(TInt64* aTime)
+{
+ if (!iImage && !iViewer)
+ {
+ // not yet prefetched
+ *aTime = KErrNotSupported;
+ }
+ else
+ {
+ // Media time of last frame is not the same as duration of
+ // media, so if media time of duration is requested, then it must
+ // be given out altough media time of last frame is lower than that.
+ if (*aTime >= iDuration)
+ {
+ User::LeaveIfError(iViewer->SetAnimationFrame(iFrameCount - 1));
+ iMediaTime = iDuration;
+ }
+ else
+ {
+ TInt frame = FindFrame(*aTime);
+ User::LeaveIfError(iViewer->SetAnimationFrame(frame));
+ iMediaTime = MediaTimeForFrame(frame);
+ }
+ *aTime = iMediaTime;
+ iEndReached = EFalse;
+ iSendEndOfMediaOnNextFrame = EFalse;
+ }
+
+}
+
+void CMMAAnimationPlayer::GetMediaTime(TInt64* aMediaTime)
+{
+ *aMediaTime = iMediaTime;
+}
+
+const TDesC& CMMAAnimationPlayer::Type()
+{
+ return KMMAVideoPlayer;
+}
+
+void CMMAAnimationPlayer::ReadCompletedL(TInt aStatus, const TDesC8& aData)
+{
+ if (aStatus < KErrNone)
+ {
+ PostActionCompleted(aStatus);
+ }
+ else
+ {
+ TRAPD(err, PrefetchDataL(aData));
+ if (err == KErrNone)
+ {
+ ChangeState(EPrefetched);
+ }
+ PostActionCompleted(err);
+ }
+}
+
+void CMMAAnimationPlayer::PrefetchFileL()
+{
+ iImage = IHLImageFactory::OpenFileImageL(iFSession, *iFileName);
+ PrepareViewerL();
+}
+
+void CMMAAnimationPlayer::PrefetchDataL(const TDesC8& aData)
+{
+ LOG1( EJavaMMAPI, EInfo, "MMA::CMMAAnimationPlayer::PrefetchDataL aData size %d",
+ aData.Size());
+
+ // Create source image from data
+ iImage = IHLImageFactory::OpenBufferedFileImageL(iFSession, aData);
+ PrepareViewerL();
+}
+
+TBool CMMAAnimationPlayer::IsFilePlayer()
+{
+ if (iFileName != NULL)
+ {
+ return ETrue;
+ }
+ return EFalse;
+}
+
+void CMMAAnimationPlayer::PrepareViewerL()
+{
+ // Non-animated gifs are not supported
+ if (!(iImage->IsAnimation()))
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // Store image dimensions
+ iSourceSize = iImage->Size();
+
+ // Create destination bitmap
+ iBitmap = IHLBitmap::CreateL();
+ User::LeaveIfError(iBitmap->Create(iSourceSize, iImage->DisplayMode()));
+
+ // Create image viewer
+ iViewer = IHLViewerFactory::CreateImageViewerL(
+ iSourceSize,
+ *iImage, // source
+ *iBitmap, // destination
+ *this); // reference to MIHLViewerObserver
+
+ // Set viewer for window
+ iWindow->SetViewer(iViewer);
+
+ // Store animation frame count locally
+ iFrameCount = iViewer->AnimationFrameCount();
+
+ // calculate duration
+ iDuration = MediaTimeForFrame(iFrameCount);
+
+ // set media time to begin
+ iMediaTime = 0;
+
+ // If init has been already done
+ if (iDisplay)
+ {
+ iDisplay->SourceSizeChanged(iSourceSize);
+ NotifyWithStringEvent(CMMAPlayerEvent::ESizeChanged, KVideoControlName);
+ }
+}
+
+MIHLImageViewer* CMMAAnimationPlayer::Viewer()
+{
+ return iViewer;
+}
+
+void CMMAAnimationPlayer::SetAnimationObserver(MMMAAnimationObserver* aAnimationObserver)
+{
+ iAnimationObserver = aAnimationObserver;
+}
+
+TInt CMMAAnimationPlayer::SetRateL(TInt aRate)
+{
+ LOG( EJavaMMAPI, EInfo, "MMA:CMMAAnimationPlayer::SetRateL");
+ if ((iState == EStarted) && (iCurrentRate != aRate))
+ {
+ if (aRate <= 0)
+ {
+ iViewer->Stop();
+ }
+ else
+ {
+ iViewer->Play();
+ }
+ }
+ iCurrentRate = aRate;
+ return iCurrentRate;
+}
+
+TInt CMMAAnimationPlayer::RateL()
+{
+ LOG( EJavaMMAPI, EInfo, "MMA:CMMAAnimationPlayer::RateL");
+ return iCurrentRate;
+}
+
+void CMMAAnimationPlayer::SetDisplayL(MMMADisplay* aDisplay)
+{
+ // now it is ready to draw
+ iDisplay = aDisplay;
+ iDisplay->SetWindowL(iWindow);
+
+ // if state < prefeteched then we dont know actual source size yet
+ // and it will be set after prefetch
+ if (iState >= EPrefetched ||
+ (iFileName && iState == ERealized))
+ {
+ iDisplay->SourceSizeChanged(iSourceSize);
+ NotifyWithStringEvent(CMMAPlayerEvent::ESizeChanged, KVideoControlName);
+ }
+}
+
+TSize CMMAAnimationPlayer::SourceSize()
+{
+ return iSourceSize;
+}
+
+void CMMAAnimationPlayer::NotifyWithStringEvent(
+ CMMAPlayerEvent::TEventType aEventType,
+ const TDesC& aStringEventData)
+{
+ PostStringEvent(aEventType, aStringEventData);
+}
+
+MMMASnapshot* CMMAAnimationPlayer::SnapshoterL()
+{
+ return this;
+}
+
+MMMASnapshot::TEncoding CMMAAnimationPlayer::TakeSnapshotL(TRequestStatus* aStatus,
+ const TSize& /*aSize*/,
+ const CMMAImageSettings& /*aSettings*/)
+{
+ if (iBitmap)
+ {
+ // Bitmap has to be copied to get ownership of the bitmap instance.
+ iSnapshotBitmap = IHLBitmapUtil::CopyBitmapL(iBitmap->Bitmap());
+ }
+ else
+ {
+ // When content comes from a stream, iBitmap is not available
+ // until prefetched state is entered. In this case an empty bitmap
+ // is returned instead.
+ iSnapshotBitmap = new(ELeave) CFbsBitmap();
+ }
+ // notify the caller, error code or KErrNone
+ User::RequestComplete(aStatus, KErrNone);
+
+ // Return raw bitmap encoding and thus SnapshotEncoded() should not
+ // get called later on.
+ return EBitmap;
+}
+
+CFbsBitmap* CMMAAnimationPlayer::SnapshotBitmap()
+{
+ CFbsBitmap* bitmap = iSnapshotBitmap;
+ // ownership is transferred to caller
+ iSnapshotBitmap = NULL;
+ return bitmap;
+}
+
+HBufC8* CMMAAnimationPlayer::SnapshotEncoded()
+{
+ // This method should never be called.
+ // Asserted in debug build to be sure.
+ __ASSERT_DEBUG(EFalse, User::Invariant());
+
+ return NULL;
+}
+
+void CMMAAnimationPlayer::ViewerBitmapChangedL()
+{
+ if (iState == EStarted)
+ {
+ ProcessCurrentFrameL();
+ }
+}
+
+void CMMAAnimationPlayer::ViewerError(TInt /*aError*/)
+{
+ // Not implemented currently because
+ // not implemented by IHL either.
+}
+
+// END OF FILE