Attached Files |
-
single_step_and_avi.patch (29,537 bytes) 2008-01-29 13:03
Index: rts/Game/Game.cpp
===================================================================
--- rts/Game/Game.cpp (revision 5418)
+++ rts/Game/Game.cpp (working copy)
@@ -499,7 +499,6 @@
#ifndef NO_AVI
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator = NULL;
}
@@ -1132,7 +1131,7 @@
}
else if (cmd == "singlestep") {
if (gameServer && gs->paused)
- gameServer->CreateNewFrame(false);
+ gameServer->CreateNewFrame(true);
}
else if (cmd == "debug") {
gu->drawdebug = !gu->drawdebug;
@@ -1169,53 +1168,40 @@
else if (cmd == "createvideo") {
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator=0;
- // logOutput.Print("Finished avi");
} else {
creatingVideo=true;
- string name;
+ string fileName;
for(int a=0;a<999;++a){
char t[50];
itoa(a,t,10);
- name=string("video")+t+".avi";
- CFileHandler ifs(name);
+ fileName=string("video")+t+".avi";
+ CFileHandler ifs(fileName);
if(!ifs.FileExists())
break;
}
- BITMAPINFOHEADER bih;
- memset(&bih,0, sizeof(BITMAPINFOHEADER));
+ int videoSizeX = (gu->viewSizeX/4)*4;
+ int videoSizeY = (gu->viewSizeY/4)*4;
+ aviGenerator = SAFE_NEW CAVIGenerator(fileName, videoSizeX, videoSizeY, 30);
- // filling bitmap info structure.
- bih.biSize=sizeof(BITMAPINFOHEADER);
- bih.biWidth=(gu->viewSizeX/4)*4;
- bih.biHeight=(gu->viewSizeY/4)*4;
- bih.biPlanes=1;
- bih.biBitCount=24;
- bih.biSizeImage=bih.biWidth*bih.biHeight*3;
- bih.biCompression=BI_RGB;
-
-
- aviGenerator = SAFE_NEW CAVIGenerator(name, &bih, 30);
int savedCursorMode = SDL_ShowCursor(SDL_QUERY);
SDL_ShowCursor(SDL_ENABLE);
- HRESULT hr=aviGenerator->InitEngine();
- SDL_ShowCursor(savedCursorMode);
- //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
- //Setting it back to 'normal'.
- streflop_init<streflop::Simple>();
- if(hr!=AVIERR_OK){
+ if(!aviGenerator->InitEngine()){
creatingVideo=false;
logOutput.Print(aviGenerator->GetLastErrorMessage());
delete aviGenerator;
aviGenerator=0;
} else {
- logOutput.Print("Recording avi to %s size %li %li", name.c_str(),
- bih.biWidth, bih.biHeight);
+ logOutput.Print("Recording avi to %s size %li x %li", fileName.c_str(), videoSizeX, videoSizeY);
}
+
+ SDL_ShowCursor(savedCursorMode);
+ //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
+ //Setting it back to default state.
+ streflop_init<streflop::Simple>();
}
}
#endif
@@ -1900,7 +1886,7 @@
#endif
if(creatingVideo && playing && gameServer){
- gameServer->CreateNewFrame();
+ gameServer->CreateNewFrame(true);
}
if(!ClientReadNet()){
@@ -2372,13 +2358,7 @@
#ifndef NO_AVI
if(creatingVideo){
gu->lastFrameTime=1.0f/GAME_SPEED;
- LPBITMAPINFOHEADER ih;
- ih = aviGenerator->GetBitmapHeader();
- unsigned char* buf = aviGenerator->GetPixelBuf();
- glReadPixels(0,0,ih->biWidth, ih->biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, buf);
-
- aviGenerator->AddFrame(buf);
-
+ aviGenerator->readOpenglPixelDataThreaded();
// logOutput.Print("Saved avi frame size %i %i",ih->biWidth,ih->biHeight);
}
#endif
Index: rts/Game/GameServer.cpp
===================================================================
--- rts/Game/GameServer.cpp (revision 5418)
+++ rts/Game/GameServer.cpp (working copy)
@@ -149,8 +149,7 @@
{
boost::mutex::scoped_lock scoped_lock(gameServerMutex);
lastTick = newlastTick;
-// serverframenum = newserverframenum;
- nextserverframenum = newserverframenum+1;
+ serverframenum = newserverframenum;
}
void CGameServer::SkipTo(int targetframe)
@@ -335,7 +334,7 @@
}
else if (serverframenum > 0 && !demoReader)
{
- CreateNewFrame(true);
+ CreateNewFrame();
}
serverNet->Update();
@@ -817,7 +816,7 @@
}
timeLeft=0;
lastTick = SDL_GetTicks()-1;
- CreateNewFrame(true);
+ CreateNewFrame();
}
void CGameServer::SetGamePausable(const bool arg)
@@ -866,44 +865,40 @@
#endif
}
-void CGameServer::CreateNewFrame(bool fromServerThread)
+void CGameServer::CreateNewFrame(bool fixedFrameTime)
{
- boost::mutex::scoped_lock scoped_lock(gameServerMutex,!fromServerThread);
+ boost::mutex::scoped_lock scoped_lock(gameServerMutex);
CheckSync();
+ int newFrames = 1;
- // Send out new frame messages.
- unsigned currentTick = SDL_GetTicks();
- unsigned timeElapsed = currentTick - lastTick;
- if (timeElapsed>200) {
- timeElapsed=200;
- }
+ if(!fixedFrameTime){
+ unsigned currentTick = SDL_GetTicks();
+ unsigned timeElapsed = currentTick - lastTick;
+ if (timeElapsed>200) {
+ timeElapsed=200;
+ }
#ifdef DEBUG
- if(gameClientUpdated){
- gameClientUpdated=false;
- }
+ if(gameClientUpdated){
+ gameClientUpdated=false;
+ }
#endif
- timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
- lastTick=currentTick;
+ timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
+ lastTick=currentTick;
+ newFrames = (timeLeft > 0) ? ceil(timeLeft) : 0;
+ timeLeft -= newFrames;
+ }
- while((timeLeft>0) && !IsPaused)
- {
-#ifndef NO_AVI
- if((!game || !game->creatingVideo) || !fromServerThread)
-#endif
- {
- if (nextserverframenum!=0) {
- serverframenum = nextserverframenum;
- nextserverframenum = 0;
- } else
- serverframenum++;
+ if((!game->creatingVideo && !IsPaused) || fixedFrameTime){
+ for(int i=0; i < newFrames; ++i){
+ ++serverframenum;
+ //Send out new frame messages.
serverNet->SendNewFrame(serverframenum);
#ifdef SYNCCHECK
outstandingSyncFrames.push_back(serverframenum);
#endif
}
- timeLeft--;
}
}
Index: rts/Game/GameServer.h
===================================================================
--- rts/Game/GameServer.h (revision 5418)
+++ rts/Game/GameServer.h (working copy)
@@ -73,7 +73,7 @@
*/
void SkipTo(int targetframe);
- void CreateNewFrame(bool fromServerThread=false);
+ void CreateNewFrame(bool fixedFrameTime=false);
bool WaitsOnCon() const;
Index: rts/System/Platform/Win/AVIGenerator.cpp
===================================================================
--- rts/System/Platform/Win/AVIGenerator.cpp (revision 5418)
+++ rts/System/Platform/Win/AVIGenerator.cpp (working copy)
@@ -1,72 +1,63 @@
-// AVIGenerator.cpp: implementation of the CAVIGenerator class.
-//
-//////////////////////////////////////////////////////////////////////
-
#include "StdAfx.h"
#include "AVIGenerator.h"
#include "Game/GameVersion.h"
+#include "LogOutput.h"
+
+#include <windows.h>
+#include <GL/gl.h>
+#if defined(_WIN32) && defined(__MINGW32__)
+#include <GL/glext.h>
+#endif
+
+#include <boost/bind.hpp>
#include <cassert>
#include "mmgr.h"
#if defined(_WIN32) && !defined(__MINGW32__)
-#pragma message(" _Adding library: vfw32.lib" )
+#pragma message("Adding library: vfw32.lib")
#pragma comment(lib, "vfw32.lib")
#endif
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
bool CAVIGenerator::initVFW(){
#if defined(_WIN32) && defined(__MINGW32__)
- HMODULE hMod = LoadLibrary("msvfw32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
- }
+ msvfw32 = LoadLibrary("msvfw32.dll");
+ avifil32 = LoadLibrary("avifil32.dll");
+ VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(msvfw32, "VideoForWindowsVersion");
+ ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(msvfw32, "ICCompressorChoose");
+ ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(msvfw32, "ICCompressorFree");
+ ICOpen_ptr=(ICOpen_type)GetProcAddress(msvfw32, "ICOpen");
- VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(hMod, "VideoForWindowsVersion");
- ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(hMod, "ICCompressorChoose");
- ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(hMod, "ICCompressorFree");
+ AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(avifil32, "AVIFileInit");
+ AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(avifil32, "AVIFileOpenA");
+ AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(avifil32, "AVIFileCreateStreamA");
+ AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(avifil32, "AVIMakeCompressedStream");
+ AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(avifil32, "AVIStreamSetFormat");
+ AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(avifil32, "AVIStreamRelease");
+ AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(avifil32, "AVIFileRelease");
+ AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(avifil32, "AVIFileExit");
+ AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(avifil32, "AVIStreamWrite");
-
- if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr){
- m_sError="initVFW Error.";
- return false;
- }
-
-
-
- hMod = LoadLibrary("avifil32.dll");
- if (NULL == hMod){
+ if(NULL == msvfw32 || NULL == avifil32){
m_sError="LoadLibrary failed.";
- return false;
+ return false;
}
+ if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr || !ICOpen_ptr){
+ m_sError="initVFW Error.";
+ return false;
+ }
- AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(hMod, "AVIFileInit");
- AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(hMod, "AVIFileOpenA");
- AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(hMod, "AVIFileCreateStreamA");
- AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(hMod, "AVIMakeCompressedStream");
- AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(hMod, "AVIStreamSetFormat");
- AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(hMod, "AVIStreamRelease");
- AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(hMod, "AVIFileRelease");
- AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(hMod, "AVIFileExit");
- AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(hMod, "AVIStreamWrite");
-
-
- if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
+ if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
!AVIMakeCompressedStream_ptr || !AVIStreamSetFormat_ptr || !AVIStreamRelease_ptr ||
!AVIFileRelease_ptr || !AVIFileExit_ptr || !AVIStreamWrite_ptr){
m_sError="initVFW Error.";
- return false;
- }
- return true;
+ return false;
+ }
#else
VideoForWindowsVersion_ptr =&VideoForWindowsVersion;
@@ -81,98 +72,162 @@
AVIStreamWrite_ptr = &AVIStreamWrite;
ICCompressorChoose_ptr = &ICCompressorChoose;
ICCompressorFree_ptr = &ICCompressorFree;
-
+ ICOpen_ptr = &ICOpen;
+#endif
return true;
-#endif
}
+CAVIGenerator::CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS)
+ :
+ fileName(fileName),
+ videoFPS(videoFPS),
+ m_sError("Ok"),
+ quitAVIgen(false),
+ AVIThread(0),
+ readBuf(0),
+ m_lFrame(0),
+ m_pAVIFile(NULL),
+ m_pStream(NULL),
+ m_pStreamCompressed(NULL){
-CAVIGenerator::CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate)
-: m_sFile(sFileName), m_dwRate(dwRate), pixelDataBuf(0),
-m_pAVIFile(NULL), m_pStream(NULL), m_pStreamCompressed(NULL)
-{
- MakeExtAvi();
- SetBitmapHeader(lpbih);
-}
+ assert(videoSizeX % 4 == 0);
+ assert(videoSizeY % 4 == 0);
-CAVIGenerator::~CAVIGenerator()
-{
- // Just checking that all allocated ressources have been released
- assert(m_pStream==NULL);
- assert(m_pStreamCompressed==NULL);
- assert(m_pAVIFile==NULL);
- assert(pixelDataBuf==NULL);
+ memset(&bitmapInfo, 0, sizeof(BITMAPINFOHEADER));
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = videoSizeX;
+ bitmapInfo.biHeight = videoSizeY;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 24;
+ bitmapInfo.biSizeImage = videoSizeX * videoSizeY * 3;
+ bitmapInfo.biCompression = BI_RGB;
+
+ if(!initVFW()){
+ quitAVIgen = true;
+ }
}
-void CAVIGenerator::SetBitmapHeader(LPBITMAPINFOHEADER lpbih)
-{
- // checking that bitmap size are multiple of 4
- assert(lpbih->biWidth%4==0);
- assert(lpbih->biHeight%4==0);
- assert(lpbih->biBitCount==24);
- assert(lpbih->biCompression==BI_RGB);
- assert(lpbih->biSizeImage==lpbih->biWidth*lpbih->biHeight*3);
- // copying bitmap info structure.
- // corrected thanks to Lori Gardi
- memcpy(&m_bih,lpbih, sizeof(BITMAPINFOHEADER));
+CAVIGenerator::~CAVIGenerator(){
+
+ if(AVIThread){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ quitAVIgen = true;
+ AVICondition.notify_all();
+ }
+ AVIThread->join();
+
+ delete AVIThread;
+ AVIThread = 0;
+ }
+
+ while(!freeDataPointers.empty()){
+ unsigned char* tmp = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ delete [] tmp;
+ }
+ while(!dataPointers.empty()){
+ unsigned char* tmp = dataPointers.front();
+ dataPointers.pop_front();
+ delete [] tmp;
+ }
+
+ delete [] readBuf;
+ readBuf = 0;
+
+
+ ReleaseAVICompressionEngine();
+ logOutput.Print("Finished writing avi file.");
+
+ //Just checking that all allocated ressources have been released.
+ assert(AVIThread == NULL);
+ assert(m_pAVIFile == NULL);
+ assert(m_pStream == NULL);
+ assert(m_pStreamCompressed == NULL);
+ assert(freeDataPointers.empty());
+ assert(dataPointers.empty());
+ assert(readBuf == NULL);
}
-HRESULT CAVIGenerator::InitEngine()
-{
- AVISTREAMINFO strHdr; // information for a single stream
- AVICOMPRESSOPTIONS opts;
+void CAVIGenerator::ReleaseAVICompressionEngine(){
- HRESULT hr;
+ if(m_pStream && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStream);
+ m_pStream=NULL;
+ }
- m_sError= "Ok";
+ if(m_pStreamCompressed && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStreamCompressed);
+ m_pStreamCompressed=NULL;
+ }
+ if(m_pAVIFile && AVIFileRelease_ptr){
+ AVIFileRelease_ptr(m_pAVIFile);
+ m_pAVIFile=NULL;
+ }
- if(!initVFW()){
- return S_FALSE;
+ if(ICCompressorFree_ptr){
+ ICCompressorFree_ptr(&cv);
}
+ if(AVIFileExit_ptr){
+ AVIFileExit_ptr();
+ }
- triggerCleanup cleaner(this);
+ if(msvfw32){
+ FreeLibrary(msvfw32);
+ }
+ if(avifil32){
+ FreeLibrary(avifil32);
+ }
+}
- // Step 0 : Let's make sure we are running on 1.1
+
+HRESULT CAVIGenerator::InitAVICompressionEngine(){
+
+ AVISTREAMINFO strHdr; //Information for a single stream
+ AVICOMPRESSOPTIONS opts;
+ HRESULT hr;
+
+
+ //Let's make sure we are running on 1.1
DWORD wVer = HIWORD(VideoForWindowsVersion_ptr());
- if (wVer < 0x010a)
- {
- // oops, we are too old, blow out of here
+ if(wVer < 0x010a){
+ //oops, we are too old, blow out of here
m_sError="Version of Video for Windows too old. Come on, join the 21th century!";
return S_FALSE;
}
- // Step 1 : initialize AVI engine
+ //Initialize AVI engine
AVIFileInit_ptr();
memset(&cv,0,sizeof(COMPVARS));
-
cv.cbSize=sizeof(COMPVARS);
cv.dwFlags=ICMF_COMPVARS_VALID;
- cv.fccHandler=mmioFOURCC('W','M','V','3');
+ //cv.fccHandler=mmioFOURCC('W','M','V','3');
+ //cv.fccHandler=mmioFOURCC('i','v','5','0');
+ cv.fccHandler=mmioFOURCC('f','f','d','s');//default video codec
cv.lQ=ICQUALITY_DEFAULT;
HWND hWnd = FindWindow(NULL, ("Spring " + std::string(VERSION_STRING)).c_str());
-
- if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &m_bih, NULL, &cv, NULL)){
+ //Set the compression, prompting dialog if necessary
+ if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &bitmapInfo, NULL, &cv, NULL)){
return S_FALSE;
}
-
// Fill in the header for the video stream....
memset(&strHdr, 0, sizeof(AVISTREAMINFO));
strHdr.fccType = streamtypeVIDEO; // video stream type
strHdr.fccHandler = cv.fccHandler;
strHdr.dwScale = 1; // should be one for video
- strHdr.dwRate = m_dwRate; // fps
- strHdr.dwSuggestedBufferSize = m_bih.biSizeImage; // Recommended buffer size, in bytes, for the stream.
- SetRect(&strHdr.rcFrame, 0, 0, (int)m_bih.biWidth, (int)m_bih.biHeight); // rectangle for stream
-
+ strHdr.dwRate = videoFPS; // fps
+ strHdr.dwSuggestedBufferSize = bitmapInfo.biSizeImage; // Recommended buffer size, in bytes, for the stream.
+ SetRect(&strHdr.rcFrame, 0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight);
+ strcpy(strHdr.szName, "Spring video.");
memset(&opts, 0, sizeof(AVICOMPRESSOPTIONS));
@@ -188,47 +243,48 @@
opts.cbParms=cv.cbState;
opts.dwInterleaveEvery=0;
- // Step 2 : Open the movie file for writing....
+
+
+ //Open the movie file for writing
hr = AVIFileOpenA_ptr(&m_pAVIFile, // Address to contain the new file interface pointer
- m_sFile.c_str(), // Null-terminated string containing the name of the file to open
- OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
+ fileName.c_str(), // Null-terminated string containing the name of the file to open
+ OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
NULL); // use handler determined from file extension.
- // Name your file .avi -> very important
if (hr != AVIERR_OK)
{
- //_tprintf(szBuffer,"AVI Engine failed to initialize. Check filename %s.",m_sFile);
m_sError="AVI Engine failed to initialize. Check filename ";
- m_sError+=m_sFile;
- // Check it succeded.
+ m_sError+=fileName;
+ //Translate error code
switch(hr)
{
- case AVIERR_BADFORMAT:
+ case AVIERR_BADFORMAT:
m_sError+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
break;
- case AVIERR_MEMORY:
- m_sError+="The file could not be opened because of insufficient memory.";
+ case AVIERR_MEMORY:
+ m_sError+="The file could not be opened because of insufficient memory.";
break;
case AVIERR_FILEREAD:
- m_sError+="A disk error occurred while reading the file.";
+ m_sError+="A disk error occurred while reading the file.";
break;
- case AVIERR_FILEOPEN:
+ case AVIERR_FILEOPEN:
m_sError+="A disk error occurred while opening the file.";
break;
- case REGDB_E_CLASSNOTREG:
+ case REGDB_E_CLASSNOTREG:
m_sError+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 3 : Create the stream;
+ //Create the stream
hr = AVIFileCreateStreamA_ptr(m_pAVIFile, // file pointer
&m_pStream, // returned stream pointer
&strHdr); // stream header
- // Check it succeded.
if (hr != AVIERR_OK)
{
m_sError="AVI Stream creation failed. Check Bitmap info.";
@@ -240,12 +296,8 @@
}
- // Step 5: Create a compressed stream using codec options.
- hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed,
- m_pStream,
- &opts,
- NULL);
-
+ //Create a compressed stream using codec options.
+ hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed, m_pStream, &opts, NULL);
if (hr != AVIERR_OK)
{
m_sError="AVI Compressed Stream creation failed.";
@@ -257,21 +309,23 @@
break;
case AVIERR_MEMORY:
m_sError+=" There is not enough memory to complete the operation.";
- break;
+ break;
case AVIERR_UNSUPPORTED:
m_sError+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 6 : sets the format of a stream at the specified position
- hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
+ //Sets the format of a stream at the specified position
+ hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
0, // position
- &m_bih, // stream format
- m_bih.biSize + // format size
- m_bih.biClrUsed * sizeof(RGBQUAD));
+ &bitmapInfo, // stream format
+ bitmapInfo.biSize + // format size
+ bitmapInfo.biClrUsed * sizeof(RGBQUAD));
if (hr != AVIERR_OK)
{
@@ -279,54 +333,39 @@
return hr;
}
- // Step 6 : Initialize step counter
- m_lFrame=0;
- pixelDataBuf = SAFE_NEW unsigned char[m_bih.biSizeImage];
- cleaner.disarm();
-
return hr;
}
-void CAVIGenerator::ReleaseEngine()
-{
- if (m_pStream)
- {
- AVIStreamRelease_ptr(m_pStream);
- m_pStream=NULL;
+bool CAVIGenerator::InitEngine(){
+
+ for(int i=0; i<10; i++){
+ unsigned char* tmpBuf = SAFE_NEW unsigned char[bitmapInfo.biSizeImage];
+ freeDataPointers.push_back(tmpBuf);
}
- if (m_pStreamCompressed)
- {
- AVIStreamRelease_ptr(m_pStreamCompressed);
- m_pStreamCompressed=NULL;
+ if(quitAVIgen){//error in initVFW
+ return false;
}
- if (m_pAVIFile)
- {
- AVIFileRelease_ptr(m_pAVIFile);
- m_pAVIFile=NULL;
+ HRESULT hr = InitAVICompressionEngine();
+ if(hr != AVIERR_OK){
+ return false;
}
- ICCompressorFree_ptr(&cv);
+ AVIThread = SAFE_NEW boost::thread(boost::bind(&CAVIGenerator::AVIGeneratorThreadProc, this));
+ return true;
+}
- delete [] pixelDataBuf;
- pixelDataBuf=0;
- // Close engine
- AVIFileExit_ptr();
-}
+HRESULT CAVIGenerator::AddFrame(unsigned char* pixelData){
-HRESULT CAVIGenerator::AddFrame(BYTE *bmBits)
-{
- HRESULT hr;
-
// compress bitmap
- hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
- m_lFrame, // time of this frame
+ HRESULT hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
+ m_lFrame, // time of this frame
1, // number to write
- bmBits, // image buffer
- m_bih.biSizeImage, // size of this frame
+ pixelData, // image buffer
+ bitmapInfo.biSizeImage, // size of this frame
AVIIF_KEYFRAME, // flags....
NULL,
NULL);
@@ -337,10 +376,59 @@
return hr;
}
-void CAVIGenerator::MakeExtAvi(){
- std::size_t pos = m_sFile.find_last_of(".avi");
- if(pos == std::string::npos || pos + 1 != m_sFile.size()){
- m_sFile += ".avi";
+void CAVIGenerator::readOpenglPixelDataThreaded(){
+
+ for(;;){
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ return;
+ }
+ if(readBuf != 0){
+ dataPointers.push_back(readBuf);
+ readBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(freeDataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ readBuf = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ break;
}
+
+ glReadPixels(0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, readBuf);
}
+
+
+void CAVIGenerator::AVIGeneratorThreadProc(){
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+ unsigned char* localWriteBuf = 0;
+
+ for(;;){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ break;
+ }
+ if(localWriteBuf != 0){
+ freeDataPointers.push_back(localWriteBuf);
+ localWriteBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(dataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ localWriteBuf = dataPointers.front();
+ dataPointers.pop_front();
+ }
+ if(AddFrame(localWriteBuf)){
+ quitAVIgen = true;
+ }
+ }
+ delete [] localWriteBuf;
+}
+
Index: rts/System/Platform/Win/AVIGenerator.h
===================================================================
--- rts/System/Platform/Win/AVIGenerator.h (revision 5418)
+++ rts/System/Platform/Win/AVIGenerator.h (working copy)
@@ -1,127 +1,81 @@
-// AVIGenerator.h: interface for the CAVIGenerator class.
-//
-// A class to easily create AVI
-//
-// Original code : Example code in WriteAvi.c of MSDN
-//
-// Author : Jonathan de Halleux. dehalleux@auto.ucl.ac.be
-//////////////////////////////////////////////////////////////////////
-
#ifndef AVIGENERATOR_H
#define AVIGENERATOR_H
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/utility.hpp>
#include <windows.h>
#include <vfw.h>
-#include <GL/gl.h>
-#if defined(_WIN32) && defined(__MINGW32__)
-#include <GL/glext.h>
-#endif
-
#include <string>
+#include <list>
-/*! \brief A simple class to create AVI video stream.
+class CAVIGenerator : boost::noncopyable {
+public:
+ CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS);
+ ~CAVIGenerator();
-\par Usage
+ //Initialize engine and choose codec
+ bool InitEngine();
-Step 1 : Declare an CAVIGenerator object
-Step 2 : Set Bitmap by calling SetBitmapHeader functions + other parameters
-Step 3 : Initialize engine by calling InitEngine
-Step 4 : Send each frames to engine with function AddFrame
-Step 5 : Close engine by calling ReleaseEngine
+ //Returns last error message
+ std::string GetLastErrorMessage() const {return m_sError;}
-\par Demo Code:
+ void readOpenglPixelDataThreaded();
-\code
-CAVIGenerator AviGen;
-BYTE* bmBits;
-// set characteristics
-AviGen.SetRate(20); // set 20fps
-AviGen.SetBitmapHeader(GetActiveView()); // give info about bitmap
+private:
+ //name of output file
+ std::string fileName;
+ //Frame rate
+ DWORD videoFPS;
+ //structure contains information for a single stream
+ BITMAPINFOHEADER bitmapInfo;
+ //last error string
+ std::string m_sError;
-AviGen.InitEngine();
+ HINSTANCE msvfw32;
+ HINSTANCE avifil32;
-..... // Draw code, bmBits is the buffer containing the frame
-AviGen.AddFrame(bmBits);
-.....
+ volatile bool quitAVIgen;
-AviGen.ReleaseEngine();
-\endcode
+ boost::thread* AVIThread;
+ boost::mutex AVIMutex;
+ boost::condition AVICondition;
-\par Update history:
-- {\b 22-10-2002} Minor changes in constructors.
+ std::list<unsigned char*> freeDataPointers;
+ std::list<unsigned char*> dataPointers;
-\author : Jonathan de Halleux, dehalleux@auto.ucl.ac.be (2001)
-*/
-class CAVIGenerator
-{
-public:
- //! \name Constructors and destructors
- //@{
- //! Inplace constructor with BITMAPINFOHEADER
- CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate);
- ~CAVIGenerator();
- //@}
+ unsigned char* readBuf;
- //! \name AVI engine function
- //@{
- /*! \brief Initialize engine and choose codex
- Some asserts are made to check that bitmap has been properly initialized
- */
- HRESULT InitEngine();
- /*! \brief Adds a frame to the movie.
- The data pointed by bmBits has to be compatible with the bitmap description of the movie.
- */
- HRESULT AddFrame(BYTE* bmBits);
- //! Release ressources allocated for movie and close file.
- void ReleaseEngine();
- //@}
+ bool initVFW();
- //! \name Setters and getters
- //@{
- //! returns a pointer to bitmap info
- LPBITMAPINFOHEADER GetBitmapHeader() {return &m_bih;}
+ HRESULT InitAVICompressionEngine();
- //! \name Error handling
- //@{
- //! returns last error message
- std::string GetLastErrorMessage() const {return m_sError;}
- //@}
- unsigned char* GetPixelBuf(){return pixelDataBuf;}
+ //Release streams allocated for movie compression.
+ void ReleaseAVICompressionEngine();
+ //Adds a frame to the movie.
+ HRESULT AddFrame(unsigned char* pixelData);
-private:
- //! name of output file
- std::string m_sFile;
- //! Frame rate
- DWORD m_dwRate;
- //! structure contains information for a single stream
- BITMAPINFOHEADER m_bih;
- //! last error string
- std::string m_sError;
+ void AVIGeneratorThreadProc();
- unsigned char* pixelDataBuf;
-
- //! Sets bitmap info as in lpbih
- void SetBitmapHeader(LPBITMAPINFOHEADER lpbih);
-
- void MakeExtAvi();
- //! frame counter
+ //frame counter
long m_lFrame;
- //! file interface pointer
+ //file interface pointer
PAVIFILE m_pAVIFile;
- //! Address of the stream interface
- PAVISTREAM m_pStream;
- //! Address of the compressed video stream
- PAVISTREAM m_pStreamCompressed;
+ //Address of the stream interface
+ PAVISTREAM m_pStream;
+ //Address of the compressed video stream
+ PAVISTREAM m_pStreamCompressed;
//Holds compression settings
COMPVARS cv;
@@ -137,6 +91,7 @@
typedef HRESULT (__stdcall *AVIStreamWrite_type)(PAVISTREAM, LONG, LONG, LPVOID, LONG, DWORD, LONG FAR *, LONG FAR *);
typedef BOOL (__stdcall *ICCompressorChoose_type)(HWND, UINT, LPVOID, LPVOID, PCOMPVARS, LPSTR);
typedef void (__stdcall *ICCompressorFree_type)(PCOMPVARS);
+ typedef HIC (__stdcall *ICOpen_type)(DWORD, DWORD, UINT);
@@ -152,26 +107,8 @@
AVIStreamWrite_type AVIStreamWrite_ptr;
ICCompressorChoose_type ICCompressorChoose_ptr;
ICCompressorFree_type ICCompressorFree_ptr;
+ ICOpen_type ICOpen_ptr;
-
- bool initVFW();
-
-
- struct triggerCleanup{
- triggerCleanup(CAVIGenerator* ptr) : clean(true), ptr(ptr){};
- ~triggerCleanup(){
- if(clean){
- ptr->ReleaseEngine();
- }
- }
- void disarm(){
- clean = false;
- }
- private:
- bool clean;
- CAVIGenerator* ptr;
- };
-
};
#endif /* AVIGENERATOR_H */
-
patch.diff (30,061 bytes) 2008-01-29 19:27
Index: tools/DedicatedServer/CMakeLists.txt
===================================================================
--- tools/DedicatedServer/CMakeLists.txt (Revision 5419)
+++ tools/DedicatedServer/CMakeLists.txt (Arbeitskopie)
@@ -1,6 +1,7 @@
PROJECT(DedicatedServer)
SET(CMAKE_CXX_FLAGS "-g -O1 -Wall")
ADD_DEFINITIONS(-DDEBUG -D_SZ_ONE_DIRECTORY -DNO_AVI -DDEDICATED -DSYNCCHECK )
+find_package(SDL REQUIRED)
AUX_SOURCE_DIRECTORY(../../rts/System/Net/ netfiles)
ADD_LIBRARY(net SHARED ${netfiles})
Index: rts/System/Platform/Win/AVIGenerator.cpp
===================================================================
--- rts/System/Platform/Win/AVIGenerator.cpp (Revision 5419)
+++ rts/System/Platform/Win/AVIGenerator.cpp (Arbeitskopie)
@@ -1,72 +1,63 @@
-// AVIGenerator.cpp: implementation of the CAVIGenerator class.
-//
-//////////////////////////////////////////////////////////////////////
-
#include "StdAfx.h"
#include "AVIGenerator.h"
#include "Game/GameVersion.h"
+#include "LogOutput.h"
+
+#include <windows.h>
+#include <GL/gl.h>
+#if defined(_WIN32) && defined(__MINGW32__)
+#include <GL/glext.h>
+#endif
+
+#include <boost/bind.hpp>
#include <cassert>
#include "mmgr.h"
#if defined(_WIN32) && !defined(__MINGW32__)
-#pragma message(" _Adding library: vfw32.lib" )
+#pragma message("Adding library: vfw32.lib")
#pragma comment(lib, "vfw32.lib")
#endif
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
bool CAVIGenerator::initVFW(){
#if defined(_WIN32) && defined(__MINGW32__)
- HMODULE hMod = LoadLibrary("msvfw32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
- }
+ msvfw32 = LoadLibrary("msvfw32.dll");
+ avifil32 = LoadLibrary("avifil32.dll");
+ VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(msvfw32, "VideoForWindowsVersion");
+ ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(msvfw32, "ICCompressorChoose");
+ ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(msvfw32, "ICCompressorFree");
+ ICOpen_ptr=(ICOpen_type)GetProcAddress(msvfw32, "ICOpen");
- VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(hMod, "VideoForWindowsVersion");
- ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(hMod, "ICCompressorChoose");
- ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(hMod, "ICCompressorFree");
+ AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(avifil32, "AVIFileInit");
+ AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(avifil32, "AVIFileOpenA");
+ AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(avifil32, "AVIFileCreateStreamA");
+ AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(avifil32, "AVIMakeCompressedStream");
+ AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(avifil32, "AVIStreamSetFormat");
+ AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(avifil32, "AVIStreamRelease");
+ AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(avifil32, "AVIFileRelease");
+ AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(avifil32, "AVIFileExit");
+ AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(avifil32, "AVIStreamWrite");
-
- if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr){
- m_sError="initVFW Error.";
- return false;
- }
-
-
-
- hMod = LoadLibrary("avifil32.dll");
- if (NULL == hMod){
+ if(NULL == msvfw32 || NULL == avifil32){
m_sError="LoadLibrary failed.";
- return false;
+ return false;
}
+ if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr || !ICOpen_ptr){
+ m_sError="initVFW Error.";
+ return false;
+ }
- AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(hMod, "AVIFileInit");
- AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(hMod, "AVIFileOpenA");
- AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(hMod, "AVIFileCreateStreamA");
- AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(hMod, "AVIMakeCompressedStream");
- AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(hMod, "AVIStreamSetFormat");
- AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(hMod, "AVIStreamRelease");
- AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(hMod, "AVIFileRelease");
- AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(hMod, "AVIFileExit");
- AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(hMod, "AVIStreamWrite");
-
-
- if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
+ if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
!AVIMakeCompressedStream_ptr || !AVIStreamSetFormat_ptr || !AVIStreamRelease_ptr ||
!AVIFileRelease_ptr || !AVIFileExit_ptr || !AVIStreamWrite_ptr){
m_sError="initVFW Error.";
- return false;
- }
- return true;
+ return false;
+ }
#else
VideoForWindowsVersion_ptr =&VideoForWindowsVersion;
@@ -81,98 +72,162 @@
AVIStreamWrite_ptr = &AVIStreamWrite;
ICCompressorChoose_ptr = &ICCompressorChoose;
ICCompressorFree_ptr = &ICCompressorFree;
-
+ ICOpen_ptr = &ICOpen;
+#endif
return true;
-#endif
}
+CAVIGenerator::CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS)
+ :
+ fileName(fileName),
+ videoFPS(videoFPS),
+ m_sError("Ok"),
+ quitAVIgen(false),
+ AVIThread(0),
+ readBuf(0),
+ m_lFrame(0),
+ m_pAVIFile(NULL),
+ m_pStream(NULL),
+ m_pStreamCompressed(NULL){
-CAVIGenerator::CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate)
-: m_sFile(sFileName), m_dwRate(dwRate), pixelDataBuf(0),
-m_pAVIFile(NULL), m_pStream(NULL), m_pStreamCompressed(NULL)
-{
- MakeExtAvi();
- SetBitmapHeader(lpbih);
-}
+ assert(videoSizeX % 4 == 0);
+ assert(videoSizeY % 4 == 0);
-CAVIGenerator::~CAVIGenerator()
-{
- // Just checking that all allocated ressources have been released
- assert(m_pStream==NULL);
- assert(m_pStreamCompressed==NULL);
- assert(m_pAVIFile==NULL);
- assert(pixelDataBuf==NULL);
+ memset(&bitmapInfo, 0, sizeof(BITMAPINFOHEADER));
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = videoSizeX;
+ bitmapInfo.biHeight = videoSizeY;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 24;
+ bitmapInfo.biSizeImage = videoSizeX * videoSizeY * 3;
+ bitmapInfo.biCompression = BI_RGB;
+
+ if(!initVFW()){
+ quitAVIgen = true;
+ }
}
-void CAVIGenerator::SetBitmapHeader(LPBITMAPINFOHEADER lpbih)
-{
- // checking that bitmap size are multiple of 4
- assert(lpbih->biWidth%4==0);
- assert(lpbih->biHeight%4==0);
- assert(lpbih->biBitCount==24);
- assert(lpbih->biCompression==BI_RGB);
- assert(lpbih->biSizeImage==lpbih->biWidth*lpbih->biHeight*3);
- // copying bitmap info structure.
- // corrected thanks to Lori Gardi
- memcpy(&m_bih,lpbih, sizeof(BITMAPINFOHEADER));
+CAVIGenerator::~CAVIGenerator(){
+
+ if(AVIThread){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ quitAVIgen = true;
+ AVICondition.notify_all();
+ }
+ AVIThread->join();
+
+ delete AVIThread;
+ AVIThread = 0;
+ }
+
+ while(!freeDataPointers.empty()){
+ unsigned char* tmp = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ delete [] tmp;
+ }
+ while(!dataPointers.empty()){
+ unsigned char* tmp = dataPointers.front();
+ dataPointers.pop_front();
+ delete [] tmp;
+ }
+
+ delete [] readBuf;
+ readBuf = 0;
+
+
+ ReleaseAVICompressionEngine();
+ logOutput.Print("Finished writing avi file.");
+
+ //Just checking that all allocated ressources have been released.
+ assert(AVIThread == NULL);
+ assert(m_pAVIFile == NULL);
+ assert(m_pStream == NULL);
+ assert(m_pStreamCompressed == NULL);
+ assert(freeDataPointers.empty());
+ assert(dataPointers.empty());
+ assert(readBuf == NULL);
}
-HRESULT CAVIGenerator::InitEngine()
-{
- AVISTREAMINFO strHdr; // information for a single stream
- AVICOMPRESSOPTIONS opts;
+void CAVIGenerator::ReleaseAVICompressionEngine(){
- HRESULT hr;
+ if(m_pStream && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStream);
+ m_pStream=NULL;
+ }
- m_sError= "Ok";
+ if(m_pStreamCompressed && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStreamCompressed);
+ m_pStreamCompressed=NULL;
+ }
+ if(m_pAVIFile && AVIFileRelease_ptr){
+ AVIFileRelease_ptr(m_pAVIFile);
+ m_pAVIFile=NULL;
+ }
- if(!initVFW()){
- return S_FALSE;
+ if(ICCompressorFree_ptr){
+ ICCompressorFree_ptr(&cv);
}
+ if(AVIFileExit_ptr){
+ AVIFileExit_ptr();
+ }
- triggerCleanup cleaner(this);
+ if(msvfw32){
+ FreeLibrary(msvfw32);
+ }
+ if(avifil32){
+ FreeLibrary(avifil32);
+ }
+}
- // Step 0 : Let's make sure we are running on 1.1
+
+HRESULT CAVIGenerator::InitAVICompressionEngine(){
+
+ AVISTREAMINFO strHdr; //Information for a single stream
+ AVICOMPRESSOPTIONS opts;
+ HRESULT hr;
+
+
+ //Let's make sure we are running on 1.1
DWORD wVer = HIWORD(VideoForWindowsVersion_ptr());
- if (wVer < 0x010a)
- {
- // oops, we are too old, blow out of here
+ if(wVer < 0x010a){
+ //oops, we are too old, blow out of here
m_sError="Version of Video for Windows too old. Come on, join the 21th century!";
return S_FALSE;
}
- // Step 1 : initialize AVI engine
+ //Initialize AVI engine
AVIFileInit_ptr();
memset(&cv,0,sizeof(COMPVARS));
-
cv.cbSize=sizeof(COMPVARS);
cv.dwFlags=ICMF_COMPVARS_VALID;
- cv.fccHandler=mmioFOURCC('W','M','V','3');
+ //cv.fccHandler=mmioFOURCC('W','M','V','3');
+ //cv.fccHandler=mmioFOURCC('i','v','5','0');
+ cv.fccHandler=mmioFOURCC('f','f','d','s');//default video codec
cv.lQ=ICQUALITY_DEFAULT;
HWND hWnd = FindWindow(NULL, ("Spring " + std::string(VERSION_STRING)).c_str());
-
- if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &m_bih, NULL, &cv, NULL)){
+ //Set the compression, prompting dialog if necessary
+ if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &bitmapInfo, NULL, &cv, NULL)){
return S_FALSE;
}
-
// Fill in the header for the video stream....
memset(&strHdr, 0, sizeof(AVISTREAMINFO));
strHdr.fccType = streamtypeVIDEO; // video stream type
strHdr.fccHandler = cv.fccHandler;
strHdr.dwScale = 1; // should be one for video
- strHdr.dwRate = m_dwRate; // fps
- strHdr.dwSuggestedBufferSize = m_bih.biSizeImage; // Recommended buffer size, in bytes, for the stream.
- SetRect(&strHdr.rcFrame, 0, 0, (int)m_bih.biWidth, (int)m_bih.biHeight); // rectangle for stream
-
+ strHdr.dwRate = videoFPS; // fps
+ strHdr.dwSuggestedBufferSize = bitmapInfo.biSizeImage; // Recommended buffer size, in bytes, for the stream.
+ SetRect(&strHdr.rcFrame, 0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight);
+ strcpy(strHdr.szName, "Spring video.");
memset(&opts, 0, sizeof(AVICOMPRESSOPTIONS));
@@ -188,47 +243,48 @@
opts.cbParms=cv.cbState;
opts.dwInterleaveEvery=0;
- // Step 2 : Open the movie file for writing....
+
+
+ //Open the movie file for writing
hr = AVIFileOpenA_ptr(&m_pAVIFile, // Address to contain the new file interface pointer
- m_sFile.c_str(), // Null-terminated string containing the name of the file to open
- OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
+ fileName.c_str(), // Null-terminated string containing the name of the file to open
+ OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
NULL); // use handler determined from file extension.
- // Name your file .avi -> very important
if (hr != AVIERR_OK)
{
- //_tprintf(szBuffer,"AVI Engine failed to initialize. Check filename %s.",m_sFile);
m_sError="AVI Engine failed to initialize. Check filename ";
- m_sError+=m_sFile;
- // Check it succeded.
+ m_sError+=fileName;
+ //Translate error code
switch(hr)
{
- case AVIERR_BADFORMAT:
+ case AVIERR_BADFORMAT:
m_sError+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
break;
- case AVIERR_MEMORY:
- m_sError+="The file could not be opened because of insufficient memory.";
+ case AVIERR_MEMORY:
+ m_sError+="The file could not be opened because of insufficient memory.";
break;
case AVIERR_FILEREAD:
- m_sError+="A disk error occurred while reading the file.";
+ m_sError+="A disk error occurred while reading the file.";
break;
- case AVIERR_FILEOPEN:
+ case AVIERR_FILEOPEN:
m_sError+="A disk error occurred while opening the file.";
break;
- case REGDB_E_CLASSNOTREG:
+ case REGDB_E_CLASSNOTREG:
m_sError+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 3 : Create the stream;
+ //Create the stream
hr = AVIFileCreateStreamA_ptr(m_pAVIFile, // file pointer
&m_pStream, // returned stream pointer
&strHdr); // stream header
- // Check it succeded.
if (hr != AVIERR_OK)
{
m_sError="AVI Stream creation failed. Check Bitmap info.";
@@ -240,12 +296,8 @@
}
- // Step 5: Create a compressed stream using codec options.
- hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed,
- m_pStream,
- &opts,
- NULL);
-
+ //Create a compressed stream using codec options.
+ hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed, m_pStream, &opts, NULL);
if (hr != AVIERR_OK)
{
m_sError="AVI Compressed Stream creation failed.";
@@ -257,21 +309,23 @@
break;
case AVIERR_MEMORY:
m_sError+=" There is not enough memory to complete the operation.";
- break;
+ break;
case AVIERR_UNSUPPORTED:
m_sError+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 6 : sets the format of a stream at the specified position
- hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
+ //Sets the format of a stream at the specified position
+ hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
0, // position
- &m_bih, // stream format
- m_bih.biSize + // format size
- m_bih.biClrUsed * sizeof(RGBQUAD));
+ &bitmapInfo, // stream format
+ bitmapInfo.biSize + // format size
+ bitmapInfo.biClrUsed * sizeof(RGBQUAD));
if (hr != AVIERR_OK)
{
@@ -279,54 +333,39 @@
return hr;
}
- // Step 6 : Initialize step counter
- m_lFrame=0;
- pixelDataBuf = SAFE_NEW unsigned char[m_bih.biSizeImage];
- cleaner.disarm();
-
return hr;
}
-void CAVIGenerator::ReleaseEngine()
-{
- if (m_pStream)
- {
- AVIStreamRelease_ptr(m_pStream);
- m_pStream=NULL;
+bool CAVIGenerator::InitEngine(){
+
+ for(int i=0; i<10; i++){
+ unsigned char* tmpBuf = SAFE_NEW unsigned char[bitmapInfo.biSizeImage];
+ freeDataPointers.push_back(tmpBuf);
}
- if (m_pStreamCompressed)
- {
- AVIStreamRelease_ptr(m_pStreamCompressed);
- m_pStreamCompressed=NULL;
+ if(quitAVIgen){//error in initVFW
+ return false;
}
- if (m_pAVIFile)
- {
- AVIFileRelease_ptr(m_pAVIFile);
- m_pAVIFile=NULL;
+ HRESULT hr = InitAVICompressionEngine();
+ if(hr != AVIERR_OK){
+ return false;
}
- ICCompressorFree_ptr(&cv);
+ AVIThread = SAFE_NEW boost::thread(boost::bind(&CAVIGenerator::AVIGeneratorThreadProc, this));
+ return true;
+}
- delete [] pixelDataBuf;
- pixelDataBuf=0;
- // Close engine
- AVIFileExit_ptr();
-}
+HRESULT CAVIGenerator::AddFrame(unsigned char* pixelData){
-HRESULT CAVIGenerator::AddFrame(BYTE *bmBits)
-{
- HRESULT hr;
-
// compress bitmap
- hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
- m_lFrame, // time of this frame
+ HRESULT hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
+ m_lFrame, // time of this frame
1, // number to write
- bmBits, // image buffer
- m_bih.biSizeImage, // size of this frame
+ pixelData, // image buffer
+ bitmapInfo.biSizeImage, // size of this frame
AVIIF_KEYFRAME, // flags....
NULL,
NULL);
@@ -337,10 +376,59 @@
return hr;
}
-void CAVIGenerator::MakeExtAvi(){
- std::size_t pos = m_sFile.find_last_of(".avi");
- if(pos == std::string::npos || pos + 1 != m_sFile.size()){
- m_sFile += ".avi";
+void CAVIGenerator::readOpenglPixelDataThreaded(){
+
+ for(;;){
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ return;
+ }
+ if(readBuf != 0){
+ dataPointers.push_back(readBuf);
+ readBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(freeDataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ readBuf = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ break;
}
+
+ glReadPixels(0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, readBuf);
}
+
+
+void CAVIGenerator::AVIGeneratorThreadProc(){
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+ unsigned char* localWriteBuf = 0;
+
+ for(;;){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ break;
+ }
+ if(localWriteBuf != 0){
+ freeDataPointers.push_back(localWriteBuf);
+ localWriteBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(dataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ localWriteBuf = dataPointers.front();
+ dataPointers.pop_front();
+ }
+ if(AddFrame(localWriteBuf)){
+ quitAVIgen = true;
+ }
+ }
+ delete [] localWriteBuf;
+}
+
Index: rts/System/Platform/Win/AVIGenerator.h
===================================================================
--- rts/System/Platform/Win/AVIGenerator.h (Revision 5419)
+++ rts/System/Platform/Win/AVIGenerator.h (Arbeitskopie)
@@ -1,127 +1,81 @@
-// AVIGenerator.h: interface for the CAVIGenerator class.
-//
-// A class to easily create AVI
-//
-// Original code : Example code in WriteAvi.c of MSDN
-//
-// Author : Jonathan de Halleux. dehalleux@auto.ucl.ac.be
-//////////////////////////////////////////////////////////////////////
-
#ifndef AVIGENERATOR_H
#define AVIGENERATOR_H
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/utility.hpp>
#include <windows.h>
#include <vfw.h>
-#include <GL/gl.h>
-#if defined(_WIN32) && defined(__MINGW32__)
-#include <GL/glext.h>
-#endif
-
#include <string>
+#include <list>
-/*! \brief A simple class to create AVI video stream.
+class CAVIGenerator : boost::noncopyable {
+public:
+ CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS);
+ ~CAVIGenerator();
-\par Usage
+ //Initialize engine and choose codec
+ bool InitEngine();
-Step 1 : Declare an CAVIGenerator object
-Step 2 : Set Bitmap by calling SetBitmapHeader functions + other parameters
-Step 3 : Initialize engine by calling InitEngine
-Step 4 : Send each frames to engine with function AddFrame
-Step 5 : Close engine by calling ReleaseEngine
+ //Returns last error message
+ std::string GetLastErrorMessage() const {return m_sError;}
-\par Demo Code:
+ void readOpenglPixelDataThreaded();
-\code
-CAVIGenerator AviGen;
-BYTE* bmBits;
-// set characteristics
-AviGen.SetRate(20); // set 20fps
-AviGen.SetBitmapHeader(GetActiveView()); // give info about bitmap
+private:
+ //name of output file
+ std::string fileName;
+ //Frame rate
+ DWORD videoFPS;
+ //structure contains information for a single stream
+ BITMAPINFOHEADER bitmapInfo;
+ //last error string
+ std::string m_sError;
-AviGen.InitEngine();
+ HINSTANCE msvfw32;
+ HINSTANCE avifil32;
-..... // Draw code, bmBits is the buffer containing the frame
-AviGen.AddFrame(bmBits);
-.....
+ volatile bool quitAVIgen;
-AviGen.ReleaseEngine();
-\endcode
+ boost::thread* AVIThread;
+ boost::mutex AVIMutex;
+ boost::condition AVICondition;
-\par Update history:
-- {\b 22-10-2002} Minor changes in constructors.
+ std::list<unsigned char*> freeDataPointers;
+ std::list<unsigned char*> dataPointers;
-\author : Jonathan de Halleux, dehalleux@auto.ucl.ac.be (2001)
-*/
-class CAVIGenerator
-{
-public:
- //! \name Constructors and destructors
- //@{
- //! Inplace constructor with BITMAPINFOHEADER
- CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate);
- ~CAVIGenerator();
- //@}
+ unsigned char* readBuf;
- //! \name AVI engine function
- //@{
- /*! \brief Initialize engine and choose codex
- Some asserts are made to check that bitmap has been properly initialized
- */
- HRESULT InitEngine();
- /*! \brief Adds a frame to the movie.
- The data pointed by bmBits has to be compatible with the bitmap description of the movie.
- */
- HRESULT AddFrame(BYTE* bmBits);
- //! Release ressources allocated for movie and close file.
- void ReleaseEngine();
- //@}
+ bool initVFW();
- //! \name Setters and getters
- //@{
- //! returns a pointer to bitmap info
- LPBITMAPINFOHEADER GetBitmapHeader() {return &m_bih;}
+ HRESULT InitAVICompressionEngine();
- //! \name Error handling
- //@{
- //! returns last error message
- std::string GetLastErrorMessage() const {return m_sError;}
- //@}
- unsigned char* GetPixelBuf(){return pixelDataBuf;}
+ //Release streams allocated for movie compression.
+ void ReleaseAVICompressionEngine();
+ //Adds a frame to the movie.
+ HRESULT AddFrame(unsigned char* pixelData);
-private:
- //! name of output file
- std::string m_sFile;
- //! Frame rate
- DWORD m_dwRate;
- //! structure contains information for a single stream
- BITMAPINFOHEADER m_bih;
- //! last error string
- std::string m_sError;
+ void AVIGeneratorThreadProc();
- unsigned char* pixelDataBuf;
-
- //! Sets bitmap info as in lpbih
- void SetBitmapHeader(LPBITMAPINFOHEADER lpbih);
-
- void MakeExtAvi();
- //! frame counter
+ //frame counter
long m_lFrame;
- //! file interface pointer
+ //file interface pointer
PAVIFILE m_pAVIFile;
- //! Address of the stream interface
- PAVISTREAM m_pStream;
- //! Address of the compressed video stream
- PAVISTREAM m_pStreamCompressed;
+ //Address of the stream interface
+ PAVISTREAM m_pStream;
+ //Address of the compressed video stream
+ PAVISTREAM m_pStreamCompressed;
//Holds compression settings
COMPVARS cv;
@@ -137,6 +91,7 @@
typedef HRESULT (__stdcall *AVIStreamWrite_type)(PAVISTREAM, LONG, LONG, LPVOID, LONG, DWORD, LONG FAR *, LONG FAR *);
typedef BOOL (__stdcall *ICCompressorChoose_type)(HWND, UINT, LPVOID, LPVOID, PCOMPVARS, LPSTR);
typedef void (__stdcall *ICCompressorFree_type)(PCOMPVARS);
+ typedef HIC (__stdcall *ICOpen_type)(DWORD, DWORD, UINT);
@@ -152,26 +107,8 @@
AVIStreamWrite_type AVIStreamWrite_ptr;
ICCompressorChoose_type ICCompressorChoose_ptr;
ICCompressorFree_type ICCompressorFree_ptr;
+ ICOpen_type ICOpen_ptr;
-
- bool initVFW();
-
-
- struct triggerCleanup{
- triggerCleanup(CAVIGenerator* ptr) : clean(true), ptr(ptr){};
- ~triggerCleanup(){
- if(clean){
- ptr->ReleaseEngine();
- }
- }
- void disarm(){
- clean = false;
- }
- private:
- bool clean;
- CAVIGenerator* ptr;
- };
-
};
#endif /* AVIGENERATOR_H */
Index: rts/Game/GameServer.h
===================================================================
--- rts/Game/GameServer.h (Revision 5419)
+++ rts/Game/GameServer.h (Arbeitskopie)
@@ -73,7 +73,7 @@
*/
void SkipTo(int targetframe);
- void CreateNewFrame(bool fromServerThread=false);
+ void CreateNewFrame(bool fixedFrameTime=false);
bool WaitsOnCon() const;
Index: rts/Game/GameServer.cpp
===================================================================
--- rts/Game/GameServer.cpp (Revision 5419)
+++ rts/Game/GameServer.cpp (Arbeitskopie)
@@ -149,8 +149,7 @@
{
boost::mutex::scoped_lock scoped_lock(gameServerMutex);
lastTick = newlastTick;
-// serverframenum = newserverframenum;
- nextserverframenum = newserverframenum+1;
+ serverframenum = newserverframenum;
}
void CGameServer::SkipTo(int targetframe)
@@ -335,7 +334,7 @@
}
else if (serverframenum > 0 && !demoReader)
{
- CreateNewFrame(true);
+ CreateNewFrame();
}
serverNet->Update();
@@ -817,7 +816,7 @@
}
timeLeft=0;
lastTick = SDL_GetTicks()-1;
- CreateNewFrame(true);
+ CreateNewFrame();
}
void CGameServer::SetGamePausable(const bool arg)
@@ -866,44 +865,44 @@
#endif
}
-void CGameServer::CreateNewFrame(bool fromServerThread)
+void CGameServer::CreateNewFrame(bool fixedFrameTime)
{
- boost::mutex::scoped_lock scoped_lock(gameServerMutex,!fromServerThread);
+ boost::mutex::scoped_lock scoped_lock(gameServerMutex, fixedFrameTime);
CheckSync();
+ int newFrames = 1;
- // Send out new frame messages.
- unsigned currentTick = SDL_GetTicks();
- unsigned timeElapsed = currentTick - lastTick;
- if (timeElapsed>200) {
- timeElapsed=200;
- }
+ if(!fixedFrameTime){
+ unsigned currentTick = SDL_GetTicks();
+ unsigned timeElapsed = currentTick - lastTick;
+ if (timeElapsed>200) {
+ timeElapsed=200;
+ }
#ifdef DEBUG
- if(gameClientUpdated){
- gameClientUpdated=false;
- }
+ if(gameClientUpdated){
+ gameClientUpdated=false;
+ }
#endif
- timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
- lastTick=currentTick;
+ timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
+ lastTick=currentTick;
+ newFrames = (timeLeft > 0) ? ceil(timeLeft) : 0;
+ timeLeft -= newFrames;
+ }
- while((timeLeft>0) && !IsPaused)
- {
#ifndef NO_AVI
- if((!game || !game->creatingVideo) || !fromServerThread)
+ if((!game->creatingVideo && !IsPaused) || fixedFrameTime){
+#else
+ if(!IsPaused || fixedFrameTime){
#endif
- {
- if (nextserverframenum!=0) {
- serverframenum = nextserverframenum;
- nextserverframenum = 0;
- } else
- serverframenum++;
+ for(int i=0; i < newFrames; ++i){
+ ++serverframenum;
+ //Send out new frame messages.
serverNet->SendNewFrame(serverframenum);
#ifdef SYNCCHECK
outstandingSyncFrames.push_back(serverframenum);
#endif
}
- timeLeft--;
}
}
Index: rts/Game/Game.cpp
===================================================================
--- rts/Game/Game.cpp (Revision 5419)
+++ rts/Game/Game.cpp (Arbeitskopie)
@@ -499,7 +499,6 @@
#ifndef NO_AVI
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator = NULL;
}
@@ -1132,7 +1131,7 @@
}
else if (cmd == "singlestep") {
if (gameServer && gs->paused)
- gameServer->CreateNewFrame(false);
+ gameServer->CreateNewFrame(true);
}
else if (cmd == "debug") {
gu->drawdebug = !gu->drawdebug;
@@ -1169,53 +1168,40 @@
else if (cmd == "createvideo") {
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator=0;
- // logOutput.Print("Finished avi");
} else {
creatingVideo=true;
- string name;
+ string fileName;
for(int a=0;a<999;++a){
char t[50];
itoa(a,t,10);
- name=string("video")+t+".avi";
- CFileHandler ifs(name);
+ fileName=string("video")+t+".avi";
+ CFileHandler ifs(fileName);
if(!ifs.FileExists())
break;
}
- BITMAPINFOHEADER bih;
- memset(&bih,0, sizeof(BITMAPINFOHEADER));
+ int videoSizeX = (gu->viewSizeX/4)*4;
+ int videoSizeY = (gu->viewSizeY/4)*4;
+ aviGenerator = SAFE_NEW CAVIGenerator(fileName, videoSizeX, videoSizeY, 30);
- // filling bitmap info structure.
- bih.biSize=sizeof(BITMAPINFOHEADER);
- bih.biWidth=(gu->viewSizeX/4)*4;
- bih.biHeight=(gu->viewSizeY/4)*4;
- bih.biPlanes=1;
- bih.biBitCount=24;
- bih.biSizeImage=bih.biWidth*bih.biHeight*3;
- bih.biCompression=BI_RGB;
-
-
- aviGenerator = SAFE_NEW CAVIGenerator(name, &bih, 30);
int savedCursorMode = SDL_ShowCursor(SDL_QUERY);
SDL_ShowCursor(SDL_ENABLE);
- HRESULT hr=aviGenerator->InitEngine();
- SDL_ShowCursor(savedCursorMode);
- //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
- //Setting it back to 'normal'.
- streflop_init<streflop::Simple>();
- if(hr!=AVIERR_OK){
+ if(!aviGenerator->InitEngine()){
creatingVideo=false;
logOutput.Print(aviGenerator->GetLastErrorMessage());
delete aviGenerator;
aviGenerator=0;
} else {
- logOutput.Print("Recording avi to %s size %li %li", name.c_str(),
- bih.biWidth, bih.biHeight);
+ logOutput.Print("Recording avi to %s size %li x %li", fileName.c_str(), videoSizeX, videoSizeY);
}
+
+ SDL_ShowCursor(savedCursorMode);
+ //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
+ //Setting it back to default state.
+ streflop_init<streflop::Simple>();
}
}
#endif
@@ -1900,7 +1886,7 @@
#endif
if(creatingVideo && playing && gameServer){
- gameServer->CreateNewFrame();
+ gameServer->CreateNewFrame(true);
}
if(!ClientReadNet()){
@@ -2372,13 +2358,7 @@
#ifndef NO_AVI
if(creatingVideo){
gu->lastFrameTime=1.0f/GAME_SPEED;
- LPBITMAPINFOHEADER ih;
- ih = aviGenerator->GetBitmapHeader();
- unsigned char* buf = aviGenerator->GetPixelBuf();
- glReadPixels(0,0,ih->biWidth, ih->biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, buf);
-
- aviGenerator->AddFrame(buf);
-
+ aviGenerator->readOpenglPixelDataThreaded();
// logOutput.Print("Saved avi frame size %i %i",ih->biWidth,ih->biHeight);
}
#endif
-
single_step_and_avi_v2.patch (29,496 bytes) 2008-01-30 08:36
Index: rts/Game/Game.cpp
===================================================================
--- rts/Game/Game.cpp (revision 5419)
+++ rts/Game/Game.cpp (working copy)
@@ -499,7 +499,6 @@
#ifndef NO_AVI
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator = NULL;
}
@@ -1132,7 +1131,7 @@
}
else if (cmd == "singlestep") {
if (gameServer && gs->paused)
- gameServer->CreateNewFrame(false);
+ gameServer->CreateNewFrame(true);
}
else if (cmd == "debug") {
gu->drawdebug = !gu->drawdebug;
@@ -1169,53 +1168,40 @@
else if (cmd == "createvideo") {
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator=0;
- // logOutput.Print("Finished avi");
} else {
creatingVideo=true;
- string name;
+ string fileName;
for(int a=0;a<999;++a){
char t[50];
itoa(a,t,10);
- name=string("video")+t+".avi";
- CFileHandler ifs(name);
+ fileName=string("video")+t+".avi";
+ CFileHandler ifs(fileName);
if(!ifs.FileExists())
break;
}
- BITMAPINFOHEADER bih;
- memset(&bih,0, sizeof(BITMAPINFOHEADER));
+ int videoSizeX = (gu->viewSizeX/4)*4;
+ int videoSizeY = (gu->viewSizeY/4)*4;
+ aviGenerator = SAFE_NEW CAVIGenerator(fileName, videoSizeX, videoSizeY, 30);
- // filling bitmap info structure.
- bih.biSize=sizeof(BITMAPINFOHEADER);
- bih.biWidth=(gu->viewSizeX/4)*4;
- bih.biHeight=(gu->viewSizeY/4)*4;
- bih.biPlanes=1;
- bih.biBitCount=24;
- bih.biSizeImage=bih.biWidth*bih.biHeight*3;
- bih.biCompression=BI_RGB;
-
-
- aviGenerator = SAFE_NEW CAVIGenerator(name, &bih, 30);
int savedCursorMode = SDL_ShowCursor(SDL_QUERY);
SDL_ShowCursor(SDL_ENABLE);
- HRESULT hr=aviGenerator->InitEngine();
- SDL_ShowCursor(savedCursorMode);
- //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
- //Setting it back to 'normal'.
- streflop_init<streflop::Simple>();
- if(hr!=AVIERR_OK){
+ if(!aviGenerator->InitEngine()){
creatingVideo=false;
logOutput.Print(aviGenerator->GetLastErrorMessage());
delete aviGenerator;
aviGenerator=0;
} else {
- logOutput.Print("Recording avi to %s size %li %li", name.c_str(),
- bih.biWidth, bih.biHeight);
+ logOutput.Print("Recording avi to %s size %li x %li", fileName.c_str(), videoSizeX, videoSizeY);
}
+
+ SDL_ShowCursor(savedCursorMode);
+ //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
+ //Setting it back to default state.
+ streflop_init<streflop::Simple>();
}
}
#endif
@@ -1900,7 +1886,7 @@
#endif
if(creatingVideo && playing && gameServer){
- gameServer->CreateNewFrame();
+ gameServer->CreateNewFrame(true);
}
if(!ClientReadNet()){
@@ -2372,13 +2358,7 @@
#ifndef NO_AVI
if(creatingVideo){
gu->lastFrameTime=1.0f/GAME_SPEED;
- LPBITMAPINFOHEADER ih;
- ih = aviGenerator->GetBitmapHeader();
- unsigned char* buf = aviGenerator->GetPixelBuf();
- glReadPixels(0,0,ih->biWidth, ih->biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, buf);
-
- aviGenerator->AddFrame(buf);
-
+ aviGenerator->readOpenglPixelDataThreaded();
// logOutput.Print("Saved avi frame size %i %i",ih->biWidth,ih->biHeight);
}
#endif
Index: rts/Game/GameServer.cpp
===================================================================
--- rts/Game/GameServer.cpp (revision 5419)
+++ rts/Game/GameServer.cpp (working copy)
@@ -149,8 +149,7 @@
{
boost::mutex::scoped_lock scoped_lock(gameServerMutex);
lastTick = newlastTick;
-// serverframenum = newserverframenum;
- nextserverframenum = newserverframenum+1;
+ serverframenum = newserverframenum;
}
void CGameServer::SkipTo(int targetframe)
@@ -335,7 +334,7 @@
}
else if (serverframenum > 0 && !demoReader)
{
- CreateNewFrame(true);
+ CreateNewFrame();
}
serverNet->Update();
@@ -817,7 +816,7 @@
}
timeLeft=0;
lastTick = SDL_GetTicks()-1;
- CreateNewFrame(true);
+ CreateNewFrame();
}
void CGameServer::SetGamePausable(const bool arg)
@@ -866,44 +865,44 @@
#endif
}
-void CGameServer::CreateNewFrame(bool fromServerThread)
+void CGameServer::CreateNewFrame(bool fixedFrameTime)
{
- boost::mutex::scoped_lock scoped_lock(gameServerMutex,!fromServerThread);
+ boost::mutex::scoped_lock scoped_lock(gameServerMutex);
CheckSync();
+ int newFrames = 1;
- // Send out new frame messages.
- unsigned currentTick = SDL_GetTicks();
- unsigned timeElapsed = currentTick - lastTick;
- if (timeElapsed>200) {
- timeElapsed=200;
- }
+ if(!fixedFrameTime){
+ unsigned currentTick = SDL_GetTicks();
+ unsigned timeElapsed = currentTick - lastTick;
+ if (timeElapsed>200) {
+ timeElapsed=200;
+ }
#ifdef DEBUG
- if(gameClientUpdated){
- gameClientUpdated=false;
- }
+ if(gameClientUpdated){
+ gameClientUpdated=false;
+ }
#endif
- timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
- lastTick=currentTick;
+ timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
+ lastTick=currentTick;
+ newFrames = (timeLeft > 0) ? ceil(timeLeft) : 0;
+ timeLeft -= newFrames;
+ }
- while((timeLeft>0) && !IsPaused)
- {
#ifndef NO_AVI
- if((!game || !game->creatingVideo) || !fromServerThread)
+ if(((!game || !game->creatingVideo) && !IsPaused) || fixedFrameTime){
+#else
+ if(!IsPaused || fixedFrameTime){
#endif
- {
- if (nextserverframenum!=0) {
- serverframenum = nextserverframenum;
- nextserverframenum = 0;
- } else
- serverframenum++;
+ for(int i=0; i < newFrames; ++i){
+ ++serverframenum;
+ //Send out new frame messages.
serverNet->SendNewFrame(serverframenum);
#ifdef SYNCCHECK
outstandingSyncFrames.push_back(serverframenum);
#endif
}
- timeLeft--;
}
}
Index: rts/Game/GameServer.h
===================================================================
--- rts/Game/GameServer.h (revision 5419)
+++ rts/Game/GameServer.h (working copy)
@@ -73,7 +73,7 @@
*/
void SkipTo(int targetframe);
- void CreateNewFrame(bool fromServerThread=false);
+ void CreateNewFrame(bool fixedFrameTime=false);
bool WaitsOnCon() const;
Index: rts/System/Platform/Win/AVIGenerator.cpp
===================================================================
--- rts/System/Platform/Win/AVIGenerator.cpp (revision 5419)
+++ rts/System/Platform/Win/AVIGenerator.cpp (working copy)
@@ -1,72 +1,63 @@
-// AVIGenerator.cpp: implementation of the CAVIGenerator class.
-//
-//////////////////////////////////////////////////////////////////////
-
#include "StdAfx.h"
#include "AVIGenerator.h"
#include "Game/GameVersion.h"
+#include "LogOutput.h"
+
+#include <windows.h>
+#include <GL/gl.h>
+#if defined(_WIN32) && defined(__MINGW32__)
+#include <GL/glext.h>
+#endif
+
+#include <boost/bind.hpp>
#include <cassert>
#include "mmgr.h"
#if defined(_WIN32) && !defined(__MINGW32__)
-#pragma message(" _Adding library: vfw32.lib" )
+#pragma message("Adding library: vfw32.lib")
#pragma comment(lib, "vfw32.lib")
#endif
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
bool CAVIGenerator::initVFW(){
#if defined(_WIN32) && defined(__MINGW32__)
- HMODULE hMod = LoadLibrary("msvfw32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
- }
+ msvfw32 = LoadLibrary("msvfw32.dll");
+ avifil32 = LoadLibrary("avifil32.dll");
+ VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(msvfw32, "VideoForWindowsVersion");
+ ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(msvfw32, "ICCompressorChoose");
+ ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(msvfw32, "ICCompressorFree");
+ ICOpen_ptr=(ICOpen_type)GetProcAddress(msvfw32, "ICOpen");
- VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(hMod, "VideoForWindowsVersion");
- ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(hMod, "ICCompressorChoose");
- ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(hMod, "ICCompressorFree");
+ AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(avifil32, "AVIFileInit");
+ AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(avifil32, "AVIFileOpenA");
+ AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(avifil32, "AVIFileCreateStreamA");
+ AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(avifil32, "AVIMakeCompressedStream");
+ AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(avifil32, "AVIStreamSetFormat");
+ AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(avifil32, "AVIStreamRelease");
+ AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(avifil32, "AVIFileRelease");
+ AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(avifil32, "AVIFileExit");
+ AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(avifil32, "AVIStreamWrite");
-
- if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr){
- m_sError="initVFW Error.";
- return false;
- }
-
-
-
- hMod = LoadLibrary("avifil32.dll");
- if (NULL == hMod){
+ if(NULL == msvfw32 || NULL == avifil32){
m_sError="LoadLibrary failed.";
- return false;
+ return false;
}
+ if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr || !ICOpen_ptr){
+ m_sError="initVFW Error.";
+ return false;
+ }
- AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(hMod, "AVIFileInit");
- AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(hMod, "AVIFileOpenA");
- AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(hMod, "AVIFileCreateStreamA");
- AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(hMod, "AVIMakeCompressedStream");
- AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(hMod, "AVIStreamSetFormat");
- AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(hMod, "AVIStreamRelease");
- AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(hMod, "AVIFileRelease");
- AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(hMod, "AVIFileExit");
- AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(hMod, "AVIStreamWrite");
-
-
- if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
+ if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
!AVIMakeCompressedStream_ptr || !AVIStreamSetFormat_ptr || !AVIStreamRelease_ptr ||
!AVIFileRelease_ptr || !AVIFileExit_ptr || !AVIStreamWrite_ptr){
m_sError="initVFW Error.";
- return false;
- }
- return true;
+ return false;
+ }
#else
VideoForWindowsVersion_ptr =&VideoForWindowsVersion;
@@ -81,98 +72,160 @@
AVIStreamWrite_ptr = &AVIStreamWrite;
ICCompressorChoose_ptr = &ICCompressorChoose;
ICCompressorFree_ptr = &ICCompressorFree;
-
+ ICOpen_ptr = &ICOpen;
+#endif
return true;
-#endif
}
+CAVIGenerator::CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS)
+ :
+ fileName(fileName),
+ videoFPS(videoFPS),
+ m_sError("Ok"),
+ quitAVIgen(false),
+ AVIThread(0),
+ readBuf(0),
+ m_lFrame(0),
+ m_pAVIFile(NULL),
+ m_pStream(NULL),
+ m_pStreamCompressed(NULL){
-CAVIGenerator::CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate)
-: m_sFile(sFileName), m_dwRate(dwRate), pixelDataBuf(0),
-m_pAVIFile(NULL), m_pStream(NULL), m_pStreamCompressed(NULL)
-{
- MakeExtAvi();
- SetBitmapHeader(lpbih);
-}
+ assert(videoSizeX % 4 == 0);
+ assert(videoSizeY % 4 == 0);
-CAVIGenerator::~CAVIGenerator()
-{
- // Just checking that all allocated ressources have been released
- assert(m_pStream==NULL);
- assert(m_pStreamCompressed==NULL);
- assert(m_pAVIFile==NULL);
- assert(pixelDataBuf==NULL);
+ memset(&bitmapInfo, 0, sizeof(BITMAPINFOHEADER));
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = videoSizeX;
+ bitmapInfo.biHeight = videoSizeY;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 24;
+ bitmapInfo.biSizeImage = videoSizeX * videoSizeY * 3;
+ bitmapInfo.biCompression = BI_RGB;
+
+ if(!initVFW()){
+ quitAVIgen = true;
+ }
}
-void CAVIGenerator::SetBitmapHeader(LPBITMAPINFOHEADER lpbih)
-{
- // checking that bitmap size are multiple of 4
- assert(lpbih->biWidth%4==0);
- assert(lpbih->biHeight%4==0);
- assert(lpbih->biBitCount==24);
- assert(lpbih->biCompression==BI_RGB);
- assert(lpbih->biSizeImage==lpbih->biWidth*lpbih->biHeight*3);
- // copying bitmap info structure.
- // corrected thanks to Lori Gardi
- memcpy(&m_bih,lpbih, sizeof(BITMAPINFOHEADER));
+CAVIGenerator::~CAVIGenerator(){
+
+ if(AVIThread){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ quitAVIgen = true;
+ AVICondition.notify_all();
+ }
+ AVIThread->join();
+
+ delete AVIThread;
+ AVIThread = 0;
+ }
+
+ while(!freeDataPointers.empty()){
+ unsigned char* tmp = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ delete [] tmp;
+ }
+ while(!dataPointers.empty()){
+ unsigned char* tmp = dataPointers.front();
+ dataPointers.pop_front();
+ delete [] tmp;
+ }
+
+ delete [] readBuf;
+ readBuf = 0;
+
+
+ ReleaseAVICompressionEngine();
+ logOutput.Print("Finished writing avi file.");
+
+ //Just checking that all allocated ressources have been released.
+ assert(AVIThread == NULL);
+ assert(m_pAVIFile == NULL);
+ assert(m_pStream == NULL);
+ assert(m_pStreamCompressed == NULL);
+ assert(freeDataPointers.empty());
+ assert(dataPointers.empty());
+ assert(readBuf == NULL);
}
-HRESULT CAVIGenerator::InitEngine()
-{
- AVISTREAMINFO strHdr; // information for a single stream
- AVICOMPRESSOPTIONS opts;
+void CAVIGenerator::ReleaseAVICompressionEngine(){
- HRESULT hr;
+ if(m_pStream && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStream);
+ m_pStream=NULL;
+ }
- m_sError= "Ok";
+ if(m_pStreamCompressed && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStreamCompressed);
+ m_pStreamCompressed=NULL;
+ }
+ if(m_pAVIFile && AVIFileRelease_ptr){
+ AVIFileRelease_ptr(m_pAVIFile);
+ m_pAVIFile=NULL;
+ }
- if(!initVFW()){
- return S_FALSE;
+ if(ICCompressorFree_ptr){
+ ICCompressorFree_ptr(&cv);
}
+ if(AVIFileExit_ptr){
+ AVIFileExit_ptr();
+ }
- triggerCleanup cleaner(this);
+ if(msvfw32){
+ FreeLibrary(msvfw32);
+ }
+ if(avifil32){
+ FreeLibrary(avifil32);
+ }
+}
- // Step 0 : Let's make sure we are running on 1.1
+
+HRESULT CAVIGenerator::InitAVICompressionEngine(){
+
+ AVISTREAMINFO strHdr; //Information for a single stream
+ AVICOMPRESSOPTIONS opts;
+ HRESULT hr;
+
+
+ //Let's make sure we are running on 1.1
DWORD wVer = HIWORD(VideoForWindowsVersion_ptr());
- if (wVer < 0x010a)
- {
- // oops, we are too old, blow out of here
+ if(wVer < 0x010a){
+ //oops, we are too old, blow out of here
m_sError="Version of Video for Windows too old. Come on, join the 21th century!";
return S_FALSE;
}
- // Step 1 : initialize AVI engine
+ //Initialize AVI engine
AVIFileInit_ptr();
memset(&cv,0,sizeof(COMPVARS));
-
cv.cbSize=sizeof(COMPVARS);
cv.dwFlags=ICMF_COMPVARS_VALID;
- cv.fccHandler=mmioFOURCC('W','M','V','3');
+ cv.fccHandler=mmioFOURCC('f','f','d','s');//default video codec
cv.lQ=ICQUALITY_DEFAULT;
HWND hWnd = FindWindow(NULL, ("Spring " + std::string(VERSION_STRING)).c_str());
-
- if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &m_bih, NULL, &cv, NULL)){
+ //Set the compression, prompting dialog if necessary
+ if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &bitmapInfo, NULL, &cv, NULL)){
return S_FALSE;
}
-
// Fill in the header for the video stream....
memset(&strHdr, 0, sizeof(AVISTREAMINFO));
strHdr.fccType = streamtypeVIDEO; // video stream type
strHdr.fccHandler = cv.fccHandler;
strHdr.dwScale = 1; // should be one for video
- strHdr.dwRate = m_dwRate; // fps
- strHdr.dwSuggestedBufferSize = m_bih.biSizeImage; // Recommended buffer size, in bytes, for the stream.
- SetRect(&strHdr.rcFrame, 0, 0, (int)m_bih.biWidth, (int)m_bih.biHeight); // rectangle for stream
-
+ strHdr.dwRate = videoFPS; // fps
+ strHdr.dwSuggestedBufferSize = bitmapInfo.biSizeImage; // Recommended buffer size, in bytes, for the stream.
+ SetRect(&strHdr.rcFrame, 0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight);
+ strcpy(strHdr.szName, "Spring video.");
memset(&opts, 0, sizeof(AVICOMPRESSOPTIONS));
@@ -188,47 +241,48 @@
opts.cbParms=cv.cbState;
opts.dwInterleaveEvery=0;
- // Step 2 : Open the movie file for writing....
+
+
+ //Open the movie file for writing
hr = AVIFileOpenA_ptr(&m_pAVIFile, // Address to contain the new file interface pointer
- m_sFile.c_str(), // Null-terminated string containing the name of the file to open
- OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
+ fileName.c_str(), // Null-terminated string containing the name of the file to open
+ OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
NULL); // use handler determined from file extension.
- // Name your file .avi -> very important
if (hr != AVIERR_OK)
{
- //_tprintf(szBuffer,"AVI Engine failed to initialize. Check filename %s.",m_sFile);
m_sError="AVI Engine failed to initialize. Check filename ";
- m_sError+=m_sFile;
- // Check it succeded.
+ m_sError+=fileName;
+ //Translate error code
switch(hr)
{
- case AVIERR_BADFORMAT:
+ case AVIERR_BADFORMAT:
m_sError+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
break;
- case AVIERR_MEMORY:
- m_sError+="The file could not be opened because of insufficient memory.";
+ case AVIERR_MEMORY:
+ m_sError+="The file could not be opened because of insufficient memory.";
break;
case AVIERR_FILEREAD:
- m_sError+="A disk error occurred while reading the file.";
+ m_sError+="A disk error occurred while reading the file.";
break;
- case AVIERR_FILEOPEN:
+ case AVIERR_FILEOPEN:
m_sError+="A disk error occurred while opening the file.";
break;
- case REGDB_E_CLASSNOTREG:
+ case REGDB_E_CLASSNOTREG:
m_sError+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 3 : Create the stream;
+ //Create the stream
hr = AVIFileCreateStreamA_ptr(m_pAVIFile, // file pointer
&m_pStream, // returned stream pointer
&strHdr); // stream header
- // Check it succeded.
if (hr != AVIERR_OK)
{
m_sError="AVI Stream creation failed. Check Bitmap info.";
@@ -240,12 +294,8 @@
}
- // Step 5: Create a compressed stream using codec options.
- hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed,
- m_pStream,
- &opts,
- NULL);
-
+ //Create a compressed stream using codec options.
+ hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed, m_pStream, &opts, NULL);
if (hr != AVIERR_OK)
{
m_sError="AVI Compressed Stream creation failed.";
@@ -257,21 +307,23 @@
break;
case AVIERR_MEMORY:
m_sError+=" There is not enough memory to complete the operation.";
- break;
+ break;
case AVIERR_UNSUPPORTED:
m_sError+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 6 : sets the format of a stream at the specified position
- hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
+ //Sets the format of a stream at the specified position
+ hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
0, // position
- &m_bih, // stream format
- m_bih.biSize + // format size
- m_bih.biClrUsed * sizeof(RGBQUAD));
+ &bitmapInfo, // stream format
+ bitmapInfo.biSize + // format size
+ bitmapInfo.biClrUsed * sizeof(RGBQUAD));
if (hr != AVIERR_OK)
{
@@ -279,54 +331,39 @@
return hr;
}
- // Step 6 : Initialize step counter
- m_lFrame=0;
- pixelDataBuf = SAFE_NEW unsigned char[m_bih.biSizeImage];
- cleaner.disarm();
-
return hr;
}
-void CAVIGenerator::ReleaseEngine()
-{
- if (m_pStream)
- {
- AVIStreamRelease_ptr(m_pStream);
- m_pStream=NULL;
+bool CAVIGenerator::InitEngine(){
+
+ for(int i=0; i<10; i++){
+ unsigned char* tmpBuf = SAFE_NEW unsigned char[bitmapInfo.biSizeImage];
+ freeDataPointers.push_back(tmpBuf);
}
- if (m_pStreamCompressed)
- {
- AVIStreamRelease_ptr(m_pStreamCompressed);
- m_pStreamCompressed=NULL;
+ if(quitAVIgen){//error in initVFW
+ return false;
}
- if (m_pAVIFile)
- {
- AVIFileRelease_ptr(m_pAVIFile);
- m_pAVIFile=NULL;
+ HRESULT hr = InitAVICompressionEngine();
+ if(hr != AVIERR_OK){
+ return false;
}
- ICCompressorFree_ptr(&cv);
+ AVIThread = SAFE_NEW boost::thread(boost::bind(&CAVIGenerator::AVIGeneratorThreadProc, this));
+ return true;
+}
- delete [] pixelDataBuf;
- pixelDataBuf=0;
- // Close engine
- AVIFileExit_ptr();
-}
+HRESULT CAVIGenerator::AddFrame(unsigned char* pixelData){
-HRESULT CAVIGenerator::AddFrame(BYTE *bmBits)
-{
- HRESULT hr;
-
// compress bitmap
- hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
- m_lFrame, // time of this frame
+ HRESULT hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
+ m_lFrame, // time of this frame
1, // number to write
- bmBits, // image buffer
- m_bih.biSizeImage, // size of this frame
+ pixelData, // image buffer
+ bitmapInfo.biSizeImage, // size of this frame
AVIIF_KEYFRAME, // flags....
NULL,
NULL);
@@ -337,10 +374,59 @@
return hr;
}
-void CAVIGenerator::MakeExtAvi(){
- std::size_t pos = m_sFile.find_last_of(".avi");
- if(pos == std::string::npos || pos + 1 != m_sFile.size()){
- m_sFile += ".avi";
+void CAVIGenerator::readOpenglPixelDataThreaded(){
+
+ for(;;){
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ return;
+ }
+ if(readBuf != 0){
+ dataPointers.push_back(readBuf);
+ readBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(freeDataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ readBuf = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ break;
}
+
+ glReadPixels(0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, readBuf);
}
+
+
+void CAVIGenerator::AVIGeneratorThreadProc(){
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+ unsigned char* localWriteBuf = 0;
+
+ for(;;){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ break;
+ }
+ if(localWriteBuf != 0){
+ freeDataPointers.push_back(localWriteBuf);
+ localWriteBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(dataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ localWriteBuf = dataPointers.front();
+ dataPointers.pop_front();
+ }
+ if(AddFrame(localWriteBuf)){
+ quitAVIgen = true;
+ }
+ }
+ delete [] localWriteBuf;
+}
+
Index: rts/System/Platform/Win/AVIGenerator.h
===================================================================
--- rts/System/Platform/Win/AVIGenerator.h (revision 5419)
+++ rts/System/Platform/Win/AVIGenerator.h (working copy)
@@ -1,127 +1,81 @@
-// AVIGenerator.h: interface for the CAVIGenerator class.
-//
-// A class to easily create AVI
-//
-// Original code : Example code in WriteAvi.c of MSDN
-//
-// Author : Jonathan de Halleux. dehalleux@auto.ucl.ac.be
-//////////////////////////////////////////////////////////////////////
-
#ifndef AVIGENERATOR_H
#define AVIGENERATOR_H
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/utility.hpp>
#include <windows.h>
#include <vfw.h>
-#include <GL/gl.h>
-#if defined(_WIN32) && defined(__MINGW32__)
-#include <GL/glext.h>
-#endif
-
#include <string>
+#include <list>
-/*! \brief A simple class to create AVI video stream.
+class CAVIGenerator : boost::noncopyable {
+public:
+ CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS);
+ ~CAVIGenerator();
-\par Usage
+ //Initialize engine and choose codec
+ bool InitEngine();
-Step 1 : Declare an CAVIGenerator object
-Step 2 : Set Bitmap by calling SetBitmapHeader functions + other parameters
-Step 3 : Initialize engine by calling InitEngine
-Step 4 : Send each frames to engine with function AddFrame
-Step 5 : Close engine by calling ReleaseEngine
+ //Returns last error message
+ std::string GetLastErrorMessage() const {return m_sError;}
-\par Demo Code:
+ void readOpenglPixelDataThreaded();
-\code
-CAVIGenerator AviGen;
-BYTE* bmBits;
-// set characteristics
-AviGen.SetRate(20); // set 20fps
-AviGen.SetBitmapHeader(GetActiveView()); // give info about bitmap
+private:
+ //name of output file
+ std::string fileName;
+ //Frame rate
+ DWORD videoFPS;
+ //structure contains information for a single stream
+ BITMAPINFOHEADER bitmapInfo;
+ //last error string
+ std::string m_sError;
-AviGen.InitEngine();
+ HINSTANCE msvfw32;
+ HINSTANCE avifil32;
-..... // Draw code, bmBits is the buffer containing the frame
-AviGen.AddFrame(bmBits);
-.....
+ volatile bool quitAVIgen;
-AviGen.ReleaseEngine();
-\endcode
+ boost::thread* AVIThread;
+ boost::mutex AVIMutex;
+ boost::condition AVICondition;
-\par Update history:
-- {\b 22-10-2002} Minor changes in constructors.
+ std::list<unsigned char*> freeDataPointers;
+ std::list<unsigned char*> dataPointers;
-\author : Jonathan de Halleux, dehalleux@auto.ucl.ac.be (2001)
-*/
-class CAVIGenerator
-{
-public:
- //! \name Constructors and destructors
- //@{
- //! Inplace constructor with BITMAPINFOHEADER
- CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate);
- ~CAVIGenerator();
- //@}
+ unsigned char* readBuf;
- //! \name AVI engine function
- //@{
- /*! \brief Initialize engine and choose codex
- Some asserts are made to check that bitmap has been properly initialized
- */
- HRESULT InitEngine();
- /*! \brief Adds a frame to the movie.
- The data pointed by bmBits has to be compatible with the bitmap description of the movie.
- */
- HRESULT AddFrame(BYTE* bmBits);
- //! Release ressources allocated for movie and close file.
- void ReleaseEngine();
- //@}
+ bool initVFW();
- //! \name Setters and getters
- //@{
- //! returns a pointer to bitmap info
- LPBITMAPINFOHEADER GetBitmapHeader() {return &m_bih;}
+ HRESULT InitAVICompressionEngine();
- //! \name Error handling
- //@{
- //! returns last error message
- std::string GetLastErrorMessage() const {return m_sError;}
- //@}
- unsigned char* GetPixelBuf(){return pixelDataBuf;}
+ //Release streams allocated for movie compression.
+ void ReleaseAVICompressionEngine();
+ //Adds a frame to the movie.
+ HRESULT AddFrame(unsigned char* pixelData);
-private:
- //! name of output file
- std::string m_sFile;
- //! Frame rate
- DWORD m_dwRate;
- //! structure contains information for a single stream
- BITMAPINFOHEADER m_bih;
- //! last error string
- std::string m_sError;
+ void AVIGeneratorThreadProc();
- unsigned char* pixelDataBuf;
-
- //! Sets bitmap info as in lpbih
- void SetBitmapHeader(LPBITMAPINFOHEADER lpbih);
-
- void MakeExtAvi();
- //! frame counter
+ //frame counter
long m_lFrame;
- //! file interface pointer
+ //file interface pointer
PAVIFILE m_pAVIFile;
- //! Address of the stream interface
- PAVISTREAM m_pStream;
- //! Address of the compressed video stream
- PAVISTREAM m_pStreamCompressed;
+ //Address of the stream interface
+ PAVISTREAM m_pStream;
+ //Address of the compressed video stream
+ PAVISTREAM m_pStreamCompressed;
//Holds compression settings
COMPVARS cv;
@@ -137,6 +91,7 @@
typedef HRESULT (__stdcall *AVIStreamWrite_type)(PAVISTREAM, LONG, LONG, LPVOID, LONG, DWORD, LONG FAR *, LONG FAR *);
typedef BOOL (__stdcall *ICCompressorChoose_type)(HWND, UINT, LPVOID, LPVOID, PCOMPVARS, LPSTR);
typedef void (__stdcall *ICCompressorFree_type)(PCOMPVARS);
+ typedef HIC (__stdcall *ICOpen_type)(DWORD, DWORD, UINT);
@@ -152,26 +107,8 @@
AVIStreamWrite_type AVIStreamWrite_ptr;
ICCompressorChoose_type ICCompressorChoose_ptr;
ICCompressorFree_type ICCompressorFree_ptr;
+ ICOpen_type ICOpen_ptr;
-
- bool initVFW();
-
-
- struct triggerCleanup{
- triggerCleanup(CAVIGenerator* ptr) : clean(true), ptr(ptr){};
- ~triggerCleanup(){
- if(clean){
- ptr->ReleaseEngine();
- }
- }
- void disarm(){
- clean = false;
- }
- private:
- bool clean;
- CAVIGenerator* ptr;
- };
-
};
#endif /* AVIGENERATOR_H */
-
single_step_and_avi_v3.patch (29,650 bytes) 2008-01-30 10:47
Index: rts/Game/Game.cpp
===================================================================
--- rts/Game/Game.cpp (revision 5421)
+++ rts/Game/Game.cpp (working copy)
@@ -499,7 +499,6 @@
#ifndef NO_AVI
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator = NULL;
}
@@ -1132,7 +1131,7 @@
}
else if (cmd == "singlestep") {
if (gameServer && gs->paused)
- gameServer->CreateNewFrame(false);
+ gameServer->CreateNewFrame(false, true);
}
else if (cmd == "debug") {
gu->drawdebug = !gu->drawdebug;
@@ -1169,53 +1168,40 @@
else if (cmd == "createvideo") {
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator=0;
- // logOutput.Print("Finished avi");
} else {
creatingVideo=true;
- string name;
+ string fileName;
for(int a=0;a<999;++a){
char t[50];
itoa(a,t,10);
- name=string("video")+t+".avi";
- CFileHandler ifs(name);
+ fileName=string("video")+t+".avi";
+ CFileHandler ifs(fileName);
if(!ifs.FileExists())
break;
}
- BITMAPINFOHEADER bih;
- memset(&bih,0, sizeof(BITMAPINFOHEADER));
+ int videoSizeX = (gu->viewSizeX/4)*4;
+ int videoSizeY = (gu->viewSizeY/4)*4;
+ aviGenerator = SAFE_NEW CAVIGenerator(fileName, videoSizeX, videoSizeY, 30);
- // filling bitmap info structure.
- bih.biSize=sizeof(BITMAPINFOHEADER);
- bih.biWidth=(gu->viewSizeX/4)*4;
- bih.biHeight=(gu->viewSizeY/4)*4;
- bih.biPlanes=1;
- bih.biBitCount=24;
- bih.biSizeImage=bih.biWidth*bih.biHeight*3;
- bih.biCompression=BI_RGB;
-
-
- aviGenerator = SAFE_NEW CAVIGenerator(name, &bih, 30);
int savedCursorMode = SDL_ShowCursor(SDL_QUERY);
SDL_ShowCursor(SDL_ENABLE);
- HRESULT hr=aviGenerator->InitEngine();
- SDL_ShowCursor(savedCursorMode);
- //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
- //Setting it back to 'normal'.
- streflop_init<streflop::Simple>();
- if(hr!=AVIERR_OK){
+ if(!aviGenerator->InitEngine()){
creatingVideo=false;
logOutput.Print(aviGenerator->GetLastErrorMessage());
delete aviGenerator;
aviGenerator=0;
} else {
- logOutput.Print("Recording avi to %s size %li %li", name.c_str(),
- bih.biWidth, bih.biHeight);
+ logOutput.Print("Recording avi to %s size %li x %li", fileName.c_str(), videoSizeX, videoSizeY);
}
+
+ SDL_ShowCursor(savedCursorMode);
+ //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
+ //Setting it back to default state.
+ streflop_init<streflop::Simple>();
}
}
#endif
@@ -1900,7 +1886,7 @@
#endif
if(creatingVideo && playing && gameServer){
- gameServer->CreateNewFrame();
+ gameServer->CreateNewFrame(false, true);
}
if(!ClientReadNet()){
@@ -2372,13 +2358,7 @@
#ifndef NO_AVI
if(creatingVideo){
gu->lastFrameTime=1.0f/GAME_SPEED;
- LPBITMAPINFOHEADER ih;
- ih = aviGenerator->GetBitmapHeader();
- unsigned char* buf = aviGenerator->GetPixelBuf();
- glReadPixels(0,0,ih->biWidth, ih->biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, buf);
-
- aviGenerator->AddFrame(buf);
-
+ aviGenerator->readOpenglPixelDataThreaded();
// logOutput.Print("Saved avi frame size %i %i",ih->biWidth,ih->biHeight);
}
#endif
Index: rts/Game/GameServer.cpp
===================================================================
--- rts/Game/GameServer.cpp (revision 5421)
+++ rts/Game/GameServer.cpp (working copy)
@@ -1,6 +1,7 @@
#include "GameServer.h"
#include <stdarg.h>
+#include <ctime>
#include <boost/bind.hpp>
#include <SDL_timer.h>
@@ -149,8 +150,7 @@
{
boost::mutex::scoped_lock scoped_lock(gameServerMutex);
lastTick = newlastTick;
-// serverframenum = newserverframenum;
- nextserverframenum = newserverframenum+1;
+ serverframenum = newserverframenum;
}
void CGameServer::SkipTo(int targetframe)
@@ -335,7 +335,7 @@
}
else if (serverframenum > 0 && !demoReader)
{
- CreateNewFrame(true);
+ CreateNewFrame(true, false);
}
serverNet->Update();
@@ -817,7 +817,7 @@
}
timeLeft=0;
lastTick = SDL_GetTicks()-1;
- CreateNewFrame(true);
+ CreateNewFrame(true, false);
}
void CGameServer::SetGamePausable(const bool arg)
@@ -866,44 +866,44 @@
#endif
}
-void CGameServer::CreateNewFrame(bool fromServerThread)
+void CGameServer::CreateNewFrame(bool fromServerThread, bool fixedFrameTime)
{
boost::mutex::scoped_lock scoped_lock(gameServerMutex,!fromServerThread);
CheckSync();
+ int newFrames = 1;
- // Send out new frame messages.
- unsigned currentTick = SDL_GetTicks();
- unsigned timeElapsed = currentTick - lastTick;
- if (timeElapsed>200) {
- timeElapsed=200;
- }
+ if(!fixedFrameTime){
+ unsigned currentTick = SDL_GetTicks();
+ unsigned timeElapsed = currentTick - lastTick;
+ if (timeElapsed>200) {
+ timeElapsed=200;
+ }
#ifdef DEBUG
- if(gameClientUpdated){
- gameClientUpdated=false;
- }
+ if(gameClientUpdated){
+ gameClientUpdated=false;
+ }
#endif
- timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
- lastTick=currentTick;
+ timeLeft+=GAME_SPEED*internalSpeed*float(timeElapsed)/1000.0f;
+ lastTick=currentTick;
+ newFrames = (timeLeft > 0) ? ceil(timeLeft) : 0;
+ timeLeft -= newFrames;
+ }
- while((timeLeft>0) && !IsPaused)
- {
#ifndef NO_AVI
- if((!game || !game->creatingVideo) || !fromServerThread)
+ if(((!game || !game->creatingVideo) && !IsPaused) || fixedFrameTime){
+#else
+ if(!IsPaused || fixedFrameTime){
#endif
- {
- if (nextserverframenum!=0) {
- serverframenum = nextserverframenum;
- nextserverframenum = 0;
- } else
- serverframenum++;
+ for(int i=0; i < newFrames; ++i){
+ ++serverframenum;
+ //Send out new frame messages.
serverNet->SendNewFrame(serverframenum);
#ifdef SYNCCHECK
outstandingSyncFrames.push_back(serverframenum);
#endif
}
- timeLeft--;
}
}
Index: rts/Game/GameServer.h
===================================================================
--- rts/Game/GameServer.h (revision 5421)
+++ rts/Game/GameServer.h (working copy)
@@ -73,7 +73,7 @@
*/
void SkipTo(int targetframe);
- void CreateNewFrame(bool fromServerThread=false);
+ void CreateNewFrame(bool fromServerThread, bool fixedFrameTime);
bool WaitsOnCon() const;
Index: rts/System/Platform/Win/AVIGenerator.cpp
===================================================================
--- rts/System/Platform/Win/AVIGenerator.cpp (revision 5421)
+++ rts/System/Platform/Win/AVIGenerator.cpp (working copy)
@@ -1,72 +1,63 @@
-// AVIGenerator.cpp: implementation of the CAVIGenerator class.
-//
-//////////////////////////////////////////////////////////////////////
-
#include "StdAfx.h"
#include "AVIGenerator.h"
#include "Game/GameVersion.h"
+#include "LogOutput.h"
+
+#include <windows.h>
+#include <GL/gl.h>
+#if defined(_WIN32) && defined(__MINGW32__)
+#include <GL/glext.h>
+#endif
+
+#include <boost/bind.hpp>
#include <cassert>
#include "mmgr.h"
#if defined(_WIN32) && !defined(__MINGW32__)
-#pragma message(" _Adding library: vfw32.lib" )
+#pragma message("Adding library: vfw32.lib")
#pragma comment(lib, "vfw32.lib")
#endif
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
bool CAVIGenerator::initVFW(){
#if defined(_WIN32) && defined(__MINGW32__)
- HMODULE hMod = LoadLibrary("msvfw32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
- }
+ msvfw32 = LoadLibrary("msvfw32.dll");
+ avifil32 = LoadLibrary("avifil32.dll");
+ VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(msvfw32, "VideoForWindowsVersion");
+ ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(msvfw32, "ICCompressorChoose");
+ ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(msvfw32, "ICCompressorFree");
+ ICOpen_ptr=(ICOpen_type)GetProcAddress(msvfw32, "ICOpen");
- VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(hMod, "VideoForWindowsVersion");
- ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(hMod, "ICCompressorChoose");
- ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(hMod, "ICCompressorFree");
+ AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(avifil32, "AVIFileInit");
+ AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(avifil32, "AVIFileOpenA");
+ AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(avifil32, "AVIFileCreateStreamA");
+ AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(avifil32, "AVIMakeCompressedStream");
+ AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(avifil32, "AVIStreamSetFormat");
+ AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(avifil32, "AVIStreamRelease");
+ AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(avifil32, "AVIFileRelease");
+ AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(avifil32, "AVIFileExit");
+ AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(avifil32, "AVIStreamWrite");
-
- if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr){
- m_sError="initVFW Error.";
- return false;
- }
-
-
-
- hMod = LoadLibrary("avifil32.dll");
- if (NULL == hMod){
+ if(NULL == msvfw32 || NULL == avifil32){
m_sError="LoadLibrary failed.";
- return false;
+ return false;
}
+ if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr || !ICOpen_ptr){
+ m_sError="initVFW Error.";
+ return false;
+ }
- AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(hMod, "AVIFileInit");
- AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(hMod, "AVIFileOpenA");
- AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(hMod, "AVIFileCreateStreamA");
- AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(hMod, "AVIMakeCompressedStream");
- AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(hMod, "AVIStreamSetFormat");
- AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(hMod, "AVIStreamRelease");
- AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(hMod, "AVIFileRelease");
- AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(hMod, "AVIFileExit");
- AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(hMod, "AVIStreamWrite");
-
-
- if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
+ if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
!AVIMakeCompressedStream_ptr || !AVIStreamSetFormat_ptr || !AVIStreamRelease_ptr ||
!AVIFileRelease_ptr || !AVIFileExit_ptr || !AVIStreamWrite_ptr){
m_sError="initVFW Error.";
- return false;
- }
- return true;
+ return false;
+ }
#else
VideoForWindowsVersion_ptr =&VideoForWindowsVersion;
@@ -81,98 +72,160 @@
AVIStreamWrite_ptr = &AVIStreamWrite;
ICCompressorChoose_ptr = &ICCompressorChoose;
ICCompressorFree_ptr = &ICCompressorFree;
-
+ ICOpen_ptr = &ICOpen;
+#endif
return true;
-#endif
}
+CAVIGenerator::CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS)
+ :
+ fileName(fileName),
+ videoFPS(videoFPS),
+ m_sError("Ok"),
+ quitAVIgen(false),
+ AVIThread(0),
+ readBuf(0),
+ m_lFrame(0),
+ m_pAVIFile(NULL),
+ m_pStream(NULL),
+ m_pStreamCompressed(NULL){
-CAVIGenerator::CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate)
-: m_sFile(sFileName), m_dwRate(dwRate), pixelDataBuf(0),
-m_pAVIFile(NULL), m_pStream(NULL), m_pStreamCompressed(NULL)
-{
- MakeExtAvi();
- SetBitmapHeader(lpbih);
-}
+ assert(videoSizeX % 4 == 0);
+ assert(videoSizeY % 4 == 0);
-CAVIGenerator::~CAVIGenerator()
-{
- // Just checking that all allocated ressources have been released
- assert(m_pStream==NULL);
- assert(m_pStreamCompressed==NULL);
- assert(m_pAVIFile==NULL);
- assert(pixelDataBuf==NULL);
+ memset(&bitmapInfo, 0, sizeof(BITMAPINFOHEADER));
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = videoSizeX;
+ bitmapInfo.biHeight = videoSizeY;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 24;
+ bitmapInfo.biSizeImage = videoSizeX * videoSizeY * 3;
+ bitmapInfo.biCompression = BI_RGB;
+
+ if(!initVFW()){
+ quitAVIgen = true;
+ }
}
-void CAVIGenerator::SetBitmapHeader(LPBITMAPINFOHEADER lpbih)
-{
- // checking that bitmap size are multiple of 4
- assert(lpbih->biWidth%4==0);
- assert(lpbih->biHeight%4==0);
- assert(lpbih->biBitCount==24);
- assert(lpbih->biCompression==BI_RGB);
- assert(lpbih->biSizeImage==lpbih->biWidth*lpbih->biHeight*3);
- // copying bitmap info structure.
- // corrected thanks to Lori Gardi
- memcpy(&m_bih,lpbih, sizeof(BITMAPINFOHEADER));
+CAVIGenerator::~CAVIGenerator(){
+
+ if(AVIThread){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ quitAVIgen = true;
+ AVICondition.notify_all();
+ }
+ AVIThread->join();
+
+ delete AVIThread;
+ AVIThread = 0;
+ }
+
+ while(!freeDataPointers.empty()){
+ unsigned char* tmp = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ delete [] tmp;
+ }
+ while(!dataPointers.empty()){
+ unsigned char* tmp = dataPointers.front();
+ dataPointers.pop_front();
+ delete [] tmp;
+ }
+
+ delete [] readBuf;
+ readBuf = 0;
+
+
+ ReleaseAVICompressionEngine();
+ logOutput.Print("Finished writing avi file.");
+
+ //Just checking that all allocated ressources have been released.
+ assert(AVIThread == NULL);
+ assert(m_pAVIFile == NULL);
+ assert(m_pStream == NULL);
+ assert(m_pStreamCompressed == NULL);
+ assert(freeDataPointers.empty());
+ assert(dataPointers.empty());
+ assert(readBuf == NULL);
}
-HRESULT CAVIGenerator::InitEngine()
-{
- AVISTREAMINFO strHdr; // information for a single stream
- AVICOMPRESSOPTIONS opts;
+void CAVIGenerator::ReleaseAVICompressionEngine(){
- HRESULT hr;
+ if(m_pStream && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStream);
+ m_pStream=NULL;
+ }
- m_sError= "Ok";
+ if(m_pStreamCompressed && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStreamCompressed);
+ m_pStreamCompressed=NULL;
+ }
+ if(m_pAVIFile && AVIFileRelease_ptr){
+ AVIFileRelease_ptr(m_pAVIFile);
+ m_pAVIFile=NULL;
+ }
- if(!initVFW()){
- return S_FALSE;
+ if(ICCompressorFree_ptr){
+ ICCompressorFree_ptr(&cv);
}
+ if(AVIFileExit_ptr){
+ AVIFileExit_ptr();
+ }
- triggerCleanup cleaner(this);
+ if(msvfw32){
+ FreeLibrary(msvfw32);
+ }
+ if(avifil32){
+ FreeLibrary(avifil32);
+ }
+}
- // Step 0 : Let's make sure we are running on 1.1
+
+HRESULT CAVIGenerator::InitAVICompressionEngine(){
+
+ AVISTREAMINFO strHdr; //Information for a single stream
+ AVICOMPRESSOPTIONS opts;
+ HRESULT hr;
+
+
+ //Let's make sure we are running on 1.1
DWORD wVer = HIWORD(VideoForWindowsVersion_ptr());
- if (wVer < 0x010a)
- {
- // oops, we are too old, blow out of here
+ if(wVer < 0x010a){
+ //oops, we are too old, blow out of here
m_sError="Version of Video for Windows too old. Come on, join the 21th century!";
return S_FALSE;
}
- // Step 1 : initialize AVI engine
+ //Initialize AVI engine
AVIFileInit_ptr();
memset(&cv,0,sizeof(COMPVARS));
-
cv.cbSize=sizeof(COMPVARS);
cv.dwFlags=ICMF_COMPVARS_VALID;
- cv.fccHandler=mmioFOURCC('W','M','V','3');
+ cv.fccHandler=mmioFOURCC('f','f','d','s');//default video codec
cv.lQ=ICQUALITY_DEFAULT;
HWND hWnd = FindWindow(NULL, ("Spring " + std::string(VERSION_STRING)).c_str());
-
- if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &m_bih, NULL, &cv, NULL)){
+ //Set the compression, prompting dialog if necessary
+ if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &bitmapInfo, NULL, &cv, NULL)){
return S_FALSE;
}
-
// Fill in the header for the video stream....
memset(&strHdr, 0, sizeof(AVISTREAMINFO));
strHdr.fccType = streamtypeVIDEO; // video stream type
strHdr.fccHandler = cv.fccHandler;
strHdr.dwScale = 1; // should be one for video
- strHdr.dwRate = m_dwRate; // fps
- strHdr.dwSuggestedBufferSize = m_bih.biSizeImage; // Recommended buffer size, in bytes, for the stream.
- SetRect(&strHdr.rcFrame, 0, 0, (int)m_bih.biWidth, (int)m_bih.biHeight); // rectangle for stream
-
+ strHdr.dwRate = videoFPS; // fps
+ strHdr.dwSuggestedBufferSize = bitmapInfo.biSizeImage; // Recommended buffer size, in bytes, for the stream.
+ SetRect(&strHdr.rcFrame, 0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight);
+ strcpy(strHdr.szName, "Spring video.");
memset(&opts, 0, sizeof(AVICOMPRESSOPTIONS));
@@ -188,47 +241,48 @@
opts.cbParms=cv.cbState;
opts.dwInterleaveEvery=0;
- // Step 2 : Open the movie file for writing....
+
+
+ //Open the movie file for writing
hr = AVIFileOpenA_ptr(&m_pAVIFile, // Address to contain the new file interface pointer
- m_sFile.c_str(), // Null-terminated string containing the name of the file to open
- OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
+ fileName.c_str(), // Null-terminated string containing the name of the file to open
+ OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
NULL); // use handler determined from file extension.
- // Name your file .avi -> very important
if (hr != AVIERR_OK)
{
- //_tprintf(szBuffer,"AVI Engine failed to initialize. Check filename %s.",m_sFile);
m_sError="AVI Engine failed to initialize. Check filename ";
- m_sError+=m_sFile;
- // Check it succeded.
+ m_sError+=fileName;
+ //Translate error code
switch(hr)
{
- case AVIERR_BADFORMAT:
+ case AVIERR_BADFORMAT:
m_sError+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
break;
- case AVIERR_MEMORY:
- m_sError+="The file could not be opened because of insufficient memory.";
+ case AVIERR_MEMORY:
+ m_sError+="The file could not be opened because of insufficient memory.";
break;
case AVIERR_FILEREAD:
- m_sError+="A disk error occurred while reading the file.";
+ m_sError+="A disk error occurred while reading the file.";
break;
- case AVIERR_FILEOPEN:
+ case AVIERR_FILEOPEN:
m_sError+="A disk error occurred while opening the file.";
break;
- case REGDB_E_CLASSNOTREG:
+ case REGDB_E_CLASSNOTREG:
m_sError+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 3 : Create the stream;
+ //Create the stream
hr = AVIFileCreateStreamA_ptr(m_pAVIFile, // file pointer
&m_pStream, // returned stream pointer
&strHdr); // stream header
- // Check it succeded.
if (hr != AVIERR_OK)
{
m_sError="AVI Stream creation failed. Check Bitmap info.";
@@ -240,12 +294,8 @@
}
- // Step 5: Create a compressed stream using codec options.
- hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed,
- m_pStream,
- &opts,
- NULL);
-
+ //Create a compressed stream using codec options.
+ hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed, m_pStream, &opts, NULL);
if (hr != AVIERR_OK)
{
m_sError="AVI Compressed Stream creation failed.";
@@ -257,21 +307,23 @@
break;
case AVIERR_MEMORY:
m_sError+=" There is not enough memory to complete the operation.";
- break;
+ break;
case AVIERR_UNSUPPORTED:
m_sError+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
break;
+ default :
+ m_sError+="Unknown error.";
}
return hr;
}
- // Step 6 : sets the format of a stream at the specified position
- hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
+ //Sets the format of a stream at the specified position
+ hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
0, // position
- &m_bih, // stream format
- m_bih.biSize + // format size
- m_bih.biClrUsed * sizeof(RGBQUAD));
+ &bitmapInfo, // stream format
+ bitmapInfo.biSize + // format size
+ bitmapInfo.biClrUsed * sizeof(RGBQUAD));
if (hr != AVIERR_OK)
{
@@ -279,54 +331,39 @@
return hr;
}
- // Step 6 : Initialize step counter
- m_lFrame=0;
- pixelDataBuf = SAFE_NEW unsigned char[m_bih.biSizeImage];
- cleaner.disarm();
-
return hr;
}
-void CAVIGenerator::ReleaseEngine()
-{
- if (m_pStream)
- {
- AVIStreamRelease_ptr(m_pStream);
- m_pStream=NULL;
+bool CAVIGenerator::InitEngine(){
+
+ for(int i=0; i<10; i++){
+ unsigned char* tmpBuf = SAFE_NEW unsigned char[bitmapInfo.biSizeImage];
+ freeDataPointers.push_back(tmpBuf);
}
- if (m_pStreamCompressed)
- {
- AVIStreamRelease_ptr(m_pStreamCompressed);
- m_pStreamCompressed=NULL;
+ if(quitAVIgen){//error in initVFW
+ return false;
}
- if (m_pAVIFile)
- {
- AVIFileRelease_ptr(m_pAVIFile);
- m_pAVIFile=NULL;
+ HRESULT hr = InitAVICompressionEngine();
+ if(hr != AVIERR_OK){
+ return false;
}
- ICCompressorFree_ptr(&cv);
+ AVIThread = SAFE_NEW boost::thread(boost::bind(&CAVIGenerator::AVIGeneratorThreadProc, this));
+ return true;
+}
- delete [] pixelDataBuf;
- pixelDataBuf=0;
- // Close engine
- AVIFileExit_ptr();
-}
+HRESULT CAVIGenerator::AddFrame(unsigned char* pixelData){
-HRESULT CAVIGenerator::AddFrame(BYTE *bmBits)
-{
- HRESULT hr;
-
// compress bitmap
- hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
- m_lFrame, // time of this frame
+ HRESULT hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
+ m_lFrame, // time of this frame
1, // number to write
- bmBits, // image buffer
- m_bih.biSizeImage, // size of this frame
+ pixelData, // image buffer
+ bitmapInfo.biSizeImage, // size of this frame
AVIIF_KEYFRAME, // flags....
NULL,
NULL);
@@ -337,10 +374,59 @@
return hr;
}
-void CAVIGenerator::MakeExtAvi(){
- std::size_t pos = m_sFile.find_last_of(".avi");
- if(pos == std::string::npos || pos + 1 != m_sFile.size()){
- m_sFile += ".avi";
+void CAVIGenerator::readOpenglPixelDataThreaded(){
+
+ for(;;){
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ return;
+ }
+ if(readBuf != 0){
+ dataPointers.push_back(readBuf);
+ readBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(freeDataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ readBuf = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ break;
}
+
+ glReadPixels(0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, readBuf);
}
+
+
+void CAVIGenerator::AVIGeneratorThreadProc(){
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+ unsigned char* localWriteBuf = 0;
+
+ for(;;){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ break;
+ }
+ if(localWriteBuf != 0){
+ freeDataPointers.push_back(localWriteBuf);
+ localWriteBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(dataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ localWriteBuf = dataPointers.front();
+ dataPointers.pop_front();
+ }
+ if(AddFrame(localWriteBuf)){
+ quitAVIgen = true;
+ }
+ }
+ delete [] localWriteBuf;
+}
+
Index: rts/System/Platform/Win/AVIGenerator.h
===================================================================
--- rts/System/Platform/Win/AVIGenerator.h (revision 5421)
+++ rts/System/Platform/Win/AVIGenerator.h (working copy)
@@ -1,127 +1,81 @@
-// AVIGenerator.h: interface for the CAVIGenerator class.
-//
-// A class to easily create AVI
-//
-// Original code : Example code in WriteAvi.c of MSDN
-//
-// Author : Jonathan de Halleux. dehalleux@auto.ucl.ac.be
-//////////////////////////////////////////////////////////////////////
-
#ifndef AVIGENERATOR_H
#define AVIGENERATOR_H
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/utility.hpp>
#include <windows.h>
#include <vfw.h>
-#include <GL/gl.h>
-#if defined(_WIN32) && defined(__MINGW32__)
-#include <GL/glext.h>
-#endif
-
#include <string>
+#include <list>
-/*! \brief A simple class to create AVI video stream.
+class CAVIGenerator : boost::noncopyable {
+public:
+ CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS);
+ ~CAVIGenerator();
-\par Usage
+ //Initialize engine and choose codec
+ bool InitEngine();
-Step 1 : Declare an CAVIGenerator object
-Step 2 : Set Bitmap by calling SetBitmapHeader functions + other parameters
-Step 3 : Initialize engine by calling InitEngine
-Step 4 : Send each frames to engine with function AddFrame
-Step 5 : Close engine by calling ReleaseEngine
+ //Returns last error message
+ std::string GetLastErrorMessage() const {return m_sError;}
-\par Demo Code:
+ void readOpenglPixelDataThreaded();
-\code
-CAVIGenerator AviGen;
-BYTE* bmBits;
-// set characteristics
-AviGen.SetRate(20); // set 20fps
-AviGen.SetBitmapHeader(GetActiveView()); // give info about bitmap
+private:
+ //name of output file
+ std::string fileName;
+ //Frame rate
+ DWORD videoFPS;
+ //structure contains information for a single stream
+ BITMAPINFOHEADER bitmapInfo;
+ //last error string
+ std::string m_sError;
-AviGen.InitEngine();
+ HINSTANCE msvfw32;
+ HINSTANCE avifil32;
-..... // Draw code, bmBits is the buffer containing the frame
-AviGen.AddFrame(bmBits);
-.....
+ volatile bool quitAVIgen;
-AviGen.ReleaseEngine();
-\endcode
+ boost::thread* AVIThread;
+ boost::mutex AVIMutex;
+ boost::condition AVICondition;
-\par Update history:
-- {\b 22-10-2002} Minor changes in constructors.
+ std::list<unsigned char*> freeDataPointers;
+ std::list<unsigned char*> dataPointers;
-\author : Jonathan de Halleux, dehalleux@auto.ucl.ac.be (2001)
-*/
-class CAVIGenerator
-{
-public:
- //! \name Constructors and destructors
- //@{
- //! Inplace constructor with BITMAPINFOHEADER
- CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate);
- ~CAVIGenerator();
- //@}
+ unsigned char* readBuf;
- //! \name AVI engine function
- //@{
- /*! \brief Initialize engine and choose codex
- Some asserts are made to check that bitmap has been properly initialized
- */
- HRESULT InitEngine();
- /*! \brief Adds a frame to the movie.
- The data pointed by bmBits has to be compatible with the bitmap description of the movie.
- */
- HRESULT AddFrame(BYTE* bmBits);
- //! Release ressources allocated for movie and close file.
- void ReleaseEngine();
- //@}
+ bool initVFW();
- //! \name Setters and getters
- //@{
- //! returns a pointer to bitmap info
- LPBITMAPINFOHEADER GetBitmapHeader() {return &m_bih;}
+ HRESULT InitAVICompressionEngine();
- //! \name Error handling
- //@{
- //! returns last error message
- std::string GetLastErrorMessage() const {return m_sError;}
- //@}
- unsigned char* GetPixelBuf(){return pixelDataBuf;}
+ //Release streams allocated for movie compression.
+ void ReleaseAVICompressionEngine();
+ //Adds a frame to the movie.
+ HRESULT AddFrame(unsigned char* pixelData);
-private:
- //! name of output file
- std::string m_sFile;
- //! Frame rate
- DWORD m_dwRate;
- //! structure contains information for a single stream
- BITMAPINFOHEADER m_bih;
- //! last error string
- std::string m_sError;
+ void AVIGeneratorThreadProc();
- unsigned char* pixelDataBuf;
-
- //! Sets bitmap info as in lpbih
- void SetBitmapHeader(LPBITMAPINFOHEADER lpbih);
-
- void MakeExtAvi();
- //! frame counter
+ //frame counter
long m_lFrame;
- //! file interface pointer
+ //file interface pointer
PAVIFILE m_pAVIFile;
- //! Address of the stream interface
- PAVISTREAM m_pStream;
- //! Address of the compressed video stream
- PAVISTREAM m_pStreamCompressed;
+ //Address of the stream interface
+ PAVISTREAM m_pStream;
+ //Address of the compressed video stream
+ PAVISTREAM m_pStreamCompressed;
//Holds compression settings
COMPVARS cv;
@@ -137,6 +91,7 @@
typedef HRESULT (__stdcall *AVIStreamWrite_type)(PAVISTREAM, LONG, LONG, LPVOID, LONG, DWORD, LONG FAR *, LONG FAR *);
typedef BOOL (__stdcall *ICCompressorChoose_type)(HWND, UINT, LPVOID, LPVOID, PCOMPVARS, LPSTR);
typedef void (__stdcall *ICCompressorFree_type)(PCOMPVARS);
+ typedef HIC (__stdcall *ICOpen_type)(DWORD, DWORD, UINT);
@@ -152,26 +107,8 @@
AVIStreamWrite_type AVIStreamWrite_ptr;
ICCompressorChoose_type ICCompressorChoose_ptr;
ICCompressorFree_type ICCompressorFree_ptr;
+ ICOpen_type ICOpen_ptr;
-
- bool initVFW();
-
-
- struct triggerCleanup{
- triggerCleanup(CAVIGenerator* ptr) : clean(true), ptr(ptr){};
- ~triggerCleanup(){
- if(clean){
- ptr->ReleaseEngine();
- }
- }
- void disarm(){
- clean = false;
- }
- private:
- bool clean;
- CAVIGenerator* ptr;
- };
-
};
#endif /* AVIGENERATOR_H */
-
avi_generator_v4.patch (28,198 bytes) 2008-02-06 15:26
Index: rts/Game/Game.cpp
===================================================================
--- rts/Game/Game.cpp (revision 5455)
+++ rts/Game/Game.cpp (working copy)
@@ -499,7 +499,6 @@
#ifndef NO_AVI
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator = NULL;
}
@@ -1169,53 +1168,40 @@
else if (cmd == "createvideo") {
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator=0;
- // logOutput.Print("Finished avi");
} else {
creatingVideo=true;
- string name;
+ string fileName;
for(int a=0;a<999;++a){
char t[50];
itoa(a,t,10);
- name=string("video")+t+".avi";
- CFileHandler ifs(name);
+ fileName=string("video")+t+".avi";
+ CFileHandler ifs(fileName);
if(!ifs.FileExists())
break;
}
- BITMAPINFOHEADER bih;
- memset(&bih,0, sizeof(BITMAPINFOHEADER));
+ int videoSizeX = (gu->viewSizeX/4)*4;
+ int videoSizeY = (gu->viewSizeY/4)*4;
+ aviGenerator = SAFE_NEW CAVIGenerator(fileName, videoSizeX, videoSizeY, 30);
- // filling bitmap info structure.
- bih.biSize=sizeof(BITMAPINFOHEADER);
- bih.biWidth=(gu->viewSizeX/4)*4;
- bih.biHeight=(gu->viewSizeY/4)*4;
- bih.biPlanes=1;
- bih.biBitCount=24;
- bih.biSizeImage=bih.biWidth*bih.biHeight*3;
- bih.biCompression=BI_RGB;
-
-
- aviGenerator = SAFE_NEW CAVIGenerator(name, &bih, 30);
int savedCursorMode = SDL_ShowCursor(SDL_QUERY);
SDL_ShowCursor(SDL_ENABLE);
- HRESULT hr=aviGenerator->InitEngine();
- SDL_ShowCursor(savedCursorMode);
- //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
- //Setting it back to 'normal'.
- streflop_init<streflop::Simple>();
- if(hr!=AVIERR_OK){
+ if(!aviGenerator->InitEngine()){
creatingVideo=false;
logOutput.Print(aviGenerator->GetLastErrorMessage());
delete aviGenerator;
aviGenerator=0;
} else {
- logOutput.Print("Recording avi to %s size %li %li", name.c_str(),
- bih.biWidth, bih.biHeight);
+ logOutput.Print("Recording avi to %s size %li x %li", fileName.c_str(), videoSizeX, videoSizeY);
}
+
+ SDL_ShowCursor(savedCursorMode);
+ //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
+ //Setting it back to default state.
+ streflop_init<streflop::Simple>();
}
}
#endif
@@ -2372,13 +2358,7 @@
#ifndef NO_AVI
if(creatingVideo){
gu->lastFrameTime=1.0f/GAME_SPEED;
- LPBITMAPINFOHEADER ih;
- ih = aviGenerator->GetBitmapHeader();
- unsigned char* buf = aviGenerator->GetPixelBuf();
- glReadPixels(0,0,ih->biWidth, ih->biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, buf);
-
- aviGenerator->AddFrame(buf);
-
+ aviGenerator->readOpenglPixelDataThreaded();
// logOutput.Print("Saved avi frame size %i %i",ih->biWidth,ih->biHeight);
}
#endif
Index: rts/Game/GameServer.cpp
===================================================================
--- rts/Game/GameServer.cpp (revision 5455)
+++ rts/Game/GameServer.cpp (working copy)
@@ -890,11 +890,15 @@
timeLeft -= newFrames;
}
+ bool rec = false;
#ifndef NO_AVI
- if(((!game || !game->creatingVideo) && !IsPaused) || fixedFrameTime){
-#else
- if(!IsPaused || fixedFrameTime){
+ rec = game && game->creatingVideo;
#endif
+ bool normalFrame = !IsPaused && !fixedFrameTime && !rec;
+ bool videoFrame = !IsPaused && fixedFrameTime && rec;
+ bool singleStep = IsPaused && fixedFrameTime && !rec;
+
+ if(normalFrame || videoFrame || singleStep){
for(int i=0; i < newFrames; ++i){
++serverframenum;
//Send out new frame messages.
Index: rts/System/Platform/Win/AVIGenerator.cpp
===================================================================
--- rts/System/Platform/Win/AVIGenerator.cpp (revision 5455)
+++ rts/System/Platform/Win/AVIGenerator.cpp (working copy)
@@ -1,72 +1,63 @@
-// AVIGenerator.cpp: implementation of the CAVIGenerator class.
-//
-//////////////////////////////////////////////////////////////////////
-
#include "StdAfx.h"
#include "AVIGenerator.h"
#include "Game/GameVersion.h"
+#include "LogOutput.h"
+
+#include <windows.h>
+#include <GL/gl.h>
+#if defined(_WIN32) && defined(__MINGW32__)
+#include <GL/glext.h>
+#endif
+
+#include <boost/bind.hpp>
#include <cassert>
#include "mmgr.h"
#if defined(_WIN32) && !defined(__MINGW32__)
-#pragma message(" _Adding library: vfw32.lib" )
+#pragma message("Adding library: vfw32.lib")
#pragma comment(lib, "vfw32.lib")
#endif
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
bool CAVIGenerator::initVFW(){
#if defined(_WIN32) && defined(__MINGW32__)
- HMODULE hMod = LoadLibrary("msvfw32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
- }
+ msvfw32 = LoadLibrary("msvfw32.dll");
+ avifil32 = LoadLibrary("avifil32.dll");
+ VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(msvfw32, "VideoForWindowsVersion");
+ ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(msvfw32, "ICCompressorChoose");
+ ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(msvfw32, "ICCompressorFree");
+ ICOpen_ptr=(ICOpen_type)GetProcAddress(msvfw32, "ICOpen");
- VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(hMod, "VideoForWindowsVersion");
- ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(hMod, "ICCompressorChoose");
- ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(hMod, "ICCompressorFree");
+ AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(avifil32, "AVIFileInit");
+ AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(avifil32, "AVIFileOpenA");
+ AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(avifil32, "AVIFileCreateStreamA");
+ AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(avifil32, "AVIMakeCompressedStream");
+ AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(avifil32, "AVIStreamSetFormat");
+ AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(avifil32, "AVIStreamRelease");
+ AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(avifil32, "AVIFileRelease");
+ AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(avifil32, "AVIFileExit");
+ AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(avifil32, "AVIStreamWrite");
+ if(NULL == msvfw32 || NULL == avifil32){
+ errorMsg="LoadLibrary failed.";
+ return false;
+ }
- if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr){
- m_sError="initVFW Error.";
- return false;
- }
-
-
-
- hMod = LoadLibrary("avifil32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
+ if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr || !ICOpen_ptr){
+ errorMsg="initVFW Error.";
+ return false;
}
-
- AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(hMod, "AVIFileInit");
- AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(hMod, "AVIFileOpenA");
- AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(hMod, "AVIFileCreateStreamA");
- AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(hMod, "AVIMakeCompressedStream");
- AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(hMod, "AVIStreamSetFormat");
- AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(hMod, "AVIStreamRelease");
- AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(hMod, "AVIFileRelease");
- AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(hMod, "AVIFileExit");
- AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(hMod, "AVIStreamWrite");
-
-
- if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
+ if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
!AVIMakeCompressedStream_ptr || !AVIStreamSetFormat_ptr || !AVIStreamRelease_ptr ||
!AVIFileRelease_ptr || !AVIFileExit_ptr || !AVIStreamWrite_ptr){
- m_sError="initVFW Error.";
- return false;
- }
- return true;
+ errorMsg="initVFW Error.";
+ return false;
+ }
#else
VideoForWindowsVersion_ptr =&VideoForWindowsVersion;
@@ -81,98 +72,160 @@
AVIStreamWrite_ptr = &AVIStreamWrite;
ICCompressorChoose_ptr = &ICCompressorChoose;
ICCompressorFree_ptr = &ICCompressorFree;
-
+ ICOpen_ptr = &ICOpen;
+#endif
return true;
-#endif
}
+CAVIGenerator::CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS)
+ :
+ fileName(fileName),
+ videoFPS(videoFPS),
+ errorMsg("Ok"),
+ quitAVIgen(false),
+ AVIThread(0),
+ readBuf(0),
+ m_lFrame(0),
+ m_pAVIFile(NULL),
+ m_pStream(NULL),
+ m_pStreamCompressed(NULL){
-CAVIGenerator::CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate)
-: m_sFile(sFileName), m_dwRate(dwRate), pixelDataBuf(0),
-m_pAVIFile(NULL), m_pStream(NULL), m_pStreamCompressed(NULL)
-{
- MakeExtAvi();
- SetBitmapHeader(lpbih);
-}
+ assert(videoSizeX % 4 == 0);
+ assert(videoSizeY % 4 == 0);
-CAVIGenerator::~CAVIGenerator()
-{
- // Just checking that all allocated ressources have been released
- assert(m_pStream==NULL);
- assert(m_pStreamCompressed==NULL);
- assert(m_pAVIFile==NULL);
- assert(pixelDataBuf==NULL);
+ memset(&bitmapInfo, 0, sizeof(BITMAPINFOHEADER));
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = videoSizeX;
+ bitmapInfo.biHeight = videoSizeY;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 24;
+ bitmapInfo.biSizeImage = videoSizeX * videoSizeY * 3;
+ bitmapInfo.biCompression = BI_RGB;
+
+ if(!initVFW()){
+ quitAVIgen = true;
+ }
}
-void CAVIGenerator::SetBitmapHeader(LPBITMAPINFOHEADER lpbih)
-{
- // checking that bitmap size are multiple of 4
- assert(lpbih->biWidth%4==0);
- assert(lpbih->biHeight%4==0);
- assert(lpbih->biBitCount==24);
- assert(lpbih->biCompression==BI_RGB);
- assert(lpbih->biSizeImage==lpbih->biWidth*lpbih->biHeight*3);
- // copying bitmap info structure.
- // corrected thanks to Lori Gardi
- memcpy(&m_bih,lpbih, sizeof(BITMAPINFOHEADER));
+CAVIGenerator::~CAVIGenerator(){
+
+ if(AVIThread){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ quitAVIgen = true;
+ AVICondition.notify_all();
+ }
+ AVIThread->join();
+
+ delete AVIThread;
+ AVIThread = 0;
+ }
+
+ while(!freeDataPointers.empty()){
+ unsigned char* tmp = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ delete [] tmp;
+ }
+ while(!dataPointers.empty()){
+ unsigned char* tmp = dataPointers.front();
+ dataPointers.pop_front();
+ delete [] tmp;
+ }
+
+ delete [] readBuf;
+ readBuf = 0;
+
+
+ ReleaseAVICompressionEngine();
+ logOutput.Print(std::string("Finished writing avi file, ") + fileName);
+
+ //Just checking that all allocated ressources have been released.
+ assert(AVIThread == NULL);
+ assert(m_pAVIFile == NULL);
+ assert(m_pStream == NULL);
+ assert(m_pStreamCompressed == NULL);
+ assert(freeDataPointers.empty());
+ assert(dataPointers.empty());
+ assert(readBuf == NULL);
}
-HRESULT CAVIGenerator::InitEngine()
-{
- AVISTREAMINFO strHdr; // information for a single stream
- AVICOMPRESSOPTIONS opts;
+void CAVIGenerator::ReleaseAVICompressionEngine(){
- HRESULT hr;
+ if(m_pStream && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStream);
+ m_pStream=NULL;
+ }
- m_sError= "Ok";
+ if(m_pStreamCompressed && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStreamCompressed);
+ m_pStreamCompressed=NULL;
+ }
+ if(m_pAVIFile && AVIFileRelease_ptr){
+ AVIFileRelease_ptr(m_pAVIFile);
+ m_pAVIFile=NULL;
+ }
- if(!initVFW()){
- return S_FALSE;
+ if(ICCompressorFree_ptr){
+ ICCompressorFree_ptr(&cv);
}
+ if(AVIFileExit_ptr){
+ AVIFileExit_ptr();
+ }
- triggerCleanup cleaner(this);
+ if(msvfw32){
+ FreeLibrary(msvfw32);
+ }
+ if(avifil32){
+ FreeLibrary(avifil32);
+ }
+}
- // Step 0 : Let's make sure we are running on 1.1
+
+HRESULT CAVIGenerator::InitAVICompressionEngine(){
+
+ AVISTREAMINFO strHdr; //Information for a single stream
+ AVICOMPRESSOPTIONS opts;
+ HRESULT hr;
+
+
+ //Let's make sure we are running on 1.1
DWORD wVer = HIWORD(VideoForWindowsVersion_ptr());
- if (wVer < 0x010a)
- {
- // oops, we are too old, blow out of here
- m_sError="Version of Video for Windows too old. Come on, join the 21th century!";
+ if(wVer < 0x010a){
+ //oops, we are too old, blow out of here
+ errorMsg="Version of Video for Windows too old. Come on, join the 21th century!";
return S_FALSE;
}
- // Step 1 : initialize AVI engine
+ //Initialize AVI engine
AVIFileInit_ptr();
memset(&cv,0,sizeof(COMPVARS));
-
cv.cbSize=sizeof(COMPVARS);
cv.dwFlags=ICMF_COMPVARS_VALID;
- cv.fccHandler=mmioFOURCC('W','M','V','3');
+ cv.fccHandler=mmioFOURCC('f','f','d','s');//default video codec
cv.lQ=ICQUALITY_DEFAULT;
HWND hWnd = FindWindow(NULL, ("Spring " + std::string(VERSION_STRING)).c_str());
-
- if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &m_bih, NULL, &cv, NULL)){
+ //Set the compression, prompting dialog if necessary
+ if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &bitmapInfo, NULL, &cv, NULL)){
return S_FALSE;
}
-
// Fill in the header for the video stream....
memset(&strHdr, 0, sizeof(AVISTREAMINFO));
strHdr.fccType = streamtypeVIDEO; // video stream type
strHdr.fccHandler = cv.fccHandler;
strHdr.dwScale = 1; // should be one for video
- strHdr.dwRate = m_dwRate; // fps
- strHdr.dwSuggestedBufferSize = m_bih.biSizeImage; // Recommended buffer size, in bytes, for the stream.
- SetRect(&strHdr.rcFrame, 0, 0, (int)m_bih.biWidth, (int)m_bih.biHeight); // rectangle for stream
-
+ strHdr.dwRate = videoFPS; // fps
+ strHdr.dwSuggestedBufferSize = bitmapInfo.biSizeImage; // Recommended buffer size, in bytes, for the stream.
+ SetRect(&strHdr.rcFrame, 0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight);
+ strcpy(strHdr.szName, "Spring video.");
memset(&opts, 0, sizeof(AVICOMPRESSOPTIONS));
@@ -188,145 +241,130 @@
opts.cbParms=cv.cbState;
opts.dwInterleaveEvery=0;
- // Step 2 : Open the movie file for writing....
+
+
+ //Open the movie file for writing
hr = AVIFileOpenA_ptr(&m_pAVIFile, // Address to contain the new file interface pointer
- m_sFile.c_str(), // Null-terminated string containing the name of the file to open
- OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
+ fileName.c_str(), // Null-terminated string containing the name of the file to open
+ OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
NULL); // use handler determined from file extension.
- // Name your file .avi -> very important
if (hr != AVIERR_OK)
{
- //_tprintf(szBuffer,"AVI Engine failed to initialize. Check filename %s.",m_sFile);
- m_sError="AVI Engine failed to initialize. Check filename ";
- m_sError+=m_sFile;
- // Check it succeded.
+ errorMsg="AVI Engine failed to initialize. Check filename ";
+ errorMsg+=fileName;
+ //Translate error code
switch(hr)
{
- case AVIERR_BADFORMAT:
- m_sError+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
+ case AVIERR_BADFORMAT:
+ errorMsg+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
break;
- case AVIERR_MEMORY:
- m_sError+="The file could not be opened because of insufficient memory.";
+ case AVIERR_MEMORY:
+ errorMsg+="The file could not be opened because of insufficient memory.";
break;
case AVIERR_FILEREAD:
- m_sError+="A disk error occurred while reading the file.";
+ errorMsg+="A disk error occurred while reading the file.";
break;
- case AVIERR_FILEOPEN:
- m_sError+="A disk error occurred while opening the file.";
+ case AVIERR_FILEOPEN:
+ errorMsg+="A disk error occurred while opening the file.";
break;
- case REGDB_E_CLASSNOTREG:
- m_sError+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
+ case REGDB_E_CLASSNOTREG:
+ errorMsg+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
break;
+ default :
+ errorMsg+="Unknown error.";
}
return hr;
}
- // Step 3 : Create the stream;
+ //Create the stream
hr = AVIFileCreateStreamA_ptr(m_pAVIFile, // file pointer
&m_pStream, // returned stream pointer
&strHdr); // stream header
- // Check it succeded.
if (hr != AVIERR_OK)
{
- m_sError="AVI Stream creation failed. Check Bitmap info.";
+ errorMsg="AVI Stream creation failed. Check Bitmap info.";
if (hr==AVIERR_READONLY)
{
- m_sError+=" Read only file.";
+ errorMsg+=" Read only file.";
}
return hr;
}
- // Step 5: Create a compressed stream using codec options.
- hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed,
- m_pStream,
- &opts,
- NULL);
-
+ //Create a compressed stream using codec options.
+ hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed, m_pStream, &opts, NULL);
if (hr != AVIERR_OK)
{
- m_sError="AVI Compressed Stream creation failed.";
+ errorMsg="AVI Compressed Stream creation failed.";
switch(hr)
{
case AVIERR_NOCOMPRESSOR:
- m_sError+=" A suitable compressor cannot be found.";
+ errorMsg+=" A suitable compressor cannot be found.";
break;
case AVIERR_MEMORY:
- m_sError+=" There is not enough memory to complete the operation.";
- break;
+ errorMsg+=" There is not enough memory to complete the operation.";
+ break;
case AVIERR_UNSUPPORTED:
- m_sError+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
+ errorMsg+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
break;
+ default :
+ errorMsg+="Unknown error.";
}
return hr;
}
- // Step 6 : sets the format of a stream at the specified position
- hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
+ //Sets the format of a stream at the specified position
+ hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
0, // position
- &m_bih, // stream format
- m_bih.biSize + // format size
- m_bih.biClrUsed * sizeof(RGBQUAD));
+ &bitmapInfo, // stream format
+ bitmapInfo.biSize + // format size
+ bitmapInfo.biClrUsed * sizeof(RGBQUAD));
if (hr != AVIERR_OK)
{
- m_sError="AVI Compressed Stream format setting failed.";
+ errorMsg="AVI Compressed Stream format setting failed.";
return hr;
}
- // Step 6 : Initialize step counter
- m_lFrame=0;
- pixelDataBuf = SAFE_NEW unsigned char[m_bih.biSizeImage];
- cleaner.disarm();
-
return hr;
}
-void CAVIGenerator::ReleaseEngine()
-{
- if (m_pStream)
- {
- AVIStreamRelease_ptr(m_pStream);
- m_pStream=NULL;
+bool CAVIGenerator::InitEngine(){
+
+ if(quitAVIgen){//error in initVFW
+ return false;
}
- if (m_pStreamCompressed)
- {
- AVIStreamRelease_ptr(m_pStreamCompressed);
- m_pStreamCompressed=NULL;
+ HRESULT hr = InitAVICompressionEngine();
+ if(hr != AVIERR_OK){
+ quitAVIgen = true;
+ return false;
}
- if (m_pAVIFile)
- {
- AVIFileRelease_ptr(m_pAVIFile);
- m_pAVIFile=NULL;
+ for(int i=0; i<10; i++){
+ unsigned char* tmpBuf = SAFE_NEW unsigned char[bitmapInfo.biSizeImage];
+ freeDataPointers.push_back(tmpBuf);
}
- ICCompressorFree_ptr(&cv);
+ AVIThread = SAFE_NEW boost::thread(boost::bind(&CAVIGenerator::AVIGeneratorThreadProc, this));
+ return true;
+}
- delete [] pixelDataBuf;
- pixelDataBuf=0;
- // Close engine
- AVIFileExit_ptr();
-}
+HRESULT CAVIGenerator::AddFrame(unsigned char* pixelData){
-HRESULT CAVIGenerator::AddFrame(BYTE *bmBits)
-{
- HRESULT hr;
-
// compress bitmap
- hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
- m_lFrame, // time of this frame
+ HRESULT hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
+ m_lFrame, // time of this frame
1, // number to write
- bmBits, // image buffer
- m_bih.biSizeImage, // size of this frame
+ pixelData, // image buffer
+ bitmapInfo.biSizeImage, // size of this frame
AVIIF_KEYFRAME, // flags....
NULL,
NULL);
@@ -337,10 +375,59 @@
return hr;
}
-void CAVIGenerator::MakeExtAvi(){
- std::size_t pos = m_sFile.find_last_of(".avi");
- if(pos == std::string::npos || pos + 1 != m_sFile.size()){
- m_sFile += ".avi";
+void CAVIGenerator::readOpenglPixelDataThreaded(){
+
+ for(;;){
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ return;
+ }
+ if(readBuf != 0){
+ dataPointers.push_back(readBuf);
+ readBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(freeDataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ readBuf = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ break;
}
+
+ glReadPixels(0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, readBuf);
}
+
+
+void CAVIGenerator::AVIGeneratorThreadProc(){
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+ unsigned char* localWriteBuf = 0;
+
+ for(;;){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ break;
+ }
+ if(localWriteBuf != 0){
+ freeDataPointers.push_back(localWriteBuf);
+ localWriteBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(dataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ localWriteBuf = dataPointers.front();
+ dataPointers.pop_front();
+ }
+ if(AddFrame(localWriteBuf)){
+ quitAVIgen = true;
+ }
+ }
+ delete [] localWriteBuf;
+}
+
Index: rts/System/Platform/Win/AVIGenerator.h
===================================================================
--- rts/System/Platform/Win/AVIGenerator.h (revision 5455)
+++ rts/System/Platform/Win/AVIGenerator.h (working copy)
@@ -1,127 +1,81 @@
-// AVIGenerator.h: interface for the CAVIGenerator class.
-//
-// A class to easily create AVI
-//
-// Original code : Example code in WriteAvi.c of MSDN
-//
-// Author : Jonathan de Halleux. dehalleux@auto.ucl.ac.be
-//////////////////////////////////////////////////////////////////////
-
#ifndef AVIGENERATOR_H
#define AVIGENERATOR_H
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/utility.hpp>
#include <windows.h>
#include <vfw.h>
-#include <GL/gl.h>
-#if defined(_WIN32) && defined(__MINGW32__)
-#include <GL/glext.h>
-#endif
-
#include <string>
+#include <list>
-/*! \brief A simple class to create AVI video stream.
+class CAVIGenerator : boost::noncopyable {
+public:
+ CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS);
+ ~CAVIGenerator();
-\par Usage
+ //Initialize engine and choose codec
+ bool InitEngine();
-Step 1 : Declare an CAVIGenerator object
-Step 2 : Set Bitmap by calling SetBitmapHeader functions + other parameters
-Step 3 : Initialize engine by calling InitEngine
-Step 4 : Send each frames to engine with function AddFrame
-Step 5 : Close engine by calling ReleaseEngine
+ //Returns last error message
+ std::string GetLastErrorMessage() const {return errorMsg;}
-\par Demo Code:
+ void readOpenglPixelDataThreaded();
-\code
-CAVIGenerator AviGen;
-BYTE* bmBits;
-// set characteristics
-AviGen.SetRate(20); // set 20fps
-AviGen.SetBitmapHeader(GetActiveView()); // give info about bitmap
+private:
+ //name of output file
+ std::string fileName;
+ //Frame rate
+ DWORD videoFPS;
+ //structure contains information for a single stream
+ BITMAPINFOHEADER bitmapInfo;
+ //last error string
+ std::string errorMsg;
-AviGen.InitEngine();
+ HINSTANCE msvfw32;
+ HINSTANCE avifil32;
-..... // Draw code, bmBits is the buffer containing the frame
-AviGen.AddFrame(bmBits);
-.....
+ volatile bool quitAVIgen;
-AviGen.ReleaseEngine();
-\endcode
+ boost::thread* AVIThread;
+ boost::mutex AVIMutex;
+ boost::condition AVICondition;
-\par Update history:
-- {\b 22-10-2002} Minor changes in constructors.
+ std::list<unsigned char*> freeDataPointers;
+ std::list<unsigned char*> dataPointers;
-\author : Jonathan de Halleux, dehalleux@auto.ucl.ac.be (2001)
-*/
-class CAVIGenerator
-{
-public:
- //! \name Constructors and destructors
- //@{
- //! Inplace constructor with BITMAPINFOHEADER
- CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate);
- ~CAVIGenerator();
- //@}
+ unsigned char* readBuf;
- //! \name AVI engine function
- //@{
- /*! \brief Initialize engine and choose codex
- Some asserts are made to check that bitmap has been properly initialized
- */
- HRESULT InitEngine();
- /*! \brief Adds a frame to the movie.
- The data pointed by bmBits has to be compatible with the bitmap description of the movie.
- */
- HRESULT AddFrame(BYTE* bmBits);
- //! Release ressources allocated for movie and close file.
- void ReleaseEngine();
- //@}
+ bool initVFW();
- //! \name Setters and getters
- //@{
- //! returns a pointer to bitmap info
- LPBITMAPINFOHEADER GetBitmapHeader() {return &m_bih;}
+ HRESULT InitAVICompressionEngine();
- //! \name Error handling
- //@{
- //! returns last error message
- std::string GetLastErrorMessage() const {return m_sError;}
- //@}
- unsigned char* GetPixelBuf(){return pixelDataBuf;}
+ //Release streams allocated for movie compression.
+ void ReleaseAVICompressionEngine();
+ //Adds a frame to the movie.
+ HRESULT AddFrame(unsigned char* pixelData);
-private:
- //! name of output file
- std::string m_sFile;
- //! Frame rate
- DWORD m_dwRate;
- //! structure contains information for a single stream
- BITMAPINFOHEADER m_bih;
- //! last error string
- std::string m_sError;
+ void AVIGeneratorThreadProc();
- unsigned char* pixelDataBuf;
-
- //! Sets bitmap info as in lpbih
- void SetBitmapHeader(LPBITMAPINFOHEADER lpbih);
-
- void MakeExtAvi();
- //! frame counter
+ //frame counter
long m_lFrame;
- //! file interface pointer
+ //file interface pointer
PAVIFILE m_pAVIFile;
- //! Address of the stream interface
- PAVISTREAM m_pStream;
- //! Address of the compressed video stream
- PAVISTREAM m_pStreamCompressed;
+ //Address of the stream interface
+ PAVISTREAM m_pStream;
+ //Address of the compressed video stream
+ PAVISTREAM m_pStreamCompressed;
//Holds compression settings
COMPVARS cv;
@@ -137,6 +91,7 @@
typedef HRESULT (__stdcall *AVIStreamWrite_type)(PAVISTREAM, LONG, LONG, LPVOID, LONG, DWORD, LONG FAR *, LONG FAR *);
typedef BOOL (__stdcall *ICCompressorChoose_type)(HWND, UINT, LPVOID, LPVOID, PCOMPVARS, LPSTR);
typedef void (__stdcall *ICCompressorFree_type)(PCOMPVARS);
+ typedef HIC (__stdcall *ICOpen_type)(DWORD, DWORD, UINT);
@@ -152,26 +107,8 @@
AVIStreamWrite_type AVIStreamWrite_ptr;
ICCompressorChoose_type ICCompressorChoose_ptr;
ICCompressorFree_type ICCompressorFree_ptr;
+ ICOpen_type ICOpen_ptr;
-
- bool initVFW();
-
-
- struct triggerCleanup{
- triggerCleanup(CAVIGenerator* ptr) : clean(true), ptr(ptr){};
- ~triggerCleanup(){
- if(clean){
- ptr->ReleaseEngine();
- }
- }
- void disarm(){
- clean = false;
- }
- private:
- bool clean;
- CAVIGenerator* ptr;
- };
-
};
#endif /* AVIGENERATOR_H */
-
avi_generator_v5.patch (28,160 bytes) 2008-02-06 17:24
Index: rts/Game/Game.cpp
===================================================================
--- rts/Game/Game.cpp (revision 5455)
+++ rts/Game/Game.cpp (working copy)
@@ -499,7 +499,6 @@
#ifndef NO_AVI
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator = NULL;
}
@@ -1169,53 +1168,40 @@
else if (cmd == "createvideo") {
if(creatingVideo){
creatingVideo=false;
- aviGenerator->ReleaseEngine();
delete aviGenerator;
aviGenerator=0;
- // logOutput.Print("Finished avi");
} else {
creatingVideo=true;
- string name;
+ string fileName;
for(int a=0;a<999;++a){
char t[50];
itoa(a,t,10);
- name=string("video")+t+".avi";
- CFileHandler ifs(name);
+ fileName=string("video")+t+".avi";
+ CFileHandler ifs(fileName);
if(!ifs.FileExists())
break;
}
- BITMAPINFOHEADER bih;
- memset(&bih,0, sizeof(BITMAPINFOHEADER));
+ int videoSizeX = (gu->viewSizeX/4)*4;
+ int videoSizeY = (gu->viewSizeY/4)*4;
+ aviGenerator = SAFE_NEW CAVIGenerator(fileName, videoSizeX, videoSizeY, 30);
- // filling bitmap info structure.
- bih.biSize=sizeof(BITMAPINFOHEADER);
- bih.biWidth=(gu->viewSizeX/4)*4;
- bih.biHeight=(gu->viewSizeY/4)*4;
- bih.biPlanes=1;
- bih.biBitCount=24;
- bih.biSizeImage=bih.biWidth*bih.biHeight*3;
- bih.biCompression=BI_RGB;
-
-
- aviGenerator = SAFE_NEW CAVIGenerator(name, &bih, 30);
int savedCursorMode = SDL_ShowCursor(SDL_QUERY);
SDL_ShowCursor(SDL_ENABLE);
- HRESULT hr=aviGenerator->InitEngine();
- SDL_ShowCursor(savedCursorMode);
- //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
- //Setting it back to 'normal'.
- streflop_init<streflop::Simple>();
- if(hr!=AVIERR_OK){
+ if(!aviGenerator->InitEngine()){
creatingVideo=false;
logOutput.Print(aviGenerator->GetLastErrorMessage());
delete aviGenerator;
aviGenerator=0;
} else {
- logOutput.Print("Recording avi to %s size %li %li", name.c_str(),
- bih.biWidth, bih.biHeight);
+ logOutput.Print("Recording avi to %s size %li x %li", fileName.c_str(), videoSizeX, videoSizeY);
}
+
+ SDL_ShowCursor(savedCursorMode);
+ //aviGenerator->InitEngine() (avicap32.dll)? modifies the FPU control word.
+ //Setting it back to default state.
+ streflop_init<streflop::Simple>();
}
}
#endif
@@ -2372,13 +2358,7 @@
#ifndef NO_AVI
if(creatingVideo){
gu->lastFrameTime=1.0f/GAME_SPEED;
- LPBITMAPINFOHEADER ih;
- ih = aviGenerator->GetBitmapHeader();
- unsigned char* buf = aviGenerator->GetPixelBuf();
- glReadPixels(0,0,ih->biWidth, ih->biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, buf);
-
- aviGenerator->AddFrame(buf);
-
+ aviGenerator->readOpenglPixelDataThreaded();
// logOutput.Print("Saved avi frame size %i %i",ih->biWidth,ih->biHeight);
}
#endif
Index: rts/Game/GameServer.cpp
===================================================================
--- rts/Game/GameServer.cpp (revision 5455)
+++ rts/Game/GameServer.cpp (working copy)
@@ -890,11 +890,15 @@
timeLeft -= newFrames;
}
+ bool rec = false;
#ifndef NO_AVI
- if(((!game || !game->creatingVideo) && !IsPaused) || fixedFrameTime){
-#else
- if(!IsPaused || fixedFrameTime){
+ rec = game && game->creatingVideo;
#endif
+ bool normalFrame = !IsPaused && !rec;
+ bool videoFrame = !IsPaused && fixedFrameTime;
+ bool singleStep = fixedFrameTime && !rec;
+
+ if(normalFrame || videoFrame || singleStep){
for(int i=0; i < newFrames; ++i){
++serverframenum;
//Send out new frame messages.
Index: rts/System/Platform/Win/AVIGenerator.cpp
===================================================================
--- rts/System/Platform/Win/AVIGenerator.cpp (revision 5455)
+++ rts/System/Platform/Win/AVIGenerator.cpp (working copy)
@@ -1,72 +1,63 @@
-// AVIGenerator.cpp: implementation of the CAVIGenerator class.
-//
-//////////////////////////////////////////////////////////////////////
-
#include "StdAfx.h"
#include "AVIGenerator.h"
#include "Game/GameVersion.h"
+#include "LogOutput.h"
+
+#include <windows.h>
+#include <GL/gl.h>
+#if defined(_WIN32) && defined(__MINGW32__)
+#include <GL/glext.h>
+#endif
+
+#include <boost/bind.hpp>
#include <cassert>
#include "mmgr.h"
#if defined(_WIN32) && !defined(__MINGW32__)
-#pragma message(" _Adding library: vfw32.lib" )
+#pragma message("Adding library: vfw32.lib")
#pragma comment(lib, "vfw32.lib")
#endif
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
bool CAVIGenerator::initVFW(){
#if defined(_WIN32) && defined(__MINGW32__)
- HMODULE hMod = LoadLibrary("msvfw32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
- }
+ msvfw32 = LoadLibrary("msvfw32.dll");
+ avifil32 = LoadLibrary("avifil32.dll");
+ VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(msvfw32, "VideoForWindowsVersion");
+ ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(msvfw32, "ICCompressorChoose");
+ ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(msvfw32, "ICCompressorFree");
+ ICOpen_ptr=(ICOpen_type)GetProcAddress(msvfw32, "ICOpen");
- VideoForWindowsVersion_ptr=(VideoForWindowsVersion_type)GetProcAddress(hMod, "VideoForWindowsVersion");
- ICCompressorChoose_ptr=(ICCompressorChoose_type)GetProcAddress(hMod, "ICCompressorChoose");
- ICCompressorFree_ptr=(ICCompressorFree_type)GetProcAddress(hMod, "ICCompressorFree");
+ AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(avifil32, "AVIFileInit");
+ AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(avifil32, "AVIFileOpenA");
+ AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(avifil32, "AVIFileCreateStreamA");
+ AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(avifil32, "AVIMakeCompressedStream");
+ AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(avifil32, "AVIStreamSetFormat");
+ AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(avifil32, "AVIStreamRelease");
+ AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(avifil32, "AVIFileRelease");
+ AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(avifil32, "AVIFileExit");
+ AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(avifil32, "AVIStreamWrite");
+ if(NULL == msvfw32 || NULL == avifil32){
+ errorMsg="LoadLibrary failed.";
+ return false;
+ }
- if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr){
- m_sError="initVFW Error.";
- return false;
- }
-
-
-
- hMod = LoadLibrary("avifil32.dll");
- if (NULL == hMod){
- m_sError="LoadLibrary failed.";
- return false;
+ if(!VideoForWindowsVersion_ptr || !ICCompressorChoose_ptr || !ICCompressorFree_ptr || !ICOpen_ptr){
+ errorMsg="initVFW Error.";
+ return false;
}
-
- AVIFileInit_ptr=(AVIFileInit_type)GetProcAddress(hMod, "AVIFileInit");
- AVIFileOpenA_ptr=(AVIFileOpenA_type)GetProcAddress(hMod, "AVIFileOpenA");
- AVIFileCreateStreamA_ptr=(AVIFileCreateStreamA_type)GetProcAddress(hMod, "AVIFileCreateStreamA");
- AVIMakeCompressedStream_ptr=(AVIMakeCompressedStream_type)GetProcAddress(hMod, "AVIMakeCompressedStream");
- AVIStreamSetFormat_ptr=(AVIStreamSetFormat_type)GetProcAddress(hMod, "AVIStreamSetFormat");
- AVIStreamRelease_ptr=(AVIStreamRelease_type)GetProcAddress(hMod, "AVIStreamRelease");
- AVIFileRelease_ptr=(AVIFileRelease_type)GetProcAddress(hMod, "AVIFileRelease");
- AVIFileExit_ptr=(AVIFileExit_type)GetProcAddress(hMod, "AVIFileExit");
- AVIStreamWrite_ptr=(AVIStreamWrite_type)GetProcAddress(hMod, "AVIStreamWrite");
-
-
- if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
+ if(!AVIFileInit_ptr || !AVIFileOpenA_ptr || !AVIFileCreateStreamA_ptr ||
!AVIMakeCompressedStream_ptr || !AVIStreamSetFormat_ptr || !AVIStreamRelease_ptr ||
!AVIFileRelease_ptr || !AVIFileExit_ptr || !AVIStreamWrite_ptr){
- m_sError="initVFW Error.";
- return false;
- }
- return true;
+ errorMsg="initVFW Error.";
+ return false;
+ }
#else
VideoForWindowsVersion_ptr =&VideoForWindowsVersion;
@@ -81,98 +72,160 @@
AVIStreamWrite_ptr = &AVIStreamWrite;
ICCompressorChoose_ptr = &ICCompressorChoose;
ICCompressorFree_ptr = &ICCompressorFree;
-
+ ICOpen_ptr = &ICOpen;
+#endif
return true;
-#endif
}
+CAVIGenerator::CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS)
+ :
+ fileName(fileName),
+ videoFPS(videoFPS),
+ errorMsg("Ok"),
+ quitAVIgen(false),
+ AVIThread(0),
+ readBuf(0),
+ m_lFrame(0),
+ m_pAVIFile(NULL),
+ m_pStream(NULL),
+ m_pStreamCompressed(NULL){
-CAVIGenerator::CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate)
-: m_sFile(sFileName), m_dwRate(dwRate), pixelDataBuf(0),
-m_pAVIFile(NULL), m_pStream(NULL), m_pStreamCompressed(NULL)
-{
- MakeExtAvi();
- SetBitmapHeader(lpbih);
-}
+ assert(videoSizeX % 4 == 0);
+ assert(videoSizeY % 4 == 0);
-CAVIGenerator::~CAVIGenerator()
-{
- // Just checking that all allocated ressources have been released
- assert(m_pStream==NULL);
- assert(m_pStreamCompressed==NULL);
- assert(m_pAVIFile==NULL);
- assert(pixelDataBuf==NULL);
+ memset(&bitmapInfo, 0, sizeof(BITMAPINFOHEADER));
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = videoSizeX;
+ bitmapInfo.biHeight = videoSizeY;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 24;
+ bitmapInfo.biSizeImage = videoSizeX * videoSizeY * 3;
+ bitmapInfo.biCompression = BI_RGB;
+
+ if(!initVFW()){
+ quitAVIgen = true;
+ }
}
-void CAVIGenerator::SetBitmapHeader(LPBITMAPINFOHEADER lpbih)
-{
- // checking that bitmap size are multiple of 4
- assert(lpbih->biWidth%4==0);
- assert(lpbih->biHeight%4==0);
- assert(lpbih->biBitCount==24);
- assert(lpbih->biCompression==BI_RGB);
- assert(lpbih->biSizeImage==lpbih->biWidth*lpbih->biHeight*3);
- // copying bitmap info structure.
- // corrected thanks to Lori Gardi
- memcpy(&m_bih,lpbih, sizeof(BITMAPINFOHEADER));
+CAVIGenerator::~CAVIGenerator(){
+
+ if(AVIThread){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ quitAVIgen = true;
+ AVICondition.notify_all();
+ }
+ AVIThread->join();
+
+ delete AVIThread;
+ AVIThread = 0;
+ }
+
+ while(!freeDataPointers.empty()){
+ unsigned char* tmp = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ delete [] tmp;
+ }
+ while(!dataPointers.empty()){
+ unsigned char* tmp = dataPointers.front();
+ dataPointers.pop_front();
+ delete [] tmp;
+ }
+
+ delete [] readBuf;
+ readBuf = 0;
+
+
+ ReleaseAVICompressionEngine();
+ logOutput.Print(std::string("Finished writing avi file, ") + fileName);
+
+ //Just checking that all allocated ressources have been released.
+ assert(AVIThread == NULL);
+ assert(m_pAVIFile == NULL);
+ assert(m_pStream == NULL);
+ assert(m_pStreamCompressed == NULL);
+ assert(freeDataPointers.empty());
+ assert(dataPointers.empty());
+ assert(readBuf == NULL);
}
-HRESULT CAVIGenerator::InitEngine()
-{
- AVISTREAMINFO strHdr; // information for a single stream
- AVICOMPRESSOPTIONS opts;
+void CAVIGenerator::ReleaseAVICompressionEngine(){
- HRESULT hr;
+ if(m_pStream && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStream);
+ m_pStream=NULL;
+ }
- m_sError= "Ok";
+ if(m_pStreamCompressed && AVIStreamRelease_ptr){
+ AVIStreamRelease_ptr(m_pStreamCompressed);
+ m_pStreamCompressed=NULL;
+ }
+ if(m_pAVIFile && AVIFileRelease_ptr){
+ AVIFileRelease_ptr(m_pAVIFile);
+ m_pAVIFile=NULL;
+ }
- if(!initVFW()){
- return S_FALSE;
+ if(ICCompressorFree_ptr){
+ ICCompressorFree_ptr(&cv);
}
+ if(AVIFileExit_ptr){
+ AVIFileExit_ptr();
+ }
- triggerCleanup cleaner(this);
+ if(msvfw32){
+ FreeLibrary(msvfw32);
+ }
+ if(avifil32){
+ FreeLibrary(avifil32);
+ }
+}
- // Step 0 : Let's make sure we are running on 1.1
+
+HRESULT CAVIGenerator::InitAVICompressionEngine(){
+
+ AVISTREAMINFO strHdr; //Information for a single stream
+ AVICOMPRESSOPTIONS opts;
+ HRESULT hr;
+
+
+ //Let's make sure we are running on 1.1
DWORD wVer = HIWORD(VideoForWindowsVersion_ptr());
- if (wVer < 0x010a)
- {
- // oops, we are too old, blow out of here
- m_sError="Version of Video for Windows too old. Come on, join the 21th century!";
+ if(wVer < 0x010a){
+ //oops, we are too old, blow out of here
+ errorMsg="Version of Video for Windows too old. Come on, join the 21th century!";
return S_FALSE;
}
- // Step 1 : initialize AVI engine
+ //Initialize AVI engine
AVIFileInit_ptr();
memset(&cv,0,sizeof(COMPVARS));
-
cv.cbSize=sizeof(COMPVARS);
cv.dwFlags=ICMF_COMPVARS_VALID;
- cv.fccHandler=mmioFOURCC('W','M','V','3');
+ cv.fccHandler=mmioFOURCC('f','f','d','s');//default video codec
cv.lQ=ICQUALITY_DEFAULT;
HWND hWnd = FindWindow(NULL, ("Spring " + std::string(VERSION_STRING)).c_str());
-
- if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &m_bih, NULL, &cv, NULL)){
+ //Set the compression, prompting dialog if necessary
+ if (!ICCompressorChoose_ptr(hWnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, &bitmapInfo, NULL, &cv, NULL)){
return S_FALSE;
}
-
// Fill in the header for the video stream....
memset(&strHdr, 0, sizeof(AVISTREAMINFO));
strHdr.fccType = streamtypeVIDEO; // video stream type
strHdr.fccHandler = cv.fccHandler;
strHdr.dwScale = 1; // should be one for video
- strHdr.dwRate = m_dwRate; // fps
- strHdr.dwSuggestedBufferSize = m_bih.biSizeImage; // Recommended buffer size, in bytes, for the stream.
- SetRect(&strHdr.rcFrame, 0, 0, (int)m_bih.biWidth, (int)m_bih.biHeight); // rectangle for stream
-
+ strHdr.dwRate = videoFPS; // fps
+ strHdr.dwSuggestedBufferSize = bitmapInfo.biSizeImage; // Recommended buffer size, in bytes, for the stream.
+ SetRect(&strHdr.rcFrame, 0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight);
+ strcpy(strHdr.szName, "Spring video.");
memset(&opts, 0, sizeof(AVICOMPRESSOPTIONS));
@@ -188,145 +241,130 @@
opts.cbParms=cv.cbState;
opts.dwInterleaveEvery=0;
- // Step 2 : Open the movie file for writing....
+
+
+ //Open the movie file for writing
hr = AVIFileOpenA_ptr(&m_pAVIFile, // Address to contain the new file interface pointer
- m_sFile.c_str(), // Null-terminated string containing the name of the file to open
- OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
+ fileName.c_str(), // Null-terminated string containing the name of the file to open
+ OF_WRITE | OF_CREATE | OF_SHARE_EXCLUSIVE, // Access mode to use when opening the file.
NULL); // use handler determined from file extension.
- // Name your file .avi -> very important
if (hr != AVIERR_OK)
{
- //_tprintf(szBuffer,"AVI Engine failed to initialize. Check filename %s.",m_sFile);
- m_sError="AVI Engine failed to initialize. Check filename ";
- m_sError+=m_sFile;
- // Check it succeded.
+ errorMsg="AVI Engine failed to initialize. Check filename ";
+ errorMsg+=fileName;
+ //Translate error code
switch(hr)
{
- case AVIERR_BADFORMAT:
- m_sError+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
+ case AVIERR_BADFORMAT:
+ errorMsg+="The file couldn't be read, indicating a corrupt file or an unrecognized format.";
break;
- case AVIERR_MEMORY:
- m_sError+="The file could not be opened because of insufficient memory.";
+ case AVIERR_MEMORY:
+ errorMsg+="The file could not be opened because of insufficient memory.";
break;
case AVIERR_FILEREAD:
- m_sError+="A disk error occurred while reading the file.";
+ errorMsg+="A disk error occurred while reading the file.";
break;
- case AVIERR_FILEOPEN:
- m_sError+="A disk error occurred while opening the file.";
+ case AVIERR_FILEOPEN:
+ errorMsg+="A disk error occurred while opening the file.";
break;
- case REGDB_E_CLASSNOTREG:
- m_sError+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
+ case REGDB_E_CLASSNOTREG:
+ errorMsg+="According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it";
break;
+ default :
+ errorMsg+="Unknown error.";
}
return hr;
}
- // Step 3 : Create the stream;
+ //Create the stream
hr = AVIFileCreateStreamA_ptr(m_pAVIFile, // file pointer
&m_pStream, // returned stream pointer
&strHdr); // stream header
- // Check it succeded.
if (hr != AVIERR_OK)
{
- m_sError="AVI Stream creation failed. Check Bitmap info.";
+ errorMsg="AVI Stream creation failed. Check Bitmap info.";
if (hr==AVIERR_READONLY)
{
- m_sError+=" Read only file.";
+ errorMsg+=" Read only file.";
}
return hr;
}
- // Step 5: Create a compressed stream using codec options.
- hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed,
- m_pStream,
- &opts,
- NULL);
-
+ //Create a compressed stream using codec options.
+ hr = AVIMakeCompressedStream_ptr(&m_pStreamCompressed, m_pStream, &opts, NULL);
if (hr != AVIERR_OK)
{
- m_sError="AVI Compressed Stream creation failed.";
+ errorMsg="AVI Compressed Stream creation failed.";
switch(hr)
{
case AVIERR_NOCOMPRESSOR:
- m_sError+=" A suitable compressor cannot be found.";
+ errorMsg+=" A suitable compressor cannot be found.";
break;
case AVIERR_MEMORY:
- m_sError+=" There is not enough memory to complete the operation.";
- break;
+ errorMsg+=" There is not enough memory to complete the operation.";
+ break;
case AVIERR_UNSUPPORTED:
- m_sError+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
+ errorMsg+="Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.";
break;
+ default :
+ errorMsg+="Unknown error.";
}
return hr;
}
- // Step 6 : sets the format of a stream at the specified position
- hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
+ //Sets the format of a stream at the specified position
+ hr = AVIStreamSetFormat_ptr(m_pStreamCompressed,
0, // position
- &m_bih, // stream format
- m_bih.biSize + // format size
- m_bih.biClrUsed * sizeof(RGBQUAD));
+ &bitmapInfo, // stream format
+ bitmapInfo.biSize + // format size
+ bitmapInfo.biClrUsed * sizeof(RGBQUAD));
if (hr != AVIERR_OK)
{
- m_sError="AVI Compressed Stream format setting failed.";
+ errorMsg="AVI Compressed Stream format setting failed.";
return hr;
}
- // Step 6 : Initialize step counter
- m_lFrame=0;
- pixelDataBuf = SAFE_NEW unsigned char[m_bih.biSizeImage];
- cleaner.disarm();
-
return hr;
}
-void CAVIGenerator::ReleaseEngine()
-{
- if (m_pStream)
- {
- AVIStreamRelease_ptr(m_pStream);
- m_pStream=NULL;
+bool CAVIGenerator::InitEngine(){
+
+ if(quitAVIgen){//error in initVFW
+ return false;
}
- if (m_pStreamCompressed)
- {
- AVIStreamRelease_ptr(m_pStreamCompressed);
- m_pStreamCompressed=NULL;
+ HRESULT hr = InitAVICompressionEngine();
+ if(hr != AVIERR_OK){
+ quitAVIgen = true;
+ return false;
}
- if (m_pAVIFile)
- {
- AVIFileRelease_ptr(m_pAVIFile);
- m_pAVIFile=NULL;
+ for(int i=0; i<10; i++){
+ unsigned char* tmpBuf = SAFE_NEW unsigned char[bitmapInfo.biSizeImage];
+ freeDataPointers.push_back(tmpBuf);
}
- ICCompressorFree_ptr(&cv);
+ AVIThread = SAFE_NEW boost::thread(boost::bind(&CAVIGenerator::AVIGeneratorThreadProc, this));
+ return true;
+}
- delete [] pixelDataBuf;
- pixelDataBuf=0;
- // Close engine
- AVIFileExit_ptr();
-}
+HRESULT CAVIGenerator::AddFrame(unsigned char* pixelData){
-HRESULT CAVIGenerator::AddFrame(BYTE *bmBits)
-{
- HRESULT hr;
-
// compress bitmap
- hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
- m_lFrame, // time of this frame
+ HRESULT hr = AVIStreamWrite_ptr(m_pStreamCompressed, // stream pointer
+ m_lFrame, // time of this frame
1, // number to write
- bmBits, // image buffer
- m_bih.biSizeImage, // size of this frame
+ pixelData, // image buffer
+ bitmapInfo.biSizeImage, // size of this frame
AVIIF_KEYFRAME, // flags....
NULL,
NULL);
@@ -337,10 +375,59 @@
return hr;
}
-void CAVIGenerator::MakeExtAvi(){
- std::size_t pos = m_sFile.find_last_of(".avi");
- if(pos == std::string::npos || pos + 1 != m_sFile.size()){
- m_sFile += ".avi";
+void CAVIGenerator::readOpenglPixelDataThreaded(){
+
+ for(;;){
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ return;
+ }
+ if(readBuf != 0){
+ dataPointers.push_back(readBuf);
+ readBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(freeDataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ readBuf = freeDataPointers.front();
+ freeDataPointers.pop_front();
+ break;
}
+
+ glReadPixels(0, 0, bitmapInfo.biWidth, bitmapInfo.biHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, readBuf);
}
+
+
+void CAVIGenerator::AVIGeneratorThreadProc(){
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+ unsigned char* localWriteBuf = 0;
+
+ for(;;){
+ {
+ boost::mutex::scoped_lock lock(AVIMutex);
+ if(quitAVIgen){
+ break;
+ }
+ if(localWriteBuf != 0){
+ freeDataPointers.push_back(localWriteBuf);
+ localWriteBuf = 0;
+ AVICondition.notify_all();
+ }
+ if(dataPointers.empty()){
+ AVICondition.wait(lock);
+ continue;
+ }
+ localWriteBuf = dataPointers.front();
+ dataPointers.pop_front();
+ }
+ if(AddFrame(localWriteBuf)){
+ quitAVIgen = true;
+ }
+ }
+ delete [] localWriteBuf;
+}
+
Index: rts/System/Platform/Win/AVIGenerator.h
===================================================================
--- rts/System/Platform/Win/AVIGenerator.h (revision 5455)
+++ rts/System/Platform/Win/AVIGenerator.h (working copy)
@@ -1,127 +1,81 @@
-// AVIGenerator.h: interface for the CAVIGenerator class.
-//
-// A class to easily create AVI
-//
-// Original code : Example code in WriteAvi.c of MSDN
-//
-// Author : Jonathan de Halleux. dehalleux@auto.ucl.ac.be
-//////////////////////////////////////////////////////////////////////
-
#ifndef AVIGENERATOR_H
#define AVIGENERATOR_H
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/utility.hpp>
#include <windows.h>
#include <vfw.h>
-#include <GL/gl.h>
-#if defined(_WIN32) && defined(__MINGW32__)
-#include <GL/glext.h>
-#endif
-
#include <string>
+#include <list>
-/*! \brief A simple class to create AVI video stream.
+class CAVIGenerator : boost::noncopyable {
+public:
+ CAVIGenerator(const std::string& fileName, int videoSizeX, int videoSizeY, DWORD videoFPS);
+ ~CAVIGenerator();
-\par Usage
+ //Initialize engine and choose codec
+ bool InitEngine();
-Step 1 : Declare an CAVIGenerator object
-Step 2 : Set Bitmap by calling SetBitmapHeader functions + other parameters
-Step 3 : Initialize engine by calling InitEngine
-Step 4 : Send each frames to engine with function AddFrame
-Step 5 : Close engine by calling ReleaseEngine
+ //Returns last error message
+ std::string GetLastErrorMessage() const {return errorMsg;}
-\par Demo Code:
+ void readOpenglPixelDataThreaded();
-\code
-CAVIGenerator AviGen;
-BYTE* bmBits;
-// set characteristics
-AviGen.SetRate(20); // set 20fps
-AviGen.SetBitmapHeader(GetActiveView()); // give info about bitmap
+private:
+ //name of output file
+ std::string fileName;
+ //Frame rate
+ DWORD videoFPS;
+ //structure contains information for a single stream
+ BITMAPINFOHEADER bitmapInfo;
+ //last error string
+ std::string errorMsg;
-AviGen.InitEngine();
+ HINSTANCE msvfw32;
+ HINSTANCE avifil32;
-..... // Draw code, bmBits is the buffer containing the frame
-AviGen.AddFrame(bmBits);
-.....
+ volatile bool quitAVIgen;
-AviGen.ReleaseEngine();
-\endcode
+ boost::thread* AVIThread;
+ boost::mutex AVIMutex;
+ boost::condition AVICondition;
-\par Update history:
-- {\b 22-10-2002} Minor changes in constructors.
+ std::list<unsigned char*> freeDataPointers;
+ std::list<unsigned char*> dataPointers;
-\author : Jonathan de Halleux, dehalleux@auto.ucl.ac.be (2001)
-*/
-class CAVIGenerator
-{
-public:
- //! \name Constructors and destructors
- //@{
- //! Inplace constructor with BITMAPINFOHEADER
- CAVIGenerator(const std::string & sFileName, LPBITMAPINFOHEADER lpbih, DWORD dwRate);
- ~CAVIGenerator();
- //@}
+ unsigned char* readBuf;
- //! \name AVI engine function
- //@{
- /*! \brief Initialize engine and choose codex
- Some asserts are made to check that bitmap has been properly initialized
- */
- HRESULT InitEngine();
- /*! \brief Adds a frame to the movie.
- The data pointed by bmBits has to be compatible with the bitmap description of the movie.
- */
- HRESULT AddFrame(BYTE* bmBits);
- //! Release ressources allocated for movie and close file.
- void ReleaseEngine();
- //@}
+ bool initVFW();
- //! \name Setters and getters
- //@{
- //! returns a pointer to bitmap info
- LPBITMAPINFOHEADER GetBitmapHeader() {return &m_bih;}
+ HRESULT InitAVICompressionEngine();
- //! \name Error handling
- //@{
- //! returns last error message
- std::string GetLastErrorMessage() const {return m_sError;}
- //@}
- unsigned char* GetPixelBuf(){return pixelDataBuf;}
+ //Release streams allocated for movie compression.
+ void ReleaseAVICompressionEngine();
+ //Adds a frame to the movie.
+ HRESULT AddFrame(unsigned char* pixelData);
-private:
- //! name of output file
- std::string m_sFile;
- //! Frame rate
- DWORD m_dwRate;
- //! structure contains information for a single stream
- BITMAPINFOHEADER m_bih;
- //! last error string
- std::string m_sError;
+ void AVIGeneratorThreadProc();
- unsigned char* pixelDataBuf;
-
- //! Sets bitmap info as in lpbih
- void SetBitmapHeader(LPBITMAPINFOHEADER lpbih);
-
- void MakeExtAvi();
- //! frame counter
+ //frame counter
long m_lFrame;
- //! file interface pointer
+ //file interface pointer
PAVIFILE m_pAVIFile;
- //! Address of the stream interface
- PAVISTREAM m_pStream;
- //! Address of the compressed video stream
- PAVISTREAM m_pStreamCompressed;
+ //Address of the stream interface
+ PAVISTREAM m_pStream;
+ //Address of the compressed video stream
+ PAVISTREAM m_pStreamCompressed;
//Holds compression settings
COMPVARS cv;
@@ -137,6 +91,7 @@
typedef HRESULT (__stdcall *AVIStreamWrite_type)(PAVISTREAM, LONG, LONG, LPVOID, LONG, DWORD, LONG FAR *, LONG FAR *);
typedef BOOL (__stdcall *ICCompressorChoose_type)(HWND, UINT, LPVOID, LPVOID, PCOMPVARS, LPSTR);
typedef void (__stdcall *ICCompressorFree_type)(PCOMPVARS);
+ typedef HIC (__stdcall *ICOpen_type)(DWORD, DWORD, UINT);
@@ -152,26 +107,8 @@
AVIStreamWrite_type AVIStreamWrite_ptr;
ICCompressorChoose_type ICCompressorChoose_ptr;
ICCompressorFree_type ICCompressorFree_ptr;
+ ICOpen_type ICOpen_ptr;
-
- bool initVFW();
-
-
- struct triggerCleanup{
- triggerCleanup(CAVIGenerator* ptr) : clean(true), ptr(ptr){};
- ~triggerCleanup(){
- if(clean){
- ptr->ReleaseEngine();
- }
- }
- void disarm(){
- clean = false;
- }
- private:
- bool clean;
- CAVIGenerator* ptr;
- };
-
};
#endif /* AVIGENERATOR_H */
|
---|