Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CVideoOutput.cpp
/* |
File: CVideoOutput.cpp |
Description: An easy to use class which encapsulates the basic set of |
methods required to use QuickTime Video Output Components. |
See CVideoOutput.h for more information. |
Author: QuickTime DTS |
Version: 2.0.2 |
Copyright: © Copyright 2000 - 2002 Apple Computer, Inc. All rights reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): <5> 06/12/02 don't call SetEchoPort in Begin by default |
<4> 05/27/02 don't leak SoundInfoList handle |
<3> 11/16/01 initial release version 2.0 |
<2> 10/11/01 modified to support multiple components |
<1> 1/28/00 initial release |
*/ |
#include "CVideoOutput.h" |
using namespace dts; |
/* Check the result of GetError() before using the object. |
NOTE: This class will not throw any exceptions but does keep track of errors internally and will |
return errors from most methods. You should call the GetError() method before working with |
the object just to make sure things haven't failed miserably. |
*/ |
CVideoOutput::CVideoOutput( const unsigned char inClientNameStr[], const Movie inMovie ) : mMovie(inMovie), mVOutputComponent(NULL), mVOutputGWorld(NULL), |
mSoundOutComponent(NULL), mVideoOutputClockInstance(NULL), |
mNumberAudioTracks(0), mVideoOutputInUse(false), mCanDoEchoPort(false), |
mHasSoundOutput(false), mHasClock(false), rc(noErr) |
{ |
// Instantiate the actual QuickTime VO Component object used by this class. |
// We could do this in the ctor init list, but we don't want any uncaught |
// exeptions getting back to the client of this class. |
try { |
CVideoOutputComponentPtr pVOComponent(new CVideoOutputComponent); |
mVOutputComponent = pVOComponent; |
} |
catch ( ... ) { |
rc = badComponentType; |
return; |
} |
// We really just need to know the version for the SetMovieVideoOutput call in QT5 |
long version; |
if ( (rc = Gestalt( gestaltQuickTime, &version )) != noErr ) return; |
mQTVersion = version >> 16; |
BlockMoveData( inClientNameStr, mClientNameStr, inClientNameStr[0]+1 ); |
for ( UInt8 i = 0; i < kMaxAudioTracks; i++ ) { |
mAudioMediaHandler[i] = NULL; |
} |
} |
#pragma mark- |
/* Open( void ) |
Opens an instance of a video output component, registers the client name with the component |
and sets up the display mode. |
*/ |
OSErr CVideoOutput::Open( void ) |
{ |
ComponentInstance theInstance = 0; |
if ( mVideoOutputInUse ) { rc = videoOutputInUseErr; goto bail; } |
if ( mVOutputComponent.get() == NULL ) { rc = badComponentType; goto bail; } |
// Specifically open a chosen video output component |
mVOutputComponent->OpenComponent(); |
if (( theInstance = mVOutputComponent->GetComponentInstance() ) == NULL ) { rc = badComponentInstance; goto bail; } |
// Register your client name with the Video Output Component |
::QTVideoOutputSetClientName( theInstance, mClientNameStr ); |
// Set the display mode |
rc = ::QTVideoOutputSetDisplayMode( theInstance, mVOutputComponent->GetDisplayMode() ); |
if ( rc ) Close(); |
bail: |
return rc; |
} |
/* Close( void ) |
Closes the component instance and zeros the object. It is also called by the destructor. |
*/ |
void CVideoOutput::Close( void ) |
{ |
if ( mVideoOutputInUse ) |
End(); |
mVOutputComponent->CloseComponent(); |
} |
#pragma mark- |
/* Begin( Boolean inUseVOsdev = true, Boolean inUseVOClk = true, AudioRate inAudioRate = eAudioRateDefault ) |
Gains exclusive access to the hardware, and sets up the sound output and clock associated with the |
video output component. Begin also acquires the GWorld used by the video output component. |
Both the sound and clock parameters are set to 'true' by default, and the |
audio rate is set to "eAudioRateDefault". |
*/ |
OSErr CVideoOutput::Begin( Boolean inUseVOsdev, Boolean inUseVOClock, AudioRate inAudioRate, Boolean inChangeMovieGWorld ) |
{ |
ComponentInstance theInstance = 0; |
UnsignedFixed theSampleRate = inAudioRate; |
if ( mMovie == NULL ) { rc = paramErr; goto bail; } |
if ( mVideoOutputInUse ) { rc = videoOutputInUseErr; goto bail; } |
if (( theInstance = mVOutputComponent->GetComponentInstance() ) == NULL ) { rc = badComponentInstance; goto bail; } |
// Find out how many tracks the movie contains, then for each track find out |
// which contain a sound media type and finally grab the media handler for those tracks |
{ // gcc complains without this in brackets |
long theTrackCount = ::GetMovieTrackCount( mMovie ); |
for ( UInt8 i = 1; i < theTrackCount + 1; i++) { |
OSType aMediaType; |
Track aTrack = ::GetMovieIndTrack( mMovie, i ); |
Media aMedia = ::GetTrackMedia( aTrack ); |
::GetMediaHandlerDescription( aMedia, &aMediaType, NULL, NULL ); |
if ( aMediaType == SoundMediaType ) { |
mAudioMediaHandler[mNumberAudioTracks] = ::GetMediaHandler( aMedia ); |
mNumberAudioTracks++; |
// When the default audio sample rate has been requested, get the sample rate |
// the sound was originally captured at - this becomes the sample rate |
// passed to the output component |
// If there are multiple audio tracks pick the higest rate |
if ( inAudioRate == eAudioRateDefault ) { |
SoundDescriptionHandle hSoundDesc = (SoundDescriptionHandle)::NewHandle(0); |
if ( hSoundDesc ) { |
::GetMediaSampleDescription( aMedia, 1, (SampleDescriptionHandle)hSoundDesc ); |
if ( theSampleRate < (**hSoundDesc).sampleRate ) |
theSampleRate = (**hSoundDesc).sampleRate; |
::DisposeHandle( (Handle)hSoundDesc ); |
} |
} |
} |
if ( mNumberAudioTracks == kMaxAudioTracks ) break; |
} |
} |
// Gain exclusive access to the video output hardware |
rc = ::QTVideoOutputBegin( theInstance ); |
if ( rc ) goto bail; |
mVideoOutputInUse = true; |
// Does this Video Output Component implement an EchoPort? |
if ( ::ComponentFunctionImplemented( theInstance, kQTVideoOutputSetEchoPortSelect ) ) |
mCanDoEchoPort = true; |
// Does this Video Output Component have a Sound Output Component associated with it? |
if ( ::ComponentFunctionImplemented( theInstance, kQTVideoOutputGetIndSoundOutputSelect ) ) { |
// Get the first sound output component associated with the video output component |
::QTVideoOutputGetIndSoundOutput( theInstance, 1, &mSoundOutComponent ); |
if ( mSoundOutComponent ) { |
mHasSoundOutput = true; |
// Does the output component actually supports the chosen audio sample rate? |
// If it does just go ahead and use it. If not, the sample rate will be changed |
// to a valid rate |
SoundInfoList theInfoList; |
rc = ::GetSoundOutputInfo( mSoundOutComponent, siSampleRateAvailable, &theInfoList); |
if ( rc ) { Close(); goto bail; } |
UnsignedFixedPtr pRates = reinterpret_cast<UnsignedFixedPtr>( *(theInfoList.infoHandle) ); |
UnsignedFixed tempRate = 0; |
for ( UInt8 i = 0; i < theInfoList.count; i++ ) { |
tempRate = pRates[i]; |
if ( tempRate == theSampleRate ) break; |
} |
DisposeHandle( theInfoList.infoHandle ); |
if ( tempRate != theSampleRate ) |
theSampleRate = tempRate; |
rc = ::SetSoundOutputInfo( mSoundOutComponent, siSampleRate, (void *)theSampleRate ); |
if ( rc ) { Close(); goto bail; } |
} |
} |
// Does this Video Output Component have a Clock Component associated with it? |
if ( ::ComponentFunctionImplemented( theInstance, kQTVideoOutputGetClockSelect ) ) { |
// Get an instance of the clock component associated with the video output component - used to |
// synchronize video and sound to the rate of the display |
::QTVideoOutputGetClock( theInstance, &mVideoOutputClockInstance ); |
if ( mVideoOutputClockInstance ) |
mHasClock = true; |
} |
if ( mQTVersion >= kQTVersion501 ) { |
// Indicates to the ICM the video output component being used with the given movie |
// You should make this call so the ICM can keep track of the video output in use |
::SetMovieVideoOutput( mMovie, theInstance ); |
} |
// Get a pointer to the graphics world used by a video output component |
rc = ::QTVideoOutputGetGWorld( theInstance, &mVOutputGWorld ); |
if ( rc ) goto bail; |
// Set up the sound device |
SetSoundDevice( inUseVOsdev ); |
// Set up the clock - needs to be called after setting up the sdev |
SetClock( inUseVOClock ); |
// Don't call SetEchoPort by default as it could cause some problems when using the standard movie |
// controller and a video output component which doesn't support an echo port (rare but still...). |
// We just force the client of this class to call SetEchoPort() when they want, instead |
// of doing it for them, unless they specifically tell us that it's ok to call it. |
if ( inChangeMovieGWorld ) { |
// Set up the Movie GWorld and initially turn off the EchoPort. |
SetEchoPort( NULL ); |
} |
bail: |
return rc; |
} |
/* End( void ) |
Relinquishes exclusive access to the hardware. Also called by Close(). |
*/ |
void CVideoOutput::End( void ) |
{ |
if ( mVideoOutputInUse ) { |
// Because the video output component disposes of the instance of the clock component which was returned to us |
// by the QTVideoOutputGetClock call in the Begin() method, we need to reset the clock for the movie to the default |
// QuickTime clock before calling QTVideoOutputEnd() |
SetSoundDevice( false ); |
SetClock( false ); |
if ( mQTVersion >= kQTVersion501 ) { |
// Set the vout parameter to NULL as soon as the video out component is no longer in use |
::SetMovieVideoOutput( mMovie, NULL ); |
} |
::QTVideoOutputEnd( mVOutputComponent->GetComponentInstance() ); |
mVideoOutputInUse = false; |
} |
// If the video output was in use, after the call to ::QTVideoOutputEnd() mVOutputGWorld is |
// no longer valid as the video output component automatically disposes of the |
// graphics world. If you need to use the GWorld after calling End(), you can call |
// CVideoOutput::GetGWorld() again but ONLY after the next time you call Begin() or it |
// will return NULL. |
// Egon's important safety tip - You must not call DisposeGWorld to dispose of the |
// graphics world used by a video output component...that would be bad. |
mVOutputGWorld = NULL; |
mSoundOutComponent = NULL; |
mVideoOutputClockInstance = NULL; |
mNumberAudioTracks = 0; |
mCanDoEchoPort = false; |
mHasSoundOutput = false; |
mHasClock = false; |
for ( UInt8 i = 0; i < kMaxAudioTracks; i++) { |
mAudioMediaHandler[i] = NULL; |
} |
} |
#pragma mark- |
/* SetEchoPort( const CGrafPtr inEchoPort = NULL ) |
Allows you to display video both on an external video display and in a window. |
Pass in a CGrafPtr to specify a window to display video sent to the device. When the |
Echo Port is on, the movie is displayed in the window and sent to the video output device. |
If the EchoPort is not supported by the video output component or is turned off, |
the Movie will be directed to the video output components GWorld as you would expect. |
Call CanDoEchoPort() before assuming the video output component supports the echo port. |
*/ |
OSErr CVideoOutput::SetEchoPort( const CGrafPtr inEchoPort ) |
{ |
ComponentInstance theInstance = 0; |
if ( mVideoOutputInUse == false ) return videoOutputInUseErr; |
if (( theInstance = mVOutputComponent->GetComponentInstance() ) == NULL ) { rc = badComponentInstance; goto bail; } |
if ( mCanDoEchoPort ) { |
if ( inEchoPort == NULL ) { |
// Turn off Echo Port |
rc = ::QTVideoOutputSetEchoPort( theInstance, (CGrafPtr)NULL ); |
if ( rc == noErr ) { |
if ( mVideoOutputInUse ) { |
::SetMovieGWorld( mMovie, mVOutputGWorld, NULL ); |
} |
} |
} else { |
// Turn on Echo Port |
rc = ::QTVideoOutputSetEchoPort( theInstance, inEchoPort ); |
if ( rc == noErr ) { |
if ( mVideoOutputInUse ) { |
::SetMovieGWorld( mMovie, inEchoPort, NULL); |
} |
} |
} |
} else { |
// The Echo Port isn't supported by this component but |
// we still need to set the Movie GWorld correctly |
if ( inEchoPort == NULL ) { |
::SetMovieGWorld( mMovie, mVOutputGWorld, NULL ); |
} else { |
::SetMovieGWorld( mMovie, inEchoPort, NULL ); |
} |
} |
bail: |
return rc; |
} |
/* SetSoundDevice( Boolean inUseVOsdev = true ) |
This call will turn on/off the use of the video output components sound device. Passing in 'true' |
will set up the use of the video output components sound device, this is the default setting. |
You should call SetClock() after this call to choose the correct clock. |
*/ |
OSErr CVideoOutput::SetSoundDevice( Boolean inUseVOsdev ) |
{ |
if ( mVideoOutputInUse == false ) return videoOutputInUseErr; |
if ( mHasSoundOutput ) { |
if ( inUseVOsdev == true ) { |
for ( UInt8 i = 0;i < mNumberAudioTracks; i++ ) { |
rc = ::MediaSetSoundOutputComponent( mAudioMediaHandler[i], mSoundOutComponent ); |
if ( rc ) goto bail; |
} |
} else { |
for ( UInt8 i = 0;i < mNumberAudioTracks; i++ ) { |
rc = ::MediaSetSoundOutputComponent( mAudioMediaHandler[i], NULL ); |
if( rc ) goto bail; |
} |
} |
} |
bail: |
return rc; |
} |
/* SetClock( Boolean inUseVOClock = true ) |
Allows you to choose which clock to use for audio / video sync. Passing in 'true' will choose |
the video output components clock to synchronize video and sound to the rate of the display. |
Passing in 'false' will use the default QuickTime clock. |
NOTE: Setting the Movie master clock to the video output clock MUST be done after |
setting up the sound device or it's gets whacked back to the default QuickTime clock. |
*/ |
void CVideoOutput::SetClock( Boolean inUseVOClock ) |
{ |
if ( mHasClock ) { |
if ( inUseVOClock == true ) { |
::SetMovieMasterClock( mMovie, (Component)mVideoOutputClockInstance, NULL ); |
} else { |
::ChooseMovieClock( mMovie, 0 ); |
} |
} |
} |
Copyright © 2010 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2010-11-08