QuickTime for Java: A Developer's Notebook/Getting Up and Running with QuickTime for Java

From WikiContent

< QuickTime for Java: A Developer's Notebook(Difference between revisions)
Jump to: navigation, search
(Initial conversion from Docbook)
Current revision (13:22, 7 March 2008) (edit) (undo)
(Initial conversion from Docbook)
 
(2 intermediate revisions not shown.)

Current revision

QuickTime for Java: A Developer's Notebook

Do you need to do anything special to start developing QuickTime for Java applications? The answer to that question is easily answered by another question: are you using Mac OS X? If so, you have everything you need: Java, QuickTime, and QuickTime for Java (QTJ). If you're using Windows, you might have some downloading to do.

Contents

Setting Up QTJ on Windows

First, you must have Java installed, presumably the latest developer kit release from Sun. As of this writing, that would be the J2SE 1.4.2 SDK, which lives at http://java.sun.com/j2se/1.4.2/download.html. Now you must install and/or update QuickTime.

How do I do that?

If you don't already have QuickTime (or iTunes, which includes QuickTime in its install), you can get it from http://quicktime.apple.com/. What's perhaps more common is that you have QuickTime, but you don't have QuickTime for Java, which is not installed by default.

In this case, you can use the QuickTime Updater to update your copy of QuickTime and install custom pieces like QTJ. If you have the QuickTime icon down in your System Tray, you can right-click it to launch the Updater, as seen in Figure 1-1. You can also get to the Updater via Start → Programs → QuickTime → QuickTime Updater.

Figure 1-1. Launching the QuickTime Updater from the system tray

Launching the QuickTime Updater from the system tray

Whether you're updating or installing QuickTime for the first time, you need to click the Custom button to perform a custom install. This will give you the opportunity to install nondefault features, most of which are optional codecs , or software components to handle various video and audio encoding formats. Scroll down the list and you should see QuickTime for Java, as shown in Figure 1-2.

Figure 1-2. Custom install of QuickTime for Java

Custom install of QuickTime for Java

Continue by clicking Update Now (or Install, if this is a new install) to put the latest version of QuickTime and QuickTime for Java on your PC.

What just happened?

The installer installed QuickTime's various pieces in your system, adding a QuickTime group to your Start Menu, a QuickTime icon in your System Tray, various pieces in C:\WINDOWS\System32\QuickTime, etc. It puts QTJava.zip in the lib/ext directory of any valid Java installations it finds, adds a systemwide environment variable called QTJAVA with the path to this file, and adds the file's path to the CLASSPATH system environment variable, creating it if necessary. Figure 1-3 shows what this looks like in Windows Explorer.

Figure 1-3. QTJava.zip file installed into a Java 1.4.2 lib/ext folder

QTJava.zip file installed into a Java 1.4.2 lib/ext folder

It should be obvious that it's important to do the installs in the order shown here: Java first, then QuickTime. That way, QuickTime can find the existing Java directories into which to install QTJava.zip. Unfortunately, this can still get messed up if you add another Java Runtime Environment (JRE) later—QuickTime might think QTJ is installed, but the new JRE won't have QTJava.zip in its lib/ext directory. In this case, copying QTJava.zip manually might be the most practical option.

Note

Note that QTJava is a zip file, not a JAR, which gives it this archive-like icon. You don't need, or want, to ever unzip this file.

What about...

...installing QTJ on Linux? Sorry. The thing that makes QTJ fast and powerful—the fact that it's a wrapper to an underlying native framework—is also its cross-platform downfall. QuickTime for Java can exist only on platforms that Apple develops QuickTime for, and right now, that means Mac and Windows. On the other hand, if Apple ever did port QuickTime to Linux, bringing QTJ along for the ride probably wouldn't be hard.

And what about installing QTJ on (Classic) Mac OS? Of course. QTJ was originally developed on and for Mac OS 8 and 9. It is part of the standard QuickTime install for Mac OS and thus gets picked up as part of a regular update (which you'd launch with the QuickTime Settings control panel, under the Update Check section). On Classic, the QTJava.zip file lives in System Folder/Extensions/MRJ Libraries/MRJClasses (yes, there's a space in MRJ Libraries , but not in MRJClasses).

Note

MRJ means Macintosh Runtime for Java, the name of Classic's JRE. The name and its confusing versioning were dropped for OS X.

However, development of QuickTime for Classic stopped at Version 6.0.3 and does not include the much-changed version of QTJ that this book covers, QTJ 6.1. Furthermore, it's worth remembering that Java on Classic Mac OS never got past Java 1.1.8, which means it doesn't include Swing, Collections, or many other J2SE classes and conveniences that modern Java developers would expect to be present.

Where's the API documentation? Even though QTJava.zip is all you need to compile, some documentation and demos would be really helpful, right? The good news is that there is a QTJ SDK that offers Javadocs and demos. Unfortunately, much of what's on Apple's web site as of this writing refers to an earlier version of QTJ that won't work with Java 1.4 on Mac OS X. The most complete SDK right now is labeled as the "QuickTime for Java Windows SDK," and is located at http://developer.apple.com/sdk/index.html#QTJavaWin. This package contains a complete set of current Javadocs and demos that have been updated to represent the new API calls in QTJ 6.1. You can also view the Javadoc online at http://developer.apple.com/documentation/Java/Reference/1.4.1/Java141API_QTJ/index.html.

Tip

When you look at the Javadoc, many methods will have a boldface reference to their equivalent C function. For example, Movie.start( ), which starts playing a movie (see the next chapter), wraps the native function QuickTime::StartMovie. You can usually find the native documentation by doing a search on Apple's page for the function name or by Googling for it with a search term like site:apple.com StartMovie.

Why would you ever look at the native docs when you're programming in Java? Because a lot of the parameters aren't described in the Javadoc, particularly when methods take behavior flags.

Embedding QuickTime in HTML

Every once in a while, a developer new to QuickTime will post to one of the developer lists, saying he needs QTJ to put a QuickTime movie in a web page.

QTJ is great, but this is way, way overkill. For this task, you don't need QTJ. In fact, you'd just be creating headaches for yourself by requiring QTJ and dealing with the hassles of applets. Instead, you can just embed QuickTime content in HTML.

Note

The mailing lists at http://lists.apple.com/ are a great source of information, particularly quicktime-java, quicktime-users (authoring), and quicktime-api (native programming). java-dev is also helpful for figuring out issues with Mac OS X's Java implementation.

How do I do that?

In your HTML page, use an <object> tag, which wraps an <embed>, as shown in Example 1-1.

Example 1-1. Embedding QuickTime in HTML

<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
 width="160" height="136"
 codebase="http://www.apple.com/qtactivex/qtplugin.cab">
   <param name="src" VALUE="buhbuhbuh.mov"/>
   <param name="autoplay" VALUE="true"/>
   <param name="loop" VALUE="true"/>
   <param name="controller" value="true"/>
<embed src="buhbuhbuh.mov" width="160" height="136"
  scale="tofit"
  controller="true"
  autoplay="true"
  loop="true"
  pluginspage="http://www.apple.com/quicktime/download/"/>
</object>

The parameters are generally self-explanatory: height, width, and src are the only ones that are actually required. Because I've chosen to include a controller widget, I add 16 to the height parameter and use the scale parameter with the value tofit.

A web page using this tag is shown in Figure 1-4.

Figure 1-4. Embedding QuickTime movie in HTML

Embedding QuickTime movie in HTML

What just happened?

The weird thing about this is, of course, the tag-within-a-tag arrangement. We do this because although most browsers use the <embed> tag to use plug-ins, Internet Explorer on Windows is special and insists that we use an <object> tag to talk to a QuickTime ActiveX control.

Because of this arrangement, you have to list all the parameters twice, once in each tag. In the <embed> tag they're attributes, and in the <object> tag they're child <param> elements. Each tag also has some boilerplate code, such as the <embed>'s pluginspage and the <object>'s classid and codebase.

What about...

...other options for the plug-in? There are too many to cover here. Check out http://www.apple.com/quicktime/authoring/embed.html. There's also some support for controlling a movie via JavaScript in some browsers (including IE and Mozilla derivatives, but not Safari as of this writing), using the attribute enablejavascript.

Preflighting a QTJ Installation

Given the hassle of setting up your own box with a custom QuickTime installation, the idea of having to walk your Windows users through such a process is probably unappealing. Installing the various QuickTime .dlls and such by yourself is not an alternative, because you promised not to redistribute QuickTime when you clicked "agree" on that license.

Tip

You know the license I mean—it's the one you didn't read! That's OK, I didn't read it either.

Fortunately, QuickTime 6 offers a "preflighting" feature that allows you to create an XML file that describes what QuickTime features you need, open the file with QuickTime, and have QuickTime download and install your features if they're absent.

How do I do that?

In your favorite text editor, create an XML file, as seen in Example 1-2.

Example 1-2. Preflighting to install QTJ

<?xml version="1.0"?>
<?quicktime type="application/x-qtpreflight"?>
<qtpreflight>
  <component type="null" subtype="qtj "/>
</qtpreflight>

Save this file with a .mov extension to associate it with QuickTime.

Have QuickTime open this file in whatever means is appropriate for your application—embed it in a web page, have an installer script open it with QuickTimePlayer.exe, etc. When you do, QuickTime will check to see if QuickTime for Java has been installed; if QTJ hasn't been installed, this will give the user a chance to download and install it, as seen in Figure 1-5.

Figure 1-5. Installing QuickTime for Java via preflighting

Installing QuickTime for Java via preflighting

What just happened?

The XML file specifies a list of QuickTime components that the application knows it needs to run. These components are classified in a type/subtype scheme. For example, to test for MPEG-4 support, you'd use type "imdc" (short for image decompressor) and subtype "mp4v". QuickTime for Java is something of a special case, so it gets type "null" and subtype "qtj". The trailing space on the subtype is really important, because all types and subtypes must be exactly four characters long.

Note

Chapter 4 has much more information about components and the FOUR_CHAR_CODES that identify them.

If any of the specified components are found to be absent, QuickTime brings up a dialog and offers the user a chance to download and install them on the spot.

Tip

Because the XML file is pretending to be a movie, QuickTime Player will open it up with a typical movie window, which will hang around whether or not the install is approved and succeeds. Apple recommends embedding the preflight movie in an HTML page and using the width and height parameters of the <embed> tag to give it an unobtrusive size of 2 pixels by 2 pixels, so the user probably won't even see it.

Compiling QTJ Code

Once you've installed QuickTime and QuickTime for Java, you have everything you need to start developing QTJ applications—no separate SDK is required.

How do I do that?

You can begin by compiling a trivial application to check the QuickTime and QTJ versions, as shown in Example 1-3.

Example 1-3. Checking the version of QuickTime

package com.oreilly.qtjnotebook.ch01;
  
import quicktime.QTSession;
import quicktime.util.QTBuild;
  
public class QTVersionCheck {
  
  public static void main (String[  ] args) {
      try {
          QTSession.open( );
          System.out.println ("QT version: " +
              QTSession.getMajorVersion( ) +
              "." +
              QTSession.getMinorVersion( ));
          System.out.println ("QTJ version: " +
              QTBuild.getVersion( ) +
              "." +
              QTBuild.getSubVersion( ));
          QTSession.close( );
      } catch (Exception e) {
          e.printStackTrace( );
      }
  }
  
}

The compilation is the tricky step here. If you do a straightforward javac, bad things happen:

cadamson% javac src/com/oreilly/qtjnotebook/ch01/QTVersionCheck.java
src/com/oreilly/qtjnotebook/ch01/QTVersionCheck.java:3:
  package quicktime does not exist
import quicktime.QTSession;
               ^
src/com/oreilly/qtjnotebook/ch01/QTVersionCheck.java:4:
  package quicktime.util does not exist
import quicktime.util.QTBuild;
                    ^
src/com/oreilly/qtjnotebook/ch01/QTVersionCheck.java:10:
  cannot resolve symbol
symbol  : variable QTSession 
location: class com.oreilly.qtjnotebook.ch01.QTVersionCheck
          QTSession.open( );
          ^

Instead, you have to explicitly provide the path to QTJava.zip, which contains the QTJ classes. On the Mac OS X command line, you would do this as follows:

Note

Here, as in many examples, you should type the entire command on one line. It's broken up in the text for printing purposes.

cadamson% javac -classpath /System/Library/Java/Extensions/QTJava.zip 
  src/com/oreilly/qtjnotebook/ch01/QTVersionCheck.java

On Windows, the path to QTJava.zip would point to wherever the QuickTime installer put the file, which presumably means into your Java installation's lib/ext:

C:\qtjtests\book stuff\code>javac -classpath
  "c:\Program Files\Java\j2re1.4.2\lib\ext\QTJava.zip"
  src\com\oreilly\qtjnotebook\ch01\QTVersionCheck.java

Once the code compiles, running it is a lot easier—you don't need to explicitly put QTJava.zip in the runtime classpath to run a QTJ application. Just supply the class name to run, as the following output illustrates:

Note

Using the ant buildfile provided with the downloaded book code (and described in the Preface) makes compiling a lot easier!

cadamson% java -cp classes com.oreilly.qtjnotebook.ch01.QTVersionCheck
QT version: 6.5
QTJ version: 6.1
cadamson%

What just happened?

As for what this trivial first application actually does, a read-through of the main( ) method shows it doing four things:

  1. Opening the QuickTime session
  2. Printing the QuickTime version by making calls to quicktime.QTSession
  3. Printing the QuickTime for Java version by making calls to quicktime.util.QTBuild
  4. Closing the QuickTime session

If any of these throws an exception, it's caught and printed to standard-out.

What about...

...the mismatch between the version numbers? QuickTime and QuickTime for Java versions are somewhat independent, because not every QT update merits a QTJ update. Typically, you'll see both roll out a major version at the same time, but then a number of QuickTime updates will be issued, usually bug-fix updates or minor feature releases, without any changes to QTJ.

Opening and Closing the QuickTime Session

All QTJ applications are responsible for managing the QuickTime "session." The call to QTSession.open( ) gives QuickTime an opportunity to initialize itself, and it must be made before any other QTJ call, or you'll get an exception. Similarly, you must call QTSession.close( ) when you're done with QuickTime to give it a chance to clean up.

In general, this means you might want to call QTSession.open( ) as early as possible and QTSession.close( ) as late as possible. The former is easy enough to do: just put it in your application's entry point or even in a static initializer so that it precedes main( ). On the other hand, ensuring that you call QTSession.close( ) gracefully is trickier, because your user could quit your application with a menu item you provide, a Ctrl-C, a Cmd-Q (on Mac), or (heaven forbid) a kill -9 your-pid from the command line. Ideally, you'd like to have a fighting chance of properly closing QuickTime in as many cases as possible.

How do I do that?

One way to close QuickTime late is to put QTSession.close() in a Java shutdown hook, which will get called as the JVM goes away. There are no guarantees, but it's better than nothing.

Note

You can also run this example with the provided ant run-ch01-qtversioncheck task.

You can use the class in Example 1-4 as a general-purpose session handler for QTJ. It is presented here so that none of the other examples in the book will need to explicitly handle opening or closing the QTSession beyond calling this class.

Example 1-4. Session handler for QuickTime for Java

package com.oreilly.qtjnotebook.ch01;

import quicktime.*;

public class QTSessionCheck {

  private Thread shutdownHook;
  private static QTSessionCheck instance;
  private QTSessionCheck( ) throws QTException {
      super( );
      // init
      QTSession.open( );
      // create shutdown handler
      shutdownHook = new Thread( ) {
              public void run( ) {
                  QTSession.close( );
              }
          };
      Runtime.getRuntime( ).addShutdownHook(shutdownHook);
  }
  private static QTSessionCheck getInstance( ) throws QTException {
      if (instance =  = null)
          instance = new QTSessionCheck( );
      return instance;
  }
  
  public static void check( ) throws QTException {
      // gets instance.  if a new one needs to be created,
      // it calls QTSession.open( ) and creates a shutdown hook
      // to call QTSession.close( )
      getInstance( );
  }
}

Warning

It looks like QTSession.close( ) hangs on some Windows installations. It might be safer to use QTSession.exitMovies( ).

What just happened?

The QTSessionHandler class uses a singleton pattern. The idea is that all the work is done in the constructor, which will be called only once (to create the singleton), so you're free to call the static QTSessionHandler.check( ) method wherever and whenever you like, knowing it will have to run only once.

When you call check( ), it makes a trivial call to getInstance( ), which creates a new instance if and only if one hasn't been created yet. The constructor calls QTSession.open( ) to initialize QuickTime, and then sets up a shutdown handler that will call QTSession.close( ) when Java is shutting down.

What about...

...managing the QTSession myself? Absolutely. If some other arrangement works for your application, go for it. This class is merely a convenience, and is arguably overkill—closing the QuickTime session is handled automatically on Mac OS X when you use the default Quit menu item, and I've never seen a problem that was definitely caused by improperly shutting down QuickTime on Windows. But, as this class shows, getting it right isn't that hard.

...making multiple open( ) or close( ) calls? According to QTSession's Javadocs, if you issue multiple open( ) calls, QuickTime won't be shut down until an equal number of close( ) calls are received. There's no benefit (or harm) to multiple open( ) calls, so this is probably just trivia.

Running inside an applet? In an applet, it might make more sense to put your open( ) and close() calls in the applet's init( ) and destroy( ) methods, respectively, instead of banking on a particular browser's behavior vis-à-vis taking down the entire JVM and executing shutdown hooks.

Playing an Audio File from the Command Line

To finish this chapter, we'll look at a very simple example of QTJ code that actually plays some media. To keep things simple, I'll completely ignore the GUI, so all this will do is take a file path from the command line—presumably an MP3 or other audio file—and play it in QTJ.

How do I do that?

Compile and run the source for TrivialAudioPlayer.java, shown in Example 1-5.

Example 1-5. Playing an audio file from the command line

package com.oreilly.qtjnotebook.ch01;
  
import quicktime.*;
import quicktime.app.time.*;
import quicktime.io.*;
import quicktime.std.*;
import quicktime.std.movies.*;
 
import java.io.*;
  
public class TrivialAudioPlayer {
 
  public static void main (String[  ] args) {
      if (args.length != 1) {
          System.out.println (
              "Usage: TrivialAudioPlayer <file>");
          return;
      }
      try {
          QTSessionCheck.check( );
          QTFile f = new QTFile (new File(args[0]));
          OpenMovieFile omf = OpenMovieFile.asRead(f);
          Movie movie = Movie.fromFile (omf);
          TaskAllMovies.addMovieAndStart( );
          movie.start( );
      } catch (QTException e) {
          e.printStackTrace( );
      }
  }
}

Once compiled, run it with the path to an audio file as a command-line argument. Note that if you downloaded the book examples and compiled with the ant buildfile, the classes will be in the classes directory, so you'll need to extend your classpath into there:

cadamson% java -classpath classes
  com.oreilly.qtjnotebook.ch01.TrivialAudioPlayer
  ~/mp3testing/Breakaway.mp3

What just happened?

This application provides a bare-bones load-and-play example. After checking that there's a valid argument, it does the QTSessionCheck from the previous task to set up the QuickTime session.

Note

Any dynamic content in QuickTime is going to be a "movie," even if it's an audio-only file, like an MP3. This program also works for AACs, WAVs, iTunes Music Store songs, and anything else QuickTime can open.

The interesting part is in converting the argument to a java.io.File, then to a quicktime.io.OpenMovieFile, from which we can create a quicktime.std.Movie, which represents any kind of playable QuickTime content, in this case our audio file.

The start( ) method begins playing the movie, so once the program is running, you'll hear your MP3 over your speakers or headphones. This program doesn't provide a way to stop playback, so when you want to end the program, you'll need to type ctrl-c, use the Windows Task Manager, or hit the Quit menu item that's provided on Mac OS X.

What about...

Note

There's more information on taksing in the next chapter.

...that weird TaskAllMovies call? This is required because our program doesn't have a GUI, which ordinarily gives QTJ some cycles for decoding and playing the audio. Most of the programs in this book have on-screen GUIs, so they don't need to do this.

Personal tools