This chapter describes the functions that are provided by sequence grabber components. These functions are described from the perspective of an application developer. If you are developing a sequence grabber component, your component must behave as described here.
Configuring Sequence Grabber Components
Controlling Sequence Grabber Components
Working With Sequence Grabber Characteristics
Working With Channel Characteristics
Working With Channel Devices
Previewing and Recording Captured Data
Playing Captured Data and Saving It in a QuickTime Movie
Application-Defined Functions
Data Types
Sequence grabber components provide a number of functions that allow you to establish the environment for grabbing or previewing digitized data. Before you can start a record or a preview operation, you must initialize the sequence grabber component, establish the channels that will be used, define the display environment for the operation, and determine the optimum screen position for the sequence grabber. In addition, if you are performing a record operation, you must define a destination movie file. The following sequence grabber component functions allow you to perform these tasks:
You can use the SGInitialize
function to initialize a sequence grabber component. Before you can call this function, you must establish a connection to the sequence grabber by calling the Component Manager’s OpenDefaultComponent
or OpenComponent
function.
The SGNewChannel
function allows you to create channels for the sequence grabber for an operation. You can use the SGNewChannelFromComponent
function to create a new channel using a specified channel component. Use the SGDisposeChannel
function to dispose of those channels that you are no longer using.
You can use the SGGetIndChannel
function to retrieve information about the channels that are currently in use by the sequence grabber.
You can use the SGSetGWorld
and SGGetGWorld
functions to establish the display environment for the sequence grabber. These functions affect only those channels that work with data that has visual information.
The SGSetDataOutput
and SGGetDataOutput
functions allow you to identify the movie file that is currently assigned to the sequence grabber. You only use these functions when you are performing a record operation.
The SGSetDataProc
function allows you to assign a data function to a channel. The sequence grabber calls your data function whenever it writes movie data to the output file.
The SGGetAlignmentProc
function allows you to determine a sequence grabber’s optimum screen position to ensure the best performance and appearance.
Sequence grabber components provide a full set of functions that allow your application to control the preview or record operation. You can use these functions to start and stop the operation, to pause data collection, and to retrieve a reference to the movie that is created during a record operation:
Use the SGStartPreview
function to start a preview operation. The SGStartRecord
function lets you start a record operation. The SGStop
function allows you to stop a sequence grabber component.
You can instruct the sequence grabber to pause by calling the SGPause
function. You can determine whether the sequence grabber is paused by calling the SGGetPause
function.
You grant processing time to the sequence grabber by calling the SGIdle
function. Be sure to call this function often during record and preview operations. If your application receives an update event during a record or preview operation, you should call the SGUpdate
function.
You can prepare the sequence grabber for an upcoming preview or record operation by calling the SGPrepare
function. This function also allows the sequence grabber to verify that it can support the parameters you have specified. By verifying the parameters you want to use, you can improve the startup of preview and record operations. Use the SGRelease
function to release system resources after calling the SGPrepare
function.
You can retrieve a reference to the movie created by a record operation by calling the SGGetMovie
function. You can determine the resource ID value assigned to the last movie resource created by the sequence grabber by calling the SGGetLastMovieResID
function.
You can extract a picture from the video source data by calling the SGGrabPict
function.
The characteristics that govern a sequence grabber operation fall into two main categories: those that apply to the sequence grabber component, and those that apply to an individual channel that has been created for the sequence grabber. Sequence grabber components provide a number of functions in each category. The following functions allow you to configure the characteristics of the sequence grabber component. See Working With Channel Characteristics for information about functions that apply to a single channel.
Use the SGSetMaximumRecordTime
function to limit the duration of a record operation. You can retrieve this time limit by calling the SGGetMaximumRecordTime
function.
The SGSetFlags
function allows you to set control flags that govern an operation. Use the SGGetFlags
function to retrieve those flags.
You can obtain information about the progress of a record operation by calling the SGGetStorageSpaceRemaining
and SGGetTimeRemaining
functions.
You can retrieve a reference to the time base used by a sequence grabber component by calling the SGGetTimeBase
function.
Sequence grabber components use channel components to obtain digitized data from external media. After you create a channel for a sequence grabber component (by calling the SGNewChannel
function), you must configure that channel before you start a preview or record operation. The sequence grabber component provides a number of functions that allow you to configure the characteristics of a channel component. Several of these functions work on any channel component. This section discusses these general channel configuration functions.
In addition, sequence grabber components provide functions that are specific to the channel type. Apple currently provides three types of channel components: video channel components, sound channel components, and text channel components. See Working With Video Channels for information about the sequence grabber configuration functions that work only with video channels. See Working With Sound Channels for information about the sequence grabber configuration functions that work only with sound channels. For information about text channels, see Text Channel Components.
Here are the principal functions that help you work with sequence grabber channel charateristics:
Use the SGSetChannelUsage
function to specify how a channel is to be used. You can restrict a channel to use during record or preview operations. In addition, this function allows you to specify whether a channel plays during a record operation. The SGGetChannelUsage
function enables you to determine a channel’s usage.
The SGGetChannelInfo
function allows you to determine whether a channel has a visual or an audio representation.
The SGSetChannelPlayFlags
function allows you to influence the speed and quality with which the sequence grabber displays captured data. The SGGetChannelPlayFlags
function lets you determine these flag settings.
The SGSetChannelMaxFrames
function establishes a limit on the number of frames that the sequence grabber will capture from a channel. The SGGetChannelMaxFrames
function allows you to determine that limit.
The SGSetChannelBounds
function allows you to set the display boundary rectangle for a channel. Use the SGGetChannelBounds
function to determine a channel’s boundary rectangle.
The SGSetChannelVolume
function allows you to control a channel’s sound volume. Use the SGGetChannelVolume
function to determine a channel’s volume.
The SGSetChannelRefCon
function allows you to set the value of a reference constant that is passed to your callback functions (see Video Channel Callback Functions for information about the callback functions that are supported by video channels).
Use the SGGetChannelSampleDescription
function to retrieve a channel’s sample description. The SGGetChannelTimeScale
function allows you to obtain the channel’s time scale.
You can modify or retrieve the channel’s clipping region by calling the SGSetChannelClip
or SGGetChannelClip
function. You can work with a channel’s transformation matrix by calling the SGSetChannelMatrix
and SGGetChannelMatrix
functions.
Sequence grabbers provide a number of functions that allow you to determine the device that is attached to a given sequence grabber channel. These devices allow the channel component to control the digitizing equipment. For example, video channels use video digitizer components, and sound channels use sound input drivers. Your application can use these routines to present a list of available devices to the user, allowing the user to select a specific device for each channel.
You may use the SGGetChannelDeviceList
function to retrieve a list of devices that may be used with a specified channel. You dispose of this device list by calling the SGDisposeDeviceList
function. You can place one or more device names into a menu by calling the SGAppendDeviceListToMenu
function. You can use the SGSetChannelDevice
function to assign a device to a channel.
Some of these functions use a device list structure to pass information about one or more channel devices. The SGDeviceListRecord
data type defines the format of the device list structure.
typedef struct SGDeviceListRecord { |
short count; /* count of devices */ |
short selectedIndex; /* current device */ |
long reserved; /* set to 0 */ |
SGDeviceName entry[1]; /* device names */ |
} SGDeviceListRecord, *SGDeviceListPtr, **SGDeviceList; |
Field |
Description |
---|---|
|
Indicates the number of devices described by this structure. The value of this field corresponds to the number of entries in the device name array defined by the |
|
Identifies the currently active device. The value of this field corresponds to the appropriate entry in the device name array defined by the |
|
Reserved for Apple. Always set to 0. |
|
Contains an array of device name structures. Each structure corresponds to one valid device. The |
Device list structures contain an array of device name structures. Each device name structure identifies a single device that may be used by the channel. The SGDeviceName
data type defines the format of a device name structure.
typedef struct SGDeviceName { |
Str63 name; /* device name */ |
Handle icon; /* device icon */ |
long flags; /* flags */ |
long refCon; /* set to 0 */ |
long reserved; /* set to 0 */ |
} SGDeviceName; |
Field |
Description |
---|---|
|
Contains the name of the device. For video digitizer components, this field contains the component's name as specified in the component resource. For sound input drivers, this field contains the driver name. |
|
Contains a handle to the device's icon. Some devices may support an icon, which you may choose to present to the user. If the device does not support an icon, or if you choose not to retrieve this information (by setting the |
|
Reflects the current status of the device. The sequence grabber sets these flags when you retrieve a device list. The |
|
Reserved for Apple. Always set to 0. |
|
Reserved for Apple. Always set to 0. |
Sequence grabber components provide a number of functions that allow you to configure the grabber’s video channels. This section describes these configuration functions, which you can use only with video channels. You can determine whether a channel has a visual representation by calling the SGGetChannelInfo
function. If you want to configure a sound channel, use the functions described in Working With Sound Channels. If you want to configure general attributes of a channel, use the functions described in Working With Channel Characteristics.
The SGGetSrcVideoBounds
function allows you to determine the coordinates of the source video boundary rectangle. This rectangle defines the size of the source video image being captured by the video channel. You can use the SGSetVideoRect
function to specify a part of the source video boundary rectangle to be captured by the channel. The SGGetVideoRect
function allows you to determine the active source video rectangle.
Typically, the sequence grabber component uses the Image Compression Manager to compress the video data it captures. You can control many aspects of this image- compression process. Use the SGSetVideoCompressorType
function to specify the type of image compressor to use. You can determine the type of image compressor currently in use by calling the SGGetVideoCompressorType
function. You can specify a particular image compressor and set many image-compression parameters by calling the SGSetVideoCompressor
function. You can determine which image compressor is being used and its parameter settings by calling the SGGetVideoCompressor
function.
The channel components that supply video data to a sequence grabber component typically work with a video digitizer component. (See About Video Digitizer Components for a description of video digitizer components.)
Sequence grabber components provide functions that allow you to work with a channel’s video digitizer component. You can use the SGGetVideoDigitizerComponent
function to determine which video digitizer component is supplying data to a specified channel component. You can set a channel’s video digitizer by calling the SGSetVideoDigitizerComponent
function. If you change any video digitizer settings by calling the video digitizer component directly, you should inform the sequence grabber component by calling the SGVideoDigitizerChanged
function.
Some video source data may contain unacceptable levels of visual noise or artifacts. One technique for removing this noise is to capture the image and then reduce it in size. During the size reduction process, the noise can be filtered out. Sequence grabber components provide functions that allow you to filter the input video data. The SGSetCompressBuffer
function sets a filter buffer for a video channel. The SGGetCompressBuffer
function returns information about your filter buffer.
You can work with a video channel’s frame rate by calling the SGSetFrameRate
and SGGetFrameRate
functions. You can control whether a channel uses an offscreen buffer by calling the SGSetUseScreenBuffer
and SGGetUseScreenBuffer
functions.
Sequence grabber components provide a number of functions that allow you to configure the grabber’s sound channels. This section describes these configuration functions, which you can use only with sound channels. You can determine whether a channel has a sound representation by calling the SGGetChannelInfo
function. If you want to configure a video channel, use the functions described in Working With Video Channels. If you want to configure general attributes of a channel, use the functions described in Working With Channel Characteristics.
Use the SGSetSoundInputDriver
function to specify a channel’s sound input device. You can determine a channel’s sound input device by calling the SGGetSoundInputDriver
function. If you change any attributes of the sound input device, you should notify the sequence grabber component by calling the SGSoundInputDriverChanged
function. By default, the sequence grabber component uses the sound driver’s best settings.
You can control the amount of sound data the sequence grabber works with at one time by calling the SGSetSoundRecordChunkSize
function. You can determine this value by calling the SGGetSoundRecordChunkSize
function.
You can control the rate at which the sound channel samples the input data by calling the SGSetSoundInputRate
function. You can determine the sample rate by calling the SGGetSoundInputRate
function.
You can control other sound input parameters by using the SGSetSoundInputParameters
and SGGetSoundInputParameters
functions.
Sequence grabber components allow you to define a number of callback functions in your application. The sequence grabber calls your functions at specific points in the process of collecting, compressing, and displaying the source video data. By defining callback functions, you can control the process more precisely or customize the operation of the sequence grabber component.
For example, you could use a callback function to draw a frame number on each video frame as it is collected. You could use either a compress callback function or a grab-complete callback function to accomplish this. The compress callback function is called after each frame is collected, in order to compress the frame. The grab-complete callback function is called just before the compress callback function, as soon as the frame has been captured.
The SGSetVideoBottlenecks
function lets you assign callback functions to a video channel. You can use the SGGetVideoBottlenecks
function to determine the callback functions that have been assigned to a video channel.
The SGSetVideoBottlenecks
function accepts a video bottlenecks structure that identifies the callback functions to be assigned to the channel. In addition, the SGGetVideoBottlenecks
function contains a pointer to this structure.
The video bottlenecks structure is defined by the VideoBottles
data type as follows:
struct VideoBottles { |
short procCount; |
GrabProc grabProc; |
GrabCompleteProc grabCompleteProc; |
DisplayProc displayProc; |
CompressProc compressProc; |
CompressCompleteProc compressCompleteProc; |
AddFrameProc addFrameProc; |
TransferFrameProc transferFrameProc; |
GrabCompressCompleteProc grabCompressCompleteProc; |
DisplayCompressProc displayCompressProc; |
}; |
typedef struct VideoBottles VideoBottles; |
Field |
Description |
---|---|
|
Specifies the number of callback functions that may be identified in the structure. Set this field to 9. |
|
Identifies the grab function. If you are setting a grab function, set this field so that it points to the function's entry point. If you are not setting a grab function, set this field to |
|
Identifies the grab-complete function. If you are setting a grab-complete function, set this field so that it points to the function's entry point. If you are not setting a grab-complete function, set this field to |
|
Identifies the display function. If you are setting a display function, set this field so that it points to the function's entry point. If you are not setting a display function, set this field to |
|
Identifies the compress function. If you are setting a compress function, set this field so that it points to the function's entry point. If you are not setting a compress function, set this field to |
|
Identifies the compress-complete function. If you are setting a compress-complete function, set this field so that it points to the function's entry point. If you are not setting a compress-complete function, set this field to |
|
Identifies the add-frame function. If you are setting an add-frame function, set this field so that it points to the function's entry point. If you are not setting an add-frame function, set this field to |
|
Identifies the transfer-frame function. If you are setting a transfer-frame function, set this field so that it points to the function's entry point. If you are not setting a transfer-frame function, set this field to |
|
Identifies the grab-compress-complete function. If you are setting a grab-compress-complete function, set this field so that it points to the function's entry point. If you are not setting a grab-compress-complete function, set this field to |
|
Identifies the display-compress function. If you are setting a display-compress function, set this field so that it points to the function's entry point. If you are not setting a display-compress function, set this field to |
The callback functions listed above are described in Application-Defined Functions.
For information about utility functions that you can use with video channel callback functions, see Utility Functions for Sequence Grabber Channel Components.
You can use sequence grabber components in two ways: to play digitized data for the user or to save captured data in a QuickTime movie. The process of displaying data that is to be captured is called previewing; saving captured data in a movie is called recording. You can use previewing to allow the user to prepare to make a recording. If you do so, your application can move directly from the preview operation to a record operation, without stopping the process.
Previewing captured data involves playing that data for the user as it is captured. For video data, this means displaying the video images on the computer screen. For audio data, this means playing the sound through the computer’s sound system.
Here are the steps you must follow to preview captured data:
First, you must open a connection to the sequence grabber component. Use the Component Manager’s OpenDefaultComponent
or OpenComponent
function.
Once you have a connection to a sequence grabber component, you must configure the component for the preview operation. Use the SGSetGWorld
function to set the graphics world in which the preview is to be displayed. Allocate the appropriate channels by calling the SGNewChannel
function. You must call this function once for each channel to be used by the sequence grabber component. Use the SGSetChannelUsage
function to specify that each channel is to be used for previewing. You can then use the appropriate channel configuration functions to prepare the channel for the preview operation. For video channels, use the functions discussed in Working With Video Channels. For sound channels, use the functions discussed in Working With Sound Channels.
You start the preview operation by calling the SGStartPreview
function. The sequence grabber component then begins collecting data from the channels that you have created and plays that data appropriately. You can pause and restart the preview by calling the SGPause
function. Use the SGStop
function to stop the preview. During the preview operation, be sure to call the SGIdle
function frequently, so that the sequence grabber and its channels can perform the operation.
When you are done previewing, you can start recording or close your connection to the sequence grabber component. When you close the sequence grabber component, it automatically disposes of the channels you created.
During a record operation, a sequence grabber component collects the data it captures and formats that data into a QuickTime movie. During a record operation, the sequence grabber can also play the captured data for the user. However, the sequence grabber tries to prevent the playback from interfering with the quality of the recording process.
Here are the steps you must follow to record captured data:
As with a preview operation, your application must establish a connection to a sequence grabber component. Use the Component Manager’s OpenDefaultComponent
or OpenComponent
function.
Once you have a connection to a sequence grabber component, you must configure the component for the record operation. Use the SGSetGWorld
function to set the graphics world in which the data is to be displayed. Allocate the appropriate channels by calling the SGNewChannel
function. You must call this function once for each channel to be used by the sequence grabber component. Use the SGSetChannelUsage
function to specify that each channel is to be used for recording. At this time, you can specify whether the sequence grabber is to play that channel’s data while recording. You can then use the appropriate channel configuration functions to prepare the channel for the record operation. For video channels, use the functions discussed in Working With Video Channels. For sound channels, use the functions discussed in Working With Sound Channels.
You must specify a movie file for use by the sequence grabber during the record operation. Use the SGSetDataOutput
function to specify this movie file. This function also allows you to control whether the sequence grabber adds the movie resource to the movie file and whether it replaces existing data or appends the new movie to the file.
You can limit the amount of data that is captured during a record operation. The SGSetMaximumRecordTime
function establishes a time limit for the record operation. The SGSetChannelMaxFrames
function limits the number of frames of data that the sequence grabber collects from a specific channel.
You start the record operation by calling the SGStartRecord
function. The sequence grabber component then begins collecting data from the channels you have created, stores the data in a QuickTime movie, and, optionally, plays that data appropriately. You can pause and restart the record process by calling the SGPause
function. During the record operation, be sure to call the SGIdle
function frequently, so that the sequence grabber and its channels can perform the operation. Use the SGStop
function to stop recording. At this time, the sequence grabber saves the movie in your movie file, if you have chosen to do so.
When you are done recording, you can go back to previewing or close your connection to the sequence grabber component. When you close the sequence grabber component, it automatically disposes of the channels you created as well as any movies it has created.
This section supplies a sample program that shows how to use a sequence grabber component to preview and record captured data. The program is divided into groups of functions that do the following tasks:
initialization
video and sound channel creation
sequence preview
capture of sound and video sequences
drawing over video frames during a capture operation
Listing 3-1 provides a sample function that creates and initializes a default sequence grabber component for a specified window (using the OpenDefaultComponent
and SGInitialize
functions, respectively). It then sets the graphics world of the sequence grabber component to the specified window with the SGSetGWorld
function. Note that the CloseComponent
function is called for housekeeping purposes in case the sequence grabber component fails.
Listing 3-1 Initializing a sequence grabber component
SeqGrabComponent MakeSequenceGrabber (WindowPtr aWindow) |
{ |
SeqGrabComponent anSG; |
OSErr err = noErr; |
/* open up the default sequence grabber */ |
anSG = OpenDefaultComponent (SeqGrabComponentType, 0); |
if (anSG) { |
/* initialize the default sequence grabber component */ |
err = SGInitialize (anSG); |
if (!err) { |
/* set the sequence grabber's graphics world to the |
specified window */ |
err = SGSetGWorld (anSG, (CGrafPtr) aWindow, nil); |
} |
} |
if (err && anSG) { |
/* clean up on failure */ |
CloseComponent (anSG); |
anSG = nil; |
} |
return anSG; |
} |
Listing 3-2 supplies a sample function that attempts to create a video channel and a sound channel for the sequence grabber component that was created in Listing 3-1. The boundaries of the video channel are set to the specifications of the bounds
parameter. The channel’s usage is always set to allow previewing. If the value of the willRecord
parameter is true
, then the usage of the channel is set to allow recording also.
The SGNewChannel
function uses the VideoMediaType
constant to create a video channel and the SoundMediaType
constant to create a sound channel. The SGSetChannelBounds
function specifies the boundaries of the video channel. The SGSetChannelUsage
function specifies whether the video and the sound channels are used for preview or record operations. The SGDisposeChannel
function cleans up upon failure for each of the channels.
Listing 3-2 Creating a sound channel and a video channel
void MakeGrabChannels (SeqGrabComponent anSG, |
SGChannel *videoChannel, |
SGChannel *soundChannel, |
const Rect *bounds, Boolean willRecord) |
{ |
OSErr err; |
long usage; |
/* figure out the usage */ |
usage = seqGrabPreview; /* always previewing */ |
if (willRecord) |
usage |= seqGrabRecord; /* sometimes recording */ |
/* create a video channel */ |
err = SGNewChannel (anSG, VideoMediaType, videoChannel); |
if (!err) { |
/* set boundaries for new video channel */ |
err = SGSetChannelBounds (*videoChannel, bounds); |
/* set usage for new video channel */ |
if (!err) |
err = SGSetChannelUsage (*videoChannel, |
usage | seqGrabPlayDuringRecord); |
if (err) { |
/* clean up on failure */ |
SGDisposeChannel (anSG, *videoChannel); |
*videoChannel = nil; |
} |
} |
/* create a sound channel */ |
err = SGNewChannel (anSG, SoundMediaType, soundChannel); |
if (!err) { |
/* set usage of new sound channel */ |
err = SGSetChannelUsage (*soundChannel, usage); |
if (err) { |
/* clean up on failure */ |
SGDisposeChannel(anSG, *soundChannel); |
*soundChannel = nil; |
} |
} |
} |
Listing 3-3 shows how to use the sequence grabber component to preview sound and video sequences in a window. Clicking the content area of the window causes the sequence grabber to pause until the mouse button is released.
The Image Compression Manager’s GetBestDeviceRect
function helps you determine the best monitor for the window. The SGStartPreview
function begins the preview of the sound and video sequences. The SGIdle
function grants the sequence grabber component the time it needs to preview data. The SGUpdate
function informs the sequence grabber of the update event. The Window Manager’s BeginUpdate
and EndUpdate
functions respond to the event. The SGPause
function instructs the sequence grabber to suspend and resume its preview operation. In this example, it is used to suspend the preview operation while the mouse button is held down. Finally, the SGStop
function halts the action of the sequence grabber component. The Component Manager’s CloseComponent
function closes the component connection. The Window Manager’s DisposeWindow
function disposes of the window.
Listing 3-3 Previewing sound and video sequences in a window
void CheckError(OSErr error, Str255 displayString) |
{ |
if (error == noErr) return; |
if (displayString[0] > 0) |
DebugStr(displayString); |
ExitToShell(); |
} |
Boolean IsQuickTimeInstalled (void) |
{ |
short error; |
long result; |
error = Gestalt (gestaltQuickTime, &result); |
return (error == noErr); |
} |
void initialize (void) |
{ |
OSErr err; |
InitGraf (&qd.thePort); |
InitFonts (); |
InitWindows (); |
InitMenus (); |
TEInit (); |
InitDialogs (nil); |
MaxApplZone(); |
if (!IsQuickTimeInstalled()) |
CheckError(-1,"\pPlease install QuickTime and try again"); |
err = EnterMovies (); |
CheckError(err,"\pUnable to initialize Movie Toolbox"); |
} |
WindowPtr makeWindow(void) |
{ |
WindowPtr aWindow; |
Rect windowRect = {0, 0, 120, 160}; |
Rect bestRect; |
/* figure out the best monitor for the window */ |
GetBestDeviceRect (nil, &bestRect); |
/* put the window in the top left corner of that monitor */ |
OffsetRect(&windowRect, bestRect.left + 10, bestRect.top + 50); |
/* create the window */ |
aWindow = NewCWindow (nil, &windowRect, "\pGrabber", |
true, noGrowDocProc, (WindowPtr)-1, |
true, 0); |
/* and set the port to the new window */ |
SetPort(aWindow); |
return aWindow; |
} |
main (void) |
{ |
WindowPtr theWindow; |
SeqGrabComponent theSG; |
SGChannel videoChannel, soundChannel; |
Boolean done = false; |
OSErr err; |
initialize(); |
theWindow = makeWindow(); |
theSG = makeSequenceGrabber(theWindow); |
if (!theSG) return; |
makeGrabChannels(theSG, &videoChannel, &soundChannel, |
&theWindow->portRect, false); |
if ((videoChannel == nil) && (soundChannel == nil)) |
CheckError(-1,"\pNo sound or video available"); |
err = SGStartPreview(theSG); |
CheckError(err, "\pCan't start preview"); |
while (!done) { |
AlignmentProcRecord alignProc; |
short part; |
WindowPtr whichWindow; |
EventRecord theEvent; |
GetNextEvent(everyEvent, &theEvent); |
switch (theEvent.what) { |
case nullEvent: /* give the sequence grabber time */ |
err = SGIdle (theSG); |
if (err) done = true; |
break; |
case updateEvt:if (theEvent.message == (long)theWindow) { |
/* inform the sequence grabber of the |
update */ |
SGUpdate(theSG,((WindowPeek) |
theWindow)->updateRgn); |
/* and swallow the update event */ |
BeginUpdate(theWindow); |
EndUpdate(theWindow); |
} |
break; |
case mouseDown:part = FindWindow (theEvent.where, |
&whichWindow); |
if (whichWindow != theWindow) break; |
switch (part) { |
case inContent: |
/* pause until mouse button is |
released */ |
SGPause (theSG, true); |
while (StillDown()) |
; |
SGPause(theSG, false); |
break; |
case inGoAway: |
done = TrackGoAway (theWindow, |
theEvent.where); |
break; |
case inDrag: |
/* pause when dragging window so video |
doesn't draw in the wrong place */ |
SGPause (theSG, true); |
SGGetAlignmentProc (theSG, &alignProc); |
DragAlignedWindow (theWindow, |
theEvent.where, |
&screenBits.bounds, |
nil, &alignProc); |
SGPause (theSG, false); |
break; |
} |
break; |
} |
} |
/* clean up */ |
SGStop (theSG); |
CloseComponent (theSG); |
DisposeWindow (theWindow); |
} |
Listing 3-4 uses the sequence grabber component to capture ten seconds of sound and video data. It prompts the user for the name of the file to create. The SGSettingsDialog
function is issued to invoke the default sound and video capture settings dialog boxes. These default dialog boxes allow the user to configure the settings for the capture operations. The SGSetMaximumRecordTime
function indicates how long the capture operations will last. The SGStartRecord
function specifies the time at which the capture operations will begin. The SGIdle
function grants the time needed to confirm the capture operations. Finally, the SGStop
function and the Window Manager’s DisposeWindow
routine are called in order to complete the capture of the sequences.
Listing 3-4 Capturing sound and video
main (void) |
{ |
WindowPtr theWindow; |
CGrafPort tempPort; |
SeqGrabComponent theSG; |
SGChannel videoChannel, soundChannel; |
OSErr err; |
initialize(); |
theWindow = makeWindow(); |
theSG = makeSequenceGrabber(theWindow); |
if (!theSG) return; |
err = setGrabFile(theSG); |
CheckError(err, "\pNo output file"); |
makeGrabChannels (theSG, &videoChannel, &soundChannel, |
&theWindow->portRect, true); |
if ((videoChannel == nil) && (soundChannel == nil)) |
CheckError(-1,"\pNo sound or video available"); |
if (videoChannel) |
SGSettingsDialog (theSG, videoChannel, 0, nil, |
DoTheRightThing, nil, 0); |
if (soundChannel) |
SGSettingsDialog(theSG, soundChannel, 0, nil, |
DoTheRightThing, nil, 0); |
err = SGSetMaximumRecordTime(theSG, 10 * 60); |
CheckError(err, "\pCan't set max record time"); |
err = SGStartRecord (theSG); |
CheckError(err, "\pCan't start record"); |
while (!err) |
err = SGIdle (theSG); |
if (err == grabTimeComplete) |
err = noErr; |
CheckError(err, "\pError while recording"); |
err = SGStop(theSG); |
CheckError(err, "\pError creating movie"); |
CloseComponent(theSG); |
DisposeWindow(theWindow); |
} |
Listing 3-5 shows how to set up the video bottleneck functions of the sequence grabber video channel component. Inside the main event loop in Listing 3-4, you should add the following lines after you call the SGSetMaximumRecordTime
function.
Listing 3-5 Setting up the video bottleneck functions
if (videoChannel) { |
err = SGSetVideoBottlenecks (videoChannel, &tempPort); |
CheckError(err, "\pCouldn't set video bottlenecks"); |
} |
Listing 3-6 shows how to use the video bottleneck functions of the sequence grabber video channel component to draw the letters “QT” over each video frame as it is captured.
Listing 3-6 Drawing information over video frames during capture
pascal ComponentResult myGrabFrameComplete (SGChannel c, |
short bufferNum, |
Boolean *done, |
long refCon) |
{ |
ComponentResult err; |
/* call the default grab-complete function */ |
err = SGGrabFrameComplete (c, bufferNum, done); |
if (*done) { |
/* frame is done */ |
CGrafPtr savePort; |
GDHandle saveGD; |
PixMapHandle bufferPM, savePM; |
Rect bufferRect; |
CGrafPtr tempPort = (CGrafPtr)refCon; |
/* set to our temporary port */ |
GetGWorld (&savePort, &saveGD); |
SetGWorld (tempPort, nil); |
/* find out about this buffer */ |
err = SGGetBufferInfo (c, bufferNum, &bufferPM, &bufferRect, |
nil, nil); |
if (!err) { |
/* set up to draw into this buffer */ |
savePM = tempPort->portPixMap; |
SetPortPix(bufferPM); |
/* draw some text into the buffer */ |
TextMode (srcXor); |
MoveTo (bufferRect.right - 20, bufferRect.bottom - 14); |
DrawString ("\pQT"); |
TextMode(srcOr); |
/* restore temporary port */ |
SetPortPix (savePM); |
} |
SetGWorld (savePort, saveGD); |
} |
return err; |
} |
OSErr setupVideoBottlenecks (SGChannel videoChannel, WindowPtr w, |
CGrafPtr tempPort) |
{ |
OSErr err; |
err = SGSetChannelRefCon (videoChannel, (long)tempPort); |
if (!err) { |
VideoBottles vb; |
/* get the current bottlenecks */ |
vb.procCount = 9; |
err = SGGetVideoBottlenecks (videoChannel, &vb); |
if (!err) { |
/* add our GrabFrameComplete function */ |
vb.grabCompleteProc = myGrabFrameComplete; |
err = SGSetVideoBottlenecks (videoChannel, &vb); |
/* set up the temporary port */ |
OpenCPort (tempPort); /* create a temporary port |
for drawing */ |
SetRectRgn (tempPort->visRgn, -32000, -32000, 32000, |
32000); /* with a wide open visible |
and clip region . . . */ |
CopyRgn (tempPort->visRgn, tempPort->clipRgn); |
/* so that you can use it in |
any video buffer */ |
PortChanged ((GrafPtr)tempPort); |
/* tell QuickDraw about the |
changes */ |
} |
} |
return err; |
} |
This section describes the functions that your application may supply to sequence grabber components.
Your grab function is used by the sequence grabber component to begin the capture of a frame of video data. Your grab-complete function allows the sequence grabber component to determine whether the current frame-capture operation is complete.
Your display function enables the sequence grabber component to move a captured video image in an offscreen buffer into the destination buffer for the video channel.
The sequence grabber component uses your compress function to commence the compression of a captured video image. Your compress-complete function helps the sequence grabber component to find out if the current frame-compression operation is finished.
Your add-frame function lets the sequence grabber component add a frame to a movie.
The sequence grabber component uses your transfer-frame function to move a video frame from the capture buffer into the channel’s filter buffer.
You may provide two functions for use with compressed-source devices. Your grab-compress-complete function determines when the current capture and compress operation is complete. Your display-compress function decompresses and displays a frame.
The sequence grabber calls your data function whenever any of the grabber’s channels write data to the movie file.
If you call the SGSettingsDialog
function, you must supply a modal-dialog filter function. The interface that your function must provide is discussed on MyModalFilter.
The sequence grabber component calls your grab function in order to start capturing a frame of video data.
Your grab function must present the following interface:
pascal ComponentResult MyGrabFunction (SGChannel c, |
short bufferNum, |
long refCon); |
Parameter |
Description |
---|---|
|
Specifies the reference that identifies the channel for this operation. |
|
Identifies the buffer for this operation. You can obtain information about this buffer by calling the |
|
Contains a reference constant value. You can set this value by calling the |
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your grab function can use the sequence grabber component’s SGGrabFrame
function to support the default behavior.
The sequence grabber component calls your grab-complete function in order to determine whether the current frame-capture operation is complete. Once a frame has been completely captured, you can modify its contents to suit your needs. For example, you can overlay text onto the video image.
Your function must present the following interface:
pascal ComponentResult MyGrabCompleteFunction (SGChannel c, |
short bufferNum, |
Boolean *done, |
long refCon); |
Parameter |
Description |
---|---|
|
Specifies the reference that identifies the channel for this operation. |
|
Identifies the buffer for this operation. You can obtain information about this buffer by calling the |
|
Contains a pointer to a Boolean value. Your function sets this Boolean value to indicate whether the frame has been completely captured. Set the Boolean value to |
|
Contains a reference constant value. You can set this value by calling the |
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your grab-complete function can use the sequence grabber component’s SGGrabFrameComplete
function to support the default behavior.
See Listing 3-6 for a sample grab-complete function. This function draws the letters “QT” over each video frame in the sequence.
The sequence grabber component calls your display function in order to transfer a captured video image in an offscreen buffer into the destination buffer for the video channel.
Your display function must support the following interface:
pascal ComponentResult MyDisplayFunction (SGChannel c, |
short bufferNum, |
MatrixRecord *mp, |
RgnHandle clipRgn, |
long refCon); |
Parameter |
Description |
---|---|
|
Specifies the reference that identifies the channel for this operation. |
|
Identifies the buffer for this operation. You can obtain information about this buffer by calling the |
|
Contains a pointer to a transformation matrix for the display operation. If there is no matrix for the operation, this parameter is set to |
|
Contains a handle to the clipping region for the destination image. This region is defined in the destination coordinate system. Apply the clipping region after applying the transformation matrix. If there is no clipping region, this parameter is set to |
|
Contains a reference constant value. You can set this value by calling the |
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your application sets the destination buffer by calling the SGSetChannelBounds
function.
Your display function can use the sequence grabber component’s SGDisplayFrame
function to support the default behavior.
The sequence grabber component calls your compress function in order to start compressing the captured video image.
Your compress function must support the following interface:
pascal ComponentResult MyCompressFunction (SGChannel c, |
short bufferNum, |
long refCon); |
Parameter |
Description |
---|---|
|
Specifies the reference that identifies the channel for this operation. |
|
Identifies the buffer for this operation. You can obtain information about this buffer by calling the |
|
Contains a reference constant value. You can set this value by calling the |
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your compress function can use the sequence grabber component’s SGCompressFrame
function to support the default behavior. This function uses the Image Compression Manager to compress the video image.
The sequence grabber component calls your compress-complete function in order to determine whether the current frame-compression operation is complete.
Your compress-complete function must support the following interface:
pascal ComponentResult MyCompressCompleteFunction (SGChannel c, |
short bufferNum, |
Boolean *done, |
SGCompressInfo *ci, |
long refCon); |
Parameter |
Description |
---|---|
|
Specifies the reference that identifies the channel for this operation. |
|
Identifies the buffer for this operation. You can obtain information about this buffer by calling the |
|
Contains a pointer to a Boolean value. Your function sets this Boolean value to indicate whether the frame has been completely compressed. Set the Boolean value to |
|
Contains a pointer to a compression information structure (defined by the |
|
Contains a reference constant value. You can set this value by calling the |
See The Compression Information Structure, for a description of the SGCompressInfo
data type.
Once a frame has been completely compressed, you can add it to the movie. Your compress-complete function can use the sequence grabber component’s SGCompressFrameComplete
function to support the default behavior.
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
The sequence grabber component calls your add-frame function in order to add a frame to a movie. Your add-frame function must support the following interface:
pascal ComponentResult MyAddFrameFunction (SGChannel c, |
short bufferNum, |
TimeValue atTime, |
TimeScale scale, |
SGCompressInfo *ci, |
long refCon); |
Parameter |
Description |
---|---|
|
Specifies the reference that identifies the channel for this operation. |
|
Identifies the buffer for this operation. You can obtain information about this buffer by calling the |
|
Specifies the time at which the frame was captured, in the time scale specified by the |
|
Specifies the time scale of the movie. You must not change this value. |
|
Contains a pointer to a compression information structure (defined by the |
|
Contains a reference constant value. You can set this value by calling the |
See The Compression Information Structure, for a description of the SGCompressInfo
data type.
You can use your add-frame function to modify the contents of the frame before it is added to the movie. This can be useful if you want to place frame numbers onto frames you are recording.
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your add-frame function can use the sequence grabber component’s SGAddFrame
function to support the default behavior.
The sequence grabber component calls your transfer-frame function in order to move a video frame from the capture buffer into the channel’s filter buffer.
Your transfer-frame function must support the following interface:
pascal ComponentResult MyTransferFrameFunction (SGChannel c, |
short bufferNum, |
MatrixRecord *mp, |
RgnHandle clipRgn, |
long refCon); |
Parameter |
Description |
---|---|
|
Specifies the reference that identifies the channel for this operation. |
|
Identifies the buffer for this operation. You can obtain information about this buffer by calling the |
|
Contains a pointer to a transformation matrix for the transfer operation. If there is no matrix for the operation, this parameter is set to |
|
Contains a handle to the clipping region for the destination image. This region is defined in the destination coordinate system. Apply the clipping region after applying the transformation matrix. If there is no clipping region, this parameter is set to |
|
Contains a reference constant value. You can set this value by calling the |
The sequence grabber component calls this function only when you are filtering the video data. By filtering the video data through a filter buffer, you can eliminate some visual artifacts that result from noisy input video sources. Your application sets a filter buffer by calling the SGSetCompressBuffer
function.
If you are using a grab-complete function to determine when frames have been grabbed, you should also implement a grab-compress-complete function (described in the next section). Otherwise, the channel will decompress the specified image before calling your grab-complete function, which will result in significantly lower performance. For details on grab-complete functions, see MyGrabCompleteFunction.
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your transfer-frame function can use the sequence grabber component’s SGTransferFrameForCompress
function to support the default behavior.
The sequence grabber calls your grab-compress-complete function when it is working with a video digitizer that supports compressed source data. Your grab-compress-complete function is responsible for determining whether the current compressed frame has been completely captured and compressed, essentially combining your grab-complete, compress, and compress-complete functions into one function.
Your function must support the following interface:
pascal ComponentResult MyGrabCompressCompleteFunction |
(SGChannel c, |
Boolean *done, |
SGCompressInfo *ci, |
TimeRecord *tr, |
long refCon); |
Parameter |
Description |
---|---|
|
Identifies the channel for this operation. |
|
Contains a pointer to a Boolean value. Set this Boolean value to indicate whether you are finished. Set it to |
|
Contains a pointer to a compression information structure. When the operation is complete, fill in this structure with information about the compression operation. |
|
Contains a pointer to a time record. When the operation is complete, fill in this structure with information indicating when the frame was grabbed. |
|
Contains a reference constant value. You can set this value by calling the |
See The Compression Information Structure, for a description of the SGCompressInfo
data type.
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your grab-compress-complete function may use the sequence grabber’s SGGrabCompressComplete
function to support the default behavior.
The sequence grabber calls your display-compress function when it is working with a video digitizer component that supports compressed source data. Your display-compress function is responsible for decompressing and displaying a compressed image.
pascal ComponentResult MyDisplayCompressFunction (SGChannel c, |
Ptr dataPtr, |
ImageDescriptionHandle desc, |
MatrixRecord *mp, |
RgnHandle clipRgn, |
long refCon); |
Parameter |
Description |
---|---|
|
Identifies the channel for this operation. The sequence grabber provides this value to your display-compress function. |
|
Contains a pointer to the compressed image data. |
|
Specifies a handle to the image description structure to use for the decompression operation. |
|
Contains a pointer to a matrix structure. This matrix structure contains the transformation matrix to use when displaying the image. If there is no matrix for the operation, this parameter is set to |
|
Contains a handle to the clipping region for the destination image. This region is defined in the destination coordinate system. Apply the clipping region after the transformation matrix. If there is no clipping region, this parameter is set to |
|
Contains a reference constant value. You can set this value by calling the |
Error constant |
Value |
Description |
---|---|---|
|
-9402 |
Request invalid in current mode |
Your display-compress function may use the sequence grabber’s SGDisplayCompress
function to support the default behavior.
The sequence grabber calls your data function whenever any of the grabber’s channels write digitized data to the destination movie file. You assign a data function to the sequence grabber by calling the SGSetDataProc
function.
Your data function must support the following interface:
pascal OSErr MyDataFunction (SGChannel c, Ptr p, long len, |
long *offset, long chRefCon, |
TimeValue time, short writeType, |
long refCon); |
Parameter |
Description |
---|---|
|
Identifies the channel component that is writing the digitized data. |
|
Contains a pointer to the digitized data. |
|
Indicates the number of bytes of digitized data. |
|
Contains a pointer to a field that may specify where you are to write the digitized data, and that is to receive a value indicating where you wrote the data. You must update the field referred to by this parameter, supplying the value indicated by the |
|
Contains control information. The low-order 16 bits contain sample flags for use by the Movie Toolbox's |
|
Identifies the starting time of the data, in the channel's time scale. You may use the |
|
Indicates the type of write operation being performed. |
|
Contains the reference constant you specified when you assigned your data function to the sequence grabber. |
The following values are defined for the writeType
parameter:
Constant |
Description |
---|---|
|
Append the new data to the end of the file. Set the field referred to by the offset parameter to reflect the location at which you added the data. |
|
Do not write any data to the output file. Instead, reserve space in the output file for the amount of data indicated by the |
|
Write the data into the location specified by the field referred to by the |
The sequence grabber calls your data function whenever any channel component writes data to the destination movie. You may use your data function to store the digitized data in some format other than a QuickTime movie.
You can instruct the sequence grabber not to write its data to a QuickTime movie by calling the SGSetDataOutput
function and setting the seqGrabDontMakeMovie
flag to 1. This can save processing time in cases where you do not want to create or update a movie.
The SGSettingsDialog
function causes the sequence grabber to present its settings dialog box to the user. This is a movable modal dialog box, so you must provide a filter function to handle update events in your window. You specify your filter function with the proc
parameter.
A modal-dialog filter function whose address is passed to SGSettingsDialog
should support the following interface:
pascal Boolean MyModalFilter (DialogPtr theDialog, |
EventRecord *theEvent, |
short *itemHit, long refCon); |
Parameter |
Description |
---|---|
|
Points to the settings dialog box's dialog structure. |
|
Contains a pointer to an event structure. This event structure contains information identifying the nature of the event. |
|
Contains a pointer to a field that contains the item selected by the user. If you handle the event, you should update this field to reflect the item number of the selected item. |
|
Contains a reference constant. You provide this reference constant to the sequence grabber in the |
Your modal-dialog filter function returns a Boolean value that indicates whether you handled the event. Set this value to true
if you handled the event; otherwise, set it to false
. If you handle the event, be sure to update the value of the field referred to by the itemHit
parameter.
This section describes the compression information structure and the sequence grabber frame information structure.
The compression information structure defines the characteristics of a buffer that contains a captured image that has been compressed. Callback functions use compression information structures to exchange information about compressed images. For example, the compress-complete function must format a compression information record whenever a video frame is compressed (see MyCompressCompleteFunction for more information about the compress-complete callback function). The SGCompressInfo
data type defines a compression information structure.
The frame information structure defines a frame for a sequence grabber component and its sequence grabber channel components. The SeqGrabExtendedFrameInfo
data type defines the format of a frame information structure. SeqGrabExtendedFrameInfo
is an extension of SeqGrabFrameInfo
, adding a new frameOutput
field and extending the frameOffset
field to 64 bits.
Note: You only need to know about the frame information structure if you are creating a sequence grabber component. If you are not creating a sequence grabber component, you may skip this section.
© 2005, 2007 Apple Inc. All Rights Reserved. (Last updated: 2007-01-08)