When QuickTime came out in 1990, it could play movies the size of a postage stamp—barely—on $7,000 hardware. It used audio and video codecs that, although still supported today, have long since been abandoned by users. Yet it’s been a smooth transition from Apple Video to Cinepak to MPEG-4. This is thanks to an extraordinarily modular design—most of the heavy lifting in QuickTime is performed by components , or shared code fragments that can be discovered and used dynamically. Components provide support for importing and exporting image and movie formats, performing image and sound compression and decompression, accessing system resources, and much more. The QuickTime installer provides components for many features, and components added later by the end user, from either Apple or third parties, can provide more functionality, like support for more media formats.
Components aren’t always front-and-center in the API—after all, the first few chapters have managed to avoid mentioning them entirely. QuickTime has been assumed to just “do the right thing” when it comes to opening files and turning them into movies, decompressing and rendering the data, saving it to disk, etc. When needed, QuickTime looks through its catalog of components for required functionality and gets what it needs.
But sometimes it’s desirable or necessary for the developer to work with components more directly, to figure out what’s available or to specify behavior. Figuring out what tools are available at runtime can be a powerful asset.
In QuickTime,
components are identified by a
type
and a
subtype
. The type specifies a broad area of
functionality, while the subtype is a specific implementation of that
functionality. For example, there’s a
“movie exporter” type, which
identifies components that can write a movie into a non-QuickTime
format, with subtypes identifying the exporters for AVI, MPEG-4, etc.
These identifiers are 32-bit int
values, but
typically they’re not enumerated constants like you
might expect from Java. Usually, the 32 bits are read as four 8-bit
ASCII characters, making a short, human-readable name. These are
defined in the native API as OSType
s, but when
populated with meaningful values, they’re called
"four character codes,”
from the native FOUR_CHAR_CODE
function that returns an
OSType
for a string. This often is abbreviated as
FCC, or
4CC.
The scheme makes a lot of sense from the C
programmer’s point of view. For example, defining
the 4CC for a movie requires a nice, simple one-liner, as seen in the
native Movies.h
header file:
MovieResourceType = 'moov'
Note
"moov” shows up a lot in QuickTime: as an identifier for a movie’s copy-and-paste type, as its Carbon file type, as the top-level “atom” in the file format, etc. Say it out loud if you don’t get the joke: moo-vee.
It turns out that dealing with 4CCs is harder in Java, thanks to Java’s more modern approach to text. Specifically, the use of Unicode means Java characters are 2 bytes each, which means help is needed to turn a Java string into a 4CC.
Fortunately, the
QTUtils
class provides two methods for converting
to and from 4CCs: toOSType()
and fromOSType( )
.
Example 4-1 exercises these methods by converting a
Java string to and from its 4CC representation.
Example 4-1. Converting to and from FOUR_CHAR_CODEs
package com.oreilly.qtjnotebook.ch04; import quicktime.util.QTUtils; public class FourCharCodeTest extends Object { public static void main (String[ ] args) { if (args.length < 1) { System.out.println ("Usage: FourCharCodeTest <fcc>"); return; } System.out.println (args[0]); int fcc = QTUtils.toOSType (args[0]); System.out.println (fcc); System.out.println (Integer.toHexString (fcc)); String fccString = QTUtils.fromOSType(fcc); System.out.println (fccString); } }
The main( )
method takes a
String
from the command line, converts it to a
4CC, prints that value in decimal and hex, then converts it back to a
String
. When it’s run with
moov
as an argument, the output looks like this:
cadamson% java -classpath classes com.oreilly.qtjnotebook.ch04.FourCharCodeTest moov moov 1836019574 6d6f6f76 moov
These utility methods provide some good, old-fashioned bit-munging to
do their conversions. toOSType( )
takes a
String
as its argument, grabbing the low 8 bits of
each character and putting them in the proper place in the returned
int
. In other words, the bottom 8 bits of the
first character take up the first 8 bits of the
int
, then the next character is used for the next
8 bits, and so on. Figure 4-1 shows where the bits
end up in the bit-shifted "moov
“.
fromOSType( )
does the opposite conversion,
masking off the bits of an int
and returning a
four-character Java string.
Get QuickTime for Java: A Developer's Notebook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.