summaryrefslogtreecommitdiff
path: root/video/quicktime_recorder.h
blob: 85aef0a347c1c7f077a1663d837cf2ec7131d6a4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//----------------------------------------------------------------------------------------

#ifndef QUICKTIME_RECORDER_H
#define QUICKTIME_RECORDER_H

#ifdef _WIN32
#pragma once
#endif

//--------------------------------------------------------------------------------

#if defined( OSX )
	#include <quicktime/QTML.h>
	#include <quicktime/Movies.h>
	#include <quicktime/QuickTimeComponents.h>
#elif defined( WIN32 )
	#include "QTML.h"
	#include "Movies.h"
	#include "QuickTimeComponents.h"
#else
    #error "Quicktime encoding is not supported on this platform"
#endif

#include "video/ivideoservices.h"

#include "video_macros.h"
#include "quicktime_common.h"


// comment out to prevent logging of creation data
//#define LOG_ENCODER_OPERATIONS
//#define LOG_ENCODER_AUDIO_OPERATIONS

// comment out to log images of frames
//#define LOG_FRAMES_TO_TGA
//#define LOG_FRAMES_TO_TGA_INTERVAL   16

#if defined( LOG_ENCODER_OPERATIONS ) || defined( LOG_ENCODER_AUDIO_OPERATIONS ) ||  defined ( LOG_FRAMES_TO_TGA ) || defined ( ENABLE_EXTERNAL_ENCODER_LOGGING )
	#include <filesystem.h>
#endif



// ------------------------------------------------------------------------
// CQTVideoFileComposer
// Class to manages to creation of a video file from a series of
// supplied bitmap images.
//
// At this time, the time interval between frames must be the same for all
// frames of the movie
// ------------------------------------------------------------------------
class CQTVideoFileComposer
{
	public:
		static const CodecType		DEFAULT_CODEC = kH264CodecType;
		static const CodecQ			DEFAULT_ENCODE_QUALITY = codecNormalQuality;
		static const Fixed			DEFAULT_GAMMA = kQTUseSourceGammaLevel;
		
		static const int			MIN_AUDIO_SAMPLE_GROUP_SIZE = 64;
		static const int			MAX_AUDIO_GROUP_SIZE_IN_SEC = 4;
		
		CQTVideoFileComposer();
		~CQTVideoFileComposer();

		bool				CreateNewMovie( const char *fileName, bool hasAudio );

		bool				SetMovieVideoParameters( int width, int height, VideoFrameRate_t movieFPS, VideoEncodeCodec_t desiredCodec, int encodeQuality, VideoEncodeGamma_t gamma );
		bool				SetMovieSourceImageParameters( int srcWidth, int srcHeight, VideoEncodeSourceFormat_t srcImageFormat );
		bool				SetMovieSourceAudioParameters( AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0, AudioEncodeOptions_t audioOptions = AudioEncodeOptions::NO_AUDIO_OPTIONS, int audioSampleGroupSize = 0 );

		bool				AppendVideoFrameToMedia( void *ImageBuffer, int strideAdjustBytes );
		bool				AppendAudioSamplesToMedia( void *soundBuffer, size_t bufferSize );
	
		bool				AbortMovie();
		bool				FinishMovie( bool SaveMovieToDisk = true );
		
		size_t				GetFrameBufferSize()						{ return m_SrcImageSize; }
		
		bool				CheckFilename( const char *filename );
	
		void				SetResult( VideoResult_t status );
		VideoResult_t		GetResult();
		bool				IsReadyToRecord();
		
		int					GetFrameCount()			{ return m_nFramesAdded; }
		int					GetSampleCount()		{ return m_nSamplesAdded; }
		
		VideoFrameRate_t	GetFPS()				{ return m_MovieRecordFPS; }
		int					GetSampleRate()			{ return m_AudioSourceFrequency; }
		
		bool				HasAudio()				{ return m_bHasAudioTrack; }
	
#ifdef ENABLE_EXTERNAL_ENCODER_LOGGING
		bool				LogMessage(  const char *msg );
#endif
	
	private:
		enum AudioGrouping_t
		{
			AG_NONE = 0,
			AG_FIXED_SIZE,
			AG_PER_FRAME
		};
	
		// disable copy constructor and copy assignment
		CQTVideoFileComposer( CQTVideoFileComposer &rhs );
		CQTVideoFileComposer&	operator= ( CQTVideoFileComposer &rhs );
		
		bool				CheckForReadyness();
		bool				BeginMovieCreation();
		bool				EndMovieCreation( bool saveMovieData );

		bool				SyncAndFlushAudio();
		int					GetAudioSampleCountThruFrame( int frameNo );

		VideoResult_t		m_LastResult;

		// Current State of Movie Creation;
		bool				m_bMovieCreated;
		bool				m_bHasAudioTrack;
		
		bool				m_bMovieConfigured;
		bool				m_bSourceImagesConfigured;
		bool				m_bSourceAudioConfigured;
		
		bool				m_bComposingMovie;
		bool				m_bMovieCompleted;
		
		int					m_nFramesAdded;
		
		int					m_nAudioFramesAdded;
		int					m_nSamplesAdded;
		int					m_nSamplesAddedToMedia;

		// parameters of the movie to create;		
		int					m_MovieFrameWidth;
		int					m_MovieFrameHeight;
		
		VideoFrameRate_t	m_MovieRecordFPS;
		TimeScale			m_MovieTimeScale;
		TimeValue			m_DurationPerFrame;

		// Audio recording options		
		AudioEncodeOptions_t m_AudioOptions;					// Option flags specifed by user
		AudioGrouping_t		m_SampleGrouping;					// Mode to group samples
		int 				m_nAudioSampleGroupSize;			// number of samples to collect per sample group
		
		int					m_AudioSourceFrequency;				// Source frequency of the supplied audio
		int					m_AudioBytesPerSample;

		bool				m_bBufferSourceAudio;
		bool				m_bLimitAudioDurationToVideo;
		
		byte			   *m_srcAudioBuffer;					// buffer to hold audio samples
		size_t				m_srcAudioBufferSize;
		size_t				m_srcAudioBufferCurrentSize;
		
		int					m_AudioSampleFrameCounter;			

		char			   *m_FileName;

		int					m_SrcImageWidth;
		int					m_SrcImageHeight;
		size_t				m_SrcImageSize;
		int					m_ScrImageMaxCompressedSize;
		byte			   *m_SrcImageBuffer;
		Handle				m_SrcImageCompressedBuffer;
		OSType				m_SrcPixelFormat;
		int					m_SrcBytesPerPixel;
		
		OSType				m_GWorldPixelFormat;		
		int					m_GWorldBytesPerPixel;
		int					m_GWorldImageWidth;
		int					m_GWorldImageHeight;

		Handle				m_srcSoundDescription;


		// parameters used by QuickTime
		CodecQ              m_EncodeQuality;
		CodecType			m_VideoCodecToUse;
		Fixed				m_EncodeGamma;
		
		Rect				m_GWorldRect;
		GWorldPtr			m_theSrcGWorld;
		
//		short				m_ResRefNum;			// QuickTime Movie Resource Ref number

		Handle				m_MovieFileDataRef;
		OSType				m_MovieFileDataRefType;
		DataHandler			m_MovieFileDataHandler;

		
		Movie				m_theMovie;
		Track				m_theVideoTrack;
		Track				m_theAudioTrack;
		Media				m_theVideoMedia;
		Media				m_theAudioMedia;
		
#ifdef LOG_ENCODER_OPERATIONS
		FileHandle_t		m_LogFile;
		void				LogMsg( PRINTF_FORMAT_STRING const char* pMsg, ... );
#endif	

#ifdef LOG_FRAMES_TO_TGA
		char				m_TGAFileBase[MAX_PATH];
#endif		
		

};



class CQuickTimeVideoRecorder : public IVideoRecorder
{
	public:
								CQuickTimeVideoRecorder();
							   ~CQuickTimeVideoRecorder();

		virtual bool			EstimateMovieFileSize( size_t *pEstSize, int movieWidth, int movieHeight, VideoFrameRate_t movieFps, float movieDuration, VideoEncodeCodec_t theCodec, int videoQuality,  AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0 );

		virtual bool			CreateNewMovieFile( const char *pFilename, bool hasAudioTrack = false );
		
		virtual bool			SetMovieVideoParameters( VideoEncodeCodec_t theCodec, int videoQuality,  int movieFrameWidth, int movieFrameHeight, VideoFrameRate_t movieFPS, VideoEncodeGamma_t gamma = VideoEncodeGamma::NO_GAMMA_ADJUST );
		virtual bool			SetMovieSourceImageParameters( VideoEncodeSourceFormat_t srcImageFormat, int imgWidth, int imgHeight );
		virtual bool			SetMovieSourceAudioParameters( AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0, AudioEncodeOptions_t audioOptions = AudioEncodeOptions::NO_AUDIO_OPTIONS, int audioSampleGroupSize = 0 );
		
		virtual bool			IsReadyToRecord();
		virtual VideoResult_t	GetLastResult();
		
		virtual bool			AppendVideoFrame( void *pFrameBuffer, int nStrideAdjustBytes = 0 );
		virtual bool			AppendAudioSamples( void *pSampleBuffer, size_t sampleSize );
		
		virtual int				GetFrameCount();
		virtual int				GetSampleCount();
		virtual int				GetSampleRate();
		virtual VideoFrameRate_t GetFPS();
		
		virtual bool			AbortMovie();
		virtual bool			FinishMovie( bool SaveMovieToDisk = true );

#ifdef ENABLE_EXTERNAL_ENCODER_LOGGING
		virtual bool            LogMessage(  const char *msg );
#endif
					   
	private:
		
		void					SetResult( VideoResult_t resultCode );
		
		float					GetDataRate( int quality, int width, int height );
		
		CQTVideoFileComposer	*m_pEncoder;
		VideoResult_t			m_LastResult;
		bool					m_bHasAudio;
		bool					m_bMovieFinished;
		
};



#endif // QUICKTIME_RECORDER_H