package controller;
//----- JDK Imports ------------------------------------------------------------
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
//----- Quicktime Imports ------------------------------------------------------
import quicktime.QTException;
import quicktime.io.OpenMovieFile;
import quicktime.io.QTFile;
import quicktime.std.StdQTConstants;
import quicktime.std.StdQTException;
import quicktime.std.clocks.TimeRecord;
import quicktime.std.movies.Movie;
import quicktime.std.movies.TimeInfo;
import quicktime.std.movies.Track;
//----- Phoenix Imports --------------------------------------------------------
import view.MovieWindow;
/**
* Video Phoenix
* Version 0.2.0
* Copyright (c) 2007 Lunderskov, Ian; Pan, Jiabei; Rebelsky, Samuel;
* Whisenhunt, Heather; Young, Ian; Zuleta Benavides, Luis.
* All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* @author Lunderskov, Ian; Pan, Jiabei; Rebelsky, Samuel; Whisenhunt, Heather;
* Young, Ian; Zuleta Benavides, Luis
* @author Glimmer Labs
* @version 0.2.0
*/
public class MovieController
{
/*--------*-------------------------------------------------------------------
* Fields *
*--------*/
// vector of windows for this controller
public Vector<MovieWindow> windows;
// this controller's instance of Phoenix
public PhoenixController phoenix;
// list of movies bound to variables
public static Hashtable<String, Movie> movieList
= new Hashtable<String, Movie>();
// name of the most recently opened movie
public String name;
/*--------------*-------------------------------------------------------------
* Constructors *
*--------------*/
/**
* Create a new MovieController
*
* @param phoenix PhoenixController for this MovieController
*/
public MovieController(PhoenixController phoenix)
{
this.phoenix = phoenix;
this.windows = new Vector<MovieWindow>();
} // MovieController(PhoenixController)
/*---------*------------------------------------------------------------------
* Methods *
*---------*/
/**
* Step a movie forward or backwards
*
* @param mov Movie to be worked on
* @param step Number of frames to be stepped; positive values indicate
* forward movement, negative backward.
* @throws QTException
* NOTE: Negative values that would step beyond the beginning of the movie
* will cause stepping to stop at the first frame in the movie. The movie
* player may or may not update in this case.
*/
public void stepFrame(Movie mov, int step)
throws QTException
{
mov.setRate(0f);
for (int i = 0; i < Math.abs(step); i++)
{
mov.setTimeValue(mov.getIndTrackType(1,
StdQTConstants.visualMediaCharacteristic,
StdQTConstants.movieTrackCharacteristic).getNextInterestingTime(
StdQTConstants.nextTimeMediaSample, mov.getTime(), step).time);
}
} // void stepFrame(Movie, int)
/**
* Go to the previous frame
*
* @param mov Movie to be worked on
* @throws QTException
*/
public void prevFrame(Movie mov) throws
QTException
{
stepFrame(mov, -1);
} // void prevFrame(Movie)
/**
* Go to the next frame
*
* @param mov Movie to be worked on
* @throws QTException
*/
public void nextFrame(Movie mov) throws
QTException
{
stepFrame(mov, 1);
} // void nextFrame(Movie)
/**
* Rewind a movie
*
* @param mov Movie to be rewound
* @throws QTException
*/
public void rewind(Movie mov)
throws StdQTException
{
float rate = mov.getRate();
// if the movie is playing or fast-forwarding
if (rate > 0)
{
// play in reverse at normal speed
rate = -1.0f;
} // if (rate > 0)
// if the movie is paused
else
{
// play in reverse at half speed
rate = rate - 0.5f;
} // else
mov.setRate(rate);
} // rewind(Movie)
/**
* Fast-forward a movie
*
* @param mov Movie to be fast-forwarded
* @throws StdQTException
*/
public void fastForward(Movie mov)
throws StdQTException
{
float rate = mov.getRate();
// if the movie is rewinding
if (rate < 0)
{
// play the movie at normal speed
rate = 1.0f;
} // if (rate < 0)
// if the movie is paused or playing
else
{
// increase the rate by half the normal framerate
rate += 0.5f;
} // else
mov.setRate(rate);
} // fastForward(Movie)
/**
* Create a new Movie object from a media file supported by QuickTime using
* a file chooser.
* Prints an error if the file type is not supported, file cannot be found, or
* File Chooser is closed prematurely.
*
* @return movie Requested movie object
*/
public Movie openFile()
{
Movie local = null;
QTFile file = null;
// open a file chooser
try
{
file = QTFile.standardGetFilePreview(QTFile.kStandardQTFileTypes);
local = Movie.fromFile(OpenMovieFile.asRead(file));
this.name = file.getName();
} // try
// if something goes wrong, print an error to SchemeWindow
catch (QTException qte)
{
// as long as it is not a user cancelled error
if (qte.errorCode() != -128)
{
PhoenixController.schemeController.printStyledText("\n IOError:"
+ " Could not load the file, check your pathname and that the file "
+ "type is supported by Quicktime", "scheme_error");
} // if (qte.errorCode() != -128)
} // catch (QTException)
return local;
} // openFile()
/**
* Create a new Movie object from a media file supported QuickTime.
* Prints an error if the file type is not supported or file cannot be found.
*
* @param path Path of desired file
* @return movie Requested movie object
*/
public Movie openFile(String path)
{
Movie local = null;
// attempt to open the file
try
{
QTFile file = new QTFile(path);
local = Movie.fromFile(OpenMovieFile.asRead(file));
this.name = file.getName();
} // try
// if open fails, print error to SchemeWindow
catch (QTException qte)
{
PhoenixController.schemeController.printStyledText("\n IOError:"
+ " Could not load the file, check your pathname and that the file type"
+ " is supported by Quicktime", "scheme_error");
} // catch (QTException)
return local;
} // openFile(String)
/**
* Display a movie in a new MovieWindow
*
* @param mov QuickTime movie to be displayed on the monitor
* @param name Name associated with movie
* @throws Exception
*/
public void showMovie(Movie mov, String name)
throws Exception
{
if (mov == null)
{
return;
} // if (mov == null)
// create a new MovieWindow
MovieWindow movieWindow = null;
// called from Scheme side, find the variable name of mov in movielist
if (name.equalsIgnoreCase("preview"))
{
// look for mov in movieList
if (movieList.contains(mov))
{
Enumeration<String> keys = movieList.keys();
while (keys.hasMoreElements())
{
String key = keys.nextElement();
if (movieList.get(key) == mov)
{
movieWindow = new MovieWindow(this, key, mov);
break;
} // if (movieList.get(key) == mov)
} // while (keys.hasMoreElements())
} // if (movieList.contains(mov))
// if not in movieList
else
{
movieWindow = new MovieWindow(this, this.name, mov);
} // else
} // if (name.equalsIgnoreCase("preview"))
// called from Java side
else
{
movieWindow = new MovieWindow(this, name, mov);
} // else
this.windows.add(movieWindow);
} // showMovie(Movie, String)
/**
* Bind a movie to a variable name
*
* @param mov Movie to be bound to name
* @param name Name associated with movie
*/
public void defineMovie(Movie mov, String name)
{
PhoenixController.clipsController.addClip(mov, name);
} // defineMovie(Movie, String)
/**
* Get the distance between the first two interesting frames in a movie
*
* @param mov Movie to calculate interval for
* @return interval Interval between first two interesting frames in mov
*/
public int getInterval(Movie mov)
{
TimeInfo time = null;
try
{
// get the video track from the movie
Track visualTrack = mov.getIndTrackType(1,
StdQTConstants.visualMediaCharacteristic,
StdQTConstants.movieTrackCharacteristic);
// if no visual track, make something up to avoid exceptions
if (visualTrack == null)
{
return 10;
} // if (visualTrack == null)
mov.setTime(new TimeRecord(mov.getTimeScale(), 0));
// get the distance to the next interesting time
time = visualTrack.getNextInterestingTime(
StdQTConstants.nextTimeMediaSample, mov.getTime(), 1);
} // try
catch (QTException qte)
{
qte.printStackTrace();
} // catch (QTException)
return time.time;
} // getInterval(Movie)
/**
* Set the volume of the movie
*
* @param mov Movie to set volume
* @param vol Volume to set movie to, between 0 and 100
*/
public void setVolume(Movie mov, float vol)
{
float volume = ((float)vol / 100.0f);
volume *= volume;
volume *= volume;
volume *= 128;
if (volume == 128)
{
volume = 127.999f;
} // if (volume = 128)
try
{
mov.setVolume(volume);
} // try
catch (StdQTException stdqte)
{
stdqte.printStackTrace();
} // catch (StdQTException)
} // setVolume(Movie, float)
/**
* Set a movie to the specified time
*
* @param mov Movie to set time
* @param time Time to set movie to
*/
public static void setMovieTime(Movie mov, float time)
{
try
{
int timeInt = Math.round(mov.getTimeScale() * time);
if (timeInt > mov.getDuration())
{
PhoenixController.schemeController.printStyledText("\n Error: Invalid "
+ "time; please select a time between 0 and "
+ mov.getDuration() / mov.getTimeScale(), "scheme_error");
} // if (timeInt > mov.getDuration())
else
{
mov.setTimeValue(timeInt);
} // else
} // try
catch (StdQTException stdqte)
{
stdqte.printStackTrace();
} // catch (StdQTException)
} // setMovieTime(Movie, float)
} // class MovieController