Server Side Stills from QuickTime
Generating still JPEG images from QuickTime movies using Java running on the server.
Often it is useful to generate preview thumbnail images of QuickTime video movies on the server. CMS type applications that allow an admin user to upload and display video would be the most obvious use of this.
Having said that, generating still images on the desktop is far quicker and more efficient. Opening 80MB video files, over the network, in the web application's RAM in not the best use of resources. This solution requires Java 1.4.1 to be running on the server and most importantly requires QuickTime for Java. QuickTime for Java is essentially a series of JNDI hooks into the native C libraries of QuickTime. What this means is that this can only be deployed on MacOS X or MS Windows servers.
Watershed uses something like the code below in WebObjects applications as part of the QuickTime generation and manipulation classes used in web sites such as watershed.co.uk, electricdecember.org and dshed.net. These are expensive operations and the results should be aggressively cached either in RAM or on disk.
The code below has been a bit mangled to fit the narrow columns and still has a lot of commented-out logging statements.
import quicktime.*;import quicktime.app.*;import quicktime.app.players.*;import quicktime.app.display.*;import quicktime.io.*;import quicktime.std.*;import quicktime.std.movies.*;import quicktime.qd.*;import quicktime.std.movies.media.*;public class GetImage {public GetImage() {}public void getImageFromMovie(String url, String offsetTime) {try {QTSession.open();DataRef ref = new DataRef(url);System.out.println("DataRef: " + ref);if (ref == null) return;Movie theMovie = Movie.fromDataRef(ref, 0);System.out.println(theMovie.getBounds());int theTime = Integer.parseInt(offsetTime) * theMovie.getTimeScale();System.out.println("theTime: " + theTime);Pict pictImage = theMovie.getPict(theTime);System.out.println("PICT: " + pictImage);// Optionally you could just use the poster image if it has been set by the person encoding the video//pictImage = theMovie.getPosterPict();// Now encode the Macintosh PICT as a JPEG or PNG or ....quicktime.std.image.GraphicsExporter graphicsExporter = new quicktime.std.image.GraphicsExporter(StdQTConstants.kQTFileTypeJPEG);graphicsExporter.setInputPicture(pictImage);QTFile exportFile = new QTFile("StillImage.jpg");graphicsExporter.setOutputFile(exportFile);System.out.println("graphicsExporter: " + graphicsExporter);// Do the exportint size = graphicsExporter.doExport();byte[] jpegBytes = graphicsExporter.GraphicsExportReadOutputData(0, size);System.out.println("jpegBytes: " + jpegBytes);QTSession.close();} catch (Exception e) {QTSession.close();System.out.println(e);System.exit(0);}}public static void main(String args[]) {if (args.length < 2) {System.out.println("You need to specify a URL and a location time in seconds when launching");return;}GetImage instance = new GetImage();instance.getImageFromMovie(args[0], args[1]);}}
Using the code
The following instructions assume you are using a Macintosh but are almost identical for other platforms. First, ensure that you have QuickTime for Java installed. Copy the code above into a text file and save the file as GetImage.java on the Desktop, or alternatively download the class in a .java file. Next, assuming you have a JDK installed, compile the source. Installing Apple's Xcode Tools will give you a Java compiler. Open the Terminal application and compile by typing:
javac -classpath /System/Library/Java/Extensions/QTJava.zip GetImage.java
A file named GetImage.class will be produced. Alternatively download the compiled application. To run the application, navigate to the directory containing the GetImage.class and type something like:
java -classpath /System/Library/Java/Extensions/QTJava.zip: GetImage http://localhost/Cremaster.mov 22
The application will save the result as a file named StillImage.jpg in the same directory. The image produced is not scaled but this is fairly easy to add in. The code sample above contains lots of debug logging so remove the System.out.println lines.