TweetFollow Us on Twitter

September 93 - SOMEWHERE IN QUICKTIME

SOMEWHERE IN QUICKTIME

DYNAMIC CUSTOMIZATION OF COMPONENTS

BILL GUSCHWAN

[IMAGE 084-088_QuickTime_rev1.GIF]

QuickTime's component architecture lets you do a number of amazing and useful things by customizing components, which you can do by deriving one component based on another. Because QuickTime components are dynamically linked, preexisting applications can take advantage of a new, derived component without recompiling or rebooting. And because QuickTime is an extension of system software, the derived component will provide systemwide functionality.

In this column I'll describe how to use object-oriented techniques to customize components using a derived component. To illustrate, I'll show you how to customize the Apple text media handler to "speak" text tracks in movies using Apple's new Text-to-Speech Manager. You'll find the derived component on this issue's CD, along with a generic derived component that you can use as a basis for doing your own customizing. I've also supplied an application to help you debug your component. This application uses the debugging technique of registering the code inline. It's very basic and simply plays back a movie, but it gives you access to the full debugging environment of THINK C.

ABOUT THOSE OBJECT-ORIENTED TECHNIQUES
As any MacApp or class library programmer knows, there are three main steps to adding or altering functionality in an object-oriented program:

  1. Identify the class responsible for the behavior you want to alter.
  2. Identify the specific methods you need to add or override.
  3. Create a new class derived from the original class and implement the new methods or enhance the inherited methods.

Because components can be overridden much like C++ classes, these object-oriented techniques can be applied to customizing components. (For a more in-depth comparison of components and C++ classes, see the "Be Our Guest" column indevelop Issue 12.)

So, the three steps to customizing components are:

  1. Identify the component to use as a starting point.
  2. Identify the routines in the component to override.
  3. Create a derived component.

Before we get into a discussion of these steps, let's drop back and look at the nuts and bolts of QuickTime component architecture with its dynamic linking capabilities. This should give you a clearer idea of how it's possible to alter QuickTime's behavior at run time.

DYNAMIC LINKING OF COMPONENTS
The QuickTime movie file format depends on the dynamic linking capabilities of the Component Manager. To play a QuickTime movie, you need more than just the movie data (video frames, digitized audio samples, text, and such): you also need a time source, code to read/write the data, and code to act on or interpret the data. It would be impractical to store all this information in each and every QuickTime movie. Instead, the time source and code are dynamically linked in as components, while the movie data remains in a QuickTime movie file.

When a movie is opened in an application like MoviePlayer, the movie file is opened first, followed by a NewMovieXXX call (such as NewMovieFromFile). The major purpose of the NewMovieXXX call is to dynamically link to all the components listed in the movie resource and return a handle to this "new" data structure.

When a NewMovieXXX call is made, QuickTime invokes the Component Manager to load the handlers described in the media. A clock component is loaded first (type 'clok', subtype 'micr'). Then the media handler for each track is brought in (type 'mhlr'). If you have video and sound, for example, video and sound media handlers are loaded (subtypes 'vide' and 'soun', respectively).

You may notice that the media handlers open other media handlers to do chores for them. The video and sound media handlers open the standard media handler (type 'mhlr', subtype 'mhlr'), which is a private, high-throughput media handler. The text media handler, though, opens the base media handler (type 'mhlr', subtype 'gnrc'). The base media handler is a public, general-purpose media handler with a lower throughput that is nevertheless fast enough for text.

Next a data handler is loaded. Note that at present there's only one kind of data handler (type 'dhlr', subtype 'alis') supporting streams of data from HFS files. If necessary, a decompressor component is loaded for video; its type depends on the compression format.

Thus, a media handler and a data handler are loaded for each track. QuickTime movies use data handlers and media handlers to load, interpret, and manage the movie data. The alias data handler is responsible for opening and closing data files and for reading and writing sample data. It doesn't understand the format of the data but merely hands off the data to the media handler to interpret.

The media handler is the component that's responsible for interpreting data retrieved from the data handler and for scheduling the rendering of this data at the correct time during movie playback. For example, the text media handler interprets text samples and renders the text track in the movie based on the current time value of the movie. The media handler interfaces with the data handler using file offsets and with the rest of QuickTime through a time value. Thus, a major media handler chore is to convert time values into file offsets.

You now know how and why a QuickTime movie dynamically links with its media handlers. With that background on QuickTime component architecture behind us, we now embark on the process of customizing the text media handler to speak its text.

IN SEARCH OF A BASE COMPONENT
The first step in customizing a component is to identify the base component -- the component to start with.

Not all components can be customized. There are two requirements. First, the component must implement the target request; that is, it must allow another component instance to intercept all its messages. To determine whether a particular component instance implements the target request, you can use the call

ComponentFunctionImplemented(myComponentInstance,
    kComponentTargetSelect) 
The second requirement is that a component must have a public API before it can be inherited from. When a component is called, it's passed the routine's selector in the ComponentParameters structure. The component parses this selector and jumps to the appropriate function. If there's no public API, you can't know the parameters and behavior of any of the component's routines and thus can't override them. The interface file QuickTimeComponent.h contains the APIs for all public QuickTime components.

To speak text as it streams by, we'll want to customize the Apple text media handler, which both implements the target request and has a public API. The Apple text media handler itself is a derived media handler that uses the services of the base media handler supplied by Apple. Consequently, its interface is defined in the MediaHandlers.h file. (For more on the intricacies of derived media handlers, see the "Somewhere in QuickTime" column indevelop Issue 14.)

IN SEARCH OF THE ROUTINES TO OVERRIDE
Our next step is to find the routines to override. In our example, one routine we need to override is the routine in the Apple text media handler where the text is rendered. In addition to rendering the text, we want to grab the text and speak it.

A media handler is normally called in response to a MoviesTask call. MoviesTask is the QuickTime workhorse routine that gives time to the media handler to get the data and render it. In turn, MoviesTask calls the MediaIdle routine to do the bulk of the processing in a media handler. MediaIdle is the main routine in MediaHandlers.h. Thus, MediaIdle is the main routine we want to override. Additionally, we'll need to override the MediaInitialize routine, which supplies us with an initial reference to the media.

CREATING A DERIVED COMPONENT
So far we've chosen a base component from which to derive our customized component, and we've identified the routines we want to override. Now we're ready to take the third step of writing a new component that targets the base component and overrides the identified routines. If you're curious about the design of the generic derived component, you can investigate it on the CD. I'm only going to point out a couple of things about its design before moving on to discuss what you need to do to make your own derived component.

To capture or not to capture. You have two possible approaches when deriving a component. First, you can simply open and target a component, which lets your component use the services of that component. The component is still available to other clients, but you're using an instance of it. Second, in addition to targeting the component, you can capture it. The base component will then be replaced by your component in the component registration list and will no longer be available to clients (although current connections are retained). The CaptureComponent routine returns a special ID so that the captured component can still be used by your component.

We'll use CaptureComponent because we want to replace the functionality of all instances of the text media handler (conceptually, you can think of capturing as patching). However, targeting without capturing is just as effective -- and it has a few advantages: it doesn't require you to keep track of the captured component's ID, and it allows clients looking for a specific component to be successful.

Let's walk through the steps you'd take to make your own derived component using the generic code on this issue's CD, which are the same steps used to create our text-speaking example. You need to make changes in specific places: the component resource, the global data file, the OpenComponent routine, and the override routines.

Changing the component resource. The first thing to change is the resource file for the component. The essential part of this file is the component description, which is a structure that describes the component type, subtype, manufacturer, and flags. The Component Manager looks at this information when it's handling an application's request for a component. You want the right information here so that QuickTime will grab your derived component instead of the base component.

You should change the component type and subtype to match those of the component you're inheriting from. In our example, when a QuickTime movie with a text track is opened, QuickTime asks the Component Manager for a text media handler, which has type 'mhlr' and subtype 'text'. Since we want QuickTime to grab our derived component instead, we need to make its type and subtype the same.

In our case, we have to change the component manufacturer to match that of the base component as well. This isn't the ideal situation, because it would be most desirable for each component to have a unique manufacturer. But clients may look for a component of a specific manufacturer and won't grab your derived component if its manufacturer is different. Because it would be better to be able to identify a derived component, it's strongly suggested that component clients always perform a default search, avoiding asking for specifics other than type and subtype.

You may also need to set the componentFlags field, which identifies specific functionality for a component. For example, video digitizers use componentFlags to identify the type of clipping the digitizer performs, among other things.

If you don't know how a client searches for a component, you can find out by running that application and trapping on FindNextComponent. The last parameter pushed on the stack is the component description, and you can find its values in a debugger (see "Inside QuickTime and Component-Based Managers" indevelop Issue 13). In our example, we know that QuickTime performs a simple type and subtype search for a text media handler, so we only have to change the type and subtype in the component resource.

The global data file. The ComponentData.h file contains the declaration of the data structure for each component instance and the global component data structure. You'll need to fill out a component description structure describing your chosen base component, which will be used to ask the Component Manager to find it.

Now you're left with defining the global data for your derived component. The generic capturing component on this issue's CD has one item that's shared across all its instances: a reference to the captured component. If you need data that's shared across instances, declare it here, but in general you shouldn't need it.

The data local to each instance is allocated in the OpenComponent routine. By default, three component instances will be kept track of: a self copy, a delegate copy, and a target copy. These instances will be stored for you, and you won't need to do any work. The target copy is the instance of a component that may capture yours. If your component calls itself, it should use this instance in case the target overrides the routine.

The other data that you allocate is specific to the type of your derived component. For our example, we'll allocate room for a speech channel, a media reference, a handle to the text to be spoken, and a StdTTSParams structure, which is filled out by the Standard Text to Speech dialog. This dialog lets the user choose voice, pitch, and modulation.

The OpenComponent routine. OpenComponent performs three major operations. First, it allocates storage for each instance. Second, it checks for QuickTime, the Text-to-Speech Manager, and other dependencies; if they're not installed, the component can't open and an error is returned. Note that software dependencies are checked here instead of in RegisterComponent to bypass possible load order conflicts. Finally, OpenComponent captures the Apple text media handler and stores a reference to it in the component globals.

The override routines. Now it's time to implement the override routines. You'll need to get the selectors for the routines from the original component's header file.

In our example, we look at MediaHandlers.h and find the MediaInitialize routine. The selector has a constant, kMediaInitializeSelect. We need to make the parameters of our override routine match those of the MediaInitialize routine.

pascal ComponentResult MediaInitialize
    (PrivateGlobals **storage,
    GetMovieCompleteParams *gmc)

MediaInitialize performs these tasks: it stores the media reference from the GetMovieCompleteParams structure in our private storage; it queries the user for a voice with the Standard Text to Speech dialog; and, with this information, it allocates and sets up the speech channel.

Next we implement the MediaIdle routine, which has a selector of kMediaIdleSelect. Our MediaIdle looks like this:

pascal ComponentResult MediaIdle
    (PrivateGlobals **storage, TimeValue
    atMediaTime, long flagsIn, long *flagsOut,
    const TimeRecord *movieTime)

This routine retrieves the media sample for the time passed in and then speaks it. The important parameter is atMediaTime, which contains the current time value of the media for the movie. We get the media sample for that time using GetMediaSample, and then we use the nifty new Text-to- Speech Manager to speak.

In this case, we'll use SpeakText, which takes three parameters: a speechChannel (allocated earlier in the OpenComponent routine), a pointer to the beginning of the text that we want to speak, and the length of the text. SpeakText is an asynchronous routine, so it won't hold up processing (or the movie) while it speaks. On the other hand, the text can't be disposed of until speaking is finished. To accommodate this requirement, a reference to the text is stored in our instance storage, and the text is disposed of when the component closes.

LETTING USERS LINK AND UNLINK COMPONENTS
Thanks to dynamic linking, a large number of users can easily take advantage of new functionality provided by customized components. Three methods can be used to register and unregister components. First, a component is registered at system startup if the component resides in the System Folder, or in the Extensions folder of the System Folder. To unregister this component, a user can remove it and reboot. Second, an application can dynamically register components as needed, and then unregister them when finished. Third, you can use the drag-and-drop applications Komponent Killer and Reinstaller II included on this issue's CD. Using these applications, you don't have to reboot. (Of course, your typical user won't do it this way; this method is for you, the programmer.)

EXCITING PROSPECTS
Now you know how to customize a component using a derived component, which will be dynamically linked at run time and thus can extend systemwide functionality. Just think of the possibilities! You can override the movie controller and implement an Apple event handler. And you can override other base components as well. Fiddle around with the generic derived component on the CD to get an idea of the exciting prospects before you.

REFERENCES

  • "Somewhere in QuickTime: Derived Media Handlers" by John Wang, develop Issue 14.
  • "Inside QuickTime and Component-Based Managers" by Bill Guschwan, develop Issue 13.
  • "Techniques for Writing and Debugging Components" by Gary Woodcock and Casey King, develop Issue 12.
  • "Be Our Guest: Components and C++ Classes Compared" by David Van Brink, develop Issue 12.

BILL GUSCHWAN (AppleLink ANGUS) hung out with Robert Schumann to discuss their symphonic feats. Robert: "Angus, I understand you compare your jobs to symphonies." Angus: "I guess so, though I'd rather compare operas to pasta. You know, Wagner is lasagna, Mozart is fettucine, Verdi is ravioli, . . ." Robert: "So on your opera pasta scale, how do you rate my symphonic music?" Angus: "Linguini." Robert: "Yo mama!" Angus: "Listen, Mr. Concerto Psycho Ward, at least my mother knows the meaning of life beyond success. Can't say the same about your wife." Robert: "You mean my beloved Clara." Angus: "Yep, Clara, the dogcow. Well, gotta go, I hear Symphony No. 2." Robert: "Before you go, what's the key?" Angus: "C Major." Robert: "No, what's the key?" Angus: "As Wittgenstein says, the key to life is that language is a game." Robert: "No, what's the key?" Angus: "Oh, it's the key to my new office in PIE DTS." Robert: "Then let the music begin, allegro." Angus: "Pass the parmesan." *

To see information about a track in a hierarchical manner, you can use Dumpster, a QuickTime tool that's included on this issue's CD.*

You can watch the components of a movie load if you set A-trap breaks as outlined in the section "Breaking on Common Component Manager Routines" in the article "Inside QuickTime and Component-Based Managers" in develop Issue 13.*

QuickTime 1.6 adds a new Component Manager selector, componentWantsUnregister, that you can take advantage of when you want to free a captured component. Set componentWantsUnregister in the componentRegisterFlags field. When the captured component is unregistered, your derived component can call UncaptureComponent and dispose of the global memory.*

To identify a captured component in a debugger, you can use the thing dcmd. The component ID of a captured component will begin with two periods (..). *

A version of the Text-to-Speech Manager can be found on this issue's CD. *

Thanks to Ken Doyle, Tim Schaaff, and Gary Woodcock for reviewing this column. *

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

1Password 6.8.1 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
EtreCheck 3.4.4 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
GarageSale 7.0.8 - Create outstanding eB...
GarageSale is a slick, full-featured client application for the eBay online auction system. Create and manage your auctions with ease. With GarageSale, you can create, edit, track, and manage... Read more
Backblaze 5.0.0.116 - Online backup serv...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
Parallels Desktop 13.0.0 - Run Windows a...
Parallels allows you to run Windows and Mac applications side by side. Choose your view to make Windows invisible while still using its applications, or keep the familiar Windows background and... Read more
Mellel 4.0.0 - The word processor for sc...
Mellel is the leading word processor for OS X and has been widely considered the industry standard for long form documents since its inception. Mellel focuses on writers and scholars for technical... Read more
Adobe Muse CC 2017 2017.1.0 - Design and...
Muse CC 2017 is available as part of Adobe Creative Cloud for as little as $14.99/month (or $9.99/month if you're a previous Muse customer). Adobe Muse 2017 enables designers to create websites as... Read more
WhatsApp 0.2.5862 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
WhatsApp 0.2.5862 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Things 3.1.3 - Elegant personal task man...
Things is a task management solution that helps to organize your tasks in an elegant and intuitive way. Things combines powerful features with simplicity through the use of tags and its intelligent... Read more

KORG iMono/Poly (Music)
KORG iMono/Poly 1.0.0 Device: iOS Universal Category: Music Price: $19.99, Version: 1.0.0 (iTunes) Description: *** Special Sale for a limited time to celebrate the debut of KORG iMono/Poly (33% OFF) until Sep 30! *** Reviving a... | Read more »
Super Phantom Cat 2 beginner's guid...
Super Phantom Cat 2 presents a whole new world of fun platforming challenges and perplexing puzzles. It's a well-designed platformer with a bright, neon aesthetic that brings the genre up to date. [Read more] | Read more »
Shadow Fight 2 Special Edition (Games)
Shadow Fight 2 Special Edition 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: ** New story chapter! **** No Ads! **** No energy! ** The best fighting series on mobile has returned and... | Read more »
4 RPGs like Final Fantasy XV that deserv...
Square Enix announced another Final Fantasy XV spin-off today - Final Fantasy XV Pocket Edition. This mobile, episodic version of the hit RPG gives the game a chibi-fied makeover. The first episode will be free, followed by 9 more premium episodes... | Read more »
Guild sieges and soul gems in latest upd...
Webzen’s MU Origin hit app stores last year, giving fans of fantasy hack-n-slash MMOs like Diablo a new fix to fixate on. This latest update introduces a competitive guild battle, a fresh dungeon challenge, a mini-game and some elemental gems to... | Read more »
Little Red Lie (Games)
Little Red Lie 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ARE YOU MORE AFRAID OF POVERTY THAN DEATH? Little Red Lie is a narrative-focused, interactive fiction experience that reduces... | Read more »
You can now apply to be Clash of Clans...
Earlier this month, word got out that the Builder, the trusty handiman who tirelessly built every single building inevery singleClash of Clansbase had called it quits. Sick of seeing his work destroyed endless, the Builder has set out for our world... | Read more »
Meshi Quest beginner's guide - how...
Meshi Quest is Square Enix's newest free-to-play release, and it's a real charmer. You start off as the head of a sushi restaurant, upgrading your food and equipment as you serve visitors heaping helpings of your delicious meals. As you progress,... | Read more »
BUST-A-MOVE JOURNEY (Games)
BUST-A-MOVE JOURNEY 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: BUST-A-MOVE Features:- Shoot bubbles and match 3 or more bubbles of the same color to make them pop!- Complete your... | Read more »
The best card combos in Clash Royale
Clash Royale is all about building a deck of units that synergise well. To help you get off to a flying start, we've put together a list of unit combinations that are incredibly effective. Looking for some choice 2v2 combos? Check out our guide. [... | Read more »

Price Scanner via MacPrices.net

Low Cost Subscription Graphics App Alternativ...
I’m not a fan of the subscription software model, I don’t use any subscription apps. Used to be that you paid your license fee and the app was yours to use indefinitely, or until one opted for a paid... Read more
Clearance 2016 13-inch MacBook Airs, Apple re...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $809. An Apple one-year warranty is included with each MacBook, and shipping is free: – 13″ 1.6GHz/8GB/128GB MacBook Air: $... Read more
2017 13-inch MacBook Airs on sale for $100 of...
B&H Photo new 2017 13″ MacBook Airs on sale today for $100 off MSRP, starting at $899: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off MSRP – 13″ 1.8GHz/256GB MacBook Air (MQD42LL/A... Read more
Sale! 13-inch 2.3GHz MacBook Pros for $100 of...
B&H Photo has 13″ 2.3GHz MacBook Pros in stock today and on sale for $100 off MSRP including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook Pro (MPXQ2LL... Read more
2016 MacBook Pros, Apple refurbished, availab...
Apple has Certified Refurbished 2016 15″ and 13″ MacBook Pros available starting at $1189. An Apple one-year warranty is included with each model, and shipping is free: – 15″ 2.7GHz Touch Bar Space... Read more
Apple offers Certified Refurbished iPhone 6s...
Apple has Certified Refurbished unlocked iPhone 6s’s and 6s Plus’s available starting at $449. An Apple one-year warranty is included with each phone, and shipping is free: – 16GB iPhone 6s: $449, $... Read more
Apple offers Certified Refurbished Pencils fo...
Apple has Certified Refurbished Apple Pencils available for $85 including free shipping. Their price is $14 off MSRP, and it’s the lowest price available for a Pencil. Read more
2016 15-inch 2.6GHz Touch Bar MacBook Pro ava...
B&H Photo has clearance 2016 15″ 2.6GHz MacBook Pros in stock today and on sale for $500 off original MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: – 15″ 2.6GHz Touch... Read more
21-inch 2.3GHz iMac on sale for $999, save $1...
Amazon has the new 2017 21″ 2.3GHz iMac (MMQA2LL/A) in stock and on sale for $999.99 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
Free Instant Translator 2.0 App For iOS Relea...
Mobile application development company, Neoappz has announced the release and immediate availability of Instant Translator 2.0 for iOS devices. Instant Translator is a user-friendly application which... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
Frameworks Engineering Manager, *Apple* Wat...
Frameworks Engineering Manager, Apple Watch Job Number: 41632321 Santa Clara Valley, California, United States Posted: Jun. 15, 2017 Weekly Hours: 40.00 Job Summary Read more
Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
Frameworks Engineering Manager, *Apple* Wat...
Frameworks Engineering Manager, Apple Watch Job Number: 41632321 Santa Clara Valley, California, United States Posted: Jun. 15, 2017 Weekly Hours: 40.00 Job Summary Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.