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