src/FrameStepper.java

//////////
//
//  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  */