2019-11-22 20:55 CET

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0000829Spring engineGeneralpublic2008-02-08 15:21
Reporterzizu 
Assigned ToAuswaschbar 
PrioritynormalSeverityfeatureReproducibilityalways
StatusresolvedResolutionfixed 
Product Version 
Target VersionFixed in Version 
Summary0000829: [patch]Single step fix + new avi generator
DescriptionThis patch fixes single step rendering and implements a new multithreaded avi generator.
TagsNo tags attached.
Checked infolog.txt for Errors
Attached Files
  • patch file icon 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 file icon single_step_and_avi.patch (29,537 bytes) 2008-01-29 13:03 +
  • diff file icon 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
    
    diff file icon patch.diff (30,061 bytes) 2008-01-29 19:27 +
  • patch file icon 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 */
    
    patch file icon single_step_and_avi_v2.patch (29,496 bytes) 2008-01-30 08:36 +
  • patch file icon 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 */
    
    patch file icon single_step_and_avi_v3.patch (29,650 bytes) 2008-01-30 10:47 +
  • patch file icon 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 */
    
    patch file icon avi_generator_v4.patch (28,198 bytes) 2008-02-06 15:26 +
  • patch file icon 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 */
    
    patch file icon avi_generator_v5.patch (28,160 bytes) 2008-02-06 17:24 +

-Relationships
+Relationships

-Notes

~0001905

Auswaschbar (reporter)

Last edited: 2008-01-29 19:30

Awesome.
But some comments:
1. Didn't compile on linux
2. After i get it to compile, the CGameServer deadlocked
3. attached modified patch with builds on linux and not deadlocks.

Didn't test other things yet.

PS.: game can be 0 (in dedicated server)

~0001912

zizu (reporter)

Here is an updated version of the patch, it is largely the same as the old one but should compile on Linux and handles the game==0 case.
Btw, do we have a dedicated server?

But I still think locking the mutex from both threads is the right thing to do, because the CGameServer member functions are only called from the server and the main thread, with the server thread always given a free pass without locking the mutex the main thread will also never block on it rendering the mutex completely irrelevant.
Could you print a stack trace from the relevant threads when it deadlocks? I cannot get it to deadlock on my machine.

~0001913

Auswaschbar (reporter)

It is because the CGameServer::UpdateLoop() already locks the mutex before calling CGameServer::Update(), and when Update() calls CreateNewFrame() there will be a deadlock because the mutex is already locked.

And dedicated server is currently under development ;)

~0001914

zizu (reporter)

Yes, I missed the lock in UpdateLoop and windows does not deadlock when recursively locking a mutex.

Attaching a new hopefully deadlock free patch.

The new patch sends two arguments to CreateNewFrame, currently you can get away with only using one but they represent different things so I would like to keep them separated.

~0001915

Auswaschbar (reporter)

Last edited: 2008-01-30 20:19

Tested, works. But someone still should test avi generation before committing.

<edit> Committed the singlestep-stuff

~0001941

Auswaschbar (reporter)

When recording a video with your patch applied, its neither possible to change game speed nor to pause the game.

Would you please fix that, because apart from this your patch works very well.

~0001947

zizu (reporter)

Pausing while recording a video works now.

But the inability to change the game speed is a side effect of the video lag reduction scheme.
No matter how slow or jerky the game play is while recording a video the resulting video will be perfectly smooth and play at normal (1.0) game speed. A video recorded during a large battle late in the game would be extremely jerky and almost unwatchable without it.
Yes, it can be extended to work with all game speeds but I do not think it is worth the extra complexity/work so I will leave it as it is.

~0001948

Auswaschbar (reporter)

commited
+Notes

-Issue History
Date Modified Username Field Change
2008-01-29 13:03 zizu New Issue
2008-01-29 13:03 zizu File Added: single_step_and_avi.patch
2008-01-29 19:27 Auswaschbar Note Added: 0001905
2008-01-29 19:27 Auswaschbar File Added: patch.diff
2008-01-29 19:30 Auswaschbar Note Edited: 0001905
2008-01-30 08:36 zizu Note Added: 0001912
2008-01-30 08:36 zizu File Added: single_step_and_avi_v2.patch
2008-01-30 09:34 Auswaschbar Note Added: 0001913
2008-01-30 10:47 zizu Note Added: 0001914
2008-01-30 10:47 zizu File Added: single_step_and_avi_v3.patch
2008-01-30 16:03 Auswaschbar Note Added: 0001915
2008-01-30 20:19 Auswaschbar Note Edited: 0001915
2008-02-04 18:24 Auswaschbar Note Added: 0001941
2008-02-04 18:24 Auswaschbar Status new => assigned
2008-02-04 18:24 Auswaschbar Assigned To => Auswaschbar
2008-02-06 15:25 zizu Note Added: 0001947
2008-02-06 15:26 zizu File Added: avi_generator_v4.patch
2008-02-06 17:24 zizu File Added: avi_generator_v5.patch
2008-02-08 15:21 Auswaschbar Status assigned => resolved
2008-02-08 15:21 Auswaschbar Resolution open => fixed
2008-02-08 15:21 Auswaschbar Note Added: 0001948
+Issue History