//////////
//
//  QuickTime for Java SDK Sample Code
//
//  Usage subject to restrictions in SDK License Agreement
//  Copyright: © 1996-1999 Apple Computer, Inc.
//
//	Contains:	Functions to step frame-by-frame through a QuickTime movie.
//
//
//	This file defines functions that you can use to step frame-by-frame through a QuickTime movie.
//	Indeed, it illustrates *two* different methods for doing this: (1) using Movie Toolbox functions
//	to advance (or retreat) to interesting times in the movie; and (2) using movie controller actions
//	to step forward or backward through a movie. To my knowledge, there are no particular advantages
//	to using one or the other method, except that the second method is (as you will see) quite a bit
//	simpler to code.
//
//	METHOD ONE: Use Movie Toolbox calls to step to interesting times in the movie. An interesting time
//	is a time value in a movie, track, or media that meets certain search conditions that you specify.
//	We'll use a very simple search condition: locate the next (or previous) sample in the movie's media.
//	Once we have an interesting time, we display the sample at that time by calling SetMovieTimeValue.
//	To implement this first method, we define three functions (which all operate on an open movie):
//
//	-> GoToNextVideoSample: display the sample that follows the current sample in a movie
//	-> GoToPrevVideoSample: display the sample that precedes the current sample in a movie
//	-> GoToFirstVideoSample: display the first video sample in a movie
//
//	Internally, these functions depend on three functions defined at the beginning of this file.
//	The code here is extremely straightforward. The only "gotcha" concerns finding the first
//	interesting time in a movie. See the description of GetStartTimeOfFirstVideoSample for
//	details.
//
//	METHOD TWO: Use movie controller actions to step through frames in the movie. Using this method,
//	the code is considerably simpler. To implement this second method, we define three functions
//	(which all operate on a movie controller that is associated with an open movie):
//
//	-> MCGoToNextVideoSample: display the sample that follows the current sample in a movie
//	-> MCGoToPrevVideoSample: display the sample that precedes the current sample in a movie
//	-> MCGoToFirstVideoSample: display the first video sample in a movie
//
//
//////////




import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.io.IOException;

import quicktime.*;
import quicktime.std.*;
import quicktime.std.movies.*;
import quicktime.std.clocks.*;



//////////
//
// FrameStepper class
//
//////////

public class FrameStepper {


    //
    // METHOD 1: Use Movie Toolbox calls to step to interesting times in the movie.
    //
    
    //////////
    //
    // GetStartTimeOfFirstVideoSample
    // Return, through the TimeInfo parameter, the starting time of the first video sample of the
    // specified QuickTime movie.
    //
    // The "trick" here is to set the nextTimeEdgeOK flag, to indicate that you want to get the
    // starting time of the beginning of the movie.
    //
    //////////

    TimeInfo GetStartTimeOfFirstVideoSample (Movie theMovie)
    {
	    try 
	    {
    	    
	        TimeInfo    interestingTime;
	        int		    interestingTimeFlags;
	        int         myTypes[]               = new int[] {StdQTConstants.visualMediaCharacteristic};
	        float       theRate                 = 1.0f;
	        int         bogusStartTime          = -1;
    	    
        	
            // specify we want the first sample in the movie	     
            interestingTimeFlags = StdQTConstants.nextTimeMediaSample + StdQTConstants.nextTimeEdgeOK;			

            // get the time of the first sample
            interestingTime = theMovie.getNextInterestingTime(interestingTimeFlags,
                                                                myTypes,
                                                                bogusStartTime,    /* bogus start time */
                                                                theRate);
	        return(interestingTime);

        }
        catch (QTException err) 
        {
		    err.printStackTrace();
	    }

	    return(null);
    }


    //////////
    //
    // DrawVideoSampleAtTime
    // Draw the video sample of a QuickTime movie at the specified time.
    //
    //////////

    void DrawVideoSampleAtTime (Movie theMovie, int theTime)
    {
    	
	    try 
	    {
	        short	myFlags;
	        long    timeValue;
    	    
	        // make sure that the specified time lies within the movie's temporal bounds
	        if ((theTime < 0) || (theTime > theMovie.getDuration()))
		        return;
        	
        	// set current movie time to the desired value
	        theMovie.setTimeValue(theTime);
        		
	        // the following calls to UpdateMovie and MoviesTask are not necessary
	        // if you are handling movie controller events in your main event loop
	        // (by passing the event to MCIsPlayerEvent); they don't hurt, however.
        	
	        // redraw the movie immediately by calling UpdateMovie and MoviesTask
	        theMovie.update();
	        theMovie.task(0);

        } 
        catch (QTException err)
        {
		    err.printStackTrace();
	    }

    }


    //////////
    //
    // DrawVideoSampleNextOrPrev
    // Draw the next or previous video sample of a QuickTime movie.
    // If theRate is 1, the next video sample is drawn; if theRate is -1, the previous sample is drawn.
    //
    //////////

    void DrawVideoSample(Movie theMovie, float theRate)
    {
    	
	    try 
	    {
	        TimeInfo    timeInfo;
	        int		    movieCurrentTime;
	        int			interestingTimeFlags;
	        int         mediaTypes[] = new int[] {StdQTConstants.visualMediaCharacteristic};
            
            // specify we want the next frame in the movie's media
	        interestingTimeFlags = StdQTConstants.nextTimeStep;
	        // get the current movie time
            movieCurrentTime = theMovie.getTime();
            // get current sample at this time
            timeInfo = theMovie.getNextInterestingTime(interestingTimeFlags,
                                                        mediaTypes,
                                                        movieCurrentTime,
                                                        theRate);
            // now draw the sample for the current time
	        DrawVideoSampleAtTime(theMovie, timeInfo.time);

        } 
        catch (QTException err)
        {
		    err.printStackTrace();
	    }
    	
    }

    //////////
    //
    // DrawVideoSampleNext
    // Draw the next video sample of a QuickTime movie.
    //
    //////////

    void DrawVideoSampleNext (Movie theMovie)
    {
        DrawVideoSample(theMovie, 1.0f);    	
    }

    //////////
    //
    // DrawVideoSamplePrev 
    // Draw the previous video sample of a QuickTime movie.
    //
    //////////

    void DrawVideoSamplePrev (Movie theMovie)
    {
        DrawVideoSample(theMovie, -1.0f);    	
    }

    //////////
    //
    // GoToFirstVideoSample
    // Draw the first video sample of a QuickTime movie.
    //
    //////////

    void GoToFirstVideoSample (Movie theMovie)
    {	
	    TimeInfo    timeInfo;
    	
	    timeInfo = GetStartTimeOfFirstVideoSample(theMovie);
    		
	    DrawVideoSampleAtTime(theMovie, timeInfo.time);
    }

    //
    // METHOD 2: Use Movie Controller calls to step to interesting times in the movie.
    //

    //////////
    //
    // MCGoToFirstVideoSample
    // Draw the first video sample of the QuickTime movie associated with the specified movie controller.
    //
    //////////

    void MCGoToFirstVideoSample (MovieController theMC)
    {
	    try {
	        Movie       theMovie        = theMC.getMovie();
    	    TimeRecord	myTimeRecord    = new TimeRecord(theMovie.getTimeScale(),0);
    	
	        theMC.goToTime(myTimeRecord);
        } 
        catch (QTException err)
        {
		    err.printStackTrace();
	    }
    	
    }


    //////////
    //
    // MCGoToNextVideoSample
    // Draw the next video sample of the QuickTime movie associated with the specified movie controller.
    //
    //////////

    void MCGoToNextVideoSample (MovieController theMC)
    {
	    try {
	        int	stepCount = 1;	// advance the movie one frame
        	
	        theMC.step(stepCount);
	    }
        catch (QTException err)
        {
		    err.printStackTrace();
	    }
    }


    //////////
    //
    // MCGoToPrevVideoSample
    // Draw the previous video sample of the QuickTime movie associated with the specified movie controller.
    //
    //////////

    void MCGoToPrevVideoSample (MovieController theMC)
    {
    	
	    try {
    	    int	stepCount = -1;	// back the movie up one frame
        	
	        theMC.step(stepCount);
	    }
        catch (QTException err)
        {
		    err.printStackTrace();
	    }
    }


}   /* end FrameStepper class  */