view src/win32/AVIWrite.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 #include "stdafx.h"
2 #include <cstdio>
3 #include <cassert>
5 #include "AVIWrite.h"
6 #include "../common/System.h"
8 AVIWrite::AVIWrite()
9 {
10 m_failed = false;
11 m_file = NULL;
12 m_stream = NULL;
13 m_streamCompressed = NULL;
14 m_streamSound = NULL;
15 m_videoFrames = 0;
16 m_samplesSound = 0;
17 m_videoFramesTotal = 0;
18 m_samplesSoundTotal= 0;
19 m_totalBytes = 0;
20 m_segmentNumber = 0;
21 m_usePrevOptions = false;
22 m_pauseRecording = false;
24 AVIFileInit();
25 }
27 void AVIWrite::CleanUp()
28 {
29 if (m_streamSound)
30 {
31 AVIStreamClose(m_streamSound);
32 m_streamSound = NULL;
33 }
34 if (m_streamCompressed)
35 {
36 AVIStreamClose(m_streamCompressed);
37 m_streamCompressed = NULL;
38 }
39 if (m_stream)
40 {
41 AVIStreamClose(m_stream);
42 m_stream = NULL;
43 }
44 if (m_file)
45 {
46 AVIFileClose(m_file);
47 m_file = NULL;
48 }
49 }
51 AVIWrite::~AVIWrite()
52 {
53 CleanUp();
54 AVIFileExit();
55 }
57 void AVIWrite::SetVideoFormat(BITMAPINFOHEADER *bh)
58 {
59 // force size to 0x28 to avoid extra fields
60 memcpy(&m_bitmap, bh, 0x28);
61 }
63 void AVIWrite::SetSoundFormat(WAVEFORMATEX *format)
64 {
65 memcpy(&m_soundFormat, format, sizeof(WAVEFORMATEX));
66 ZeroMemory(&m_soundHeader, sizeof(AVISTREAMINFO));
67 // setup the sound stream header
68 m_soundHeader.fccType = streamtypeAUDIO;
69 m_soundHeader.dwQuality = (DWORD)-1;
70 m_soundHeader.dwScale = format->nBlockAlign;
71 m_soundHeader.dwInitialFrames = 1;
72 m_soundHeader.dwRate = format->nAvgBytesPerSec;
73 m_soundHeader.dwSampleSize = format->nBlockAlign;
75 // create the sound stream
76 if (FAILED(AVIFileCreateStream(m_file, &m_streamSound, &m_soundHeader)))
77 {
78 m_failed = true;
79 return;
80 }
82 // setup the sound stream format
83 if (FAILED(AVIStreamSetFormat(m_streamSound, 0, (void *)&m_soundFormat,
84 sizeof(WAVEFORMATEX))))
85 {
86 m_failed = true;
87 return;
88 }
89 }
91 bool AVIWrite::Open(const char *filename)
92 {
93 // this is only here because AVIFileOpen doesn't seem to do it for us
94 FILE*fd = fopen(filename, "wb");
95 if (!fd)
96 {
97 systemMessage(0, "AVI recording failed: file is read-only or already in use.");
98 m_failed = true;
99 return false;
100 }
101 fclose(fd);
103 // create the AVI file
104 if (FAILED(AVIFileOpen(&m_file,
105 filename,
106 OF_WRITE | OF_CREATE,
107 NULL)))
108 {
109 m_failed = true;
110 return false;
111 }
112 // setup the video stream information
113 ZeroMemory(&m_header, sizeof(AVISTREAMINFO));
114 m_header.fccType = streamtypeVIDEO;
115 m_header.dwScale = 1;
116 m_header.dwRate = m_fps;
117 m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage;
119 // create the video stream
120 if (FAILED(AVIFileCreateStream(m_file,
121 &m_stream,
122 &m_header)))
123 {
124 m_failed = true;
125 return false;
126 }
128 if (!m_usePrevOptions)
129 {
130 ZeroMemory(&m_options, sizeof(AVICOMPRESSOPTIONS));
131 m_arrayOptions[0] = &m_options;
133 // call the dialog to setup the compress options to be used
134 if (!AVISaveOptions(AfxGetApp()->m_pMainWnd->GetSafeHwnd(), 0, 1, &m_stream, m_arrayOptions))
135 {
136 m_failed = true;
137 return false;
138 }
139 }
141 // create the compressed stream
142 if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL)))
143 {
144 m_failed = true;
145 return false;
146 }
148 // setup the video stream format
149 if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0,
150 &m_bitmap,
151 m_bitmap.biSize +
152 m_bitmap.biClrUsed * sizeof(RGBQUAD))))
153 {
154 m_failed = true;
155 return false;
156 }
158 m_videoFrames = 0;
159 m_samplesSound = 0;
160 m_totalBytes = 0;
161 if (!m_usePrevOptions) {
162 m_videoFramesTotal = 0;
163 m_samplesSoundTotal = 0;
164 }
166 strncpy(m_aviFileName, filename, MAX_PATH);
167 strncpy(m_aviBaseName, filename, MAX_PATH);
168 m_aviFileName[MAX_PATH - 1] = '\0';
169 m_aviBaseName[MAX_PATH - 1] = '\0';
170 char *dot = strrchr(m_aviBaseName, '.');
171 if (dot && dot > strrchr(m_aviBaseName, '/') && dot > strrchr(m_aviBaseName, '\\'))
172 {
173 strcpy(m_aviExtension, dot);
174 dot[0] = '\0';
175 }
177 return true;
178 }
180 bool AVIWrite::AddSound(const u8 *sound, int len)
181 {
182 LONG byteBuffer;
184 // return if we failed somewhere already
185 if (m_failed)
186 return false;
188 assert(len % m_soundFormat.nBlockAlign == 0);
189 int samples = len / m_soundFormat.nBlockAlign;
191 if (FAILED(AVIStreamWrite(m_streamSound,
192 m_samplesSound,
193 samples,
194 (LPVOID)sound,
195 len,
196 0,
197 NULL,
198 &byteBuffer)))
199 {
200 m_failed = true;
201 return false;
202 }
203 m_samplesSound += samples;
204 m_samplesSoundTotal += samples;
205 m_totalBytes += byteBuffer;
206 return true;
207 }
209 bool AVIWrite::NextSegment()
210 {
211 char avi_fname[MAX_PATH];
212 strcpy(avi_fname, m_aviBaseName);
213 char avi_fname_temp[MAX_PATH];
214 sprintf(avi_fname_temp, "%s_part%d%s", avi_fname, m_segmentNumber+2, m_aviExtension);
215 m_segmentNumber++;
217 CleanUp();
219 m_usePrevOptions = true;
220 bool ret = Open(avi_fname_temp);
221 m_usePrevOptions = false;
222 strcpy(m_aviBaseName, avi_fname);
224 return ret;
225 }
227 bool AVIWrite::AddFrame(const u8 *bmp)
228 {
229 LONG byteBuffer;
231 if (m_failed)
232 return false;
234 // write the frame to the video stream
235 if (FAILED(AVIStreamWrite(m_streamCompressed,
236 m_videoFrames,
237 1,
238 (LPVOID)bmp,
239 m_bitmap.biSizeImage,
240 AVIIF_KEYFRAME,
241 NULL,
242 &byteBuffer)))
243 {
244 m_failed = true;
245 return false;
246 }
247 m_videoFrames++;
248 m_videoFramesTotal++;
249 m_totalBytes += byteBuffer;
251 // segment / split AVI when it's almost 2 GB (2000MB, to be precise)
252 if (!(m_videoFrames % 60) && m_totalBytes > 2097152000)
253 return NextSegment();
254 else
255 return true;
256 }
258 bool AVIWrite::IsSoundAdded()
259 {
260 return m_streamSound != NULL;
261 }
263 void AVIWrite::SetFPS(int f)
264 {
265 m_fps = f;
266 }
268 int AVIWrite::videoFrames()
269 {
270 return m_videoFramesTotal;
271 }
273 void AVIWrite::Pause(bool pause)
274 {
275 m_pauseRecording = pause;
276 }
278 bool AVIWrite::IsPaused()
279 {
280 return m_pauseRecording;