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