Important: The information in this document is obsolete and should not be used for new development.
QuickTime 6 adds support for using variable bitrate (VBR)-enabled
sound compressor components. Both the QuickTime Movie exporter component
available in the export dialog (also known as the ConvertMovieToFile API
dialog) and the Standard Sound compression dialog component have
been updated to use and to recognize VBR compressor components.
QuickTime 6 also provides QuickTime developers with the capability of building their own custom VBR-enabled sound compressor components, as discussed in this section.
Background
QuickTime 6 VBR Support
Some Techniques For Compressing VBR Audio
Using the Standard Sound Compression Component and VBR Compression
Audio File Formats and VBR Compression
Doing Something with VBR Audio Data
New Tween Component API
Changes to Effects Dialog
QuickTime Effects Classes
QuickTime Effects Presets
None Codec Enhancements
Additional Still Image Metadata Support in Mac OS 9 and Windows
New APIs For Creating Exif Files
Improved Movie Toolbox Support for Data Handlers
OpenADataHandler Extended
Advanced APIs
QuickTime 4.1 and the Sound Manager introduced support for the playback of VBR audio––in particular, VBR support for the decoding and playback of MP3 audio. A number of modern audio compression formats, such as MP3, either support or require VBR decoding.
Versions of QuickTime prior to QuickTime 4.1 provided support only for constant bitrate (CBR) audio. The fundamental difference between constant bitrate and variable bitrate audio is related to the rate at which audio data is presented to the sound decoder to generate sound.
In CBR audio, the rate is constant. If one second of audio requires 40 K bytes, then 5 seconds will require 200 K bytes (= 40 Kbytes/sec * 5 sec). Moreover, given a stream of 3 minutes of audio compressed like this, to start playing at 2:30, you would advance 6,000K into the stream.
With VBR audio, the data rate varies depending upon the complexity of the encoded sound. For example, a very quiet passage of a score could be compressed much more than a very exciting passage. A VBR encoder will analyze the audio and use the appropriate number of bits, varying its usage in the process. This means that the amount of data for a complex passage is greater than for a less complex passage. This also complicates locating data in the stream because the “road map” is located within the stream.
By way of analogy, video encoding formats are typically VBR in nature. A more complex image requires more bits than a less complex image. As different images are encoded, the number of bits required for each will vary. The analog to CBR audio in the video space is raw RGB or uncompressed YUV.
As discussed, QuickTime and the Sound Manager have been able to decode self-framed, variable bitrate formats such as MP3 since QuickTime 4.1. In addition, the QuickTime Movie file format has been able to carry variable bitrate audio.
With QuickTime 6, QuickTime and the Sound Manager add much richer and more comprehensive support for VBR audio, including support for both compression of VBR audio and decompression of non-self-framed VBR audio formats. An example of a non-self-framed audio format is AAC, described in the section “Defining AAC.” Table 1-2 shows the audio support available since QuickTime 4.1.
Version |
VBR Audio |
Support |
|---|---|---|
QuickTime 6 |
Encode and decode, e.g., MP3 |
Non-self-framed VBR audio, e.g., AAC |
QuickTime 5 |
Decode and playback |
Self-framed VBR |
QuickTime 4.1 |
Decode and playback, e.g., MP3 |
Self-framed VBR |
This section discusses some of the techniques you can use if you need to compress VBR audio.
Because variable bitrate audio may contain audio frames of
different sizes, it is important that an application use the appropriate
APIs to generate the compressed audio. If, for example, your application
receives a -213 (siVBRCompressionNotSupported)
error from QuickTime or the Sound Manager, it indicates either QuickTime
or the Sound Manager doesn’t “know” about VBR compression,
or doesn’t believe your application understands VBR compression.
To inform QuickTime that your application understands the details of VBR compression, here are some steps that you should consider:
To begin with, you must use the SoundConverterFillBuffer() API.
If you are using the SoundConverterFillBuffer() API,
you’ve already done most of the work. Although SoundConverterConvertBuffer() cannot
be used for VBR compression, you can configure the SoundConverter
without making a decision as to using FillBuffer or ConvertBuffer
yet, in case you want to continue using the SoundConverterConvertBuffer() routine
for fixed compression audio. There is no good reason to do so, but
it may be important in your current implementation.
Your application must inform the SoundConverter that it can
handle VBR audio. To do this, immediately after opening the SoundConverter
with SoundConverterOpen(),
make a call to SoundConverterSetInfo(),
passing the siClientAcceptsVBR selector
like the following:
SoundConverterSetInfo(theSoundConverter, siClientAcceptsVBR,(void*)true); |
This lets the sound converter know that you are VBR compression-aware.
After configuring the sound converter with compression parameters (if present), request the compressor’s compression information, so you know how many PCM samples are generated per audio frame.
Ask for siCompressionFactor and
look at the resulting CompressionInfo.
If the compInfo.compressionID field
is set to variableCompression,
then the codec is configured to generate VBR audio. If it has another
value, the codec is configured for a fixed bitrate––just as
it would in versions of QuickTime prior to QuickTime 6. Remember
that a single codec can support fixed and variable compression,
so don’t assume its capabilities from its codec type.
Just as before, samplesPerPacket holds
the PCM sample count per audio frame (packet). For VBR audio, you
can ignore bytesPerFrame/bytesPerPacket,
since the sizes aren’t constant.
For variable compression codecs, you need to
know the worst case size of a single audio frame (packet). You
can then allocate the output buffer for use with the SoundConverterFillBuffer() routine,
based on a multiple of this size. Failing to do this might result
in SoundConverterFillBuffer() not
being able to generate even a single audio frame. If you spin on SoundConverterFillBuffer() waiting
for it to generate at least one audio frame before continuing but
don’t provide a large enough output buffer, you have the makings
of a really cool and involved infinite loop.
Use the new selector siCompressionMaxPacketSize to
retrieve the worst case packet size. The following code shows an
example:
UInt32 maxPacketSize = 0; |
err = SoundConverterGetInfo( theSoundConverter, |
siCompressionMaxPacketSize, |
&maxPacketSize ); |
If a VBR codec doesn’t support this selector, you may want to use a worst case output buffer size such as 32K.
Note: VBR codec developers should implement this selector. This will not be implemented by fixed bitrate compressors, although it is not illegal to do so.
Use SoundConvertFillBuffer() to
perform the encoding, as shown in the code below. The value should
be tied to the codec’s current configuration.
err = SoundConverterFillBuffer(theSoundConverter, //a sound converter |
fillBufferUPP, // proc |
fillBufferRefCon, // refCon passed to FillDataProc |
soundOutputBuffer, // compressed audio buffer |
soundOutputBufferSize, // size of compressed audio buffer |
&actualOutputBytes, // number of output bytes |
&outputFrames, // number of output frames |
&outputFlags); // fillbuffer returned advisory flags |
The difference with VBR compression is that each call only
returns audio, where all the frames have the same size in bytes.
This is necessary because the SoundConverterFillBuffer() API returns
the number of bytes it wrote and the number of frames but doesn’t
return any kind of array indicating the boundaries between frames.
If you divide actualOutputBytes by outputFrames,
you can determine how large each audio frame is.
As an example, if the audio frames have the following sizes in bytes
[ 40 ] [ 40 ] [ 50 ] [ 50 ] [ 50 ] [ 30 ] [ 40 ] |
at least four calls to SoundConverterFillBuffer will
be necessary in order to encode these frames. This call would return
the following values:
actualOutputBytes outputFrames |
----------------- ------------ |
80 2 |
150 3 |
30 1 |
40 1 |
Like the SoundConverter, QuickTime doesn’t want to offer
VBR sound compressors to applications that cannot support them.
This means that if your application uses the Standard Sound Compression
dialog to select and configure sound compressors, you should pass
the new (in QuickTime 6) scSoundVBRCompressionOK selector
to SCSetInfo() as in
the following code example:
ComponentInstance ci = OpenDefaultComponent(StandardCompressionType, |
StandardCompressionSubTypeSound); |
if (ci ) { |
Boolean doVBR = true; |
SCSetInfo (ci, scSoundVBRCompressionOK, &doVBR); |
. . . |
If you don’t pass the new scSoundVBRCompressionOK selector
to SCSetInfo(), only
fixed compression codecs will be presented in the list.
In fact, compressors that perform fixed and variable compression
will be presented if this selector is not called, but those compressors
will only offer their fixedCompression options. Since AAC only performs
variable compression, it will not appear in the dialog unless you
call SCSetInfo with scSoundVBRCompressionOK.
In QuickTime 6, a new Standard Compression selector is provided
in QuickTimeComponents.h that
returns a list of available codecs. The selector, a pointer to a
handle, is defined as follows:
scAvailableCompressionListType = FOUR_CHAR_CODE('avai') |
This is the same kind of handle as the existing scCompressionListType selector.
Applications that need to build lists of codecs (compressors) for
their user interface should adopt this API. If the scAvailableCompressionListType
selector is not recognized, use the previous code.
Not all audio file formats can hold variable compression audio, since the information about framing isn’t always available in every format.
QuickTime Movies provide a format that can hold the information, just as MPEG-4 files can. AIFF and WAVE, however, are formats that do not carry such information.
This explains why you see the MPEG-4 audio codec available
in the QuickTime Movie exporter’s sound options––but not in
the AIFF options. Not surprisingly, these exporters use the Standard
Sound Compression dialog as above. Because VBR compression is opted in
by the client, only the QuickTime Movie exporter passes the scSoundVBRCompressionOK selector.
At this point in the process, your application is either generating VBR audio to be stored in a QuickTime Movie for playback later, or you want to play or decode the audio directly. Of course, you may be using your own format to store the audio, but remember, you need to store the framing information yourself.
If you store the data in the QuickTime Movie, you need to store the generated audio frames in a way that is compatible with how QuickTime stores VBR audio in sound tracks.
To play or decode the audio, you need to use the additional
fields in the ExtendedSoundComponentData, ExtendedScheduledSoundHeader,
or ExtendedSoundParamBlock,
depending on how you are playing the data. Fortunately, they are
the same fields.
The following fields are introduced in QuickTime 6:
long frameCount; // number of audio frames |
long * frameSizesArray; // pointer to array of longs with frame sizes |
// in bytes |
long commonFrameSize; // size of each frame if common |
Specifically, frameCount, frameSizesArray and commonFrameSize are
relevant for playback and decoding of AAC audio, as well as for
other non-self-framed audio VBR audio formats.
As discussed earlier, QuickTime versions prior to QuickTime
6 could handle self-framed VBR audio. This is why the existing extended bufferSize field
is sufficient for MP3 audio. AAC audio, though, doesn’t have information
within it to indicate framing, and depends upon out-of-band data
to carry that information. In the case of QuickTime and MPEG-4 movies,
that information is in the sample tables.
The fields just described (new in QuickTime 6) are used to
convey the information to the audio decoder (or sound decompressor
in Sound Manager parlance) and are necessary for use with AAC audio.
In all cases, these fields all describe a single buffer of audio.
The existing sampleCount, buffer and bufferSizes fields
all must be valid.
In addition, either frameCount and frameSizesArray or commonFrameSize must
be valid (indicated by extendedFlags)
in order to decode AAC data. (Note that frameCount and frameSizesArray must
be valid as a unit because they work together, not as separate fields.)
The flags for extendedFlags are
in the header file Sound.h as
follows:
kExtendedSoundFrameSizesValid = 1L << 2, |
// set if frameSizesArray is valid |
// (this will be nil if all sizes are common and |
// kExtendedSoundCommonFrameSizeValid is set) |
kExtendedSoundCommonFrameSizeValid = 1L << 3, |
// set if all audio frames have the same size and |
// the commonFrameSize field is valid |
If commonFrameSize is
set, this means that all audio frames in the VBR buffer have exactly
the same size in bytes. There is no frame count, since bufferSize divided
by commonFrameSize is
the frame count.
If frameCount and frameSizesArray are
valid (remember, these fields must be considered as a unit), then frameCount holds
a count of the number of elements in the frameSizesArray array.
This array is a set of 32-bit values holding the size of each audio
frame. In the above example, the fields would look like this:
frameCount = 7; |
frameSizeArray = --> { 40, 40, 50, 50, 50, 30, 40 } |
Note: The frameCount and frameSizesArray fields
will be updated by the decoder, so you should not allocate a pointer
and store that in frameSizesArray and expect
to be able to deallocate it when done. Instead, allocate the pointer
and store a copy of the address in frameSizesArray.
Just as you can use the SoundConverterFillBuffer() routine
to encode VBR audio, you can also use it to decode AAC audio. However,
the SoundConverterFillBufferDataProc’s
returned ExtendedSoundComponentData must
set the appropriate flags, including the fields described above.
In QuickTime 6, tween components now provide an interrupt-safe
interface using a new API routine, QTDoTweenPtr.
This new call provides for return values in a pointer rather than a
handle. Some specific tweens implemented as components required
changes to ensure their interrupt safeness. Not all Apple-defined
tween components support this new API. However, all of those needed
for effects have been so revised.
Runs a tween component, providing for return values in a pointer rather than a handle.
OSErr QTDoTweenPtr (QTTweener tween, TimeValue atTime, Ptr result, long resultSize) ;
A tween to be run.
A value that defines the time to run the tween.
The result of the tweening operation.
The size of the result returned.
This routine is an interrupt-safe version of the QTDoTween routine,
which also runs a tween component. Note that it has the following
limitations:
Not all tween types support this call (those
which must allocate memory), in which case they return codecUnimpErr.
The QTAtomContainer used for the tween must be locked.
The dataSize must
be large enough to contain the result.
This call is not supported for sequence tweens; you should use interpolation tweens instead.
Introduced in QuickTime 6.
Movies.h
C interface file: Movies.h
In QuickTime 6, the effects dialog has been revised and enhanced. The new features include
Grouping into types within the scrolling list on the left side of the dialog. In this new design, each effect defines what subgroup it belongs to, as shown in Figure 1-11. Any third-party effects installed appear under “Misc” until they are revised to include their subgroup information.
Resizability of the dialog and split bars to control the list vs. preview vs. effect-specific areas. Note that the resize control is only drawn in Mac OS 8.1 and later.
Providing a widget for picking points, which can be used in any effect that allows the selection of points (that is, x and y values). Notice that such items have turned from a multitude of sliders into this point-picking widget.
Allowing effect components to specify custom “picking interfaces” for parts of their user interface, while allowing the Generic effect to handle the remainder.
Providing a way to set slider values by typing. Any slider within the effects dialog will now allow this. Command-clicking any slider brings up a modal dialog. The dialog is centered below the control to edit. The dialog is sized appropriately for name and length of number edit. The dialog contains a type-in field, parameter name label, and OK and Cancel buttons.
A knob control that provides a way to set angles greater than 360 degrees. This is used in the Slide effect. Knob control now has an inner section that serves as an hour hand. When the knob is manipulated beyond one rotation, the hour hand increments. This wraps properly both forward and backward over the 12 o’clock position.
Effects may now specify some common “presets” that the user can easily select. These are used in the Slide effect. When such an effect is selected, the first subpanel is a list of presets, each with a name and preview. The pane scales to the available space, and implements a scroll bar if needed.
The subgroup pop-up menu at the top of the screen will read Easy and Custom if there are no additional subpanes. If there are, the pop-up menu reads Easy and the names of the other subpanes.
A new effect called Channel Composite provides a way to create a bitmap whose color components are a combination of source A and B color components, reshuffled, and inverted as desired.
The Color Tint effect now allows user to specify an amount of tinting to allow a gradual transition to a particular color, such as Sepia. A new pair of sliders controls this. Tweening is allowed. The default value is to tint fully (for backwards compatibility) for the entire duration of the effect.
Effects may now have tween values when filtering during export, that is, Movie to QuickTime Movies. Some effects, such as Lens Flare and RGB Balance, now have a starting and ending value that you can set. Some (such as RGB Balance) display this information only if the Option key is pressed when selecting the Filter button. This is because tweening these values is uncommon.
Effects may choose to implement custom controls to allow the user to more easily edit complex parameters that are ill-served by simple sliders or type in boxes. Effects may allow a custom control for either a single parameter, or for a group of parameters.
Parameter(s) for a custom control must still be data types defined by the standard set, or for complex records of data, must be defined within a group as individual parameters made up from base data types (for example, a point is a group containing two Fixed point numbers).
This is to allow applications that do not wish to use the custom control for the effect to set values themselves.
Effects should be aware that these custom controls may be deployed by the application in either a dialog or a window, with application-defined background colors or patterns, along with application-defined font characteristics for the window.
It is recommended that an effect implement custom controls only when needed, and that custom controls be used for specific types of parameters (i.e., point, rectangle, polygon, path) rather than the entire user interface for the effect. Effects may choose to implement multiple custom controls that combine with standard controls to present the total user interface.
For effects that have very complex user interfaces not well
suited for inclusion within a single window, it is recommended to
use kParameterImageIsPreset––which
allows the effect to have an external editing application for parameters
that may then be set within the standard User Interface via the
open file dialog or drag and drop. The Lens Flare (shown in Figure 1-12) effect’s
“Flare Type” is an example of such a preset.
kCustomControl AddedFor parameters that use a custom control to control a single
parameter value, a new behavior flag has been added (kCustomControl),
and the behavior for the parameter should be kParameterItemControl.
For parameters that are groups, the same flag (kCustomControl)
should be used, and the behavior should be kParameterItemGroupDivider.
Groups with the kCustomControl bit
set will be implemented by calling the custom control for that group––the
parameters within that group will not be processed in the normal
manner.
In both cases, the new customType and customID fields
of the behavior must be filled in. These are used in order to allow
your custom control to determine which parameter is being edited
in the case where the custom control is used for the editing of
multiple parameters. These values are passed into the pdActionCustomNewControl call.
Since the custom control mechanism is also used by QuickTime’s
default effect dialogs, you should be prepared to pass onto the
base effect any pdActionCustomNewControl calls
for type/id pairs that you do not handle yourself. When pdActionCustomNewControl is
called for controls of types handled by QuickTime, customType is kParameterAtomTypeAndID and
customID is the ID of the parameter atom.
pdActionCustomNewControlControl to
Create New Custom ControlspdActionCustomNewControlControl is
called by the application to create a new custom control or set
of controls for an effect parameter. When pdActionCustomNewControl is
called, the effect should perform any basic allocation it needs
for storage and return the result in storage. The options parameter
tells the control if the application wishes to support interpolated, optionally
interpolated, or a single value parameter.
Since pdActionCustomNewControlControl may
call upon your effect for other items within the dialog, it is recommended
that your effect have an easy way to determine which controls it
implements by using one of these two techniques:
by having storage be a pointer with an OSType at the beginning to mark controls implemented by your code
keeping track in your component globals those custom controls that you have created
When pdActionCustomDisposeControl is
called, any allocation done by the control should be disposed of.
In addition, pdActionCustomDisposeControl is
the last chance the control has to commit any user changes into
the sample.
Controls that implement type-in fields typically need to commit any final user edits at this time.
struct QTCustomControlNewRecord { |
void * storage; /* storage allocated/disposed by the control*/ |
QTParameterDialogOptions options; /* options used to control |
interpolation/not*/ |
QTAtomContainer sample; /* sample that holds the data to be edited*/ |
long customType; /* custom type and ID specified by effect for |
creation of this control*/ |
long customID; |
}; |
typedef struct QTCustomControlNewRecord QTCustomControlNewRecord; |
typedef QTCustomControlNewRecord * QTCustomControlNewPtr; |
pdActionCustomPositionControl is
called by the application to position the control within a window
or dialog.
The control should determine if it will fit in the allotted
area and position itself there. It should also return the space
taken up by the control. Note you are free to implement controls
which are variable in size depending upon which parameter you are
editing. You don’t need to scale your control to the requested
size. If the area presented to your control is too small, set didFit to FALSE.
You should still return in used the size you would have liked to
use for the control. The application will then try again with
a new size. Note that all controls must be able to fit within a
minimum of 300 by 250 pixels.
Custom controls that draw text should make note of the text font, size, and style at this time in order to properly display within application windows.
Note that the default state for the control is hidden. You
will receive a pdActionCustomShowHideControl in
order to enable your control. You should not draw your control in
response to pdActionCustomPositionControl.
struct QTCustomControlPositionControlRecord { |
void * storage; /* storage for the control*/ |
WindowPtr window; /* window to be used by the control*/ |
Rect location; /* location within the window the control may use*/ |
Rect used; /* returned by the control to indicate size it actually |
used*/ |
Boolean didFit; /* did the control fit in the specified area?*/ |
Boolean pad[3]; |
}; |
typedef struct QTCustomControlPositionControlRecord QTCustomControlPositionControlRecord; |
typedef QTCustomControlPositionControlRecord * QTCustomControlPositionControlPtr; |
pdActionCustomShowHideControl is
called when the application wishes to enable/disable your control,
or completely disable drawing of the control.
Your control should make note of the new state (if different
from the last) and perform an InvalRect() on
your drawing area, or you may draw your control’s initial state
in the case of show. You should not attempt to erase your control
as the result of a hide. Instead, call InvalRect() and
allow the application to process the resulting event as appropriate.
struct QTCustomControlShowHideControlRecord { |
void * storage; /* storage for the control*/ |
Boolean show; /* display the control?*/ |
Boolean enable; /* enable the control (ie, black vs gray display)*/ |
Boolean pad[2]; |
}; |
typedef struct QTCustomControlShowHideControlRecord QTCustomControlShowHideControlRecord; |
typedef QTCustomControlShowHideControlRecord * QTCustomControlShowHideControlPtr; |
pdActionCustomHandleEvent To
Process EventspdActionCustomHandleEvent is
called to allow your custom control to process events.
Typical controls handle the following events:
activate to
draw your control in normal/gray mode
update to draw
your control
mouseDown to handle
clicks
keyDown to handle
typing when you have focus
idle to perform
idle drawing (if applicable)
If your control handles the entire event, set didProcess to TRUE.
If you handled the event, but other controls still need the event,
set didProcess to FALSE.
If your control supports the concept of focus for the purposes
of typing (such as by having a type-in box for the parameter), then
you set the tookFocus Boolean
as part of your processing of the event. It is assumed that your
control will draw the appropriate focus user interface as a result,
and the calling application will disable any focus drawing within the
remainder of the user interface.
By default, custom controls are not given idle time. If you
need idle time, set needIdle to TRUE in
response to the event that causes you to need idle (typically the
taking of focus, or the first draw).
Your control will continue to be given idle events until you
set needIdle to FALSE
in response to a nullEvent.
struct QTCustomControlHandleEventRecord { |
void * storage; /* storage for the control*/ |
EventRecord * pEvent; /* event to process*/ |
Boolean didProcess; /* did we process entire event?*/ |
Boolean tookFocus; /* did we take focus as a result of this event |
(typically mouseDowns)*/ |
Boolean needIdle; /* does this control need idle events?*/ |
Boolean didEdit; /* did we edit the samples?*/ |
}; |
typedef struct QTCustomControlHandleEventRecord
QTCustomControlHandleEventRecord;
typedef QTCustomControlHandleEventRecord
* QTCustomControlHandleEventPtr;
pdActionCustomSetFocus to
Set or Advance Current FocuspdActionCustomSetFocus is
called in order to set or advance the current focus of the user interface,
typically because the user has pressed the tab or shift-tab keys,
or because the user clicked within the area defined by your control.
Your control will be called with pdActionFocusFirst, pdActionFocusLast,
or pdActionFocusOff to
set or clear focus on your control. Your control will be called
with pdActionFocusForward or pdActionFocusBackward to
cycle focus within your control (if your control has multiple focus). If
your control does not support focus, or the focus request results
in focus moving beyond your supported range, return pdActionFocusOff in
the focus parameter. Otherwise, return the focus that you set.
Controls which have no focus would always set focus to be pdActionFocusOff.
Controls with a single focus would set pdActionFocusFirst when
requested to set either pdActionFocusFirst or pdActionFocusLast,
and would set pdActionFocusOff for
either pdActionFocusForward or pdActionFocusBackward.
enum { pdActionFocusOff = 0, /* no focus */ pdActionFocusFirst = 1, /* focus on first element */ pdActionFocusLast = 2, /* focus on last element */ pdActionFocusForward = 3, /* focus on next element */ pdActionFocusBackward = 4 /* focus on previous element */ }; struct QTCustomControlSetFocusRecord { void * storage; /* storage for the control*/ long focus; /* focus to set, return resulting focus*/ }; typedef struct QTCustomControlSetFocusRecord QTCustomControlSetFocusRecord; typedef QTCustomControlSetFocusRecord * QTCustomControlSetFocusPtr;
pdActionCustomSetEditMenu To
Locate The Edit MenupdActionCustomSetEditMenu will
be called to inform your custom control of the location of the edit
menu.
If your control has editing boxes, this is useful in order to allow the user to perform cut, copy, and paste operations when focus is on one of these boxes.
struct QTCustomControlSetEditMenuRecord { |
void * storage; /* storage for the control*/ |
MenuHandle editMenu; /* edit menu, or NIL*/ |
}; |
typedef struct QTCustomControlSetEditMenuRecord QTCustomControlSetEditMenuRecord; |
typedef QTCustomControlSetEditMenuRecord * QTCustomControlSetEditMenuPtr; |
pdActionCustomSetPreviewPicture To
Preview InformationpdActionCustomSetPreviewPicture is
called to inform your custom control of preview information that
you may wish to use in the drawing of your user interface.
struct QTCustomControlSetPreviewPictureRecord { |
void * storage; /* storage for the control*/ |
QTParamPreviewPtr preview; /* preview to set*/ |
}; |
typedef struct QTCustomControlSetPreviewPictureRecord QTCustomControlSetPreviewPictureRecord; |
typedef QTCustomControlSetPreviewPictureRecord * QTCustomControlSetPreviewPicturePtr; |
pdActionCustomSetEditCallout tells
your control of the need by the application to be informed of changes
to the parameter values (typically for the purposes of updating
previews).
If a callout is available, your custom control should call it whenever a change has been made to the parameter(s) that your control is editing (as a result of user actions, most typically). If you choose not to implement this, live dragging or updating of values will not work.
struct QTCustomControlSetEditCalloutRecord { |
void * storage; /* storage for the control*/ |
QTParamPreviewCalloutPtr callout; /* requested callout, or NIL to |
disable*/ |
}; |
typedef struct QTCustomControlSetEditCalloutRecord QTCustomControlSetEditCalloutRecord; |
typedef QTCustomControlSetEditCalloutRecord * QTCustomControlSetEditCalloutPtr; |
pdActionCustomGetEnableValue to
Enable or Disable Other ControlspdActionCustomGetEnableValue allows
you to return a value for the purposes of enabling or disabling
other controls.
Most custom controls do not need to implement this call.
If your control is able to control the enabling and disabling of other parameter controls (such as is done by standard pop up or enumerated type controls), you need to supply a value that can be use for greater than or less than types of comparisons.
struct QTCustomControlGetEnableValueRecord { |
void * storage; /* storage for the control*/ |
long currentValue; /* value to compare against for enable/disable |
purposes*/ |
}; |
typedef struct QTCustomControlGetEnableValueRecord QTCustomControlGetEnableValueRecord; |
typedef QTCustomControlGetEnableValueRecord * QTCustomControlGetEnableValuePtr; |
pdActionCustomSetSampleTime to
Specify Duration and Start TimepdActionCustomSetSampleTime tells
your control information from the application about the duration
and start time for the sample being edited.
Most controls do not need this information, but some may choose to use it in the interface they present the user. However, this call need not be made by applications, so the custom control should be prepared to run when the sample time information is not available.
struct QTCustomControlSetSampleTimeRecord { |
void * storage; /* storage for the control*/ |
QTParamSampleTimePtr sampleTime; /* sample time information or NIL*/ |
}; |
typedef struct QTCustomControlSetSampleTimeRecord QTCustomControlSetSampleTimeRecord; |
typedef QTCustomControlSetSampleTimeRecord * QTCustomControlSetSampleTimePtr; |
pdActionCustomGetValue tells
your control to store any value(s) into the specified atom container.
All custom controls must implement this call.
struct QTCustomControlGetValueRecord { |
void * storage; /* storage for the control*/ |
QTAtomContainer sample; /* sample to store into*/ |
}; |
typedef struct QTCustomControlGetValueRecord QTCustomControlGetValueRecord; |
typedef QTCustomControlGetValueRecord * QTCustomControlGetValuePtr; |
pdActionCustomDoEditCommand to
Handle Edit CommandspdActionCustomDoEditCommand tells
your control to handle edit commands if it allow focus and type
in boxes.
All custom controls must implement this call if they support edit boxes.
struct QTCustomControlDoEditCommandRecord { |
void * storage; /* storage for the control*/ |
long command; /* command to execute, return 0 here if processed*/ |
}; |
typedef struct QTCustomControlDoEditCommandRecord QTCustomControlDoEditCommandRecord; |
typedef QTCustomControlDoEditCommandRecord * QTCustomControlDoEditCommandPtr; |
typedef long QTParameterDialog; |
enum { |
elOptionsIncludeNoneInList = 0x00000001 /* "None" effect is included |
in list */ |
}; |
typedef long QTEffectListOptions; |
enum { |
pdOptionsCollectOneValue = 0x00000001, /* should collect a single |
value only*/ |
pdOptionsAllowOptionalInterpolations = 0x00000002, /* non-novice |
interpolation options are shown */ |
pdOptionsModalDialogBox = 0x00000004, /* dialog box should be modal */ |
pdOptionsEditCurrentEffectOnly = 0x00000008, /* List of effects will not |
be shown */ |
pdOptionsHidePreview = 0x00000010 /* Preview item will not be shown */ |
enum { |
effectIsRealtime = 0 /* effect can be rendered in real time */ |
}; |
The following is a new API introduced in QuickTime 6.
Provides for more advanced filtering of effects to be placed into the effect list.
QTGetEffectsListExtended (QTAtomContainer * list, long minSources, long maxSources, QTEffectListOptions getOptions, OSType majorClass, OSType minorClass, QTEffectListFilterUPP filterProc, void * filterRefCon);
The effect list returned here.
The minimum number of sources that an effect must have to be added to the list. Pass –1 as this parameter to specify no minimum.
The maximum number of sources that an effect
can have to be added to the list. Pass –1 as this parameter to
specify no maximum. The minSources and maxSources parameters
allow you to restrict which effects are returned in the list, by
specifying the minimum and maximum number of sources that qualifying
effects can have.
The options for populating the list.
The major class to include, 0 for all.
The minor class to include, 0 for all.
Additional client filtering.
A reference constant for the filter proc.
This routine provides for more advanced filtering of effects to be placed into the effect list. Applications can filter on:
the number of input sources
effect major or minor class
custom filtering through a callback
The callback is called for each effect which passes the other
criteria for inclusion. If the callback returns a TRUE result,
the effect is included in the list.
Note that your filter proc may receive multiple effects from
various manufacturers. If you return TRUE for
multiple effects of a given type, only the one with the higher parameter version
number will be included.
If you wish other filtering such as effects from a given manufacturer,
you can do this by returning FALSE for
the other effects and TRUE for
those that you prefer.
typedef CALLBACK_API( Boolean, QTEffectListFilterProcPtr )(Component |
effect, long effectMinSource, long effectMaxSource, OSType majorClass, OSType minorClass, void *refcon); |
typedef STACK_UPP_TYPE(QTEffectListFilterProcPtr) QTEffectListFilterUPP; |
Introduced in QuickTime 6.
QTGetEffectsList,
which returns a QT atom container holding a list of the currently
installed effects components.
Movies.h
C interface file: Movies.h
With an ever-increasing number of effect components, it has become difficult for applications and users to navigate through the list. This section documents upcoming atoms that can be used for tagging effects into useful categories.
This will be of use to developers of applications that supply custom effect picking UI. It will also be of use for developers of effect components. Two groupings for effects are here defined: Major Class and Minor Class.
The Major Class for an effect defines the purpose of an effect
to allow applications to perform better filtering. It is not intended
that the user see effects grouped by major class. For example, a
two source effect might be given a major class of kTransitionMajorClass,
which allows applications to tell the difference between two source
effects that perform a transition vs. those that perform operations
such as Chroma Key. Some applications may wish to exclude all effects
that are not transitions.
Effects supply information about their Major Class through the use of an atom that can be found within their Effect Parameter Description atom container. Applications can read in this atom to determine the Major Class of a particular Effect.
#define kEffectMajorClassType 'clsa' |
#define kEffectMajorClassID (1) |
The following are the defined legal values for the Major Class
atom. Effects that fail to include a kEffectMajorClassType will
be classified as kMiscMajorClass.
Developers who feel their effect requires a new Major Class should
contact Apple. Because Major Classes are used for filtering by applications,
any extensions will need to be documented before they can become
useful.
#define kGeneratorMajorClass 'genr' // zero source effects |
#define kFilterMajorClass 'filt' // one source effects |
#define kTransitionMajorClass 'tran' // multisource morph |
// effects |
#define kCompositorMajorClass 'comp' // multisource layer |
// effects |
#define kMiscMajorClass 'misc' // all other effects |
Like the Major Class, the Minor Class of an effect serves to group the effect into a more refined definition. Unlike the Major Class, however, the Minor Class is intended to be used for grouping for the purposes of User Interface presentation. It is not intended that the Minor Class should be used for limiting the list of effects that a user might see––that is the purpose of the Major Class.
Effects supply information about their Minor Class through the use of an atom that can be found within their Effect Parameter Description atom container. Applications can read in this atom to determine the Minor Class of a particular Effect.
#define kEffectMinorClassType 'clsi' |
#define kEffectMinorClassID (1) |
The following are Apple-defined values for the Minor Class
atom, along with the recommended name to be used for display purposes.
Effects that fail to include a kEffectMinorClassType will
be classified as kMiscMinorClass.
Effects are free to define their own Minor Classes, although Apple
recommends that standard values be used if at all possible.
#define kGeneratorMinorClass 'genr' // "Generators" |
#define kRenderMinorClass 'rend' // "Render" |
#define kFilterMinorClass 'filt' // "Filters" |
#define kArtisticMinorClass 'arts' // "Artistic |
#define kBlurMinorClass 'blur' // "Blur" |
#define kSharpenMinorClass 'shrp' // "Sharpen" |
#define kDistortMinorClass 'dist' // "Distort" |
#define kNoiseMinorClass 'nois' // "Noise" |
#define kAdjustmentMinorClass 'adst' // "Adjustments" |
#define kTransitionMinorClass 'tran' // "Transitions" |
#define kWipeMinorClass 'wipe' // "Wipes" |
#define k3DMinorClass 'pzre' // "3D Transitions" |
#define kCompositorMinorClass 'comp' // "Compositors" |
#define kEffectsMinorClass 'fxfx' // "Special Effects" |
#define kMiscMinorClass 'misc' // "Miscellaneous" |
Effects that don’t fit into the above listed groupings can supply another value for their Minor Class. However, it is likely that these effects will want to have a user visible name to go along with their class. The name is supplied by another atom, which should contain a Pascal string that is the name of the minor class. If the minor class is one which already has a standard name, this atom will be ignored.
#define kEffectMinorClassNameType 'clsn' |
#define kEffectMinorClassNameID (1) |
Some effects with complex parameters would like to provide the user with groups of useful parameter values that can be easily selected. This section documents an optional mechanism that can be used by effects to define these “presets.” Applications may also use these presets to present to the user a list of selectable effect parameters.
Like most options within effects, the presets are defined
through the use of atoms present within the Effect Parameter Description
atom container. Effects may define any number of presets, with the
atom type being kEffectPresetType and
the ID being numbers from 1 to N (where N is the number of presets).
Within each preset, three child atoms are found:
#define kPresetNameType 'pnam' |
#define kPresetNameID (1) |
#define kPresetPreviewPictureType 'ppct' |
#define kPresetPreviewPictureID (1) |
#define kPresetSettingsType 'psst' |
#define kPresetSettingsID (1) |
The preset name defines the name of the preset as a Pascal string. The preset preview picture defines the image to be displayed to the user as a picture with a minimum size of 86 by 64 pixels. The preset settings atom contains within it all of the parameter values that define a particular preset.
'atms' ResourceThis example shows the presets present in the Slide effect
that define a Top and Bottom directed slide. The example is a portion
of the 'atms' resource
and demonstrates how to define these presets through the use of
Rez.
// atom type ID Child count |
kEffectPresetType, 1, 3, |
{ |
}; |
kPresetNameType, kPresetNameID, noChildren, |
{ |
string { "Top" }; |
}; |
kPresetPreviewPictureType, kPresetPreviewPictureID, noChildren, |
{ |
lstring { |
$"08A0 0000 0000 0040 0056 0011 02FF 0C00" |
/* MORE PICTURE DATA HERE */ |
$"7FE0 03AB 7FE0 03AB 7FE0 03AB 7FE0 00FF" |
}; |
}; |
kPresetSettingsType, kPresetSettingsID, 2, |
{ |
}; |
'pcnt', 1, 2, |
{ |
}; |
'twnt', 1, noChildren, |
{ |
kParameterTypeDataFixed; |
}; |
'data', 1, noChildren, |
{ |
long { "0" }; |
long { "65536" }; |
}; |
'angl', 1, noChildren, |
{ |
Fixed { "0.0" }; |
}; |
// atom type ID Child count |
kEffectPresetType, 2, 3, |
{ |
}; |
kPresetNameType, kPresetNameID, noChildren, |
{ |
string { "Bottom" }; |
}; |
kPresetPreviewPictureType, kPresetPreviewPictureID, noChildren, |
{ |
lstring { |
$"083C 0000 0000 0040 0056 0011 02FF 0C00" |
/* MORE PICTURE DATA HERE */ |
$"0277 BF42 1F08 5FE8 001F 00FF" |
}; |
}; |
kPresetSettingsType, kPresetSettingsID, 2, |
{ |
}; |
'pcnt', 1, 2, |
{ |
}; |
'twnt', 1, noChildren, |
{ |
kParameterTypeDataFixed; |
}; |
'data', 1, noChildren, |
{ |
long { "0" }; |
long { "65536" }; |
}; |
'angl', 1, noChildren, |
{ |
Fixed { "180.0" }; |
}; |
QuickTime 6 includes an improved None codec (also known as the Raw codec because it deals with manipulations of uncompressed pixels). The new version provides the following enhancements:
improved quality
increased speed
greater robustness
significantly decreased memory usage, with little increase in code size.
In QuickTime 5.0.x and before, the None codec would always use point sampling. The new version uses point sampling in the fastest, lowest-quality mode, bilinear interpolation in a slower, medium-quality mode, and bicubic anti-aliasing in the slowest, highest-quality mode.
The enhanced None codec introduces two new quality levels beyond the point-sampling quality provided in the previous None codec:
bilinear interpolation
bicubic anti-aliasing
This quality is especially apparent in
(1) rotation,
(2) perspective,
(3) image size reduction, and
(4) image size zooming.
Bilinear interpolation is available with codecHighQuality.
codecMaxQuality yields
either bicubic anti-aliasing or bicubic interpolation, depending
on the complexity of the transformation: anti-aliasing is currently
only available with pure scaling operations, not rotation or perspective.
The anti-aliasing is designed to meet or exceed the quality produced
by Adobe PhotoShop. When specifying codecNormalQuality, point-sampling
is used.
When doing minor size changes or phase changes, there is little apparent difference in quality between bilinear and bicubic interpolation: the primary difference is in sharpness and contrast. This is especially noticeable after multiple generations of processing, where bilinear processing will lose sharpness and contrast, whereas bicubic interpolation tends to preserve it.
When zooming up by a factor of 4 or more, bilinear interpolation suffers from “stellation”: where stars are superimposed on the pixels. Bicubic interpolation yields more natural, rounded, smooth features without artifacts.
When decimating an image (that is, reducing its size), bicubic anti-aliasing produces the best possible quality. Bilinear interpolation can yield acceptable quality if only shrinking a small amount, but decimation by greater than a factor of 2 will cause aliasing, which is manifested as jaggies, disappearing detail, and “popping pixels.”
As expected, higher quality comes at a price. With point-sampling (codecNormalQuality) taking 1 T seconds, the others take approximately:
1 T: codecNormalQuality = point-sampling
3 T: codecHighQuality = bilinear interpolation
10 T: codecMaxQuality = bicubic interpolation or anti-aliasing
Using a higher quality may have a negative effect on frame
rate, especially on older machines. Typically, codecMaxQuality is
to be used for off-line, non-real-time applications, whereas codecHighQuality can
be used successfully for real-time applications on faster machines.
You might want to check the frame rate and throttle the quality
as appropriate. Even faster machines can benefit from this throttling,
because their frame rate can suffer on higher resolution images.
The new enhanced None codec is a complete implementation of its component interface. Complete implementation is defined as:
11 pixel formats for the source
11 pixel formats for the destination
8 transfer modes
3 quality levels
full 3x3 matrix transformations, including rotation and perspective
Pixel formats:
8 bit color mapped
8 bit grayscale
16 bit BE555
16 bit LE555*
16 bit LE565*
24 bit RGB
24 bit BGR*
32 bit ARGB
32 bit ABGR*
32 bit BGRA*
32 bit RGBA*
(Note that formats flagged with an asterisk (*) are only available on Windows).
Transfer modes:
Copy
Dither Copy
Transparent (chroma-key)
Blend
Straight alpha
Alpha premultiplied to black
Alpha premultiplied to white
Straight alpha blend
Alpha-premultiplied-to-black is the fastest of the alpha compositing modes. For example, it is possible to transform a 32 bit ARGB PixMap by a 3x3 perspective transformation, interpolating it with bicubic interpolation, and alpha-compositing it to an 8-bit color-mapped PixMap––directly––one-pass.
More pixel formats (1, 2 and 4 bits) are supported, but in a less than desirable way, by relying on CopyBits and multiple instantiations of the enhanced None codec. Other transfer modes (for example, XOR) are feebly supported in the same manner.
Alpha is a first class component of 32 bit pixels. The previous None codec sometimes behaved badly with the alpha component, but the enhanced None codec preserves it and involves it in computations. The result of an alpha composition has a meaningful alpha component, which can then be used as a source for a subsequent alpha composition; using this, rendering can be optimized by caching partial composites of the static portions of scenes, requiring only the dynamic portions to be composited individually. From an architectural viewpoint, these alpha operations lend themselves then to a composition tree or DAG (directed acyclic graph), rather than a simple composition pipeline as limited in the previous None codec. This comes at no additional computational cost.
The enhanced None codec in QuickTime 6 is typically invoked using:
MakeImageDescriptionForPixMap()
DecompressSequenceBegin()
SetDSequenceTransferMode()
DecompressSequenceFrameS()
CDSequenceEnd()
and other calls.
Unlike the previous None codec, there is a negligible penalty for startup, and matrix changes. In particular, the matrix can be changed every frame with no degradation of the frame rate. Thus, it can be used for immersive imaging applications, where a series of images are embedded in 3D.
For more information, see Ice Floe Note #23 at
http://developer.apple.com/quicktime/icefloe/dispatch023.html |
The new enhanced None codec can be used as a general texture-mapped rendering and compositing engine, when accessed directly through the API. However, it is also invoked automatically by the Image Compression Manager (ICM) to assist other codecs, by the Sprite Media to implement animation, and by others.
The JPEG and TIFF graphics exporters should be able to create Exif files containing application-specified metadata and thumbnail images. QuickTime for Mac OS X (10.1) provided this support, which is now also available in Mac OS 9 and Windows.
Several graphics importers support access to individual images
within a multiple-image file. By using the GraphicsImportGetImageCount and GraphicsImportSetImageIndex routines,
you can select an individual layer from a Photoshop file, or an
individual resolution from a multi-resolution FlashPix file, for
example. However, there has not been a way to distinguish between
different types of indexed images: thumbnail, layer, page, resolution, etc.
Although applications can sometimes use the file type to suggest
the interpretation, this inhibits them from being able to take full
advantage of new third-party graphics importers. Furthermore, some
formats, such as TIFF, can support a variety of indexed image types.
The user data type kQTIndexedImageType has
now been defined for graphics importers to indicate what a particular
indexed image is. The following sample code shows how to determine
whether the second image in a file is a thumbnail.
Boolean IsSecondImageThumbnail( GraphicsImportComponent gi ) |
{ |
OSErr err; |
unsigned long saveIndex = 1; |
UserData userData = nil; |
Handle h = nil; |
Boolean isThumbnail = false; |
long count, i; |
GraphicsImportGetImageIndex( gi, &saveIndex ); |
err = GraphicsImportSetImageIndex( gi, 2 ); |
if( err ) goto bail; |
err = NewUserData( &userData ); |
if( err ) goto bail; |
err = GraphicsImportGetMetaData( gi, userData ); |
if( err ) goto bail; |
h = NewHandle( 0 ); |
err = MemError(); |
if( err ) goto bail; |
err = GetUserData( userData, h, kQTIndexedImageType, 1 ); |
if( err ) goto bail; |
// Is kQTIndexedImageIsThumbnail present in the list? |
count = GetHandleSize( h ) / sizeof( OSType ); |
for( i = 0; i < count; i++ ) { |
if( EndianU32_NtoB(kQTIndexedImageIsThumbnail) == ((OSType *)*h)[ i ] ) { |
isThumbnail = true; |
break; |
} |
} |
bail: |
if( userData ) DisposeUserData( userData ); |
if( h ) DisposeHandle( h ); |
GraphicsImportSetImageIndex( gi, saveIndex ); |
return isThumbnail; |
} |
The user data type kQTAlphaMode has
been defined to allow graphics importers to indicate the recommended
interpretation of an image’s alpha channel, if known. For example,
a graphics importer could indicate that the image data has been
premultiplied with the alpha channel against a black background
by reporting a metadata item of type kQTAlphaMode and
value graphicsModePreBlackAlpha.
If the image data has not been premultiplied, it would report graphicsModeStraightAlpha.
Image Data |
User Data Type |
|---|---|
Not premultiplied |
|
Premultiplied with alpha channel against black background |
|
Premultiplied with alpha channel against white background |
|
Premultiplied with alpha channel against other color |
|
The depth value of 32 in an image description indicates the presence of an alpha channel.
The TIFF graphics importer can extract metadata from a variety of TIFF tags for which QuickTime does not have standard user data type codes. Rather than define an individual code for each TIFF tag imported in this way, the graphics importer constructs user data type codes from the TIFF tags by adding the TIFF tag values (which are unsigned 2-byte integers) to defined prefix values (which fill in the two most significant bytes).
The following fields in the main TIFF directory are translated to standard QuickTime user data types:
TIFF Field |
User Data Type |
|---|---|
DocumentName |
|
ImageDescription |
|
Make |
|
Model |
|
Software |
|
DateTime |
|
Artist |
|
HostComputer |
|
Copyright |
|
IPTC (0x8469) |
|
The following fields in the main TIFF directory are translated
to user data using the prefix value kQTTIFFUserDataPrefix:
Orientation (0x0112)
TransferFunction (0x012D)
WhitePoint (0x013E)
PrimaryChromaticities (0x013F)
ColorMap (0x0140)
TransferRange (0x0156)
YCbCrCoefficients (0x0211)
YCbCrPositioning (0x0213)
ReferenceBlackWhite (0x0214)
ModelPixelScale (0x830E)
ModelTransformation (0x85D8)
ModelTiepoint (0x8482)
GeoKeyDirectory (0x87AF)
GeoDoubleParams (0x87B0)
GeoAsciiParams (0x87B1)
IntergraphMatrix (0x8480)
In Exif TIFF files, all fields in the Exif directory are translated
to user data using the prefix value kQTTIFFExifUserDataPrefix.
All fields in a GPS directory are translated to user data using the
prefix value kQTTIFFExifGPSUserDataPrefix.
The TIFF graphics exporter also supports storing the following user data types in exported TIFF files:
User Data Type TIFF Field
kUserDataTextFullName
DocumentName
kUserDataTextInformation
ImageDescription
kUserDataTextMake
Make
kUserDataTextModel Model
kUserDataTextArtist
Artist
kUserDataTextCopyright
Copyright
Software, DateTime, and HostComputer are written automatically.
In Exif mode, the TIFF graphics exporter will also write tags
defined in the Exif version 2.1 specification by reversing the kQTTIFFExifUserDataPrefix and kQTTIFFExifGPSUserDataPrefix mappings.
In Exif mode, the JPEG graphics exporter supports all the same metadata fields as the TIFF graphics exporter.
Note that UserData item data is always stored big-endian. The TIFF graphics importer and graphics exporter perform whatever translation is necessary.
The following are a group of new APIs available on Mac OS X, Mac OS 9, and Windows for creating Exif files.
Sets whether or not the graphics exporter component should create Exif files.
ComponentResult GraphicsExportSetExifEnabled (GraphicsExportComponent ci, Boolean enableExif );
The component instance that identifies your connection to the graphics exporter component.
Indicates whether to turn Exif export on or off.
Turning on Exif export disables incompatible settings, such
as grayscale JPEG and compressed TIFF, and enables export of Exif
metadata. Use the GraphicsExportSetMetaData routine
to supply Exif metadata.
This routine is only supported by the TIFF and JPEG graphics exporters.
ImageCompression.h
Returns the current Exif export setting.
ComponentResult GraphicsExportGetExifEnabled ( GraphicsExportComponent ci, Boolean * exifEnabled );
The component instance that identifies your connection to the graphics exporter component.
Points to a variable to receive the current Exif export setting.
This routine is only supported by the TIFF and JPEG graphics exporters.
ImageCompression.h
Sets whether or not the graphics exporter component should create an embedded thumbnail inside the exported file.
ComponentResult GraphicsExportSetThumbnailEnabled ( GraphicsExportComponent ci, Boolean enableThumbnail, long maxThumbnailWidth, long maxThumbnailHeight );
The component instance that identifies your connection to the graphics exporter component.
Indicates whether thumbnail creation should be turned on or off.
The maximum width for created thumbnails.
The maximum height for created thumbnails. If one maximum dimension is zero, only the other will be used. If both maximum dimensions are 0, the graphics exporter will decide for itself.
This routine also sets optional maximum dimensions for the thumbnail. The graphics exporter will not change the aspect ratio of the image when creating the thumbnail; nor will it create a thumbnail larger than the image.
This routine is currently only supported by the TIFF and JPEG graphics exporters. The JPEG graphics exporter can only create thumbnails when writing Exif files.
ImageCompression.h
Returns the current thumbnail export settings.
ComponentResult GraphicsExportGetThumbnailEnabled ( GraphicsExportComponent ci, Boolean * thumbnailEnabled, long * maxThumbnailWidth, long * maxThumbnailHeight );
The component instance that identifies your connection to the graphics exporter component.
Points to a variable to receive the current thumbnail setting. Pass NULL if you do not want to receive this information.
Points to a variable to receive the current maximum thumbnail width. Pass NULL if you do not want to receive this information.
Points to a variable to receive the current maximum thumbnail height. Pass NULL if you do not want to receive this information.
This routine is currently only supported by the TIFF and JPEG graphics exporters.
ImageCompression.h
QuickTime 6 enhances the ability of third-party developers to add new types of data references through the introduction of QuickTime data handler components. These are called custom data handlers.
QuickTime has always had two ways to reference storage of media data.
The first is through Mac OS-style file specification records known as FSSpec records. These FSSpec records are used by the Mac OS toolbox to reference files on disk and can describe any file in the file system.
The other type of storage reference is through a QuickTime abstraction known as a data reference. Data references are handles to blocks of data describing the location of data to be either read or written. The type of reference is described by a 4 char code (an OSType) and is used to select the QuickTime component––a data handler component––that performs the actual I/O operations.
The currently defined data handler types available with QuickTime are the following:
rAliasType
= FOUR_CHAR_CODE(‘alis’)
URLDataHandlerSubType = FOUR_CHAR_CODE('url
')
HandleDataHandlerSubType = FOUR_CHAR_CODE('hndl')
PointerDataHandlerSubType = FOUR_CHAR_CODE('ptr
')
ResourceDataHandlerSubType = FOUR_CHAR_CODE('rsrc')
NullDataHandlerSubType = FOUR_CHAR_CODE('null')
Note: The rAliasType data
reference type manages access to files. The reference itself is
an Alias handle and can describe any file describable by a FSSpec record.
Although the QuickTime software architecture provides rich support for both FSSpecs and data references, some APIs have not supported data references as fully as possible. This has meant that certain operations could only be performed on files described by FSSpec records. These operations, then, could not be performed with data handler components, either those provided by QuickTime or those that were custom.
This section discusses a group of new APIs in Movies.h that
accept a data reference where an older call accepted an FSSpec or
a data handler where a file reference.
The goal is twofold: (1) to support the writing of custom data handlers, and (2) to ensure that data references can be used wherever a File Manager API might have only existed before.
Table 1-3 describes the mapping of old calls to new calls:
Old Calls |
New Calls |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Writes a movie in a given file managed by the data handler.
OSErr PutMovieIntoStorage ( Movie theMovie, DataHandler dh, const wide *offset, unsigned long maxSize );
A movie identifier. Your application obtains
this identifier from such functions as NewMovie (II–1098), NewMovieFromFile (II–1110),
and NewMovieFromHandle (II–1113).
A data handler for the data fork of the given
storage. You pass in an open write path in the dh parameter.
A pointer to a value that indicates where the movie should be written.
The largest number of bytes that may be written.
You can access Movie
Toolbox error returns through GetMoviesError (I–505) and GetMoviesStickyError (I–506),
as well as in the function result. See “Error Codes” (IV–2718).
If you are writing a custom data handler, make sure that the following data handler APIs are implemented:
DataHGetDataRef
DataHWrite64
DataHWrite, if
not support 64-bit offsets
Introduced in QuickTime 6.
Movies.h
C interface file: Movies.h
Creates an empty storage to hold the movie which references the data reference, and opens a data handler to the movie file with write permission.
CreateMovieStorage (Handle dataRef, OSType dataRefType, OSType creator, ScriptCode scriptTag, long createMovieFileFlags, DataHandler * outDataHandler, Movie * newmovie);
A data reference to the storage for the movie file to be created.
The type of data reference.
The creator value for the new file.
The script in which the movie file should
be created. Use the Script Manager constant smSystemScript to
use the system script; use the smCurrentScript constant to
use the current script.
Controls movie file creation flags (see below).
Indicates whether to delete an existing file.
If you set this flag to 1, the Movie Toolbox deletes the file (if
it exists) before creating the new movie file. If you set this flag
to 0 and the file specified by the dataRef parameter
already exists, the Movie Toolbox uses the existing file.
Controls whether CreateMovieStorage creates
a new movie in the movie file. If you set this flag to 1, the Movie
Toolbox does not create a movie in the new movie file. In this case,
the function ignores the newmovie parameter.
If you set this flag to 0, the Movie Toolbox creates a movie and
returns the movie identifier in the field referred to by the newmovie parameter.
Controls whether CreateMovieStorage opens
the new movie file. If you set this flag to 1, the Movie Toolbox
does not open the new movie file. In this case, the function ignores
the outDataHandler parameter. If you set this flag to 0, the Movie
Toolbox opens the new movie file and returns an instance of a data
handler in the outDataHandler parameter.
Controls whether the new movie is active. Set
this flag to 1 to make the new movie active. A movie that does not
have any tracks can still be active. When the Movie Toolbox tries
to play the movie, no images are displayed, because there is no movie
data. You can make a movie active or inactive by calling SetMovieActive (III–1654).
Controls whether the Movie Toolbox automatically selects enabled tracks from alternate track groups. If you set this flag to 1, the Movie Toolbox does not automatically select tracks for the movie; you must enable tracks yourself.
A pointer to a field that is to receive the data handler for the opened movie file. Your application must use this value when calling other Movie Toolbox functions that work with movie files. If you set this parameter to NIL, the Movie Toolbox creates the movie file but does not open the file.
A pointer to a field that is to receive the
identifier of the new movie. CreateMovieStorage returns
the identifier of the new movie. If the function could not create
a new movie, it sets this returned value to NIL. If you set this parameter
to NIL, the Movie Toolbox does not create a movie.
You can
access Movie Toolbox error returns through GetMoviesError (I–505) and GetMoviesStickyError (I–506),
as well as in the function result. See “Error Codes” (IV–2718).
If you are writing a custom data handler, make sure that the following data handler APIs are implemented:
DataHGetDataRef
DataHWrite64
DataHWrite, if
not support 64-bit offsets
DataHDeleteFile,
if createMovieFileDeleteCurFile is
passed
DataHCreateFileWithFlags or DataHCreateFile
DataHOpenForRead/DataHOpenForWrite
The data hanlder must support both kDataHCanRead and kDataHCanWrite.
Introduced in QuickTime 6.
Movies.h
C interface file: Movies.h
Opens a data handler that specifies movie storage.
OpenMovieStorage (Handle dataRef, OSType dataRefType, long flags, DataHandler * outDataHandler);
A data reference to a handle for the movie to be stored.
The type of data reference.
(See
below.)
A pointer to a field that is to receive the data handler for the opened movie file. Your application must use this value when calling other Movie Toolbox functions that work with movie files.
Flags:
kDataHCanReadkDataHCanWriteThis routine is rarely used.
Introduced in QuickTime 6.
Movies.h
C interface file: Movies.h
Closes an open movie storage.
CloseMovieStorage (DataHandler dh);
A data handler.
This routine is equivalent to CloseComponent.
Introduced in QuickTime 6.
Movies.h
C interface file: Movies.h