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 #include "cinder/Cinder.h" 00024 #include "cinder/qtime/QuickTime.h" 00025 #include "cinder/ImageIo.h" 00026 #include "cinder/Stream.h" 00027 00028 #include <string> 00029 00030 // These forward declarations prevent us from having to bring all of QuickTime into the global namespace in MSW 00032 #if defined( CINDER_MSW ) 00033 typedef struct ComponentInstanceRecord ComponentInstanceRecord; 00034 typedef ComponentInstanceRecord * ComponentInstance; 00035 typedef ComponentInstance DataHandler; 00036 typedef struct TrackType** Track; 00037 typedef struct MediaType** Media; 00038 typedef struct OpaqueICMCompressionSession* ICMCompressionSessionRef; 00039 typedef struct OpaqueICMCompressionSessionOptions* ICMCompressionSessionOptionsRef; 00040 typedef const struct OpaqueICMEncodedFrame* ICMEncodedFrameRef; 00041 typedef signed long OSStatus; 00042 typedef unsigned long CodecType; 00043 typedef unsigned long ICMCompressionPassModeFlags; 00044 #else 00045 #include <QuickTime/QuickTime.h> 00046 #include <QuickTime/ImageCompression.h> 00047 #endif // defined( CINDER_MSW ) 00048 00049 00050 namespace cinder { namespace qtime { 00051 00052 class MovieWriter { 00053 struct Obj; 00054 00055 public: 00057 class Format { 00058 public: 00059 Format(); 00060 Format( uint32_t codec, float quality ); 00061 Format( const ICMCompressionSessionOptionsRef settings, uint32_t codec, float quality, float frameRate, bool enableMultiPass ); 00062 Format( const Format &format ); 00063 ~Format(); 00064 00065 const Format& operator=( const Format &format ); 00066 00068 uint32_t getCodec() const { return mCodec; } 00070 Format& setCodec( uint32_t codec ) { mCodec = codec; return *this; } 00072 Format& setQuality( float quality ); 00074 float getDefaultDuration() const { return mDefaultTime; } 00076 Format& setDefaultDuration( float defaultDuration ) { mDefaultTime = defaultDuration; return *this; } 00078 long getTimeScale() const { return mTimeBase; } 00080 Format& setTimeScale( long timeScale ) { mTimeBase = timeScale; return *this; } 00082 float getGamma() const { return mGamma; } 00084 Format& setGamma( float gamma ) { mGamma = gamma; return *this; } 00086 Format& enableTemporal( bool enable = true ); 00088 Format& enableReordering( bool enable = true ); 00090 Format& setMaxKeyFrameRate( int32_t rate ); 00092 Format& enableFrameTimeChanges( bool enable = true ); 00094 bool isMultiPass() const { return mEnableMultiPass; } 00096 Format& enableMultiPass( bool enable = true ) { mEnableMultiPass = enable; return *this; } 00097 00098 private: 00099 void initDefaults(); 00100 00101 uint32_t mCodec; 00102 long mTimeBase; 00103 float mDefaultTime; 00104 float mGamma; 00105 bool mEnableMultiPass; 00106 00107 ICMCompressionSessionOptionsRef mOptions; 00108 00109 friend class MovieWriter; 00110 friend struct Obj; 00111 }; 00112 00113 00114 MovieWriter() {} 00115 MovieWriter( const std::string &path, int32_t width, int32_t height, const Format &format = Format::Format() ); 00116 00118 float getDefaultDuration() const { return mObj->mFormat.mDefaultTime; } 00120 int32_t getWidth() const { return mObj->mWidth; } 00122 int32_t getHeight() const { return mObj->mHeight; } 00124 Vec2i getSize() const { return Vec2i( getWidth(), getHeight() ); } 00126 float getAspectRatio() const { return getWidth() / (float)getHeight(); } 00128 Area getBounds() const { return Area( 0, 0, getWidth(), getHeight() ); } 00129 00131 const Format& getFormat() const { return mObj->mFormat; } 00132 00135 static bool getUserCompressionSettings( Format *result, ImageSourceRef previewImage = ImageSourceRef() ); 00136 00139 void addFrame( const ImageSourceRef &imageSource, float duration = -1.0f ) { mObj->addFrame( imageSource, duration ); } 00140 00142 uint32_t getNumFrames() const { return mObj->mNumFrames; } 00143 00145 void finish() { mObj->finish(); } 00146 00147 enum { CODEC_H264 = 'avc1', CODEC_JPEG = 'jpeg', CODEC_MP4 = 'mp4v', CODEC_PNG = 'png ', CODEC_RAW = 'raw ', CODEC_ANIMATION = 'rle ' }; 00148 00149 private: 00151 struct Obj { 00152 Obj( const std::string &path, int32_t width, int32_t height, const Format &format ); 00153 ~Obj(); 00154 00155 void addFrame( const ImageSourceRef &imageSource, float duration ); 00156 void createCompressionSession(); 00157 void finish(); 00158 00159 static OSStatus encodedFrameOutputCallback( void *refCon, ::ICMCompressionSessionRef session, OSStatus err, ICMEncodedFrameRef encodedFrame, void *reserved ); 00160 00161 ::Movie mMovie; 00162 ::DataHandler mDataHandler; 00163 ::Track mTrack; 00164 ::Media mMedia; 00165 ::ICMCompressionSessionRef mCompressionSession; 00166 ::ICMCompressionPassModeFlags mMultiPassModeFlags; 00167 std::string mPath; 00168 uint32_t mNumFrames; 00169 int64_t mCurrentTimeValue; 00170 00171 int32_t mWidth, mHeight; 00172 Format mFormat; 00173 bool mRequestedMultiPass, mDoingMultiPass, mFinished; 00174 00175 IoStreamRef mMultiPassFrameCache; 00176 00177 std::vector<std::pair<int64_t,int64_t> > mFrameTimes; 00178 }; 00180 00181 shared_ptr<Obj> mObj; 00182 00183 public: 00185 00186 typedef shared_ptr<Obj> MovieWriter::*unspecified_bool_type; 00187 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &MovieWriter::mObj; } 00188 void reset() { mObj.reset(); } 00190 }; 00191 00192 class MovieWriterExc : public Exception { 00193 }; 00194 class MovieWriterExcInvalidPath : public MovieWriterExc { 00195 }; 00196 class MovieWriterExcFrameEncode : public MovieWriterExc { 00197 }; 00198 class MovieWriterExcAlreadyFinished : public MovieWriterExc { 00199 }; 00200 00201 } } // namespace cinder::qtime