1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-19 21:10:12 +02:00

Linux video player updates.

This commit is contained in:
Frank Zago 2009-06-27 23:33:59 +00:00
parent 0b20c0cf61
commit 6be7a77fee
6 changed files with 227 additions and 150 deletions

View File

@ -370,12 +370,10 @@ void processCommand(const std::string &message, CClient *&client)
//plays intro, ends when intro is over or button has been pressed (handles events)
void playIntro()
{
#ifdef _WIN32
if(CGI->videoh->openAndPlayVideo("3DOLOGO.SMK", 60, 40, screen, true))
{
CGI->videoh->openAndPlayVideo("AZVS.SMK", 60, 80, screen, true);
}
#endif
}
void dispose()

View File

@ -2055,6 +2055,8 @@ StartInfo CPreGame::runLoop()
#ifdef _WIN32
CGI->videoh->open("ACREDIT.SMK");
#else
CGI->videoh->open("ACREDIT.SMK", true, false);
#endif
while(run)
@ -2324,10 +2326,8 @@ StartInfo CPreGame::runLoop()
}
} HANDLE_EXCEPTION
#ifdef _WIN32
if(currentItems())
CGI->videoh->update(8, 105, screen, true, false);
#endif
CGI->curh->draw1();
SDL_Flip(screen);
@ -2335,9 +2335,8 @@ StartInfo CPreGame::runLoop()
SDL_Delay(20); //give time for other apps
}
ret.mode = (fromMenu==newGame) ? 0 : 1;
#ifdef _WIN32
CGI->videoh->close();
#endif
return ret;
}

View File

@ -638,77 +638,12 @@ void CSpellWindow::deactivate()
void CSpellWindow::turnPageLeft()
{
// Note: video decoders are different, and one is buggy.
#ifndef _WIN32
if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, pos.y+14))
{
while(CGI->videoh->nextFrame())
{
SDL_framerateDelay(LOCPLINT->mainFPSmng);
SDL_framerateDelay(LOCPLINT->mainFPSmng);
SDL_framerateDelay(LOCPLINT->mainFPSmng);
}
CGI->videoh->close();
}
#else
CGI->videoh->openAndPlayVideo("PGTRNLFT.SMK", pos.x+13, pos.y+15, screen);
#endif
//#ifdef _WIN32
// const int y = pos.y+15;
//
//#endif
//
// if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, y)) {
// while(CGI->videoh->nextFrame()) {
// SDL_framerateDelay(LOCPLINT->mainFPSmng);
//#ifndef _WIN32
// SDL_framerateDelay(LOCPLINT->mainFPSmng);
// SDL_framerateDelay(LOCPLINT->mainFPSmng);
//#endif
// }
// CGI->videoh->close();
// }
}
void CSpellWindow::turnPageRight()
{
// Note: video decoders are different, and one is buggy.
#ifndef _WIN32
if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, pos.y+14))
{
while(CGI->videoh->nextFrame())
{
SDL_framerateDelay(LOCPLINT->mainFPSmng);
SDL_framerateDelay(LOCPLINT->mainFPSmng);
SDL_framerateDelay(LOCPLINT->mainFPSmng);
}
CGI->videoh->close();
}
#else
CGI->videoh->openAndPlayVideo("PGTRNRGH.SMK", pos.x+13, pos.y+15, screen);
#endif
//#ifdef _WIN32
// const int y = pos.y+15;
//#else
// const int y = pos.y+14;
//#endif
//
// if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, y)) {
// while(CGI->videoh->nextFrame()) {
// SDL_framerateDelay(LOCPLINT->mainFPSmng);
//#ifndef _WIN32
// SDL_framerateDelay(LOCPLINT->mainFPSmng);
// SDL_framerateDelay(LOCPLINT->mainFPSmng);
//#endif
// }
// CGI->videoh->close();
// }
}
CSpellWindow::SpellArea::SpellArea(SDL_Rect pos, CSpellWindow * owner)

View File

@ -2795,6 +2795,8 @@ CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2,
#ifdef _WIN32
CGI->videoh->open("TAVERN.BIK");
#else
CGI->videoh->open("tavern.mjpg", true, false);
#endif
}
@ -2807,9 +2809,7 @@ void CTavernWindow::recruitb()
CTavernWindow::~CTavernWindow()
{
#ifdef _WIN32
CGI->videoh->close();
#endif
SDL_FreeSurface(bg);
delete cancel;
delete thiefGuild;
@ -2848,9 +2848,7 @@ void CTavernWindow::close()
void CTavernWindow::show(SDL_Surface * to)
{
blitAt(bg,pos.x,pos.y,to);
#ifdef _WIN32
CGI->videoh->update(pos.x+70, pos.y+56, to, true, false);
#endif
if(h1.h)
h1.show(to);
if(h2.h)

View File

@ -3,10 +3,22 @@
#include "CSndHandler.h"
#include "CVideoHandler.h"
#include <SDL.h>
#include "../client/SDL_Extensions.h"
//reads events and throws on key down
static bool keyDown()
{
SDL_Event ev;
while(SDL_PollEvent(&ev))
{
if(ev.type == SDL_KEYDOWN || ev.type == SDL_MOUSEBUTTONDOWN)
return true;
}
return false;
}
#ifdef _WIN32
#include "../client/SDL_Extensions.h"
#include <boost/algorithm/string/predicate.hpp>
@ -409,18 +421,6 @@ void CVideoPlayer::redraw( int x, int y, SDL_Surface *dst, bool update )
current->redraw(x, y, dst, update);
}
//reads events and throws on key down
bool keyDown()
{
SDL_Event ev;
while(SDL_PollEvent(&ev))
{
if(ev.type == SDL_KEYDOWN || ev.type == SDL_MOUSEBUTTONDOWN)
return true;
}
return false;
}
bool CVideoPlayer::playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey)
{
int frame = 0;
@ -443,8 +443,6 @@ bool CVideoPlayer::playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey)
#else
#include "../client/SDL_Extensions.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
@ -491,12 +489,24 @@ static int lod_read(URLContext *context, unsigned char *buf, int size)
return size;
}
static int64_t lod_seek(URLContext *context, int64_t pos, int whence)
{
CVideoPlayer *video = (CVideoPlayer *)context->priv_data;
// Not sure what the parameter whence is. Assuming it always
// indicates an absolute value;
video->offset = pos;
amin(video->offset, video->length);
return -1;//video->offset;
}
static URLProtocol lod_protocol = {
protocol_name,
lod_open,
lod_read,
NULL, // no write
NULL, // no seek
lod_seek,
lod_close
};
@ -507,6 +517,7 @@ CVideoPlayer::CVideoPlayer()
codec = NULL;
sws = NULL;
overlay = NULL;
dest = NULL;
// Register codecs. TODO: May be overkill. Should call a
// combination of av_register_input_format() /
@ -519,34 +530,39 @@ CVideoPlayer::CVideoPlayer()
vidh = new CVidHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "VIDEO.VID"));
}
bool CVideoPlayer::open(std::string fname, int x, int y)
// loop = to loop through the video
// useOverlay = directly write to the screen.
bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay)
{
char url[100];
close();
offset = 0;
refreshWait = 3;
refreshCount = -1;
doLoop = loop;
data = vidh->extract(fname, length);
if (data == NULL)
return false;
if (data) {
// Create our URL name with the 'lod' protocol as a prefix and a
// back pointer to our object. Should be 32 and 64 bits compatible.
char url[100];
sprintf(url, "%s:0x%016llx", protocol_name, (unsigned long long)(uintptr_t)this);
offset = 0;
// Create our URL name with the 'lod' protocol as a prefix and a
// back pointer to our object. Should be 32 and 64 bits compatible.
sprintf(url, "%s:0x%016llx", protocol_name, (unsigned long long)(uintptr_t)this);
if (av_open_input_file(&format, url, NULL, 0, NULL)!=0)
return false;
if (av_open_input_file(&format, url, NULL, 0, NULL)!=0) {
return false;
}
} else {
// File is not in a container
if (av_open_input_file(&format, (DATA_DIR "Data/video/" + fname).c_str(), NULL, 0, NULL)!=0) {
// tlog1 << "Video file not found: " DATA_DIR "Data/video/" + fname << std::endl;
return false;
}
}
// Retrieve stream information
if (av_find_stream_info(format) < 0)
return false;
#if 0
// Dump information about file onto standard error
dump_format(format, 0, url, 0);
#endif
// Find the first video stream
stream = -1;
@ -583,66 +599,140 @@ bool CVideoPlayer::open(std::string fname, int x, int y)
frame = avcodec_alloc_frame();
// Allocate a place to put our YUV image on that screen
overlay = SDL_CreateYUVOverlay(codecContext->width, codecContext->height,
SDL_YV12_OVERLAY, screen);
if (useOverlay) {
overlay = SDL_CreateYUVOverlay(codecContext->width, codecContext->height,
SDL_YV12_OVERLAY, screen);
} else {
dest = CSDL_Ext::newSurface(codecContext->width, codecContext->height);
destRect.x = destRect.y = 0;
destRect.w = codecContext->width;
destRect.h = codecContext->height;
}
if (overlay == NULL && dest == NULL)
return false;
// Convert the image into YUV format that SDL uses
sws = sws_getContext(codecContext->width, codecContext->height,
codecContext->pix_fmt, codecContext->width, codecContext->height,
PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
if (overlay) {
sws = sws_getContext(codecContext->width, codecContext->height,
codecContext->pix_fmt, codecContext->width, codecContext->height,
PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
} else {
sws = sws_getContext(codecContext->width, codecContext->height,
codecContext->pix_fmt, codecContext->width, codecContext->height,
PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
}
if (sws == NULL)
return false;
pos.x = x;
pos.y = y;
pos.w = codecContext->width;
pos.h = codecContext->height;
return true;
}
// Display the next frame. Return false on error/end of file.
// Read the next frame. Return false on error/end of file.
bool CVideoPlayer::nextFrame()
{
AVPacket packet;
int frameFinished = 0;
bool gotError = false;
while(!frameFinished && av_read_frame(format, &packet)>=0) {
if (sws == NULL)
return false;
// Is this a packet from the video stream?
if (packet.stream_index == stream) {
// Decode video frame
avcodec_decode_video(codecContext, frame, &frameFinished,
packet.data, packet.size);
// Did we get a video frame?
if (frameFinished) {
SDL_LockYUVOverlay(overlay);
while(!frameFinished) {
AVPicture pict;
pict.data[0] = overlay->pixels[0];
pict.data[1] = overlay->pixels[2];
pict.data[2] = overlay->pixels[1];
pict.linesize[0] = overlay->pitches[0];
pict.linesize[1] = overlay->pitches[2];
pict.linesize[2] = overlay->pitches[1];
sws_scale(sws, frame->data, frame->linesize,
0, codecContext->height, pict.data, pict.linesize);
SDL_UnlockYUVOverlay(overlay);
SDL_DisplayYUVOverlay(overlay, &pos);
int ret = av_read_frame(format, &packet);
if (ret < 0) {
// Error. It's probably an end of file.
if (doLoop && !gotError) {
// Rewind
if (av_seek_frame(format, stream, 0, 0) < 0)
break;
gotError = true;
} else {
break;
}
}
} else {
// Is this a packet from the video stream?
if (packet.stream_index == stream) {
// Decode video frame
avcodec_decode_video(codecContext, frame, &frameFinished,
packet.data, packet.size);
av_free_packet(&packet);
// Did we get a video frame?
if (frameFinished) {
AVPicture pict;
if (overlay) {
SDL_LockYUVOverlay(overlay);
pict.data[0] = overlay->pixels[0];
pict.data[1] = overlay->pixels[2];
pict.data[2] = overlay->pixels[1];
pict.linesize[0] = overlay->pitches[0];
pict.linesize[1] = overlay->pitches[2];
pict.linesize[2] = overlay->pitches[1];
sws_scale(sws, frame->data, frame->linesize,
0, codecContext->height, pict.data, pict.linesize);
SDL_UnlockYUVOverlay(overlay);
} else {
pict.data[0] = (uint8_t *)dest->pixels;
pict.linesize[0] = dest->pitch;
sws_scale(sws, frame->data, frame->linesize,
0, codecContext->height, pict.data, pict.linesize);
}
}
}
av_free_packet(&packet);
}
}
return frameFinished != 0;
}
void CVideoPlayer::show( int x, int y, SDL_Surface *dst, bool update )
{
if (sws == NULL)
return;
pos.x = x;
pos.y = y;
SDL_BlitSurface(dest, &destRect, dst, &pos);
if (update)
SDL_UpdateRect(dst, pos.x, pos.y, pos.w, pos.h);
}
void CVideoPlayer::redraw( int x, int y, SDL_Surface *dst, bool update )
{
show(x, y, dst, update);
}
void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool forceRedraw, bool update )
{
if (sws == NULL)
return;
if (refreshCount <= 0)
{
refreshCount = refreshWait;
if (nextFrame())
show(x,y,dst,update);
} else {
redraw(x, y, dst, update);
}
refreshCount --;
}
void CVideoPlayer::close()
{
if (sws) {
@ -655,6 +745,11 @@ void CVideoPlayer::close()
overlay = NULL;
}
if (dest) {
SDL_FreeSurface(dest);
dest = NULL;
}
if (frame) {
av_free(frame);
frame = NULL;
@ -671,6 +766,44 @@ void CVideoPlayer::close()
format = NULL;
}
}
// Plays a video. Only works for overlays.
bool CVideoPlayer::playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey)
{
// Note: either the windows player or the linux player is
// broken. Compensate here until the bug is found.
y--;
pos.x = x;
pos.y = y;
FPSmanager mainFPSmng;
SDL_initFramerate(&mainFPSmng);
SDL_setFramerate(&mainFPSmng, 48);
while(nextFrame()) {
if(stopOnKey && keyDown())
return false;
SDL_DisplayYUVOverlay(overlay, &pos);
// Wait 3 frames
SDL_framerateDelay(&mainFPSmng);
SDL_framerateDelay(&mainFPSmng);
SDL_framerateDelay(&mainFPSmng);
}
return true;
}
bool CVideoPlayer::openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey)
{
open(name, false, true);
bool ret = playVideo(x, y, dst, stopOnKey);
close();
return ret;
}
CVideoPlayer::~CVideoPlayer()
{

View File

@ -2,12 +2,12 @@
#define __CVIDEOHANDLER_H__
#include "../global.h"
struct SDL_Surface;
#ifdef _WIN32
#include <windows.h>
struct SDL_Surface;
#pragma pack(push,1)
struct BINK_STRUCT
{
@ -57,7 +57,6 @@ 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 IVideoPlayer
{
public:
@ -194,7 +193,7 @@ typedef struct AVFrame AVFrame;
struct SwsContext;
class CVidHandler;
class CVideoPlayer
class CVideoPlayer //: public IVideoPlayer
{
private:
int stream; // stream index in video
@ -204,20 +203,35 @@ private:
AVFrame *frame;
struct SwsContext *sws;
// Destination. Either overlay or dest.
SDL_Overlay *overlay;
SDL_Rect pos; // overlay position
SDL_Surface *dest;
SDL_Rect destRect; // valid when dest is used
SDL_Rect pos; // destination on screen
CVidHandler *vidh;
int refreshWait; // Wait several refresh before updating the image
int refreshCount;
bool doLoop; // loop through video
public:
CVideoPlayer();
~CVideoPlayer();
bool init();
bool open(std::string fname, int x, int y);
bool open(std::string fname, bool loop=false, bool useOverlay=false);
void close();
bool nextFrame(); // display 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 parameter is set true
// 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);
bool openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey = false);
const char *data; // video buffer
int length; // video size
unsigned int offset; // current data offset