mirror of https://github.com/PCSX2/pcsx2.git
485 lines
14 KiB
C++
485 lines
14 KiB
C++
#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame.
|
|
|
|
#include <string>
|
|
using namespace std;
|
|
|
|
#include <memory.h>
|
|
#include <mmsystem.h>
|
|
#include <vfw.h>
|
|
|
|
BOOL AVI_Init()
|
|
{
|
|
/* first let's make sure we are running on 1.1 */
|
|
WORD wVer = HIWORD(VideoForWindowsVersion());
|
|
if (wVer < 0x010a){
|
|
/* oops, we are too old, blow out of here */
|
|
//MessageBeep(MB_ICONHAND);
|
|
MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP);
|
|
return FALSE;
|
|
}
|
|
|
|
AVIFileInit();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename)
|
|
{
|
|
HRESULT hr = AVIFileOpen(pfile, // returned file pointer
|
|
filename, // file name
|
|
OF_WRITE | OF_CREATE, // mode to open file with
|
|
NULL); // use handler determined
|
|
// from file extension....
|
|
if (hr != AVIERR_OK)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD getFOURCC(const char* value)
|
|
{
|
|
if(_stricmp(value, "DIB") == 0)
|
|
{
|
|
return mmioFOURCC(value[0],value[1],value[2],' ');
|
|
}
|
|
else if((_stricmp(value, "CVID") == 0)
|
|
|| (_stricmp(value, "IV32") == 0)
|
|
|| (_stricmp(value, "MSVC") == 0)
|
|
|| (_stricmp(value, "IV50") == 0))
|
|
{
|
|
return mmioFOURCC(value[0],value[1],value[2],value[3]);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Fill in the header for the video stream....
|
|
// The video stream will run in rate ths of a second....
|
|
BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second
|
|
unsigned long buffersize, int rectwidth, int rectheight,
|
|
const char* _compressor)
|
|
{
|
|
AVISTREAMINFO strhdr;
|
|
memset(&strhdr, 0, sizeof(strhdr));
|
|
strhdr.fccType = streamtypeVIDEO;// stream type
|
|
strhdr.fccHandler = getFOURCC(_compressor);
|
|
//strhdr.fccHandler = 0; // no compression!
|
|
//strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed
|
|
//strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak
|
|
//strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2
|
|
//strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1
|
|
//strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0
|
|
//strhdr.dwFlags = AVISTREAMINFO_DISABLED;
|
|
//strhdr.dwCaps =
|
|
//strhdr.wPriority =
|
|
//strhdr.wLanguage =
|
|
strhdr.dwScale = 1;
|
|
strhdr.dwRate = rate; // rate fps
|
|
//strhdr.dwStart =
|
|
//strhdr.dwLength =
|
|
//strhdr.dwInitialFrames =
|
|
strhdr.dwSuggestedBufferSize = buffersize;
|
|
strhdr.dwQuality = -1; // use the default
|
|
//strhdr.dwSampleSize =
|
|
SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream
|
|
(int) rectwidth,
|
|
(int) rectheight);
|
|
//strhdr.dwEditCount =
|
|
//strhdr.dwFormatChangeCount =
|
|
//strcpy(strhdr.szName, "Full Frames (Uncompressed)");
|
|
|
|
// And create the stream;
|
|
HRESULT hr = AVIFileCreateStream(pfile, // file pointer
|
|
ps, // returned stream pointer
|
|
&strhdr); // stream header
|
|
if (hr != AVIERR_OK) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
string getFOURCCVAsString(DWORD value)
|
|
{
|
|
string returnValue = "";
|
|
if( value == 0 )
|
|
return returnValue;
|
|
|
|
DWORD ch0 = value & 0x000000FF;
|
|
returnValue.push_back((char) ch0);
|
|
DWORD ch1 = (value & 0x0000FF00)>>8;
|
|
returnValue.push_back((char) ch1);
|
|
DWORD ch2 = (value & 0x00FF0000)>>16;
|
|
returnValue.push_back((char) ch2);
|
|
DWORD ch3 = (value & 0xFF000000)>>24;
|
|
returnValue.push_back((char) ch3);
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts)
|
|
{
|
|
char tmp[255];
|
|
string returnValue = "Dump of AVICOMPRESSOPTIONS\n";
|
|
|
|
returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n";
|
|
returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n";
|
|
|
|
_snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery);
|
|
returnValue += tmp;
|
|
|
|
_snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality);
|
|
returnValue += tmp;
|
|
|
|
_snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond);
|
|
returnValue += tmp;
|
|
|
|
if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");}
|
|
else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");}
|
|
else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");}
|
|
else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");}
|
|
else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);}
|
|
returnValue += tmp;
|
|
|
|
_snprintf(tmp, 255, "LPVOID lpFormat = %d\n", opts.lpFormat);
|
|
returnValue += tmp;
|
|
|
|
_snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat);
|
|
returnValue += tmp;
|
|
|
|
_snprintf(tmp, 255, "LPVOID lpParms = %d\n", opts.lpParms);
|
|
returnValue += tmp;
|
|
|
|
_snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms);
|
|
returnValue += tmp;
|
|
|
|
_snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery);
|
|
returnValue += tmp;
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi,
|
|
const char* _compressor)
|
|
{
|
|
|
|
AVICOMPRESSOPTIONS opts;
|
|
AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts};
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
|
opts.fccType = streamtypeVIDEO;
|
|
opts.fccHandler = getFOURCC(_compressor);
|
|
//opts.fccHandler = 0;
|
|
//opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed
|
|
//opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak
|
|
//opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2
|
|
//opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1
|
|
//opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0
|
|
//opts.dwKeyFrameEvery = 5;
|
|
//opts.dwQuality
|
|
//opts.dwBytesPerSecond
|
|
//opts.dwFlags = AVICOMPRESSF_KEYFRAMES;
|
|
//opts.lpFormat
|
|
//opts.cbFormat
|
|
//opts.lpParms
|
|
//opts.cbParms
|
|
//opts.dwInterleaveEvery
|
|
|
|
/* display the compression options dialog box if specified compressor is unknown */
|
|
if(getFOURCC(_compressor) == NULL)
|
|
{
|
|
if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//printf("%s", dumpAVICOMPRESSOPTIONS(opts));
|
|
//MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK);
|
|
}
|
|
|
|
HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL);
|
|
if (hr != AVIERR_OK) {
|
|
return FALSE;
|
|
}
|
|
|
|
hr = AVIStreamSetFormat(*psCompressed, 0,
|
|
lpbi, // stream format
|
|
lpbi->biSize // format size
|
|
+ lpbi->biClrUsed * sizeof(RGBQUAD)
|
|
);
|
|
if (hr != AVIERR_OK) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight)
|
|
{
|
|
// Fill in the stream header for the text stream....
|
|
AVISTREAMINFO strhdr;
|
|
DWORD dwTextFormat;
|
|
// The text stream is in 60ths of a second....
|
|
|
|
memset(&strhdr, 0, sizeof(strhdr));
|
|
strhdr.fccType = streamtypeTEXT;
|
|
strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W');
|
|
strhdr.dwScale = 1;
|
|
strhdr.dwRate = 60;
|
|
strhdr.dwSuggestedBufferSize = sizeof(szText);
|
|
SetRect(&strhdr.rcFrame, 0, (int) height,
|
|
(int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20
|
|
|
|
// ....and create the stream.
|
|
HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr);
|
|
if (hr != AVIERR_OK) {
|
|
return FALSE;
|
|
}
|
|
|
|
dwTextFormat = sizeof(dwTextFormat);
|
|
hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat));
|
|
if (hr != AVIERR_OK) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi)
|
|
{
|
|
int ImageSize = lpbi->biSizeImage;
|
|
if (ImageSize == 0)
|
|
{
|
|
if (lpbi->biBitCount == 24)
|
|
{
|
|
ImageSize = lpbi->biWidth * lpbi->biHeight * 3;
|
|
}
|
|
}
|
|
HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer
|
|
time, // time of this frame
|
|
1, // number to write
|
|
(LPBYTE) lpbi + // pointer to data
|
|
lpbi->biSize +
|
|
lpbi->biClrUsed * sizeof(RGBQUAD),
|
|
ImageSize, // lpbi->biSizeImage, // size of this frame
|
|
AVIIF_KEYFRAME, // flags....
|
|
NULL,
|
|
NULL);
|
|
if (hr != AVIERR_OK)
|
|
{
|
|
char strMsg[255];
|
|
_snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr);
|
|
MessageBox(NULL, strMsg, "", MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText)
|
|
{
|
|
int iLen = strlen(szText);
|
|
|
|
HRESULT hr = AVIStreamWrite(psText,
|
|
time,
|
|
1,
|
|
szText,
|
|
iLen + 1,
|
|
AVIIF_KEYFRAME,
|
|
NULL,
|
|
NULL);
|
|
if (hr != AVIERR_OK)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText)
|
|
{
|
|
if (ps)
|
|
AVIStreamClose(ps);
|
|
|
|
if (psCompressed)
|
|
AVIStreamClose(psCompressed);
|
|
|
|
if (psText)
|
|
AVIStreamClose(psText);
|
|
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AVI_CloseFile(PAVIFILE pfile)
|
|
{
|
|
if (pfile)
|
|
AVIFileClose(pfile);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AVI_Exit()
|
|
{
|
|
AVIFileExit();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Here are the additional functions we need! */
|
|
|
|
|
|
static PAVIFILE pfile = NULL;
|
|
static PAVISTREAM ps = NULL;
|
|
static PAVISTREAM psCompressed = NULL;
|
|
static int count = 0;
|
|
|
|
|
|
// Initialization...
|
|
bool START_AVI(const char* file_name)
|
|
{
|
|
if(! AVI_Init())
|
|
{
|
|
//printf("Error - AVI_Init()\n");
|
|
return false;
|
|
}
|
|
|
|
if(! AVI_FileOpenWrite(&pfile, file_name))
|
|
{
|
|
//printf("Error - AVI_FileOpenWrite()\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata)
|
|
{
|
|
if(count == 0)
|
|
{
|
|
if(! AVI_CreateStream(pfile, &ps, _frameRate,
|
|
width*height/bits,
|
|
width,
|
|
height, _compressor))
|
|
{
|
|
//printf("Error - AVI_CreateStream()\n");
|
|
return false;
|
|
}
|
|
|
|
BITMAPINFOHEADER bi;
|
|
memset(&bi, 0, sizeof(bi));
|
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.biWidth = width;
|
|
bi.biHeight = height;
|
|
bi.biPlanes = 1;
|
|
bi.biBitCount = bits;
|
|
bi.biCompression = BI_RGB;
|
|
bi.biSizeImage = width * height * bits /8;
|
|
if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer
|
|
count, // time of this frame
|
|
1, // number to write
|
|
pdata,
|
|
width*height/8, // lpbi->biSizeImage, // size of this frame
|
|
AVIIF_KEYFRAME, // flags....
|
|
NULL,
|
|
NULL);
|
|
if (hr != AVIERR_OK)
|
|
{
|
|
char strMsg[255];
|
|
_snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr);
|
|
MessageBox(NULL, strMsg, "", MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
count++;
|
|
return true;
|
|
}
|
|
|
|
//Now we can add frames
|
|
// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25);
|
|
bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate)
|
|
{
|
|
LPBITMAPINFOHEADER lpbi;
|
|
if(count == 0)
|
|
{
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib);
|
|
if(! AVI_CreateStream(pfile, &ps, _frameRate,
|
|
(unsigned long) lpbi->biSizeImage,
|
|
(int) lpbi->biWidth,
|
|
(int) lpbi->biHeight, _compressor))
|
|
{
|
|
//printf("Error - AVI_CreateStream()\n");
|
|
GlobalUnlock(lpbi);
|
|
return false;
|
|
}
|
|
|
|
if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor))
|
|
{
|
|
//printf("Error - AVI_SetOptions()\n");
|
|
GlobalUnlock(lpbi);
|
|
return false;
|
|
}
|
|
|
|
GlobalUnlock(lpbi);
|
|
}
|
|
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib);
|
|
if(! AVI_AddFrame(psCompressed, count * 1, lpbi))
|
|
{
|
|
//printf("Error - AVI_AddFrame()\n");
|
|
GlobalUnlock(lpbi);
|
|
return false;
|
|
}
|
|
|
|
GlobalUnlock(lpbi);
|
|
count++;
|
|
return true;
|
|
}
|
|
|
|
// The end...
|
|
bool STOP_AVI()
|
|
{
|
|
if(! AVI_CloseStream(ps, psCompressed, NULL))
|
|
{
|
|
//printf("Error - AVI_CloseStream()\n");
|
|
return false;
|
|
}
|
|
|
|
if(! AVI_CloseFile(pfile))
|
|
{
|
|
//printf("Error - AVI_CloseFile()\n");
|
|
return false;
|
|
}
|
|
|
|
if(! AVI_Exit())
|
|
{
|
|
//printf("Error - AVI_Exit()\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|