//DirectXAVI.cpp : AVI code by Tobias Johansson
#include "DirectXAVI.h"
AVISTREAMINFO aviStreamInfo;
PAVIFILE pAviFile = NULL;
PAVISTREAM psStream = NULL;
PAVISTREAM psCompressed = NULL;
AVICOMPRESSOPTIONS FAR * lpOptions;
//Width of video
int gAVIWidth = 0;
//Height of video
int gAVIHeight = 0;
//Fps of the video
int gAVIfps = 0;
//pixel depth of the video
int gAVIBpp = 0;
//current video frame
long gVideoFrame = 0;
BOOL bAVIFileOpened = FALSE;
#define ERROR_LOG(x) LogFile->Print(x)
//#define ERROR_LOG(x) MessageBox(NULL, x,"Fatal Error",MB_OK)
int WriteAVIFile( char *fname, LPDIRECTDRAWSURFACE7 lpSurf, int FramesPerSecond )
{
HRESULT hr;
DDSURFACEDESC2 ddsd;
//See if the vfw is new enough
WORD wVer = HIWORD( VideoForWindowsVersion() );
if (wVer < 0x010a)
{
ERROR_LOG("VideoForWindows too old.\n");
return AVI_ERROR_OTHERERROR;
}
_DDInit( ddsd );
lpSurf->GetSurfaceDesc( &ddsd );
gAVIWidth = ddsd.dwWidth;
gAVIHeight = ddsd.dwHeight;
gAVIBpp = ddsd.ddpfPixelFormat.dwRGBBitCount;
gAVIfps = MAX( FramesPerSecond, 0 ); //If some wiseguy tries a negative fps :)
if( gAVIBpp <= 8 )
{
ERROR_LOG("Unsupported Pixel Format.\n");
return AVI_ERROR_UNSUPPORTEDPIXELFORMAT;
}
AVIFileInit();
hr = AVIFileOpen( &pAviFile, fname, OF_WRITE | OF_CREATE, NULL );
if( hr != AVIERR_OK )
{
ERROR_LOG("AVIFileOpen failed.\n");
return AVI_ERROR_OTHERERROR;
}
BITMAPINFO bmpVideoFormat =
{
{
sizeof( BITMAPINFO ),
gAVIWidth,
gAVIHeight,
1,
24,
BI_RGB,
gAVIWidth * gAVIHeight * 3,
0,
0,
0,
0
}
};
memset(&aviStreamInfo, 0, sizeof( aviStreamInfo ));
aviStreamInfo.fccType = streamtypeVIDEO;
aviStreamInfo.fccHandler = 0;
aviStreamInfo.dwScale = 1;
aviStreamInfo.dwRate = gAVIfps;
aviStreamInfo.dwSuggestedBufferSize = 0;
aviStreamInfo.dwQuality = -1;
SetRect(&aviStreamInfo.rcFrame, 0, 0, (int) bmpVideoFormat.bmiHeader.biWidth, (int) bmpVideoFormat.bmiHeader.biHeight);
hr = AVIFileCreateStream( pAviFile, &psStream, &aviStreamInfo );
if( hr != AVIERR_OK )
{
ERROR_LOG("Couldn't create AVI stream.\n");
CloseAVIFile();
return AVI_ERROR_OTHERERROR;
}
lpOptions = new AVICOMPRESSOPTIONS;
memset( lpOptions, 0, sizeof( AVICOMPRESSOPTIONS ));
if( !AVISaveOptions( gMainWnd , ICMF_CHOOSE_KEYFRAME|ICMF_CHOOSE_DATARATE , 1, &psStream, &lpOptions))
{
ERROR_LOG("AVISaveOptions failed.\n");
CloseAVIFile();
return AVI_ERROR_OTHERERROR;
}
hr = AVIMakeCompressedStream( &psCompressed, psStream, lpOptions, NULL);
if( hr != AVIERR_OK )
{
ERROR_LOG("Couldn't create compressed stream.\n");
CloseAVIFile();
return AVI_ERROR_OTHERERROR;
}
hr = AVIStreamSetFormat( psCompressed, 0, &bmpVideoFormat, sizeof( bmpVideoFormat ));
if( hr != AVIERR_OK )
{
ERROR_LOG("AVIStreamSetFormat returned an ERROR_LOG.\n");
CloseAVIFile();
return AVI_ERROR_OTHERERROR;
}
gVideoFrame = 0;
bAVIFileOpened = TRUE;
delete lpOptions;
return 1;
}
void CloseAVIFile()
{
if ( psStream )
AVIStreamClose( psStream );
if ( psCompressed )
AVIStreamClose( psCompressed );
if ( pAviFile )
AVIFileClose( pAviFile );
psStream = psCompressed = NULL;
pAviFile = NULL;
AVIFileExit();
bAVIFileOpened = FALSE;
}
int WriteFrame( LPDIRECTDRAWSURFACE7 lpSurf )
{
DDSURFACEDESC2 ddsd;
BYTE *bSurface;
BYTE *bAVIData;
WORD wPitch, wPixel;
HRESULT hr;
DWORD dwIndex, dwPixel;
int iX, iY, iByte;
if( !bAVIFileOpened )
return AVI_ERROR_OTHERERROR;
_DDInit( ddsd );
lpSurf->GetSurfaceDesc( &ddsd );
if( (gAVIWidth != (int)ddsd.dwWidth) || (gAVIHeight != (int)ddsd.dwHeight) || (gAVIBpp != (int)ddsd.ddpfPixelFormat.dwRGBBitCount ))
{
ERROR_LOG("Wrong Surface.\n");
return AVI_ERROR_WRONGSURFACE;
}
_DDInit( ddsd );
hr = lpSurf->Lock( NULL , &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT , NULL );
if( FAILED( hr ))
{
ERROR_LOG("Couldn't lock surface.\n");
return AVI_ERROR_OTHERERROR;
}
bSurface = (BYTE *)ddsd.lpSurface;
wPitch = (WORD)ddsd.lPitch;
if( gAVIBpp == 16 ) wPitch /= 2;
dwIndex = 0;
bAVIData = new BYTE[ gAVIWidth * gAVIHeight * 3 ];
switch( gAVIBpp )
{
case 32:
for( iY = gAVIHeight - 1; iY >= 0; iY -- )
{
for( iX = 0; iX < gAVIWidth; iX ++ )
{
dwPixel = *((DWORD *)( bSurface + iX * 4 + iY * wPitch ));
iByte = ( dwPixel ) & 0x000000ff; //Blue
bAVIData[ dwIndex ++ ] = iByte;
iByte = ( dwPixel >> 8 ) & 0x000000ff; //Green
bAVIData[ dwIndex ++ ] = iByte;
iByte = ( dwPixel >> 16 ) & 0x000000ff; //Red
bAVIData[ dwIndex ++ ] = iByte;
}
}
break;
case 24:
for( iY = gAVIHeight - 1; iY >= 0; iY -- )
{
for( iX = 0; iX < gAVIWidth; iX ++ )
{
bAVIData[ dwIndex ++ ] = *( bSurface + iX * 3 + iY * wPitch + 2 );
bAVIData[ dwIndex ++ ] = *( bSurface + iX * 3 + iY * wPitch + 1 );
bAVIData[ dwIndex ++ ] = *( bSurface + iX * 3 + iY * wPitch + 0 );
}
}
break;
case 16:
if( ddsd.ddpfPixelFormat.dwGBitMask == 0x07E0 ) // 565 mode
{
for( iY = gAVIHeight - 1; iY >= 0; iY -- )
{
for( iX = 0; iX < gAVIWidth; iX ++ )
{
wPixel = *((WORD *)( bSurface + iX * 2 + iY * wPitch * 2));
iByte = ( 8 * (( wPixel ) & 0x001f ));
bAVIData[ dwIndex ++ ] = iByte;
iByte = ( 4 * (( wPixel >> 5 ) & 0x003f ));
bAVIData[ dwIndex ++ ] = iByte;
iByte = ( 8 * (( wPixel >> 11 ) & 0x001f ));
bAVIData[ dwIndex ++ ] = iByte;
}
}
}
else // 5550 (1) mode
{
for( iY = gAVIHeight - 1; iY >= 0; iY -- )
{
for( iX = 0; iX < gAVIWidth; iX ++ )
{
wPixel = *((WORD *)( bSurface + iX * 2 + iY * wPitch * 2));
iByte = ( 8 * (( wPixel ) & 0x001f ));
bAVIData[ dwIndex ++ ] = iByte;
iByte = ( 8 * (( wPixel >> 5 ) & 0x001f ));
bAVIData[ dwIndex ++ ] = iByte;
iByte = ( 8 * (( wPixel >> 10 ) & 0x001f ));
bAVIData[ dwIndex ++ ] = iByte;
}
}
}
break;
} //switch
hr = AVIStreamWrite( psCompressed, gVideoFrame, 1, bAVIData, gAVIWidth * gAVIHeight * 3, 0, NULL, NULL );
if (hr != AVIERR_OK)
{
ERROR_LOG("Couldn't write video data.\n");
CloseAVIFile();
return AVI_ERROR_OTHERERROR;
}
gVideoFrame ++;
delete bAVIData;
lpSurf->Unlock( NULL );
return 1;
} |