mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-03-28 15:59:40 -06:00
248 lines
4.9 KiB
C++
248 lines
4.9 KiB
C++
#include "..\ht.h"
|
|
#include <windowsx.h>
|
|
#include <memory.h>
|
|
#include <mmsystem.h>
|
|
#include <time.h>
|
|
|
|
AviRecorder *gpavir;
|
|
|
|
AviRecorder::AviRecorder()
|
|
{
|
|
m_pavif = NULL;
|
|
m_pstmVideo = NULL;
|
|
m_pstmAudio = NULL;
|
|
m_pbmFlip = NULL;
|
|
m_ptbmPointer = NULL;
|
|
m_nSample = 0;
|
|
m_fAudioReady = false;
|
|
}
|
|
|
|
AviRecorder::~AviRecorder()
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
bool AviRecorder::Start(int cx, int cy, char *pszFn)
|
|
{
|
|
#ifndef DEV_BUILD
|
|
// Don't let mortals record avis
|
|
|
|
return false;
|
|
#endif
|
|
|
|
#if 1
|
|
// Modify cx & cy to be 4 by 3 for NTSC video,
|
|
// which is what Microsoft Movie Maker makes.
|
|
|
|
if (cx > cy) {
|
|
int cyT = cx * 3 / 4;
|
|
if (cyT < cy) {
|
|
cx = cy * 4 / 3;
|
|
} else {
|
|
cy = cyT;
|
|
}
|
|
} else {
|
|
int cxT = cy * 4 / 3;
|
|
if (cxT < cx) {
|
|
cy = cx * 3 / 4;
|
|
} else {
|
|
cx = cxT;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Now dword align the dst, for Windows sake
|
|
|
|
cx = (cx + 3) & ~3;
|
|
|
|
// Create a temp buffer that we'll use for flipping the dib since it needs to
|
|
// be upside down for windows.
|
|
|
|
m_pbmFlip = CreateDibBitmap(NULL, cx, cy);
|
|
if (m_pbmFlip == NULL)
|
|
return false;
|
|
|
|
// Init
|
|
|
|
m_ptbmPointer = LoadTBitmap("arrow5.tbm");
|
|
AVIFileInit();
|
|
|
|
// Create filename
|
|
|
|
if (pszFn == NULL) {
|
|
char szFn[MAX_PATH];
|
|
strcpy(szFn, "c:\\ht.avi");
|
|
pszFn = szFn;
|
|
}
|
|
|
|
// Open AVI file
|
|
|
|
HRESULT hr = AVIFileOpen(&m_pavif, pszFn, OF_CREATE | OF_WRITE, NULL);
|
|
if (hr != AVIERR_OK)
|
|
return false;
|
|
|
|
// Create the video streams if they don't exist
|
|
|
|
AVISTREAMINFO stmInfo;
|
|
memset(&stmInfo, 0, sizeof(stmInfo));
|
|
stmInfo.fccType = streamtypeVIDEO;
|
|
stmInfo.fccHandler = 0; // mmioFOURCC('M','S','V','C');
|
|
stmInfo.dwScale = 2;
|
|
stmInfo.dwRate = 25;
|
|
stmInfo.dwSuggestedBufferSize = cx * cy;
|
|
stmInfo.dwQuality = 0; // 10000;
|
|
SetRect(&stmInfo.rcFrame, 0, 0, cx, cy);
|
|
|
|
// Create video stream
|
|
|
|
if (m_pstmVideo == NULL) {
|
|
hr = AVIFileCreateStream(m_pavif, &m_pstmVideo, &stmInfo);
|
|
if (hr != AVIERR_OK)
|
|
return false;
|
|
}
|
|
|
|
// Set the stream format
|
|
|
|
struct Header {
|
|
BITMAPINFOHEADER bih;
|
|
RGBQUAD argbqPal[256];
|
|
};
|
|
|
|
Header hdr;
|
|
memset(&hdr, 0, sizeof(hdr));
|
|
hdr.bih.biSize = sizeof(hdr.bih);
|
|
hdr.bih.biWidth = cx;
|
|
hdr.bih.biHeight = cy;
|
|
hdr.bih.biPlanes = 1;
|
|
hdr.bih.biBitCount = 8;
|
|
hdr.bih.biCompression = BI_RGB;
|
|
hdr.bih.biClrUsed = 256;
|
|
|
|
// Get the palette
|
|
|
|
gpdisp->GetWindowsPalette(hdr.argbqPal);
|
|
|
|
// Set the format
|
|
|
|
hr = AVIStreamSetFormat(m_pstmVideo, 0, &hdr, sizeof(hdr));
|
|
if (hr != AVIERR_OK)
|
|
return false;
|
|
|
|
// When recording started, useful for keeping video in sync
|
|
|
|
m_tStart = HostGetTickCount();
|
|
|
|
// Now create the audio stream
|
|
|
|
memset(&stmInfo, 0, sizeof(stmInfo));
|
|
stmInfo.fccType = streamtypeAUDIO;
|
|
stmInfo.fccHandler = 0;
|
|
stmInfo.dwScale = 1;
|
|
stmInfo.dwRate = 8000;
|
|
|
|
// Create audio stream
|
|
|
|
if (m_pstmAudio == NULL) {
|
|
hr = AVIFileCreateStream(m_pavif, &m_pstmAudio, &stmInfo);
|
|
if (hr != AVIERR_OK)
|
|
return false;
|
|
}
|
|
|
|
// Set the audio format
|
|
|
|
WAVEFORMATEX fmt;
|
|
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
|
fmt.nChannels = 1;
|
|
fmt.nSamplesPerSec = 8000;
|
|
fmt.nAvgBytesPerSec = 8000;
|
|
fmt.nBlockAlign = 1;
|
|
fmt.wBitsPerSample = 8;
|
|
fmt.cbSize = 0;
|
|
|
|
// Set the format
|
|
|
|
hr = AVIStreamSetFormat(m_pstmAudio, 0, &fmt, sizeof(fmt));
|
|
if (hr != AVIERR_OK)
|
|
return false;
|
|
|
|
// Now we can allow the audio thread to call
|
|
|
|
m_fAudioReady = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
void AviRecorder::Stop()
|
|
{
|
|
m_fAudioReady = false;
|
|
|
|
if (m_pstmVideo != NULL) {
|
|
AVIStreamClose(m_pstmVideo);
|
|
m_pstmVideo = NULL;
|
|
}
|
|
|
|
if (m_pstmAudio != NULL) {
|
|
AVIStreamClose(m_pstmAudio);
|
|
m_pstmAudio = NULL;
|
|
}
|
|
|
|
if (m_pavif != NULL) {
|
|
AVIFileClose(m_pavif);
|
|
m_pavif = NULL;
|
|
}
|
|
|
|
AVIFileExit();
|
|
|
|
m_nSample = 0;
|
|
delete m_pbmFlip;
|
|
m_pbmFlip = NULL;
|
|
delete m_ptbmPointer;
|
|
m_ptbmPointer = NULL;
|
|
}
|
|
|
|
void AviRecorder::AddFrame(DibBitmap *pbm)
|
|
{
|
|
// Find the center of the flip dib
|
|
|
|
Size sizSrc;
|
|
pbm->GetSize(&sizSrc);
|
|
Size sizDst;
|
|
m_pbmFlip->GetSize(&sizDst);
|
|
int xDst = (sizDst.cx - sizSrc.cx) / 2;
|
|
int yDst = (sizDst.cy - sizSrc.cy) / 2;
|
|
int cbRowDst = m_pbmFlip->GetRowBytes();
|
|
int cbRowSrc = pbm->GetRowBytes();
|
|
|
|
// Flip the dib for Windows' sake into this spot
|
|
|
|
m_pbmFlip->Clear(GetColor(kiclrBlack));
|
|
byte *pbSrc = pbm->GetBits();
|
|
byte *pbDst = m_pbmFlip->GetBits();
|
|
for (int y = 0; y < sizSrc.cy; y++)
|
|
memcpy(&pbDst[(yDst + y) * cbRowDst + xDst], &pbSrc[(sizSrc.cy - y - 1) * cbRowSrc], cbRowSrc);
|
|
|
|
// Take out for screenshot purposes
|
|
// Point a pointer in there to represent where the mouse / stylus is
|
|
|
|
Size sizT;
|
|
m_ptbmPointer->GetSize(&sizT);
|
|
int xT = xDst + gxPenLast - 5;
|
|
int yT = yDst + sizSrc.cy - gyPenLast - (sizT.cy - 5);
|
|
m_ptbmPointer->BltTo(m_pbmFlip, xT, yT, GetKeyState(VK_LBUTTON) < 0 ? kside2 : ksideNeutral, NULL);
|
|
|
|
// Write to the video stream
|
|
|
|
int nFrame = (HostGetTickCount() - m_tStart) / 8;
|
|
AVIStreamWrite(m_pstmVideo, nFrame, 1, pbDst, sizDst.cx * sizDst.cy, 0, NULL, NULL);
|
|
}
|
|
|
|
void AviRecorder::AddAudio(byte *pb8Unsigned, dword cb)
|
|
{
|
|
if (!m_fAudioReady)
|
|
return;
|
|
|
|
// Write to the audio stream
|
|
|
|
AVIStreamWrite(m_pstmAudio, m_nSample, cb, pb8Unsigned, cb, 0, NULL, NULL);
|
|
m_nSample += cb;
|
|
} |