Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
QTFrameStepper.c
////////// |
// |
// File: QTFrameStepper.c |
// |
// Contains: Functions to step frame-by-frame through a QuickTime movie. |
// |
// Written by: Tim Monroe |
// Parts based on DTSQTUtilities.c by Apple Developer Technical Support |
// and on SimpleInMovies sample code by Guillermo A. Ortiz. |
// |
// Copyright: © 1997 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <5> 11/18/98 rtm added QTStep_GetFrameCount, for illustrative purposes only |
// <4> 03/09/98 rtm changed nextTimeMediaSample flag to nextTimeStep (to support MPEG files) |
// <3> 01/05/98 rtm revised and augmented comments |
// <2> 01/02/98 rtm some code clean-up |
// <1> 12/22/97 rtm first file |
// |
// 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): |
// |
// -> QTStep_GoToNextVideoSample: display the sample that follows the current sample in a movie |
// -> QTStep_GoToPrevVideoSample: display the sample that precedes the current sample in a movie |
// -> QTStep_GoToFirstVideoSample: display the first video sample in a movie |
// |
// Internally, these functions depend on three static 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 QTStep_GetStartTimeOfFirstVideoSample for |
// details. |
// |
// METHOD TWO: Use movie controller actions to step through frames in the movie. This method uses |
// the MCDoAction function with the mcActionStep and mcActionGoToTime actions. 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): |
// |
// -> QTStep_MCGoToNextVideoSample: display the sample that follows the current sample in a movie |
// -> QTStep_MCGoToPrevVideoSample: display the sample that precedes the current sample in a movie |
// -> QTStep_MCGoToFirstVideoSample: display the first video sample in a movie |
// |
// Historical note: Method One is based loosely on sample-stepping code in the DTSQTUtilities package |
// developed by Apple Macintosh Developer Technical Support. Method Two is based on a few functions |
// in the SimpleInMovies sample code written by Guillermo A. Ortiz. |
// |
////////// |
#include "QTFrameStepper.h" |
////////// |
// |
// METHOD ONE: Use Movie Toolbox calls to step to interesting times in the movie. |
// |
////////// |
////////// |
// |
// QTStep_GetStartTimeOfFirstVideoSample |
// Return, through the theTime 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. |
// |
// If this function encounters an error, it returns a (bogus) starting time of -1. Note that |
// GetMovieNextInterestingTime also returns -1 as a starting time if the search criteria |
// specified in the myFlags parameter are not matched by any interesting time in the movie. |
// |
////////// |
static OSErr QTStep_GetStartTimeOfFirstVideoSample (Movie theMovie, TimeValue *theTime) |
{ |
short myFlags; |
OSType myTypes[1]; |
*theTime = kBogusStartingTime; // a bogus starting time |
if (theMovie == NULL) |
return(invalidMovie); |
myFlags = nextTimeMediaSample + nextTimeEdgeOK; // we want the first sample in the movie |
myTypes[0] = VisualMediaCharacteristic; // we want video samples |
GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, (TimeValue)0, fixed1, theTime, NULL); |
return(GetMoviesError()); |
} |
////////// |
// |
// QTStep_DrawVideoSampleAtTime |
// Draw the video sample of a QuickTime movie at the specified time. |
// |
////////// |
static OSErr QTStep_DrawVideoSampleAtTime (Movie theMovie, TimeValue theTime) |
{ |
short myFlags; |
OSErr myErr = noErr; |
if (theMovie == NULL) |
return(invalidMovie); |
// make sure that the specified time lies within the movie's temporal bounds |
if ((theTime < 0) || (theTime > GetMovieDuration(theMovie))) |
return(paramErr); |
SetMovieTimeValue(theMovie, theTime); |
myErr = GetMoviesError(); |
if (myErr != noErr) |
goto bail; |
// 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 |
UpdateMovie(theMovie); |
myErr = GetMoviesError(); |
if (myErr != noErr) |
goto bail; |
MoviesTask(theMovie, 0L); |
myErr = GetMoviesError(); |
bail: |
return(myErr); |
} |
////////// |
// |
// QTStep_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. |
// |
////////// |
static OSErr QTStep_DrawVideoSampleNextOrPrev (Movie theMovie, Fixed theRate) |
{ |
TimeValue myCurrTime; |
TimeValue myNextTime; |
short myFlags; |
OSType myTypes[1]; |
OSErr myErr = noErr; |
if (theMovie == NULL) |
return(invalidMovie); |
myFlags = nextTimeStep; // we want the next frame in the movie's media |
myTypes[0] = VisualMediaCharacteristic; // we want video samples |
myCurrTime = GetMovieTime(theMovie, NULL); |
GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, myCurrTime, theRate, &myNextTime, NULL); |
myErr = GetMoviesError(); |
if (myErr != noErr) |
return(myErr); |
myErr = QTStep_DrawVideoSampleAtTime(theMovie, myNextTime); |
return(myErr); |
} |
////////// |
// |
// QTStep_GoToFirstVideoSample |
// Draw the first video sample of a QuickTime movie. |
// |
////////// |
OSErr QTStep_GoToFirstVideoSample (Movie theMovie) |
{ |
TimeValue myTime; |
OSErr myErr = noErr; |
if (theMovie == NULL) |
return(invalidMovie); |
myErr = QTStep_GetStartTimeOfFirstVideoSample(theMovie, &myTime); |
if (myErr != noErr) |
return(myErr); |
myErr = QTStep_DrawVideoSampleAtTime(theMovie, myTime); |
return(myErr); |
} |
////////// |
// |
// QTStep_GoToNextVideoSample |
// Draw the next video sample of a QuickTime movie. |
// |
////////// |
OSErr QTStep_GoToNextVideoSample (Movie theMovie) |
{ |
return(QTStep_DrawVideoSampleNextOrPrev(theMovie, fixed1)); |
} |
////////// |
// |
// QTStep_GoToPrevVideoSample |
// Draw the previous video sample of a QuickTime movie. |
// |
////////// |
OSErr QTStep_GoToPrevVideoSample (Movie theMovie) |
{ |
return(QTStep_DrawVideoSampleNextOrPrev(theMovie, FixMul(Long2Fix(-1), fixed1))); |
} |
////////// |
// |
// METHOD TWO: Use movie controller actions to step thru frames in the movie. |
// |
////////// |
////////// |
// |
// QTStep_MCGoToFirstVideoSample |
// Draw the first video sample of the QuickTime movie associated with the specified movie controller. |
// |
////////// |
OSErr QTStep_MCGoToFirstVideoSample (MovieController theMC) |
{ |
TimeRecord myTimeRecord; |
Movie myMovie = NULL; |
OSErr myErr = noErr; |
if (theMC == NULL) |
return(paramErr); |
myMovie = MCGetMovie(theMC); |
if (myMovie == NULL) |
return(paramErr); |
myTimeRecord.value.hi = 0; |
myTimeRecord.value.lo = 0; |
myTimeRecord.base = 0; |
myTimeRecord.scale = GetMovieTimeScale(myMovie); |
myErr = GetMoviesError(); |
if (myErr != noErr) |
return(myErr); |
return(MCDoAction(theMC, mcActionGoToTime, &myTimeRecord)); |
} |
////////// |
// |
// QTStep_MCGoToNextVideoSample |
// Draw the next video sample of the QuickTime movie associated with the specified movie controller. |
// |
////////// |
OSErr QTStep_MCGoToNextVideoSample (MovieController theMC) |
{ |
short myStep = 1; // advance the movie one frame |
if (theMC == NULL) |
return(paramErr); |
return(MCDoAction(theMC, mcActionStep, (Ptr)myStep)); |
} |
////////// |
// |
// QTStep_MCGoToPrevVideoSample |
// Draw the previous video sample of the QuickTime movie associated with the specified movie controller. |
// |
////////// |
OSErr QTStep_MCGoToPrevVideoSample (MovieController theMC) |
{ |
short myStep = -1; // back the movie up one frame |
if (theMC == NULL) |
return(paramErr); |
return(MCDoAction(theMC, mcActionStep, (Ptr)myStep)); |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// Frame utilities. |
// |
// These functions illustrate some other useful things you might want to do with movie frames; |
// they are not used elsewhere in this file. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// QTStep_GetFrameCount |
// Get the number of frames in the specified movie track. We return the value -1 if |
// an error occurs and we cannot determine the number of frames in the track. |
// |
// Based (loosely) on frame-counting code in ConvertToMovie Jr.c. |
// |
// We count the frames in the track by stepping through all of its interesting times |
// (the places where the track displays a new sample). |
// |
////////// |
long QTStep_GetFrameCount (Track theTrack) |
{ |
long myCount = -1; |
short myFlags; |
TimeValue myTime = 0; |
if (theTrack == NULL) |
goto bail; |
// we want to begin with the first frame (sample) in the track |
myFlags = nextTimeMediaSample + nextTimeEdgeOK; |
while (myTime >= 0) { |
myCount++; |
// look for the next frame in the track; when there are no more frames, |
// myTime is set to -1, so we'll exit the while loop |
GetTrackNextInterestingTime(theTrack, myFlags, myTime, fixed1, &myTime, NULL); |
// after the first interesting time, don't include the time we're currently at |
myFlags = nextTimeStep; |
} |
bail: |
return(myCount); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14