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 MovieBase { 00063 public: 00064 virtual ~MovieBase() {} 00065 00067 bool checkPlayable(); 00068 00070 int32_t getWidth() const { return getObj()->mWidth; } 00072 int32_t getHeight() const { return getObj()->mHeight; } 00074 float getAspectRatio() const { return getObj()->mWidth / (float)getObj()->mHeight; } 00076 float getPixelAspectRatio() const; 00078 float getDuration() const { return getObj()->mDuration; } 00080 float getFramerate() const; 00082 int32_t getNumFrames() const; 00084 bool hasAlpha() const; 00085 00087 bool hasVisuals() const; 00089 bool hasAudio() const; 00090 00091 00093 float getCurrentTime() const; 00095 void seekToTime( float seconds ); 00097 void seekToFrame( int frame ); 00099 void seekToStart(); 00101 void seekToEnd(); 00103 void setActiveSegment( float startTime, float duration ); 00105 void resetActiveSegment(); 00106 00108 void setLoop( bool loop = true, bool palindrome = false ); 00110 void stepForward(); 00112 void stepBackward(); 00114 void setRate( float rate ); 00115 00117 void setVolume( float volume ); 00119 float getVolume() const; 00120 00122 void setupMonoFft( uint32_t numBands ); 00124 void setupStereoFft( uint32_t numBands ); 00126 void setupMultiChannelFft( uint32_t numBands ); 00127 00128 float* getFftData() const; 00129 uint32_t getNumFftBands() const; 00130 uint32_t getNumFftChannels() const; 00131 00133 bool isPlaying() const; 00135 bool isDone() const; 00137 void play(); 00139 void stop(); 00140 00142 void setNewFrameCallback( void(*aNewFrameCallback)( long, void * ), void *aNewFrameCallbackRefcon ); 00143 00145 ::Movie getMovieHandle() const { return getObj()->mMovie; } 00146 00147 protected: 00148 MovieBase() {} 00149 void init(); 00150 void updateFrame(); 00151 void updateLoadState(); 00152 00153 void setupFft( FourCharCode code, uint32_t bandNum, uint8_t channelNum ); 00154 00155 static int32_t countFrames( ::Movie theMovie ); 00156 TimeValue getStartTimeOfFirstSample() const; 00157 00158 protected: 00159 void initFromPath( const std::string &path ); 00160 void initFromLoader( const class MovieLoader &loader ); 00161 void initFromMemory( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint ); 00162 void initFromDataSource( DataSourceRef dataSource, const std::string &mimeTypeHint ); 00163 00164 struct Obj { 00165 Obj(); 00166 virtual ~Obj(); 00167 00168 void prepareForDestruction(); 00169 00170 void lock() { mMutex.lock(); } 00171 void unlock() { mMutex.unlock(); } 00172 00173 // because the MovieBase* might change over time, but the MovieBase::Obj* will not, we need our callbacks to take an Obj* as a refcon 00174 // which in turn means this functionality must be in the Obj, not the MovieBase 00175 virtual void releaseFrame() = 0; 00176 virtual void newFrame( CVImageBufferRef cvImage ) = 0; 00177 00178 int32_t mWidth, mHeight; 00179 int32_t mFrameCount; 00180 float mDuration; 00181 bool mLoaded, mPlayable; 00182 bool mPlayingForward, mLoop, mPalindrome; 00183 00184 QTAudioFrequencyLevels *mFFTData; 00185 FourCharCode mFFTFourCharCode; 00186 uint32_t mFFTNumBandLevels; 00187 uint32_t mFFTNumChannels; 00188 QTVisualContextRef mVisualContext; 00189 ::Movie mMovie; 00190 00191 void (*mNewFrameCallback)(long timeValue, void *refcon); 00192 void *mNewFrameCallbackRefcon; 00193 00194 std::mutex mMutex; 00195 DataSourceRef mDataSource; // sometimes used to retain a reference to a data source so that it doesn't go away before we do 00196 }; 00197 00198 virtual Obj* getObj() const = 0; 00199 }; 00200 00201 class MovieSurface : public MovieBase { 00202 public: 00203 MovieSurface() : MovieBase() {} 00204 MovieSurface( const std::string &path ); 00205 MovieSurface( const class MovieLoader &loader ); 00207 00208 MovieSurface( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint = "" ); 00209 MovieSurface( DataSourceRef dataSource, const std::string mimeTypeHint = "" ); 00210 00212 Surface getSurface(); 00213 00214 protected: 00215 void allocateVisualContext(); 00216 00217 struct Obj : public MovieBase::Obj { 00218 virtual ~Obj(); 00219 00220 virtual void releaseFrame(); 00221 virtual void newFrame( CVImageBufferRef cvImage ); 00222 00223 Surface mSurface; 00224 }; 00225 00226 shared_ptr<Obj> mObj; 00227 virtual MovieBase::Obj* getObj() const { return mObj.get(); } 00228 00229 public: 00231 00232 typedef shared_ptr<Obj> MovieSurface::*unspecified_bool_type; 00233 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &MovieSurface::mObj; } 00234 void reset() { mObj.reset(); } 00236 }; 00237 00242 class MovieGl : public MovieBase { 00243 public: 00244 MovieGl() : MovieBase() {} 00245 MovieGl( const std::string &path ); 00246 MovieGl( const class MovieLoader &loader ); 00248 00249 MovieGl( const void *data, size_t dataSize, const std::string &fileNameHint, const std::string &mimeTypeHint = "" ); 00250 MovieGl( DataSourceRef dataSource, const std::string mimeTypeHint = "" ); 00251 00253 const gl::Texture getTexture(); 00254 00255 protected: 00256 void allocateVisualContext(); 00257 00258 struct Obj : public MovieBase::Obj { 00259 Obj(); 00260 ~Obj(); 00261 00262 virtual void releaseFrame(); 00263 virtual void newFrame( CVImageBufferRef cvImage ); 00264 00265 gl::Texture mTexture; 00266 #if defined( CINDER_MSW ) 00267 gl::TextureCache mTextureCache; 00268 #endif 00269 }; 00270 00271 shared_ptr<Obj> mObj; 00272 virtual MovieBase::Obj* getObj() const { return mObj.get(); } 00273 00274 public: 00276 00277 typedef shared_ptr<Obj> MovieGl::*unspecified_bool_type; 00278 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &MovieGl::mObj; } 00279 void reset() { mObj.reset(); } 00281 }; 00282 00283 class MovieLoader { 00284 public: 00285 MovieLoader() {} 00286 MovieLoader( const Url &url ); 00287 00289 bool checkLoaded() const; 00291 bool checkPlayable() const; 00293 bool checkPlaythroughOk() const; 00294 00296 void waitForLoaded() const; 00298 void waitForPlayable() const; 00300 void waitForPlaythroughOk() const; 00301 00303 const Url& getUrl() const { return mObj->mUrl; } 00304 00306 ::Movie getMovieHandle() const { return mObj->mMovie; } 00307 00309 ::Movie transferMovieHandle() const { mObj->mOwnsMovie = false; return mObj->mMovie; } 00310 00311 protected: 00312 void updateLoadState() const; 00313 00314 struct Obj { 00315 Obj( const Url &url ); 00316 ~Obj(); 00317 00318 mutable bool mOwnsMovie; 00319 ::Movie mMovie; 00320 Url mUrl; 00321 mutable bool mLoaded, mPlayable, mPlaythroughOK; 00322 }; 00323 00324 shared_ptr<Obj> mObj; 00325 00326 public: 00328 00329 typedef shared_ptr<Obj> MovieLoader::*unspecified_bool_type; 00330 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &MovieLoader::mObj; } 00331 void reset() { mObj.reset(); } 00333 }; 00334 00336 void startQuickTime(); 00338 extern int32_t getQuickTimeVersion(); 00340 extern std::string getQuickTimeVersionString(); 00341 00343 extern void quickTimeTask(); 00344 00345 class QuickTimeExc : public std::exception { 00346 }; 00347 00348 class QuickTimePathInvalidExc : public QuickTimeExc { 00349 }; 00350 00351 class QuickTimeFileInvalidExc : public QuickTimeExc { 00352 }; 00353 00354 class QuickTimeExcUrlInvalid : public QuickTimeExc { 00355 }; 00356 00357 class QuickTimeErrorLoadingExc : public QuickTimeExc { 00358 }; 00359 00360 class QuickTimeExcFft : public QuickTimeExc { 00361 }; 00362 00363 } /* namespace qtime */ } /* namespace cinder */ 00364 #endif // ! defined( __LP64__ )