javauis/mmapi_qt/animated_gif_notUsed/src/cmmaanimationplayer.cpp
changeset 23 98ccebc37403
child 26 dc7c549001d5
--- /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