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