1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-03 13:01:33 +02:00

Mingw build with ffmpeg

(*) get rid of BIK SMK dlls
(-) missing sound
(-) spellbook is scaled to fullscreen
This commit is contained in:
AlexVinS 2014-07-08 16:40:25 +04:00
parent ca86416953
commit c71237bba3
3 changed files with 7 additions and 720 deletions

View File

@ -23,553 +23,7 @@ static bool keyDown()
}
#endif
#if defined(_WIN32) && (_MSC_VER < 1800 || !defined(USE_FFMPEG))
void checkForError(bool throwing = true)
{
int error = GetLastError();
if(!error)
return;
logGlobal->errorStream() << "Error " << error << " encountered!";
std::string msg;
char* pTemp = nullptr;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
nullptr, error, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPSTR)&pTemp, 1, nullptr );
logGlobal->errorStream() << "Error: " << pTemp;
msg = pTemp;
LocalFree( pTemp );
pTemp = nullptr;
if(throwing)
throw std::runtime_error(msg);
}
void blitBuffer(char *buffer, int x, int y, int w, int h, SDL_Surface *dst)
{
const int bpp = dst->format->BytesPerPixel;
char *dest;
for(int i = h; i > 0; i--)
{
dest = (char*)dst->pixels + dst->pitch*(y+h-i) + x*dst->format->BytesPerPixel;
memcpy(dest, buffer, bpp*w);
buffer += bpp*w;
}
}
void DLLHandler::Instantiate(const char *filename)
{
name = filename;
dll = LoadLibraryA(filename);
if(!dll)
{
logGlobal->errorStream() << "Failed loading " << filename;
checkForError(true);
}
}
void *DLLHandler::FindAddress(const char *symbol)
{
void *ret;
if(!dll)
{
logGlobal->errorStream() << "Cannot look for " << symbol << " because DLL hasn't been appropriately loaded!";
return nullptr;
}
ret = (void*) GetProcAddress(dll,symbol);
if(!ret)
{
logGlobal->errorStream() << "Failed to find " << symbol << " in " << name;
checkForError();
}
return ret;
}
DLLHandler::~DLLHandler()
{
if(dll)
{
if(!FreeLibrary(dll))
{
logGlobal->errorStream() << "Failed to free " << name;
checkForError();
}
}
}
DLLHandler::DLLHandler()
{
dll = nullptr;
}
CBIKHandler::CBIKHandler()
{
Instantiate("BINKW32.DLL");
//binkGetError = FindAddress("_BinkGetError@0");
binkOpen = (BinkOpen)FindAddress("_BinkOpen@8");
binkSetSoundSystem = (BinkSetSoundSystem)FindAddress("_BinkSetSoundSystem@8");
//getPalette = (BinkGetPalette)FindAddress("_BinkGetPalette@4");
binkNextFrame = (BinkNextFrame)FindAddress("_BinkNextFrame@4");
binkDoFrame = (BinkDoFrame)FindAddress("_BinkDoFrame@4");
binkCopyToBuffer = (BinkCopyToBuffer)FindAddress("_BinkCopyToBuffer@28");
binkWait = (BinkWait)FindAddress("_BinkWait@4");
binkClose = (BinkClose)FindAddress("_BinkClose@4");
hBinkFile = nullptr;
hBink = nullptr;
buffer = nullptr;
bufferSize = 0;
}
bool CBIKHandler::open(std::string name)
{
hBinkFile = CreateFileA
(
name.c_str(), // file name
GENERIC_READ, // access mode
FILE_SHARE_READ, // share mode
nullptr, // Security Descriptor
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL,//FILE_FLAG_SEQUENTIAL_SCAN, // file attributes
0 // handle to template file
);
if(hBinkFile == INVALID_HANDLE_VALUE)
{
logGlobal->errorStream() << "BIK handler: failed to open " << name;
goto checkErrorAndClean;
}
//GCC wants scope of waveout to don`t cross labels/swith/goto
{
void *waveout = GetProcAddress(dll,"_BinkOpenWaveOut@4");
if(waveout)
binkSetSoundSystem(waveout,nullptr);
}
hBink = binkOpen(hBinkFile, 0x8a800000);
if(!hBink)
{
logGlobal->errorStream() << "bink failed to open " << name;
goto checkErrorAndClean;
}
allocBuffer();
return true;
checkErrorAndClean:
CloseHandle(hBinkFile);
hBinkFile = nullptr;
checkForError();
throw std::runtime_error("BIK failed opening video!");
}
void CBIKHandler::show( int x, int y, SDL_Surface *dst, bool update )
{
const int w = hBink->width,
h = hBink->height,
Bpp = dst->format->BytesPerPixel;
int mode = -1;
//screen color depth might have changed... (eg. because F4)
if(bufferSize != w * h * Bpp)
{
freeBuffer();
allocBuffer(Bpp);
}
switch(Bpp)
{
case 2:
mode = 3; //565, mode 2 is 555 probably
break;
case 3:
mode = 0;
break;
case 4:
mode = 1;
break;
default:
return; //not supported screen depth
}
binkDoFrame(hBink);
binkCopyToBuffer(hBink, buffer, w*Bpp, h, 0, 0, mode);
blitBuffer(buffer, x, y, w, h, dst);
if(update)
SDL_UpdateRect(dst, x, y, w, h);
}
bool CBIKHandler::nextFrame()
{
binkNextFrame(hBink);
return true;
}
void CBIKHandler::close()
{
binkClose(hBink);
hBink = nullptr;
CloseHandle(hBinkFile);
hBinkFile = nullptr;
delete [] buffer;
buffer = nullptr;
bufferSize = 0;
}
bool CBIKHandler::wait()
{
return binkWait(hBink);
}
int CBIKHandler::curFrame() const
{
return hBink->currentFrame;
}
int CBIKHandler::frameCount() const
{
return hBink->frameCount;
}
void CBIKHandler::redraw( int x, int y, SDL_Surface *dst, bool update )
{
int w = hBink->width, h = hBink->height;
blitBuffer(buffer, x, y, w, h, dst);
if(update)
SDL_UpdateRect(dst, x, y, w, h);
}
void CBIKHandler::allocBuffer(int Bpp)
{
if(!Bpp) Bpp = screen->format->BytesPerPixel;
bufferSize = hBink->width * hBink->height * Bpp;
buffer = new char[bufferSize];
}
void CBIKHandler::freeBuffer()
{
delete [] buffer;
buffer = nullptr;
bufferSize = 0;
}
bool CSmackPlayer::nextFrame()
{
ptrSmackNextFrame(data);
return true;
}
bool CSmackPlayer::wait()
{
return ptrSmackWait(data);
}
CSmackPlayer::CSmackPlayer() : data(nullptr)
{
Instantiate("smackw32.dll");
ptrSmackNextFrame = (SmackNextFrame)FindAddress("_SmackNextFrame@4");
ptrSmackWait = (SmackWait)FindAddress("_SmackWait@4");
ptrSmackDoFrame = (SmackDoFrame)FindAddress("_SmackDoFrame@4");
ptrSmackToBuffer = (SmackToBuffer)FindAddress("_SmackToBuffer@28");
ptrSmackOpen = (SmackOpen)FindAddress("_SmackOpen@12");
ptrSmackSoundOnOff = (SmackSoundOnOff)FindAddress("_SmackSoundOnOff@8");
ptrSmackClose = (SmackClose)FindAddress("_SmackClose@4");
ptrVolumePan = (SmackVolumePan)FindAddress("_SmackVolumePan@16");
}
CSmackPlayer::~CSmackPlayer()
{
if(data)
close();
}
void CSmackPlayer::close()
{
ptrSmackClose(data);
data = nullptr;
}
bool CSmackPlayer::open( std::string name )
{
Uint32 flags[2] = {0xff400, 0xfe400};
data = ptrSmackOpen( (void*)name.c_str(), flags[1], -1);
if (!data)
{
logGlobal->errorStream() << "Smack cannot open " << name;
checkForError();
throw std::runtime_error("SMACK failed opening video");
}
buffer = new char[data->width*data->height*2];
buf = buffer+data->width*(data->height-1)*2; // adjust pointer position for later use by 'SmackToBuffer'
//ptrVolumePan(data, 0xfe000, 3640 * GDefaultOptions.musicVolume / 11, 0x8000); //set volume
return true;
}
void CSmackPlayer::show( int x, int y, SDL_Surface *dst, bool update)
{
int w = data->width;
int stripe = (-w*2) & (~3);
//put frame to the buffer
ptrSmackToBuffer(data, 0, 0, stripe, w, buf, 0x80000000);
ptrSmackDoFrame(data);
redraw(x, y, dst, update);
}
int CSmackPlayer::curFrame() const
{
return data->currentFrame;
}
int CSmackPlayer::frameCount() const
{
return data->frameCount;
}
void CSmackPlayer::redraw( int x, int y, SDL_Surface *dst, bool update )
{
int w = std::min<int>(data->width, dst->w - x), h = std::min<int>(data->height, dst->h - y);
/* Lock the screen for direct access to the pixels */
if ( SDL_MUSTLOCK(dst) )
{
if ( SDL_LockSurface(dst) < 0 )
{
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
return;
}
}
// draw the frame
Uint16* addr = (Uint16*) (buffer+w*(h-1)*2-2);
if(dst->format->BytesPerPixel >= 3)
{
for( int j=0; j<h-1; j++) // why -1 ?
{
for ( int i=w-1; i>=0; i--)
{
Uint16 pixel = *addr;
Uint8 *p = (Uint8 *)dst->pixels + (j+y) * dst->pitch + (i + x) * dst->format->BytesPerPixel;
p[2] = ((pixel & 0x7c00) >> 10) * 8;
p[1] = ((pixel & 0x3e0) >> 5) * 8;
p[0] = ((pixel & 0x1F)) * 8;
addr--;
}
}
}
else if(dst->format->BytesPerPixel == 2)
{
for( int j=0; j<h-1; j++) // why -1 ?
{
for ( int i=w-1; i>=0; i--)
{
//convert rgb 555 to 565
Uint16 pixel = *addr;
Uint16 *p = (Uint16 *)((Uint8 *)dst->pixels + (j+y) * dst->pitch + (i + x) * dst->format->BytesPerPixel);
*p = (pixel & 0x1F)
+ ((pixel & 0x3e0) << 1)
+ ((pixel & 0x7c00) << 1);
addr--;
}
}
}
if ( SDL_MUSTLOCK(dst) )
{
SDL_UnlockSurface(dst);
}
if(update)
SDL_UpdateRect(dst, x, y, w, h);
}
CVideoPlayer::CVideoPlayer()
{
current = nullptr;
}
CVideoPlayer::~CVideoPlayer()
{
}
bool CVideoPlayer::open(std::string name)
{
fname = name;
first = true;
try
{
// Extract video from video.vid so we can play it.
// We can handle only videos in form of single file, no archive support yet.
{
ResourceID videoID = ResourceID("VIDEO/" + name, EResType::VIDEO);
auto data = CResourceHandler::get()->load(videoID)->readAll();
// try to determine video format using magic number from header (3 bytes, SMK or BIK)
std::string magic(reinterpret_cast<char*>(data.first.get()), 3);
if (magic == "BIK")
current = &bikPlayer;
else if (magic == "SMK")
current = &smkPlayer;
else
throw std::runtime_error("Unknown video format: " + magic);
std::ofstream out(name, std::ofstream::binary);
out.exceptions(std::ifstream::failbit | std::ifstream::badbit);
out.write(reinterpret_cast<char*>(data.first.get()), data.second);
}
current->open(name);
return true;
}
catch(std::exception &e)
{
current = nullptr;
logGlobal->warnStream() << "Failed to open video file " << name << ": " << e.what();
}
return false;
}
void CVideoPlayer::close()
{
if(!current)
{
logGlobal->warnStream() << "Closing no opened player...?";
return;
}
current->close();
current = nullptr;
if(!DeleteFileA(fname.c_str()))
{
logGlobal->errorStream() << "Cannot remove temporarily extracted video file: " << fname;
checkForError(false);
}
fname.clear();
}
bool CVideoPlayer::nextFrame()
{
if(current)
{
current->nextFrame();
return true;
}
else
return false;
}
void CVideoPlayer::show(int x, int y, SDL_Surface *dst, bool update)
{
if(current)
current->show(x, y, dst, update);
}
bool CVideoPlayer::wait()
{
if(current)
return current->wait();
else
return false;
}
int CVideoPlayer::curFrame() const
{
if(current)
return current->curFrame();
else
return -1;
}
int CVideoPlayer::frameCount() const
{
if(current)
return current->frameCount();
else
return -1;
}
bool CVideoPlayer::openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey)
{
if(!open(name))
return false;
bool ret = playVideo(x, y, dst, stopOnKey);
close();
return ret;
}
void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool forceRedraw, bool update )
{
if(!current)
return;
bool w = false;
if(!first)
{
w = wait(); //check if should keep current frame
if(!w)
nextFrame();
}
else
{
first = false;
}
if(!w)
{
show(x,y,dst,update);
}
else if (forceRedraw)
{
redraw(x, y, dst, update);
}
}
void CVideoPlayer::redraw( int x, int y, SDL_Surface *dst, bool update )
{
if(current)
current->redraw(x, y, dst, update);
}
bool CVideoPlayer::playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey)
{
if(!current)
return false;
int frame = 0;
while(frame < frameCount()) //play all frames
{
if(stopOnKey && keyDown())
return false;
if(!wait())
{
show(x, y, dst);
nextFrame();
frame++;
}
SDL_Delay(20);
}
return true;
}
#else
#ifdef _MSC_VER
#pragma comment(lib, "avcodec.lib")
@ -1029,4 +483,3 @@ CVideoPlayer::~CVideoPlayer()
#endif
#endif

View File

@ -43,178 +43,6 @@ public:
};
#if defined(_WIN32) && (_MSC_VER < 1800 || !defined(USE_FFMPEG))
#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
#include <windows.h>
#pragma pack(push,1)
struct BINK_STRUCT
{
si32 width;
si32 height;
si32 frameCount;
si32 currentFrame;
si32 lastFrame;
si32 FPSMul;
si32 FPSDiv;
si32 unknown0;
ui8 flags;
ui8 unknown1[260];
si32 CurPlane; // current plane
void *plane0; // posi32er to plane 0
void *plane1; // posi32er to plane 1
si32 unknown2;
si32 unknown3;
si32 yWidth; // Y plane width
si32 yHeight; // Y plane height
si32 uvWidth; // U&V plane width
si32 uvHeight; // U&V plane height
};
#pragma pack(pop)
typedef BINK_STRUCT* HBINK;
class DLLHandler
{
public:
std::string name;
HINSTANCE dll;
void Instantiate(const char *filename);
const char *GetLibExtension();
void *FindAddress(const char *symbol);
DLLHandler();
virtual ~DLLHandler(); //d-tor
};
typedef void*(__stdcall* BinkSetSoundSystem)(void * soundfun, void*);
typedef HBINK(__stdcall* BinkOpen)(HANDLE bikfile, int flags);
typedef void(__stdcall* BinkClose)(HBINK);
//typedef si32(__stdcall* BinkGetPalette)(HBINK);
typedef void(__stdcall* BinkNextFrame)(HBINK);
typedef void(__stdcall* BinkDoFrame)(HBINK);
typedef ui8(__stdcall* BinkWait)(HBINK);
typedef si32(__stdcall* BinkCopyToBuffer)(HBINK, void* buffer, int stride, int height, int x, int y, int mode);
class CBIKHandler : public DLLHandler, public IVideoPlayer
{
void allocBuffer(int Bpp = 0);
void freeBuffer();
public:
HANDLE hBinkFile;
HBINK hBink;
char * buffer;
int bufferSize;
BinkSetSoundSystem binkSetSoundSystem;
BinkOpen binkOpen;
//BinkGetPalette getPalette;
BinkNextFrame binkNextFrame;
BinkDoFrame binkDoFrame;
BinkCopyToBuffer binkCopyToBuffer;
BinkWait binkWait;
BinkClose binkClose;
CBIKHandler();
bool open(std::string name);
void close();
bool nextFrame();
void show(int x, int y, SDL_Surface *dst, bool update = true);
void redraw(int x, int y, SDL_Surface *dst, bool update = true); //reblits buffer
bool wait();
int curFrame() const;
int frameCount() const;
};
//////////SMK Player ///////////////////////////////////////////////////////
struct SmackStruct
{
si32 version;
si32 width;
si32 height;
si32 frameCount;
si32 mspf;
ui8 unk1[88];
ui8 palette[776];
si32 currentFrame; // Starting with 0
ui8 unk[56];
ui32 fileHandle; // exact type is HANDLE in windows.h
};
// defines function pointer types
typedef SmackStruct* (__stdcall* SmackOpen)(void* , ui32, si32 );
typedef int (__stdcall* SmackDoFrame)( SmackStruct * );
typedef void (__stdcall * SmackGoto )(SmackStruct *, int frameNumber);
typedef void (__stdcall* SmackNextFrame)(SmackStruct*);
typedef void (__stdcall* SmackClose)(SmackStruct*);
typedef void (__stdcall* SmackToBuffer) (SmackStruct*, int, int, int, int, char *, ui32);
typedef bool (__stdcall* SmackWait)(SmackStruct*);
typedef void (__stdcall* SmackSoundOnOff) (SmackStruct*, bool);
typedef int (__stdcall* SmackVolumePan)(SmackStruct *, int SmackTrack, int volume, int pan);
class CSmackPlayer: public DLLHandler, public IVideoPlayer
{
public:
SmackOpen ptrSmackOpen;
SmackDoFrame ptrSmackDoFrame;
SmackToBuffer ptrSmackToBuffer;
SmackNextFrame ptrSmackNextFrame;
SmackWait ptrSmackWait;
SmackSoundOnOff ptrSmackSoundOnOff;
SmackClose ptrSmackClose;
SmackVolumePan ptrVolumePan;
char *buffer, *buf;
SmackStruct* data;
CSmackPlayer();
~CSmackPlayer();
bool open(std::string name);
void close();
bool nextFrame();
void show(int x, int y, SDL_Surface *dst, bool update = true);
void redraw(int x, int y, SDL_Surface *dst, bool update = true); //reblits buffer
bool wait();
int curFrame() const;
int frameCount() const;
};
class CVidHandler;
class CVideoPlayer : public IMainVideoPlayer
{
private:
CSmackPlayer smkPlayer; //for .SMK
CBIKHandler bikPlayer; //for .BIK
IVideoPlayer *current; //points to bik or smk player, appropriate to type of currently played video
bool first; //are we about to display the first frame (blocks update)
public:
CVideoPlayer(); //c-tor
~CVideoPlayer(); //d-tor
bool open(std::string name);
void close();
bool nextFrame(); //move animation to the next frame
void show(int x, int y, SDL_Surface *dst, bool update = true); //blit current frame
void redraw(int x, int y, SDL_Surface *dst, bool update = true); //reblits buffer
void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true); //moves to next frame if appropriate, and blits it or blits only if redraw paremeter is set true
bool wait(); //true if we should wait before displaying next frame (for keeping FPS)
int curFrame() const; //current frame number <1, framecount>
int frameCount() const;
bool openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey = false); //opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
bool playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey = false); //plays whole opened video; returns: true when whole video has been shown, false when it has been interrupted
};
#else
#ifndef DISABLE_VIDEO
#include "../lib/filesystem/CInputStream.h"
@ -285,4 +113,4 @@ public:
};
#endif
#endif

View File

@ -104,6 +104,7 @@
<Add directory="$(#boost.include)" />
<Add directory="../include" />
<Add directory="../client" />
<Add directory="$(#ffmpeg.include)" />
</Compiler>
<Linker>
<Add option="-lole32" />
@ -115,8 +116,13 @@
<Add option="-lboost_thread$(#boost.libsuffix)" />
<Add option="-lboost_chrono$(#boost.libsuffix)" />
<Add option="-lVCMI_lib" />
<Add option="-lavcodec.dll" />
<Add option="-lavformat.dll" />
<Add option="-lswscale.dll" />
<Add option="-lavutil.dll" />
<Add directory="$(#boost.lib32)" />
<Add directory="../" />
<Add directory="$(#ffmpeg.lib)" />
</Linker>
<Unit filename="../CCallback.cpp" />
<Unit filename="../CCallback.h" />