Mercurial > vba-clojure
view src/win32/AVIWrite.cpp @ 5:8fe0c57e53d2
concentrating on lua first
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:39:40 -0600 |
parents | f9f4f1b99eed |
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 fields60 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 header68 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 stream76 if (FAILED(AVIFileCreateStream(m_file, &m_streamSound, &m_soundHeader)))77 {78 m_failed = true;79 return;80 }82 // setup the sound stream format83 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 us94 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 file104 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 information113 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 stream120 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 used134 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 stream142 if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL)))143 {144 m_failed = true;145 return false;146 }148 // setup the video stream format149 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 already185 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 stream235 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 else255 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;281 }