Making Media from Scratch, Part 2
Pages: 1, 2, 3

### The `Matrix` Reloaded

Part 1 demonstrated how QuickTime's `Matrix` class could be used to define a spatial transformation. Mainly, we used it to move text located at (0,0) to a point at the bottom of a movie, but look at the javadocs and you'll see some intriguing methods, like `rotate()` and `scale()`.

The key to our improved strategy is a method called `rect()` that combines a coordinate mapping with a scaling operation. This allows us to use any source rectangle and scale it to the size of the frames we're compressing for the movie.

To make this work, the sample code creates an offscreen `QDGraphics` and tells the `GraphicsImporter` to use this for its `draw()`s. The new `QDGraphics`'s dimensions are the same as those of the frames we intend to compress. That means its bounds are a `QDRect` with upper-left corner 0,0 and constant dimensions `VIDEO_TRACK_WIDTH` by `VIDEO_TRACK_HEIGHT` (which I've set to 360 by 240, but you're welcome to change in the code). For each intermediate `fromRect`, we create a `Matrix` to map from the `fromRect`'s QDRect to our `QDRect`'s bounds.

The revised process looks like this:

1. Get starting and ending rectangles, where a rectangle is a `QDRect` representing an upper-left corner point and width by height dimensions.

Step One

2. Calculate a series of intermediate rectangles that take us from the `startRect` to the `endRect`.

Step Two

3. For each of these intermediate `fromRect`s, use a `Matrix` to scale the rectangle into the bounds of an offscreen `QDGraphics`, draw it into the `QDGraphics`, and then call `compressFrame` to make a frame from the offscreen `QDGraphics`. Add each frame as a sample.

Step Three

### Making It Real

Given that strategy, let's step through the code that makes it all work. We'll skip over creating the movie itself, which we covered last time. Similarly, creating and adding the `VideoTrack` and `VideoMedia` are a very straightforward analogue to last article's `TextTrack` and `TextMedia` setup.

If this is your first time compiling and running QuickTime for Java code, see my earlier article, "A Gentle Re-Introduction to QuickTime for Java," for information on how to work out `CLASSPATH` and Java versioning issues.

To get things started in this example, we need to know the source image file, as well as the `startRect` and `endRect` rectangles that define the movie we are to make. The sample code expects a makecsequence.properties file to be in the current directory, with entries that look something like this:

``````file=/Users/cadamson/Pictures/keagy/DSC01763.jpg

start.x=545
start.y=370
start.width=1500
start.height=1125

end.x=400
end.y=390
end.width=800
end.height=600``````

If this file is absent, the user will be queried for an image file at runtime, and the rectangles will be chosen randomly.

Given a `QTFile` for the image file, creating the `GraphicsImporter` is quite straightforward:

``GraphicsImporter importer = new GraphicsImporter (imgFile);``

Next, we create the offscreen `QDGraphics` and tell the `GraphicsImporter` to use it for its drawing:

``````QDGraphics gw =
new QDGraphics (new QDRect (0, 0,
VIDEO_TRACK_WIDTH,
VIDEO_TRACK_HEIGHT));
importer.setGWorld (gw, null);``````

Notice that I inadvertently called the variable `gw`, as in "GWorld". The use of that term in the API and Apple's docs is really pervasive!

One thing we have to prepare early is a block of memory big enough to hold the largest possible frame that the chosen video compressor could create. To do this, we call a `getMaxCompressionSize()` method, allocate a block of memory of that size (as referenced by a `QTHandle`), and "lock" the handle so it can't move while we're working with it. Finally, we can create a `RawEncodedImage` object with this buffer:

``````int rawImageSize =
QTImage.getMaxCompressionSize (gw,
gRect,
gw.getPixMap().getPixelSize(),
StdQTConstants.codecNormalQuality,
CODEC_TYPE,
CodecComponent.anyCodec);
QTHandle imageHandle = new QTHandle (rawImageSize, true);
imageHandle.lock();
RawEncodedImage compressedImage =
RawEncodedImage.fromQTHandle(imageHandle);``````
 Related Reading

The `CODEC_TYPE` is a constant defined early in the sample code. It is an `int` that indicates which QuickTime-supported compression scheme we've chosen to use, "codec" being the term for a scheme by which video is encoded and decoded. Many of these are provided as constants in the `StdQTConstants` class. Among the popular choices are:

• `kCinepakCodecType`. Cinepak is a widely supported codec dating back to the early 90s. However, its image quality and compression ratios aren't very compelling anymore.

• `kSorensonCodecType`. Sorenson Video pretty much replaced Cinepak for a lot of QuickTime users with its higher quality and great compression.

• `kH263CodecType`. H.263 is a codec originally designed for videoconferencing but widely used in other environments. It is also supported by Windows Media Player, the Java Media Framework, and is a simple form of MPEG-4 video.

• `kAnimationCodecType`. A compressor meant for use with synthetic images. Apple's demo code uses this a lot, but that's because their sample apps create their own image data. Our photo doesn't compress well with the Animation codec, so only use it here if you want to be shocked by how big the resulting file is (hint: make sure you have at least 15MB free!).

There are more supported codecs than QTJ lets on, but you have to look in the native API's `ImageCompression.h` to find them. Two great options are:

• Sorenson 3. A newer version of the Sorenson codec, Sorenson 3 is available in QuickTime 5 and up. The identifier for this codec is `SVQ3`, so to create the `int` that QuickTime wants, we take the bottom eight bits of each character (we pretend that we've gone back in time and Unicode doesn't exist yet). Since `S` is `0x53`, `V` is `0x56`, `Q` is `0x51`, and `3` is `0x33`, the `int` value is `0x53565133`.

• MPEG-4. You can use MPEG-4 video in a regular QuickTime `.mov` container, with the caveat that only QuickTime will be able to read it — to create a real `.mp4` file, you'd need to use a `MovieExporter`, as shown in the article on the QuickTime File Format. For our current purposes, the codec type of MPEG-4 video is `mp4v`, which translates to the `int` value `0x6d703476`.

 Pages: 1, 2, 3