rlm@1: #include "stdafx.h" rlm@1: #include rlm@1: #include rlm@1: rlm@1: #include "AVIWrite.h" rlm@1: #include "../common/System.h" rlm@1: rlm@1: AVIWrite::AVIWrite() rlm@1: { rlm@1: m_failed = false; rlm@1: m_file = NULL; rlm@1: m_stream = NULL; rlm@1: m_streamCompressed = NULL; rlm@1: m_streamSound = NULL; rlm@1: m_videoFrames = 0; rlm@1: m_samplesSound = 0; rlm@1: m_videoFramesTotal = 0; rlm@1: m_samplesSoundTotal= 0; rlm@1: m_totalBytes = 0; rlm@1: m_segmentNumber = 0; rlm@1: m_usePrevOptions = false; rlm@1: m_pauseRecording = false; rlm@1: rlm@1: AVIFileInit(); rlm@1: } rlm@1: rlm@1: void AVIWrite::CleanUp() rlm@1: { rlm@1: if (m_streamSound) rlm@1: { rlm@1: AVIStreamClose(m_streamSound); rlm@1: m_streamSound = NULL; rlm@1: } rlm@1: if (m_streamCompressed) rlm@1: { rlm@1: AVIStreamClose(m_streamCompressed); rlm@1: m_streamCompressed = NULL; rlm@1: } rlm@1: if (m_stream) rlm@1: { rlm@1: AVIStreamClose(m_stream); rlm@1: m_stream = NULL; rlm@1: } rlm@1: if (m_file) rlm@1: { rlm@1: AVIFileClose(m_file); rlm@1: m_file = NULL; rlm@1: } rlm@1: } rlm@1: rlm@1: AVIWrite::~AVIWrite() rlm@1: { rlm@1: CleanUp(); rlm@1: AVIFileExit(); rlm@1: } rlm@1: rlm@1: void AVIWrite::SetVideoFormat(BITMAPINFOHEADER *bh) rlm@1: { rlm@1: // force size to 0x28 to avoid extra fields rlm@1: memcpy(&m_bitmap, bh, 0x28); rlm@1: } rlm@1: rlm@1: void AVIWrite::SetSoundFormat(WAVEFORMATEX *format) rlm@1: { rlm@1: memcpy(&m_soundFormat, format, sizeof(WAVEFORMATEX)); rlm@1: ZeroMemory(&m_soundHeader, sizeof(AVISTREAMINFO)); rlm@1: // setup the sound stream header rlm@1: m_soundHeader.fccType = streamtypeAUDIO; rlm@1: m_soundHeader.dwQuality = (DWORD)-1; rlm@1: m_soundHeader.dwScale = format->nBlockAlign; rlm@1: m_soundHeader.dwInitialFrames = 1; rlm@1: m_soundHeader.dwRate = format->nAvgBytesPerSec; rlm@1: m_soundHeader.dwSampleSize = format->nBlockAlign; rlm@1: rlm@1: // create the sound stream rlm@1: if (FAILED(AVIFileCreateStream(m_file, &m_streamSound, &m_soundHeader))) rlm@1: { rlm@1: m_failed = true; rlm@1: return; rlm@1: } rlm@1: rlm@1: // setup the sound stream format rlm@1: if (FAILED(AVIStreamSetFormat(m_streamSound, 0, (void *)&m_soundFormat, rlm@1: sizeof(WAVEFORMATEX)))) rlm@1: { rlm@1: m_failed = true; rlm@1: return; rlm@1: } rlm@1: } rlm@1: rlm@1: bool AVIWrite::Open(const char *filename) rlm@1: { rlm@1: // this is only here because AVIFileOpen doesn't seem to do it for us rlm@1: FILE*fd = fopen(filename, "wb"); rlm@1: if (!fd) rlm@1: { rlm@1: systemMessage(0, "AVI recording failed: file is read-only or already in use."); rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: fclose(fd); rlm@1: rlm@1: // create the AVI file rlm@1: if (FAILED(AVIFileOpen(&m_file, rlm@1: filename, rlm@1: OF_WRITE | OF_CREATE, rlm@1: NULL))) rlm@1: { rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: // setup the video stream information rlm@1: ZeroMemory(&m_header, sizeof(AVISTREAMINFO)); rlm@1: m_header.fccType = streamtypeVIDEO; rlm@1: m_header.dwScale = 1; rlm@1: m_header.dwRate = m_fps; rlm@1: m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage; rlm@1: rlm@1: // create the video stream rlm@1: if (FAILED(AVIFileCreateStream(m_file, rlm@1: &m_stream, rlm@1: &m_header))) rlm@1: { rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (!m_usePrevOptions) rlm@1: { rlm@1: ZeroMemory(&m_options, sizeof(AVICOMPRESSOPTIONS)); rlm@1: m_arrayOptions[0] = &m_options; rlm@1: rlm@1: // call the dialog to setup the compress options to be used rlm@1: if (!AVISaveOptions(AfxGetApp()->m_pMainWnd->GetSafeHwnd(), 0, 1, &m_stream, m_arrayOptions)) rlm@1: { rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: } rlm@1: rlm@1: // create the compressed stream rlm@1: if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) rlm@1: { rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: rlm@1: // setup the video stream format rlm@1: if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, rlm@1: &m_bitmap, rlm@1: m_bitmap.biSize + rlm@1: m_bitmap.biClrUsed * sizeof(RGBQUAD)))) rlm@1: { rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: rlm@1: m_videoFrames = 0; rlm@1: m_samplesSound = 0; rlm@1: m_totalBytes = 0; rlm@1: if (!m_usePrevOptions) { rlm@1: m_videoFramesTotal = 0; rlm@1: m_samplesSoundTotal = 0; rlm@1: } rlm@1: rlm@1: strncpy(m_aviFileName, filename, MAX_PATH); rlm@1: strncpy(m_aviBaseName, filename, MAX_PATH); rlm@1: m_aviFileName[MAX_PATH - 1] = '\0'; rlm@1: m_aviBaseName[MAX_PATH - 1] = '\0'; rlm@1: char *dot = strrchr(m_aviBaseName, '.'); rlm@1: if (dot && dot > strrchr(m_aviBaseName, '/') && dot > strrchr(m_aviBaseName, '\\')) rlm@1: { rlm@1: strcpy(m_aviExtension, dot); rlm@1: dot[0] = '\0'; rlm@1: } rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool AVIWrite::AddSound(const u8 *sound, int len) rlm@1: { rlm@1: LONG byteBuffer; rlm@1: rlm@1: // return if we failed somewhere already rlm@1: if (m_failed) rlm@1: return false; rlm@1: rlm@1: assert(len % m_soundFormat.nBlockAlign == 0); rlm@1: int samples = len / m_soundFormat.nBlockAlign; rlm@1: rlm@1: if (FAILED(AVIStreamWrite(m_streamSound, rlm@1: m_samplesSound, rlm@1: samples, rlm@1: (LPVOID)sound, rlm@1: len, rlm@1: 0, rlm@1: NULL, rlm@1: &byteBuffer))) rlm@1: { rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: m_samplesSound += samples; rlm@1: m_samplesSoundTotal += samples; rlm@1: m_totalBytes += byteBuffer; rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool AVIWrite::NextSegment() rlm@1: { rlm@1: char avi_fname[MAX_PATH]; rlm@1: strcpy(avi_fname, m_aviBaseName); rlm@1: char avi_fname_temp[MAX_PATH]; rlm@1: sprintf(avi_fname_temp, "%s_part%d%s", avi_fname, m_segmentNumber+2, m_aviExtension); rlm@1: m_segmentNumber++; rlm@1: rlm@1: CleanUp(); rlm@1: rlm@1: m_usePrevOptions = true; rlm@1: bool ret = Open(avi_fname_temp); rlm@1: m_usePrevOptions = false; rlm@1: strcpy(m_aviBaseName, avi_fname); rlm@1: rlm@1: return ret; rlm@1: } rlm@1: rlm@1: bool AVIWrite::AddFrame(const u8 *bmp) rlm@1: { rlm@1: LONG byteBuffer; rlm@1: rlm@1: if (m_failed) rlm@1: return false; rlm@1: rlm@1: // write the frame to the video stream rlm@1: if (FAILED(AVIStreamWrite(m_streamCompressed, rlm@1: m_videoFrames, rlm@1: 1, rlm@1: (LPVOID)bmp, rlm@1: m_bitmap.biSizeImage, rlm@1: AVIIF_KEYFRAME, rlm@1: NULL, rlm@1: &byteBuffer))) rlm@1: { rlm@1: m_failed = true; rlm@1: return false; rlm@1: } rlm@1: m_videoFrames++; rlm@1: m_videoFramesTotal++; rlm@1: m_totalBytes += byteBuffer; rlm@1: rlm@1: // segment / split AVI when it's almost 2 GB (2000MB, to be precise) rlm@1: if (!(m_videoFrames % 60) && m_totalBytes > 2097152000) rlm@1: return NextSegment(); rlm@1: else rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool AVIWrite::IsSoundAdded() rlm@1: { rlm@1: return m_streamSound != NULL; rlm@1: } rlm@1: rlm@1: void AVIWrite::SetFPS(int f) rlm@1: { rlm@1: m_fps = f; rlm@1: } rlm@1: rlm@1: int AVIWrite::videoFrames() rlm@1: { rlm@1: return m_videoFramesTotal; rlm@1: } rlm@1: rlm@1: void AVIWrite::Pause(bool pause) rlm@1: { rlm@1: m_pauseRecording = pause; rlm@1: } rlm@1: rlm@1: bool AVIWrite::IsPaused() rlm@1: { rlm@1: return m_pauseRecording; rlm@1: }