annotate 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
rev   line source
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 }