Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2002-408
$eventId
ID of event: wwdc2002
$eventContentId
ID of session without event part: 408
$eventShortId
Shortened ID of event: wwdc02
$year
Year of session: 2002
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC02 • Session 408

QuickTime for Java Overview

Java • 54:37

QuickTime for Java provides a set of cross-platform APIs that allows Java developers to build multimedia, including streaming audio and video, into their applications and applets. This session provides a technology overview of QuickTime for Java and covers new features available with the latest release. Common programming issues, installation, and how to write more efficient code using the QTJava APIs will be discussed. Highlights include the introduction of several new APIs and a discussion of new QuickTime 6-based features.

Speakers: Anant Sonone, Michael Hopkins

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Thank you very much. I'd like to thank all of you for taking the Advil this morning after the beer bash and coming on out to hear our quick time for Java talk. We have some exciting new features that we're going to be showing tonight or this morning, excuse me. I think it's still last night.

We're also going to have Anat come up a little bit later to show you how to do some optimization on your code and to use some programming methods for some topics that are maybe somewhat less understood or a little bit confusing. We'll be showing that a little bit later.

Before I begin, I'd like to start off by displaying our names because I'm an egomaniac. We're going to start out just summarizing what QuickTime for Java is before we go into some of the new features. So we're going to start off by showing you some of the new features that we're going to be showing tonight.

We're going to start off by showing you some of the new features that we're going to be showing tonight. So we're going to start off by showing you some of the new features that we're going to be showing tonight. So we're going to start off by showing you some of the new features that we're going to be showing tonight.

QuickTime for Java is really based on two separate technologies. There's QuickTime, of course, most of you here are probably familiar with. It's a mature cross-platform flexible media framework that provides a number of services that allow you to play movies, play sounds, do virtual reality, things like that. And it's also based upon Java, which is Sun Microsystems' fully featured modern object-oriented language feature. So it's featuring garbage collection, the ability to deploy your applet in a browser, or to use the new Web Start features that were brought to Java.

And you can also make use of those features with your QuickTime for Java application. And the biggest key here is the ability to deploy your application in a cross-platform manner. So what is it that QuickTime for Java that's based on these two technologies include? Well, first of all, it's a very powerful, as I mentioned, it's cross-platform Java class library that allows you to access the native QuickTime runtime on your platform.

And it provides two different types of services. And the first, and perhaps most primitive, is the presentation of QuickTime C APIs, so that from your Java applet or application or Web Start application, you can call the QuickTime C APIs directly. And we've organized these in an obvious way, and we've done a lot of work on the Web Start application.

And we've also done a lot of work on the Web Start application. We've done a lot of work on the Web Start application. And we've done a lot of work on the Web Start application, and we've done a lot of work on the Web Start application. And we've also done a lot of work on the Web Start application, and we've done a lot of work on the Web Start application. And then we've also done a lot of work on the Web Start application. And we've also done a lot of work on the Web Start application. So, we've done a lot of work on the Web Start application.

And we've also done a lot of work on the Web Start application. And we've also done a lot of work on the Web Start application. And we've also done a lot of work on the Web Start application. And we've also done a lot of work on the Web Start application.

And we've also done a lot of work on the Web Start Okay, so let's talk about what platforms are available to you as a Java developer. We support Mac OS, and we're referring there specifically to the classic Mac OS 9 runtime. That requires MRJ 2.1 and above. We also work on Windows, and that's all the slew of NT, Windows 98, Windows 2000. All those we support, as long as you have a Sun-compatible GRE.

And we also are bundled on Mac OS X using the Java 2 Standard Edition. And the great thing about that platform is that everything's pre-installed for you, so your users don't have to install any additional software, and you as a developer can depend on those services being available to you.

So let's talk about now some of the new features that are available with QuickTime for Java that are provided by QuickTime 6. For those of you that have been to previous QuickTime sessions, you may have heard all this buzz around MPEG-4 and the new video features that are brought by that. Additionally, we've added support for new idle manager routine that we're going to be talking about in later slides.

But in addition to the new 6 functionality, we still have complete coverage of the QuickTime 4 and 5 APIs, as well as some additional functionality and services. And new in this release is support on Windows for the JDK 1.4. So those of you that are in that space can now transparently use 1.4 without any additional changes to your code. So that's a nice feature.

Okay, continuing on in the new feature space is a new manager called the idle manager. And what exactly does this allow you to do as a developer? Before I go into that, I'd actually kind of like to summarize the way things used to work before this idle manager was introduced, so that you can understand the need for that new technology.

Previously in QuickTime, applications that used QuickTime needed to call a number of calls, such as MCIsPlayerEvent to determine if a specific event coming in on the event loop is for the QuickTime player, or MCIdle to allow QuickTime to have some idle time to perform tasks such as decompression or display of videos, and movies, tasks, and task media. And these calls were required to be called on a periodic basis.

But the problem is that the developer doesn't necessarily know how frequently these calls need to be called in order to provide enough time for QuickTime to do its work. And I'd also like to point out that for QuickTime for Java developers, occasionally these calls may be called implicitly for you, so you might not even realize that they're being called for you on your behalf.

So there was a lot of confusion here, since it was difficult... for the developer to determine how often QuickTime needed time to perform its operations. So this is especially true in the case of a movie where you have a wired sprite, and the rate of the movie could be zero, yet, for example, if you had a fire effect that's still animating even when the rate of the movie is zero.

So you couldn't depend on the rate to determine if you needed to make these calls. And so most developers would just pick some delay time that seems reasonable, and just call that routine, those routines, over and over and over again. And this is a problem, primarily because it's wasteful. There'd be a lot of cases when you'd call the idle routines, and QuickTime wouldn't really need the time to do any work, so it would just sit there and you'd be wasting valuable CPU processor time.

So in order to allay these problems, we've introduced a new idle manager API. And the whole purpose of this is that you no longer have to look into your crystal ball and say, oh, when does QuickTime need time? You can actually request that from QuickTime. Brilliant idea. So what you do in QuickTime for Java is from your movie object you call getTimeUntilNextTask and specify the scale that you wish that time to be delivered in. And you'd get a delay return to you.

And this allows you to determine exactly when the next time QuickTime thinks that it needs processing time. If you wanted to, say, in your movies task, specify that same interval, you then call taskAll with the delay that was returned to you by the idle manager. And then the tasker object will use that new delay value.

There's also a mechanism whereby you can register a callback with QuickTime, and that's called the next task needed sooner callback. And the way that works is you can tell QuickTime... Okay, I know that you told me that you didn't need any time for the next five milliseconds, but if you do, here's this routine that you can call to notify me that something came up, you made a mistake, and you need time more quickly than you last reported to me. So in order to set up that callback, you implement the next time-needed-sooner interface and override the public execute method.

So a little bit more detail about how that callback works. To install a callback, you call setNextPathNeededSoonerCallback, say that five times fast, and pass in your class that implements that interface into it. When QuickTime decides that it needs additional time, for example, if a network operation happened or if there was some kind of a callback within that movie that fired, and QuickTime decides, oh my god, I need time more soon or sooner than I previously reported, it will go ahead and call your callback for you.

and your execute method. So to remove that same callback, you call removeNextTaskNeededSooner callback with the same callback. And since you're specifying a callback in that routine, it's important to note that you don't have to have just one callback. You can install as many of those as you want.

Okay, so now that we've talked a little bit about that, I'd like to talk about some additional new features supported in QuickTime for Java with QuickTime 6. And that's primarily support for Flash 5. Yay! A lot of people were complaining because there were some new... Yeah, Ant over there, he's just doing flips right now because he loves Flash.

It enhances the action syrup capabilities of Flash, provides HTML text rendering, XML data exchange, and all sorts of other features that people were clamoring about, so we put it into QuickTime. Additionally, in QuickTime 6 is support for variable bitrate sound compression. Previously, you could play back a sound that used VBR compression, but you couldn't actually encode one. Well, now you can.

Okay, so another brand new feature that people have been clamoring about a lot is support for QuickTime for Java in a swing-based component. So I'd like to talk about that a little bit now. What we've done is we've added a new component. And the reason for this is that our previous component, QTCanvas, was heavyweight. And incorporating this into a swing application was very problematic.

As you can see by the diagram here, we have a QTCanvas that is inside of a window. And because it's a heavyweight component on top of a lightweight component, all the lightweight components are being drawn over. And that is somewhat undesirable for people doing swing applications. So what do you do now? Well, now new in QuickTime for Java 6, we have a new class, JQTCanvas, which is a lightweight. component. Yay! Thank you. So this provides most of the functionality of QT Canvas.

On Mac OS X, it's hardware accelerated, so that enhances the frame rate. And it's pretty easy to use. And when I talk about providing most of the functionality of the QT Canvas, there are some caveats. And those are primarily caused by the fact that your drawing of the movie is being done off-screen, and then it has to be transferred on-screen into a lightweight component. And this introduces a lot of the same limitations as you have in the compositor. Primarily, well, you have a lower frame rate because you have to do twice as much work, draw off-screen, then copy on-screen.

And you also can't display a movie controller in that, simply because QuickTime can't display movie controllers off-screen. So you can't have that feature. However, if you like, you could either make your own controller using lightweight components. And tie those to your movie. Or you could choose to detach your controller and have that in a heavyweight component elsewhere where it wouldn't interfere with your lightweight components. And Anant will be talking about how to do that later in the presentation.

So additionally, all time-based clients that you want to use in your lightweight swing component need to implement the drawing notifier interface, because that's the mechanism whereby the swing JQT canvas is told that it has a frame that needs to be updated. And examples of those classes are SWCompositorMoviePresenter and QTFectPresenter. You can look in the Javadoc to see which classes implement that interface.

So, how do you use jqt-canvas? Well, it's remarkably similar to using the regular canvas. In fact, most of your code you can just change by adding a little j in front and it will work. So, but for those of you that have never done that before, you create a new canvas, jqt-canvas in this example, using the same sizing parameters and constraints as you used with the previous component. Set the client. In this case, we're using a movie player object. Creating a new movie player, associating a movie with it, and then calling setClient on that.

And then we add the JQT canvas to the frame. In this case, you'll note that if you're adding it to a J frame, you need to get the content frame first before you can add it. And then if you're on Mac OS X, there's a property called useMacOSX acceleration. And right now, because we haven't had a lot of feedback as to how well this works, we set that by default to false. Once we get feedback from people that that's working, we set that to false. working fine, then we'll probably make true the default so you don't have to have this Okay, and what everybody loves most of all, and I'm going to show a demo of how this works.

Okay, so we have a little example here. And what we have going on, those of you might recognize this as being a swing component with J internal frames. And as you can see here, we have an internal frame window here that we're moving all around in the video. Go ahead and change this to something really big.

"All working just fine. You also noticed it is a minimized, reduced stat. You can see the transparent effects right over the movie here. So it's truly compositing in a swing component just fine. Frame rate is great. You can't really tell any difference between that and something that you'd see in a QuickTime player. And even more fun..." This is MPEG-4 playing in a J internal frame. Overlapping another internal frame, not drawing on top, behaving correctly, excellent frame rate. This is about 900k bitrate, I believe. So that's pretty neat to see that kind of thing happening in a TrueSwing demo.

So it works. Use it. And please give us feedback. If you see any cases where you think something should be working and you're having trouble, let us know. We're always looking at those kind of things, and we really do appreciate your feedback. Okay, continuing on for current features in QuickTime for Java.

As I mentioned earlier, we've provided a couple of enhancements, such as the support for the JDK 1.4 on Windows. We will be having that on Mac OS X once that's available. This on Windows doesn't require any API-level changes. It's completely transparent to the user. We have a new Movie Media Handler support.

Excuse me. So that if you have a movie that includes other movies, you can do that. We have some additional getter and setter calls on QTVR view parameter. And we have a public constructor for the sequence grabber output. And now we support file names with accent and characters. Yay.

An additional bug fix, which is high on people's list, were some enhancements for the Mac OS X dialogs. There used to be a bug where if you had a native dialog displaying in Java, it would just be blank. So for those of you that are still seeing that, try your Jaguar CD. That's all fixed. It's working great. We also have a number of fixes in the sequence grabber so that that actually works.

You can have, and let us know if you find a case where you're still having problems with that because we believe it to be working correctly now. You now can have a SGData proc added, and the sequence grabber will call that function when it records some data, and that allows you to have the opportunity to do some editing or manipulating on that data before it gets drawn. And there's just some little code here for those of you that don't know how to do that.

You basically call setDataProc from the sequence grabber and create your own class which implements the SGDataProc interface and then override the execute method. And you return an int which tells you whether you changed the data or zero if you didn't change any of the data. So that all works now.

Still from the previous version, QuickTime 5, we have support for the presentation API. This has been enhanced in QuickTime 6 so that you now can do MPEG-4 streaming. And this API allows you to broadcast from a sequence grabber source, such as an audio device, microphone, CD, or a video device, such as a DV camera.

We also have support now in the API to pick another source, such as a file that resides on disk for the sequence grabber. And that's all done through the sourcer component, and that's all there now. So go ahead and try that. Your broadcast can be unicast, multicast, and it's user configurable using a settings dialog.

Okay, so that's all I have. Now I'd like to turn over the presentation to Anant Sonone, who is on the QuickTime for Java engineering team, and he's going to be talking about efficient programming methods. Thank you. Anant? Thank you very much, Michael. That was a nice introduction to the new QuickTime for Java 6 features.

Now, for the rest of the session, I want to talk about certain issues that the developers have raised regarding QuickTime for Java in general. And also, we're going to look at certain programming tasks that developers need to do, and we're going to show how efficiently we can program using these QuickTime for Java APIs.

As you know, QuickTime is so massive, QuickTime for Java certainly has to support all those features, and that makes QuickTime for Java API also pretty big. That is kind of confusing and sometimes leads to certain programming ways for developers which make it inefficient. So the best way of doing this, that is what I want to tell you.

Whoops. All right. The first topic that I've chosen to talk about is the detached controller. Now, actually, before we dive into the details of what a detached controller is and how and why we should use it, I want to introduce to those newbies in the crowd as to what movie controllers are.

So, movie controllers basically present the user with an interface for controlling the movie. So what you can do is you can either stop and start the playback of a movie, you can jump within the time base of a movie by clicking within the controller, or you can even, you know, play with the sound.

Not only that, even if you see the picture that's displayed over here, that's the standard way in which a controller is displayed. The controller bar is always... It's always beneath the movie content. So this is the standard way a movie will always be displayed along with the controller. There's no other place that the controller can be displayed if it's displayed in the standard way.

So now, if you want to basically change the position of the controller, place it in the top, or you want to display it in some other window besides the movie content itself, you'll have to detach the controller. And... That is where detached controllers come into picture. So, this is a pictorial representation of how a detached controller will look.

You can see that the controller has been detached from the movie content itself. So, Spider-Man is happy to go in some other window he wants to, and the controller can stay in some other window. So let's now go further into this and see when one would want to use a detached controller.

When an application basically wants to treat the movie content and the movie controller as two graphical entities, you would want to detach the controller from the movie itself. Not only that, by detaching it, you have more than one advantage. You can slave multiple movies to a single controller.

So suppose the application has multiple time bases running, which are active, and suppose you want to control all these movies using a single controller, you can do that. You detach all the movies from the controller and just have one single controller placed, which will control all the other movies.

By detaching the controller, as Michael told you previously, movie controllers have a constraint. That is, they cannot be drawn off screen. So they cannot be used in a swing component. So the only option remains is to detach the controller, place that controller in a different heavyweight component like a QT canvas in a separate window, and place the movie content in a swing component. That way you can have the movie and the controller in two separate windows and display the movie in a swing component. Not only that, you can actually get rid of the controller completely and have your own custom controller to control the movie.

So here is some code over here which shows you how to basically do that. You create a QT canvas for holding the controller. And then you create the movie controller itself by using the movie controller class. Pass it the movie that you want to display. Now, here's the important call. Controller.setAttached false. Here you're telling the controller that I want you to detach from the movie.

Once you have detached the controller, now you want to display this controller in the canvas. For that, you will need to pass this controller to a drivable object, which will basically display the controller in the canvas. For that, you need to create a QT player object and pass it to the controller. Then, once you have done that, you will pass the QT player to the canvas and set the client.

Now that's for the controller, to display the controller. The second part is to display the movie. To display the movie, again, you'll need a drawable object. In this case, we're going to use a movie player object and pass in the movie that we need to display. And again, similarly, we'll set the client for the movie canvas, which we create and display the movie player in there. So let's see the demonstration of how a detached controller would work.

So what you see over here is three separate components, all of them having their own time basis and they're happily running. So you have two movies over here with their own controllers. And now what you can do is basically when I press this button, detach it... Okay, cool. So what's done is it's basically detached the controller from both the movies and it's placed the controller on top of it.

And what you see is the first movie is the master time base, and the rest of the two have been slaved to it. So you saw in the beginning that the second movie was much bigger in duration, but now since it has been slaved to the first movie time base, it's all kind of like getting back once the first movie stops playing, and it goes back to the beginning. And this is a good example of, you know, slaving movies to each other and using the attached controller to control multiple time bases.

All right. So the second topic of discussion is playing a sound file. Now, why did we choose to discuss this one is because one of the mistakes that we have done previously is we actually released some code in the SDK that obviously played the sound file, but that wasn't the right way to play it or that wasn't the most efficient way to play it. We want to rectify that and show you what is the best way of doing that. So the previous example and documentation recommended using a QTDrawable object.

In case of a sound file, when you just want to play a sound file, there's nothing to draw. You're just going to play some sound bytes over there. But in the previous example, we are using the standard way. That is, we recommended using a QTPlayer object, and we also needed an explicit call task on it.

This led to the fact that on Mac OS X, since the QTPlayer was being not set as the client of the canvas, because we weren't using a canvas, the movie controller that was being used was getting set to an off-screen port, and that was creating a problem on Mac OS X, and the movie controller was getting drawn somewhere in the menu bar. So there were these graphical artifacts that we wanted to overcome as well. So here is a better way of playing a sound file.

What you do is open the movie file that you want to play using the movie.form file, pass in the sound file to that. Here's the important class over here, task.movies class. So basically, task.movies class, what it does is it basically tasks all the active time bases of the movies that are present in an application.

So basically what you do is whenever you have an active time base that needs to be tasked, you basically call task.movies addMovie and start. This will basically increment the counter that the task.movies has and says that, okay, I've got one client which needs to be tasked. And when you add another time, it will basically increment the counter and so on and so forth. So this will provide those active time bases with the task time that's needed to process and play.

And then you basically call--

[Transcript missing]

All right. So now we're going to look at some different topic over here, which is the wide action or the wide sprite movies. Over the last, we have been having requests from the developers regarding having some way of creating wide action movies using some QTJava APIs. We have been working in this direction to give you an interface for the wide action movie APIs that QuickTime currently provides. We have been working in this direction to give you an interface for the wide action movie APIs that QuickTime currently provides.

We have been working in this direction to give you an interface for the wide action movie APIs that QuickTime currently provides. Just to give you a brief introduction as to what wide-action movies are, movies that contain interactive components are called wide movies. Any movie with which you can interact, basically click a mouse and get some interaction from the movie content, is called a wide movie.

What happens in a sense is, user input is translated into events, which can basically target various components in a movie. It can be the movie itself, or a particular track in the movie, or it can even target a particular sprite in the sprite track of the movie. What happens is, events fire actions which modify certain or particular properties of the target. In case of a sprite, for example, what you will do is change the... image index of the sprite that's currently being displayed. And that way you can achieve the interactive effect over there.

[Transcript missing]

Now, the keyframe samples, the sprite track, the override samples, all of these in QuickTime are represented using the QTAtoms architecture. So you can look at the movie as a whole, as an entire hierarchy of atoms and atom containers. So the movie is a top-level atom container which has the sprite track atom container, and sprite tracks has various atom containers of keyframe samples and so on and so forth. So this is a complete tree of atom containers which is basically passed by QuickTime and the movie is displayed. This holds true for any movie, not just sprite movies.

So when normally using the C QuickTime APIs that are currently available, what are the challenges developers are facing? As people who might have probably used these C QuickTime APIs, you would have understood the amount of difficulty one has to go through to understand those cryptic and big API names themselves.

And the architecture in general itself is pretty difficult to understand. Not only that, C QuickTime APIs are pretty tedious to use because they have n number of parameters and there are these flags that you need to take care of. And keeping that in mind is kind of like a pretty daunting task to do it.

Using C APIs also makes your application platform dependent. And also, there are issues that you need to take care of. So if you're making a movie for Windows or on Mac, you have to take care of the issues. These all things lead to a major development curve. So basically, you have to invest time in reading the material and understanding this, and that is going to be a big overhead. And if you're thinking of using a third-party tool, that probably might not be suited for your kind of needs if you're using it to do just small things. So third-party tools can prove to be expensive.

So, that is where QuickTime for Java APIs that we are introducing come into picture. Reasons are, obviously, those which QuickTime for Java API leverage from Java, which is the object-oriented model. Our APIs are also set on those same, excuse me, on the same object-oriented model. Using this, Java APIs make application cross-platform.

So, you don't have to worry about the Indian issues. We are going to take care of all the Indian issues. You just run your application, run it on Mac or Windows, any platform, it will run the same and create movies, or you can modify movies, whatever you want, using those APIs.

So, people even coming from the background of Java, which don't have much exposure to see QuickTime API or even understanding of the QTAtoms architecture, can use these classes to create wire-sprite movies. And, you know, you get kind of a jump start using these classes. So, obviously, this is leading to a very small learning curve.

So let's go further and see how these APIs can be used. So we're going to look at an example of how to create or modify a wide sprite movie. What you would do is basically create a new movie file with a single sprite track in it. Then you make a single keyframe sample containing the sprites and all of the image data in it. Then what you would do is basically set the sprite track's properties.

So you can, as I told you, even the sprite track is an Atom container, you can set the properties for the sprite track. Then you create override samples as needed and override the properties of the sprites that were declared in the keyframe. And then once you have done that, you have to wire all these sprites. And that is done by setting the actions on the sprites for specified user events.

Keeping all that in mind and the overall format of the Wired Sprite track and the architecture, we have laid out this package of Wired Sprite, which has grouped a bunch of atom containers into logical classes over here. For example, actionAtom basically represents the actionAtom containers, which holds the actions which are targeting either the sprite or the track.

Image container, as the name says, holds the images which are shared by the different sprites in the sprite track. Sample frame. A sample frame either represents a keyframe or it represents an override sample. So you can basically create a keyframe or sample frame using this class. And the rest of the classes represent the sprite atom, represent the individual sprites. The sprite track atom basically represents the sprite track in the movie. And there are these utility classes and other constant classes in there.

So let's look at how you can use these classes to create the white sprite movie. As usual, you'll call the createMovieFrom file on the movie class to create a new movie. Now this is an empty movie which doesn't have a resource yet and no track in it. So follow that with the movie.addSpriteTrack call, which will basically add a track to the sprite movie. Then the track basically contains media.

So you will have to call new sprite media and pass in the track for which you want to create the media. Now you have come to a point where the actual action begins, and you have to start adding the keyframe samples and the override samples. So we create a keyframe sample using the sample frame, and now to the keyframe you're going to add the image data that you create using the image container class.

And call the makeImageContainer. That gives you an object which you can call the addSpriteImageOn, and you can add your images and pass in the image information and the various properties for the images to it. So that will basically create the image data bank for you in the keyframe sample.

Now, once you have created the image data for the sprites, you have to create the sprites itself. That you do using the spriteAtom class. So you create a new spriteAtom and pass in the ID, which is unique for every sprite that's in the keyframe sample. And as I told you, sprites have different properties. And in the keyframe, as I said, you have to define the initial scene, so you have to set the initial properties. And that is done using the setProperties call.

So you have set, for example, setImageIndex will set the image index, setGraphicsMode will set the graphics mode. So these are the different properties, and we have all these set actions on the spriteAtom class, which will help you set all these properties. Then you move on to create the actual actions that will be attached to the sprite itself. So what you do is, you create these actionAtom using the actionAtom class.

And again, using the setAction methods and passing in the event on which you want to fire the action, you call the setAction. For example, you can fire a setVisible action method on the sprite and pass in the event, for example, on mouseEnter, I want the sprite to be visible. So you say spriteAction dot set spriteVisible and pass in the event and the action itself.

And the data, which is either I want to make it visible or invisible. And finally, when you have made a bunch of these actions together, you can basically set all these actions on the sprite by calling the setAction method on the spriteAtom class and passing the action object that you have created. Once we have done that, now you want to add the sprite atom.

Then you call the keyframe.addSpriteAtom and pass in the sprite that you have created. So image container and the sprites, as I said, is a part of the keyframe, so you have to add the sprites to the keyframe as well. So this is, in short, how you would create a keyframe sample and add the images and the actions and the sprites to that.

So internally, what we are doing behind the scenes, what we are doing is basically handling all the QTAtoms calls for you and creating all these container hierarchies for you, which will basically represent these actions and sprites. Once you have done that, you'll go on to create the override samples, similar to the way you have created the keyframe samples.

And then you will, again, override the properties of the individual sprites that you want to animate or want to have some action done on it. So, mind you, override frames just override the properties. They don't contain any actions as such. Then finally, you add the keyframe and the overhead samples to the media. So these are the samples that you basically add to the media and that you do using the spriteTrack.insertMedia and pass in the media to the spriteTrack.

Another class that I talked about is the sprite track atom, which you would use to set the properties on the sprite track. Again, you have the different set properties calls on the sprite track atoms, which you can set the properties for the sprite track. You finally set the properties of that sprite track on the media. Once you have done doing all these things, you're ready to save it to a movie. You call the add movie resource to the movie and save the movie. This is how you would basically create a wire sprite movie.

All right, so talking of all this, one would wonder how much effort one has got to take while doing all this. I would say as compared to the C QuickTime APIs for widespread movies, one would have to take very minimal effort over here. Now, this is what I'm going to demonstrate using this example that I have over here.

The time that I've invested in this example, which basically shows you how to create a movie, a widespread movie, and also modify that movie dynamically and save it back, this all might seem to be very easy. But if you are a C programmer and you've used a C API, you'll understand how much time and effort it would take to create a movie. But using these classes, it's going to simplify your life for the better. So let's see.

So what I'm going to do is basically create a widespread movie. So I'm going to save it. So what it has done is, I have a bunch of images over here, and I've created two sprite atoms over here with initial properties. And this is the keyframe that has been displayed with the initial properties.

Now, I've added some actions, like on mouse center, I'm able to change the property of the sprite and have some animating effect over here. And now, when I click on it, it's basically targeted the other sprite and told to start animating it. So the override samples come into picture. I set the movie rate to 1, and it'll start animating the sprite.

This is what a widespread movie looks like. Now, while this is running, I would want to-- if somebody has an existing widespread movie, he can also basically pass that widespread movie Modify it. So this is the structure of the sprite track. It basically has sprite track atoms, which has the properties that you can see.

You have the image container atom in it. You have two sprite atoms in it with the initial properties. You see all these action events, actions for the events that we have set. These are the initial properties for the sprite, atom number two. And all this has been done using my APIs. It basically goes, you have these get methods on these atoms, and you can get these properties easily. And now what I'm going to do is basically just modify these properties. Say I want to location for that.

I want to change the initial image index for the sprite item 2, which is the sprite in the bottom. And I want to save it back. So, I'm going to save it back. That's it. So there you go. So this was the initial position. I have dynamically, using my object, changed the sprite location and even changed the image index, and the rest of the movie remains the same.

So this is all done using the QuickTime for Java API. And these can be used on Windows and Mac OS X, respectively. Another issue that has often come on the mailing list is regarding the QuickTime for Java installation process. We have been getting a lot of questions regarding this, so we thought it would be nice to address this issue.

So the QuickTime for Java standard installation procedure. Let's look at Mac OS X. Well, you don't need any installation because it's already pre-installed on the machine. It's all there for you to use. So just go ahead and use the Mac OS X system. You have QuickTime for Java installed for you in the right place. On Mac OS 9, to install QuickTime for Java, you need to use the QuickTime installer, and you need to select the custom install, and you do a select all, and that will install the QuickTime for Java pieces in the write directory of MRJ.

For Windows, well, we have been having a lot of grief regarding this platform for installation as all these varied VMs and all these registry entries that we need to take care of. And that's where we have invested a lot of time and a lot of efforts in making sure that the installation for QuickTime for Java works fine. So the standard installation on Windows basically would be to do it in certain steps. First, you install the Sun-Java compatible VM. We don't support any other VM which is not 100% Sun-compliant.

Once you have installed the Java VM, you have to install QuickTime and, again, do a custom install with a select all option in it. So this sequence of installation is very important over here because otherwise, if you don't have Java installed, QuickTime wouldn't know where to install the QuickTime for Java pieces so that your applets and application will run properly.

So this is the proper sequence of installation for QuickTime for Java on Windows. So we decided that besides this, there are some other issues revolving around QuickTime for Java installation if developers are releasing applications with their own private VMs and we have to basically deal with those issues as well. So, you can license the QuickTime installer itself by going to this

[Transcript missing]

So there are two ways of writing a custom installer. Either you license the individual pieces of QuickTime. So there are three pieces in QuickTime, the DLLs-- sorry, the DLLs and the library.

We have facilitated the developers or the application writers to basically license the individual pieces. So what we do is we give the pieces to you, and you can then basically take care of installing the pieces wherever you want so your applications can run properly. In case of private Java VMs, as I said, the standard installation for QuickTime for Java won't be able to find the private Java VM that the application uses because we basically look for registry entries, and private Java VMs don't have registry entries. And that leads to problems of where to put the QuickTime for Java pieces. Besides that, you can also modify the .ini file for the standalone QuickTime installation.

The .ini file is a quicktime installer in which you set the QTJava = true variable, and that will basically tell QuickTime installer that if you find this variable set to true, just go ahead and install QuickTime for Java pieces in the right directory. All right, so that's for it that I have. This is the contact information we have for developer support and information. This is the roadmap. We have the QuickTime feedback forum going on right now, actually, in which they're discussing. And we have all these other sessions.