javauis/mmapi_qt/baseline/javasrc/com/nokia/microedition/media/animation/AnimationPlayer.java
changeset 48 e0d6e9bd3ca7
parent 35 85266cc22c7f
child 50 023eef975703
child 61 bf7ee68962da
--- a/javauis/mmapi_qt/baseline/javasrc/com/nokia/microedition/media/animation/AnimationPlayer.java	Wed Jun 23 18:07:10 2010 +0300
+++ b/javauis/mmapi_qt/baseline/javasrc/com/nokia/microedition/media/animation/AnimationPlayer.java	Tue Jul 06 14:10:26 2010 +0300
@@ -16,10 +16,15 @@
 */
 package com.nokia.microedition.media.animation;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.Enumeration;
 import java.util.Hashtable;
+import java.util.Timer;
+import java.util.TimerTask;
 
 import javax.microedition.media.Control;
 import javax.microedition.media.MediaException;
@@ -27,6 +32,7 @@
 import javax.microedition.media.PlayerListener;
 import javax.microedition.media.protocol.DataSource;
 
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.SWTException;
 import org.eclipse.swt.events.PaintEvent;
 import org.eclipse.swt.events.PaintListener;
@@ -45,14 +51,14 @@
 import com.nokia.mj.impl.nokialcdui.LCDUIInvoker;
 import com.nokia.mj.impl.utils.Logger;
 
-public class AnimationPlayer extends PlayerBase
+public class AnimationPlayer extends PlayerBase implements ESWTinitializeListener
 {
     // GIF image information, array length will be equal to the number of frames in image
     protected ImageData [] iImageData;
     // number of times we need to repeat the animation
     // by default it's value is one
     private int iTotalLoopCount=1;
-    // this holds all control related to this player
+    // HashTable object which contains all control related to this player
     private Hashtable iControls= new Hashtable();
     // Current frame index of the Animation file
     private int iFrameIndex;
@@ -91,24 +97,33 @@
     // as user can change the size of the image later, in that case too, getSourceheight and getSourceWidth
     // of VideoControl should return the actual width and height of the image
     private Point iSourceDimension;
-    // Total time taken so far to playe the animation
+    // Current dimension of the image, MIDlet developer may change the size of VideoControl
+//    private Point iCurrentVideoDimension;
+    // Total time taken so far to player the animation, it keeps updating as player moves
     private long iMediaTime;
     // Time at which, player should be stopped
     // This will set through StopTimeControl.setTime();
-    private long iStopTime=Long.MAX_VALUE;
+    // otherwise default time is Long.MAX_VALUE
+    //private long iStopTime=Long.MAX_VALUE;
+    AnimationObserver iAnimationObserver;
 
     // Display Location, of the image
     // there won't be any use of this, in case of Form(customItem)
     private Point iDisplayLocation= new Point(0,0);
-
+    // in case of Canvas(USE_DIRECT_VIDEO) , it should be invisible by default
+    // this is handled in initDisplayMode function, if the mode is USE_DIRECT_VIDEO, we are
+    // changing it to false
     private boolean iIsControlVisible=true;
+    // we keep the background pixel in it, used while taking the snapshot of the currentframe
+    private int iBackgroundPixel=-1;
+    // Total duration of the player
+    private long iDuration=TIME_UNKNOWN;
     /**
      *
      * @param ds DataSource which contains the data to be displayed
      */
     public AnimationPlayer(DataSource ds)
     {
-        System.out.println("AnimationPlayer(DataSource ds) + ");
         iPlayerListenerImpl= new PlayerListenerImpl(this);
         //TODO check if we can do it in better way
         // this is temporary solution
@@ -129,11 +144,11 @@
             {
                 e.printStackTrace();
             }
-            //iRepeatCount=imageLoader.repeatCount;
             iSourceDimension= new Point(imageLoader.logicalScreenWidth, imageLoader.logicalScreenHeight);
+            iBackgroundPixel= imageLoader.backgroundPixel;
         }
         populateControl();
-        System.out.println("AnimationPlayer(DataSource ds) - ");
+
     }
 
     /**
@@ -143,15 +158,13 @@
      */
     public AnimationPlayer(String locator) throws SWTException
     {
-        System.out.println("AnimationPlayer(String locator) + ");
         iPlayerListenerImpl= new PlayerListenerImpl(this);
         ImageLoader imageLoader= new ImageLoader();
         // Following line may throw SWTException
         iImageData=imageLoader.load(locator);
-        //iRepeatCount=imageLoader.repeatCount;
         iSourceDimension= new Point(imageLoader.logicalScreenWidth, imageLoader.logicalScreenHeight);
+        iBackgroundPixel= imageLoader.backgroundPixel;
         populateControl();
-        System.out.println("AnimationPlayer(String locator) - ");
     }
 
     /**
@@ -159,29 +172,31 @@
      */
     protected void doClose()
     {
-        iState=CLOSED;
+        // state is already changed in playerbase.close() method
+        //      changePlayerState(CLOSED);
         iPlayerListenerImpl.postEvent(PlayerListener.CLOSED, null);
     }
 
     /**
-     * Called from the PlayerBase class
+     * Called from the PlayerBase class if the Player is in pre-fetched state
+     *
      */
     protected void doDeallocate()
     {
-        // dummy implementation
+        //when the player is in pre-fetched state, calling this
+        //function should change the state of the player to RELAIZED state
+        changePlayerState(REALIZED);
     }
 
     protected void doPrefetch() throws MediaException
     {
-        iState=PREFETCHED;
+        changePlayerState(PREFETCHED);
+        iDuration= getMediaTimeForFrame(getTotalNumberFrames());
     }
 
     protected void doRealize() throws MediaException
     {
-        iState=REALIZED;
-        // this is temporary solution implement it in proper way
-        // initialize the iImage object with first frame
-        iImage=new Image(iDisplay, iImageData[0]);
+        changePlayerState(REALIZED);
     }
 
     /**
@@ -190,7 +205,7 @@
     protected void doStop() throws MediaException
     {
         // since after stopping the player the player state will move to pre-fetched state
-        iState=PREFETCHED;
+        changePlayerState(PREFETCHED);
         iPlayerListenerImpl.postEvent(PlayerListener.STOPPED, new Long(iMediaTime * 10000));
     }
 
@@ -222,19 +237,12 @@
     }
 
     /**
-     * This function will return, total time in microseconds this player can be played
+     * This function will return total time in microseconds, this player can be played
      */
     public long getDuration()
     {
         closeCheck();
-        long time = TIME_UNKNOWN;
-        int totalNoOfFrames = iImageData.length;
-        for (int i = 0; i < totalNoOfFrames; i++)
-        {
-            time += iImageData[i].delayTime;
-        }
-        // Since we have to return it in microsecond multiply it with 1000;
-        return time * 10000;
+        return iDuration;
     }
 
     /**
@@ -242,7 +250,8 @@
      */
     public long getMediaTime()
     {
-        // Since we have to return it in microsecond multiply it with 1000;
+        closeCheck();
+        // Since we have to return it in microsecond multiply it with 10000;
         return iMediaTime*10000;
     }
 
@@ -267,60 +276,43 @@
     public void start() throws MediaException
     {
         final String DEBUG_STR = "AnimationPlayer::start()";
-        final long inTime= System.currentTimeMillis();
-        // Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,DEBUG_STR + "++++++++");
-        System.out.println(DEBUG_STR + "+++");
+        final long inTime = System.currentTimeMillis();
+
         prefetch();
         // Only prefetched player may be started. If player is already started
         // this method returns silently.
         if (getState() == PREFETCHED)
         {
-            initialize();
-            iState = STARTED;
+            //initialize();
+            changePlayerState(STARTED);
             Thread thread = new Thread("Animation")
             {
                 int loopCount = iCurrentLoopCount;
                 GC gc = null;
-
                 public void run()
                 {
+                    //changePlayerState(STARTED);
                     final int noOfFrames = iImageData.length;
-                    while (iFrameIndex < noOfFrames &&
-                            (iRepeatForeEver || (loopCount < iTotalLoopCount))&&
-                            (iState == STARTED))
+                    while (iState == STARTED)
                     {
                         final int delayTimeForNextFrame = iImageData[iFrameIndex].delayTime;
-                        // if stop time has become more than the media time
-                        // TODO This solution may not give the accurate result, if the delay
-                        // between two frames is grater than 1 second.
-                        // Do we need to implement the TimerTask only?
-                        if (iMediaTime > iStopTime)
+                        // Since we are going to display first frame, notify all
+                        // PlayerListener that Player has started
+                        if (iFrameIndex == 0)
                         {
                             iPlayerListenerImpl.postEvent(
-                                PlayerListener.STOPPED_AT_TIME, new Long(
+                                PlayerListener.STARTED, new Long(
                                     iMediaTime * 10000));
-                            break;
                         }
-
                         if (iDisplay != null)
                         {
-                            iDisplay.asyncExec(new Runnable()
+                            iDisplay.syncExec(new Runnable()
                             {
                                 public void run()
                                 {
-                                    System.out.println(DEBUG_STR+"asynchronous block +++");
-                                    // Since we are going to display first frame, notify all
-                                    // PlayerListener that Player has started
-                                    if (iFrameIndex == 0)
-                                    {
-                                        iPlayerListenerImpl.postEvent(
-                                            PlayerListener.STARTED, new Long(
-                                                iMediaTime * 10000));
-                                    }
                                     if (gc == null)
                                         gc = new GC(iImage);
-                                    Image tempImage = new Image(iDisplay,
-                                                                iImageData[iFrameIndex]);
+                                    Image tempImage = new Image(iDisplay,iImageData[iFrameIndex]);
                                     gc.drawImage(tempImage, 0, 0);
                                     tempImage.dispose();
                                     iFrameIndex = (iFrameIndex + 1) % noOfFrames;
@@ -328,55 +320,14 @@
                                     {
                                         iControl.redraw();
                                     }
-                                    // update the mediaTime, as Animation
-                                    // progress
                                     iMediaTime += delayTimeForNextFrame;
-                                    // If imageIndex becomes zero it means, all frames
-                                    // has been displayed
-                                    // So increase the loopCount
-                                    if (iFrameIndex == 0)
-                                    {
-                                        // send the END_OF_MEDIA event to all
-                                        // listener
-                                        iPlayerListenerImpl.postEvent(
-                                            PlayerListener.END_OF_MEDIA,
-                                            new Long(iMediaTime * 10000));
-                                        loopCount++;
-                                        // set iMediaTime to 0
-                                        iMediaTime = 0;
-                                    }
-                                    System.out.println(DEBUG_STR+"asynchronous block ---");
                                 }
                             });
                         }
-                        else
+                        else// if the initDisplayMode is not called yer
                         {
-                            System.out.println(DEBUG_STR+"InitDisplaymode has not been called yet");
-                            if (iFrameIndex == 0)
-                            {
-                                iPlayerListenerImpl.postEvent(
-                                    PlayerListener.STARTED, new Long(
-                                        iMediaTime * 10000));
-                            }
-                            // This else block will execute if the initDisplayMode hasn't been called yet
-                            // check if initDisplayMode has been called
-                            initialize();
                             iFrameIndex = (iFrameIndex + 1) % noOfFrames;
                             iMediaTime += delayTimeForNextFrame;
-                            // post EOM event
-                            if (iFrameIndex == 0)
-                            {
-                                // send the END_OF_MEDIA event to all
-                                // listener
-                                iPlayerListenerImpl.postEvent(
-                                    PlayerListener.END_OF_MEDIA, new Long(
-                                        iMediaTime * 10000));
-                                loopCount++;
-                                // since player is again going to start from
-                                // the first frame
-                                // so media time should be set to zero
-                                iMediaTime = 0;
-                            }
                         }
                         try
                         {
@@ -387,30 +338,53 @@
                             // TODO Auto-generated catch block
                             e.printStackTrace();
                         }
-                        System.out.println(DEBUG_STR+"while lopp ---");
+                        // post EOM event
+                        if (iFrameIndex == 0)
+                        {
+                            loopCount++;
+                            if (!(iRepeatForeEver || (loopCount < iTotalLoopCount)))
+                            {
+                                // when this loop is getting braked, we need to change the state to pre-fetched
+                                //TODO Player should change it's state in doStop();
+                                changePlayerState(PREFETCHED);
+                            }
+                            // send the END_OF_MEDIA event to all
+                            // listener
+                            iPlayerListenerImpl.postEvent(
+                                PlayerListener.END_OF_MEDIA,
+                                new Long(iMediaTime * 10000));
+                            iMediaTime = 0;
+                        }
+                        if (iAnimationObserver!=null)
+                        {
+                            iAnimationObserver.animationAdvanced(iMediaTime*10000);
+                        }
                     }// end of while loop
                     iCurrentLoopCount = loopCount;
                     // Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo, DEBUG_STR
-                    System.out.println(DEBUG_STR
-                                       + "Came out side the while loop " + iState
-                                       + " iFrameIndex " + iFrameIndex + " loopCount "
-                                       + loopCount);
+
                 }
             };
             thread.start();
         }
         // Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,DEBUG_STR + "-");
-        System.out.println(DEBUG_STR+" Total time taken:> "+(System.currentTimeMillis()-inTime)+" ---");
     }
 
     /**
-     * This function is also being called from VideoControl class,
-     * since on each repaint event, control is getting disposed and created each time
+     * State of the player should be changed from this function only.
+     * @param aState
+     */
+    private synchronized void  changePlayerState(int aState)
+    {
+        iState=aState;
+    }
+    /**
+     * On each repaint event, control is getting disposed and created each time,
+     * So we need to call each time the Control is available
      * @param aControl
      */
-    void addPaintListener(org.eclipse.swt.widgets.Control aControl)
+    private void addPaintListener(org.eclipse.swt.widgets.Control aControl)
     {
-        System.out.println("AnimationPlayer::addPaintListener +++");
         iControl=aControl;
         if (iControl != null)
         {
@@ -422,8 +396,6 @@
                     {
                         public void paintControl(PaintEvent pe)
                         {
-                            //System.out.println("AnimationPlayer::addpaintListener paintControl "+ iImage+" iIsControlVisible "+iIsControlVisible+"current time is "+System.currentTimeMillis());
-                            System.out.println("AnimationPlayer::addPaintListener::PaintListener::paintControl");
                             if (iImage != null && iIsControlVisible)
                             {
                                 pe.gc.drawImage(iImage, iDisplayLocation.x,
@@ -434,7 +406,6 @@
                 }
             });
         }
-        System.out.println("AnimationPlayer::addPaintListener ---");
     }
 
 
@@ -530,35 +501,63 @@
      */
     public long setMediaTime(long aNow) throws MediaException
     {
-        final String DEBUG_STR="AnimationPlayer::setmediaTime()";
         long now = super.setMediaTime(aNow);
-        int totalFrames = iImageData.length;
-        int totalTime = 0;
-        for (int i = 0; i < totalFrames; i++)
+        if (iDuration == TIME_UNKNOWN)
+            iDuration=getMediaTimeForFrame(getTotalNumberFrames());
+        if (now >= iDuration)
         {
-            totalTime += iImageData[i].delayTime;
-            if (totalTime*10000 >= now)
-            {
-                iFrameIndex=i;
-                break;
-            }
+            iFrameIndex=getTotalNumberFrames()-1;
+            iMediaTime = iDuration;
         }
-        // we need to update the iMediaTime as well
-        iMediaTime=totalTime;
-        return totalTime * 10000;
+        else
+        {
+            iFrameIndex = findFrame(now);
+            iMediaTime= getMediaTimeForFrame(iFrameIndex);
+        }
+        return iMediaTime ;
     }
     //////////////////////////////////////////////////////////////////////////////////////
     // Following functions are for internal use, and not exposed to MIDlet developer//////
     /////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Before calling this function check frameIndex is in range or not, from 0 to last index
+     */
+    long getMediaTimeForFrame(int aFrameIndex)
+    {
+        long time=0;
+        for (int i=0; i < aFrameIndex; i++)
+        {
+            time+=iImageData[i].delayTime;
+        }
+        return time*10000;
+    }
+
+    /**
+     * Utility function to calculate the framNumber
+     * @param aTime
+     * @return
+     */
+    int findFrame(long aTime)
+    {
+        long time=0;
+        int frameIndex=0;
+        if (aTime > iDuration)
+            return -1;
+        else if (aTime==0)
+            return 0;
+        int totalNoOfFrame= getTotalNumberFrames();
+        while (time *10000 < aTime && frameIndex < totalNoOfFrame)
+        {
+            time += iImageData[frameIndex++].delayTime;
+        }
+        return frameIndex;
+    }
     /**
      * This function is responsible for creating all controls and adding it into Controls hashtable.
      */
     private void populateControl()
     {
-//      VideoControl videoControl = new VideoControl(this);
-//      FramePositioningControl fpc = new FramePositioningControl(this);
-//      StopTimeControl stc = new StopTimeControl(this);
-//      RateControl rc = new RateControl(this);
         // there are four control provided by AnimationPlayer
         // adding all one by one to the controlList(iControls)
         addControl(new VideoControl(this), fVideoControl);
@@ -568,35 +567,25 @@
     }
 
     /**
-     * This function initialize iControl and iDisplay object if it is null,
-     * otherwise return immediately.
-     *
-     * In case of Canvas, eSWT control will be returned immediately from VideoControl(vc.getControl()),
-     * but in case of CustomItem we need to keep polling, eSWT doesn't return the control for CustomItem
-     * until CustomItem is appended to Form.
+     *  Notified when the display object of ESWT is created
+     *  It is getting created, when initDisplayMode of VideoControl class is called.
      */
-
-    private void initialize()
+    public void notifyDisplayAvailable(Display aDisplay)
     {
-        System.out.println("AnimationPlayer::initialize +++");
-        if (iControl == null || iDisplay == null)
-        {
-            VideoControl vc = (VideoControl) getControl(fVideoControl);
-            iDisplay = vc.getiDisplay();
-            iControl=vc.getControl();
-            addPaintListener(iControl);
-            System.out.println("AnimationPlayer::initialize iDsplay "+iDisplay+" iControl "+iControl);
-            // in case of CustomItem,
-//          while ((iControl = vc.getControl()) == null) {
-//              try {
-//                  Thread.sleep(100);
-//              } catch (InterruptedException e) {
-//                  e.printStackTrace();
-//              }
-//          }
-        }
-        System.out.println("AnimationPlayer::initialize ---");
+        iDisplay= aDisplay;
+        iImage=new Image(iDisplay, iImageData[0]);
     }
+    /**
+     * Notified when the control is available
+     * @param aControl(this is eSWTControl )
+     */
+    public void notifyControlAvailable(org.eclipse.swt.widgets.Control aControl)
+    {
+        iControl=aControl;
+        addPaintListener(iControl);
+    }
+
+
 
     /**
      * This function will be called from setDisplaySize(int width, int height) of animation/VideoControl class
@@ -611,7 +600,7 @@
         {
             iImageData[i]=iImageData[i].scaledTo(width, height);
         }
-        iImage=new Image(iDisplay, iImageData[0]);
+        iImage=new Image(iDisplay, iImageData[iFrameIndex]);
     }
 
     /**
@@ -629,10 +618,22 @@
      * @param format
      */
     // This function is not implemented fully
-    javax.microedition.lcdui.Image getCurrentFrame(String format)
+    byte[] getCurrentFrame(String format)
     {
-        javax.microedition.lcdui.Image currentFrameImage= LCDUIInvoker.createLcduiImage(iImage);
-        return currentFrameImage;
+        // create a new ImageLoader object
+        ImageLoader il= new ImageLoader();
+        // create a ImageData array of length 1 and assign it to 'data' member of ImageLoader
+        il.data= new ImageData[1];
+        int currentFrameIndex= iFrameIndex;
+        // assign the current frame ImageData to image
+        il.data[0]= iImageData[currentFrameIndex];
+        il.logicalScreenWidth  = iImageData[currentFrameIndex].width;
+        il.logicalScreenHeight = iImageData[currentFrameIndex].height;
+        il.backgroundPixel= iBackgroundPixel;
+        ByteArrayOutputStream baos= new ByteArrayOutputStream();
+        il.save(baos, SWT.IMAGE_PNG);
+        //il.save(baos, SWT.IMAGE_GIF);
+        return baos.toByteArray();
     }
 
     /**
@@ -640,27 +641,25 @@
      * Called from VideoControl to get the image width and height,
      * so that Item will be created exactly of same dimension
      */
-    org.eclipse.swt.graphics.Point getImageDimension()
+    Point getImageDimension()
     {
+//      return iCurrentVideoDimension;
         return new org.eclipse.swt.graphics.Point(iImageData[0].width, iImageData[0].height);
     }
 
-    /**
-     * This returns the imageData array,
-     * called from FramePositioningControl class to calculate the frame time
-     */
-    ImageData[] getImageData()
+
+    int getTotalNumberFrames()
     {
-        return iImageData;
+        return iImageData.length;
     }
-
     /**
      *
      * @param aDisplayLocation x,y coordinate where image is to be displayed
      */
     void setDisplayLocation(int aX, int aY)
     {
-        iDisplayLocation=new Point(aX,aY);
+        iDisplayLocation.x=aX;
+        iDisplayLocation.y=aY;
     }
 
     /**
@@ -677,6 +676,7 @@
     Point getSourceDimension()
     {
         return iSourceDimension;
+        //return new Point(iImageData[0].width, iImageData[0].height);
     }
 
     /**
@@ -719,7 +719,7 @@
                 // following line will break the while loop in start method
                 // Objective here is to pause the animation, if it is in started state
                 // also we do not need to notify to the playerListener that player has been stopped or paused
-                iState=PREFETCHED;
+                changePlayerState(PREFETCHED);
             }
             else
             {
@@ -742,19 +742,30 @@
     }
 
     /**
-     * @param iStopTime the iStopTime to set
-     */
-    void setiStopTime(long iStopTime)
-    {
-        this.iStopTime = iStopTime;
-    }
-
-    /**
      * @param iIsControlVisible the iIsControlVisible to set
      */
     void setiIsControlVisible(boolean iIsControlVisible)
     {
         this.iIsControlVisible = iIsControlVisible;
     }
+    /**
+     * Called from
+     */
+    void postEvent(long aMediaTime)
+    {
+        changePlayerState(PREFETCHED);
+        iPlayerListenerImpl.postEvent(PlayerListener.STOPPED_AT_TIME, new Long(
+                                          aMediaTime));
+    }
+
+    /**
+     * @param aAnimationObserver the iAnimationObserver to set
+     */
+    void setiAnimationObserver(AnimationObserver aAnimationObserver)
+    {
+        this.iAnimationObserver = aAnimationObserver;
+    }
+
+
 }