include/cinder/qtime/QuickTime.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2010, The Barbarian Group
00003  All rights reserved.
00004 
00005  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00006  the following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00009     the following disclaimer.
00010     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00011     the following disclaimer in the documentation and/or other materials provided with the distribution.
00012 
00013  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00014  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00015  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00016  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00017  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00018  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00019  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00020  POSSIBILITY OF SUCH DAMAGE.
00021 */
00022 
00023 #pragma once
00024 
00025 // None of this works in 64 bit on the mac or Windows. We'll need to move to QTKit on the mac.
00026 #if ! defined( __LP64__ )
00027 
00028 #include "cinder/Cinder.h"
00029 #include "cinder/gl/gl.h"
00030 #include "cinder/Surface.h"
00031 #include "cinder/gl/Texture.h"
00032 #include "cinder/Display.h"
00033 #include "cinder/Url.h"
00034 #include "cinder/DataSource.h"
00035 #include "cinder/Thread.h"
00036 
00037 #include <string>
00038 
00039 #if defined( CINDER_MAC )
00040     #include <QuickTime/QuickTime.h>
00041     #if defined( __OBJC__ )
00042         @class QTMovie;
00043     #else
00044         class QTMovie;
00045     #endif
00046 #endif
00047 
00048 
00049 // these are forward-declared to avoid bringing all of QuickTime into the global namespace on Windows
00050 #if defined( CINDER_MSW )
00051     typedef struct MovieType**              Movie;
00052     typedef struct OpaqueQTVisualContext*   QTVisualContextRef;
00053     typedef long                            TimeValue;
00054     typedef struct QTAudioFrequencyLevels   QTAudioFrequencyLevels;
00055     typedef unsigned long                   FourCharCode;
00056     typedef struct __CVBuffer*              CVBufferRef;
00057     typedef CVBufferRef                     CVImageBufferRef;
00058 #endif
00059 
00060 namespace cinder { namespace qtime {
00061 
00062 class MovieLoader;
00063 typedef std::shared_ptr<MovieLoader>    MovieLoaderRef;
00064 
00065 class MovieBase {
00066  public:
00067     virtual     ~MovieBase() {} 
00068     
00070     bool        checkPlayable();
00071     
00073     int32_t     getWidth() const { return getObj()->mWidth; }
00075     int32_t     getHeight() const { return getObj()->mHeight; }
00077     Vec2i       getSize() const { return Vec2i( getWidth(), getHeight() ); }    
00079     float       getAspectRatio() const { return getObj()->mWidth / (float)getObj()->mHeight; }
00081     Area        getBounds() const { return Area( 0, 0, getWidth(), getHeight() ); }
00083     float       getPixelAspectRatio() const;
00085     float       getDuration() const { return getObj()->mDuration; }
00087     float       getFramerate() const;
00089     int32_t     getNumFrames() const;
00091     bool        hasAlpha() const;
00092 
00094     bool        hasVisuals() const;
00096     bool        hasAudio() const;
00097 
00099     bool        checkNewFrame();
00100 
00102     float       getCurrentTime() const;
00104     void        seekToTime( float seconds );
00106     void        seekToFrame( int frame );
00108     void        seekToStart();
00110     void        seekToEnd();
00112     void        setActiveSegment( float startTime, float duration );
00114     void        resetActiveSegment();
00115 
00117     void        setLoop( bool loop = true, bool palindrome = false );
00119     void        stepForward();
00121     void        stepBackward();
00123     void        setRate( float rate );
00124 
00126     void        setVolume( float volume );
00128     float       getVolume() const;
00129 
00131     void        setupMonoFft( uint32_t numBands );
00133     void        setupStereoFft( uint32_t numBands );
00135     void        setupMultiChannelFft( uint32_t numBands );  
00136     
00137     float*      getFftData() const;
00138     uint32_t    getNumFftBands() const;
00139     uint32_t    getNumFftChannels() const;  
00140 
00142     bool    isPlaying() const;
00144     bool    isDone() const;
00146     void    play();
00148     void    stop();
00149 
00151     void    setNewFrameCallback( void(*aNewFrameCallback)( long, void * ), void *aNewFrameCallbackRefcon );
00152 
00154     ::Movie getMovieHandle() const { return getObj()->mMovie; }
00155 
00156  protected:
00157     MovieBase() {}
00158     void            init();
00159     void            updateFrame();
00160     void            updateLoadState();
00161 
00162     void            setupFft( FourCharCode code, uint32_t bandNum, uint8_t channelNum );
00163 
00164     static int32_t      countFrames( ::Movie theMovie );
00165     TimeValue           getStartTimeOfFirstSample() const;
00166 
00167  protected:
00168     void    initFromPath( const fs::path &filePath );
00169     void    initFromLoader( const class MovieLoader &loader );
00170     void    initFromMemory( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint );
00171     void    initFromDataSource( DataSourceRef dataSource, const std::string &mimeTypeHint );
00172  
00173     struct Obj {
00174         Obj();
00175         virtual ~Obj();
00176     
00177         void prepareForDestruction();
00178     
00179         void lock() { mMutex.lock(); }
00180         void unlock() { mMutex.unlock(); }
00181 
00182         // because the MovieBase* might change over time, but the MovieBase::Obj* will not, we need our callbacks to take an Obj* as a refcon
00183         // which in turn means this functionality must be in the Obj, not the MovieBase
00184         virtual void        releaseFrame() = 0;
00185         virtual void        newFrame( CVImageBufferRef cvImage ) = 0;
00186                 
00187         int32_t                     mWidth, mHeight;
00188         int32_t                     mFrameCount;
00189         float                       mDuration;
00190         bool                        mLoaded, mPlayable;
00191         bool                        mPlayingForward, mLoop, mPalindrome;
00192 
00193         QTAudioFrequencyLevels      *mFFTData;
00194         FourCharCode                mFFTFourCharCode;
00195         uint32_t                    mFFTNumBandLevels;
00196         uint32_t                    mFFTNumChannels;
00197         QTVisualContextRef          mVisualContext;
00198         ::Movie                     mMovie;
00199 
00200         void        (*mNewFrameCallback)(long timeValue, void *refcon);
00201         void        *mNewFrameCallbackRefcon;           
00202 
00203         std::mutex                  mMutex; 
00204         DataSourceRef               mDataSource; // sometimes used to retain a reference to a data source so that it doesn't go away before we do
00205     };
00206     
00207     virtual Obj*        getObj() const = 0;
00208 };
00209 
00210 class MovieSurface;
00211 typedef std::shared_ptr<MovieSurface>   MovieSurfaceRef;
00212 
00213 class MovieSurface : public MovieBase {
00214  public:
00215     MovieSurface() : MovieBase() {}
00216     MovieSurface( const fs::path &path );
00217     MovieSurface( const class MovieLoader &loader );
00219 
00220     MovieSurface( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint = "" );
00221     MovieSurface( DataSourceRef dataSource, const std::string mimeTypeHint = "" );
00222 
00223     static MovieSurfaceRef create( const fs::path &path ) { return std::shared_ptr<MovieSurface>( new MovieSurface( path ) ); }
00224     static MovieSurfaceRef create( const MovieLoaderRef &loader );
00225     static MovieSurfaceRef create( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint = "" )
00226          { return std::shared_ptr<MovieSurface>( new MovieSurface( data, dataSize, fileNameHint, mimeTypeHint ) ); }
00227     static MovieSurfaceRef create( DataSourceRef dataSource, const std::string mimeTypeHint = "" )
00228          { return std::shared_ptr<MovieSurface>( new MovieSurface( dataSource, mimeTypeHint ) ); }
00229 
00231     Surface     getSurface();
00232 
00233  protected:
00234     void                allocateVisualContext();
00235  
00236     struct Obj : public MovieBase::Obj {
00237         virtual ~Obj();
00238         
00239         virtual void        releaseFrame(); 
00240         virtual void        newFrame( CVImageBufferRef cvImage );
00241     
00242         Surface             mSurface;
00243     };
00244     
00245     std::shared_ptr<Obj>        mObj;
00246     virtual MovieBase::Obj*     getObj() const { return mObj.get(); }
00247 
00248   public:
00250 
00251     typedef std::shared_ptr<Obj> MovieSurface::*unspecified_bool_type;
00252     operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &MovieSurface::mObj; }
00253     void reset() { mObj.reset(); }
00255 };
00256 
00257 class MovieGl;
00258 typedef std::shared_ptr<MovieGl>    MovieGlRef;
00263 class MovieGl : public MovieBase {
00264   public:
00265     MovieGl() : MovieBase() {}
00266     MovieGl( const fs::path &path );
00267     MovieGl( const class MovieLoader &loader );
00269 
00270     MovieGl( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint = "" );
00271     MovieGl( DataSourceRef dataSource, const std::string mimeTypeHint = "" );
00272 
00273     static MovieGlRef create( const fs::path &path ) { return std::shared_ptr<MovieGl>( new MovieGl( path ) ); }
00274     static MovieGlRef create( const MovieLoaderRef &loader );
00275     static MovieGlRef create( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint = "" )
00276          { return std::shared_ptr<MovieGl>( new MovieGl( data, dataSize, fileNameHint, mimeTypeHint ) ); }
00277     static MovieGlRef create( DataSourceRef dataSource, const std::string mimeTypeHint = "" )
00278          { return std::shared_ptr<MovieGl>( new MovieGl( dataSource, mimeTypeHint ) ); }
00279 
00281     const gl::Texture   getTexture();
00282 
00283   protected:
00284     void                allocateVisualContext();
00285 
00286     struct Obj : public MovieBase::Obj {
00287         Obj();
00288         ~Obj();
00289 
00290         virtual void        releaseFrame();
00291         virtual void        newFrame( CVImageBufferRef cvImage );
00292         
00293         gl::Texture         mTexture;
00294 #if defined( CINDER_MSW )
00295         gl::TextureCache    mTextureCache;
00296 #endif
00297     };
00298     
00299     std::shared_ptr<Obj>                mObj;
00300     virtual MovieBase::Obj*     getObj() const { return mObj.get(); }
00301 
00302   public:
00304 
00305     typedef std::shared_ptr<Obj> MovieGl::*unspecified_bool_type;
00306     operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &MovieGl::mObj; }
00307     void reset() { mObj.reset(); }
00309 };
00310 
00311 class MovieLoader {
00312   public:
00313     MovieLoader() {}
00314     MovieLoader( const Url &url );
00315 
00316     static MovieLoaderRef   create( const Url &url ) { return std::shared_ptr<MovieLoader>( new MovieLoader( url ) ); }
00317 
00319     bool    checkLoaded() const;
00321     bool    checkPlayable() const;
00323     bool    checkPlaythroughOk() const;
00324 
00326     void    waitForLoaded() const;
00328     void    waitForPlayable() const;
00330     void    waitForPlaythroughOk() const;
00331 
00333     const Url&      getUrl() const { return mObj->mUrl; }
00334 
00336     ::Movie getMovieHandle() const { return mObj->mMovie; }
00337 
00339     ::Movie transferMovieHandle() const { mObj->mOwnsMovie = false; return mObj->mMovie; }
00340     
00341   protected:
00342     void    updateLoadState() const;
00343  
00344     struct Obj {
00345         Obj( const Url &url );
00346         ~Obj();
00347         
00348         mutable bool    mOwnsMovie;
00349         ::Movie         mMovie;
00350         Url             mUrl;
00351         mutable bool    mLoaded, mPlayable, mPlaythroughOK;
00352     };
00353     
00354     std::shared_ptr<Obj>        mObj;
00355     
00356   public:
00358 
00359     typedef std::shared_ptr<Obj> MovieLoader::*unspecified_bool_type;
00360     operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &MovieLoader::mObj; }
00361     void reset() { mObj.reset(); }
00363 };
00364 
00365 inline int32_t floatToFixed( float fl ) { return ((int32_t)((float)(fl) * ((int32_t) 0x00010000L))); }
00366 
00368 void startQuickTime();
00370 extern int32_t getQuickTimeVersion();
00372 extern std::string getQuickTimeVersionString();
00373 
00375 extern void quickTimeTask();
00376 
00377 class QuickTimeExc : public std::exception {
00378 };
00379 
00380 class QuickTimePathInvalidExc : public QuickTimeExc {
00381 };
00382 
00383 class QuickTimeFileInvalidExc : public QuickTimeExc {
00384 };
00385 
00386 class QuickTimeExcUrlInvalid : public QuickTimeExc {
00387 };
00388 
00389 class QuickTimeErrorLoadingExc : public QuickTimeExc {
00390 };
00391 
00392 class QuickTimeExcFft : public QuickTimeExc {
00393 };
00394 
00395 } /* namespace qtime */ } /* namespace cinder */
00396 #endif // ! defined( __LP64__ )