1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Basic video player, with no sound, using FFMpeg. Currently plays SMK only.

This commit is contained in:
Frank Zago 2009-06-20 01:34:26 +00:00
parent e874681fc0
commit dcbf717a07
2 changed files with 290 additions and 2 deletions

View File

@ -1,7 +1,10 @@
#include "../stdafx.h"
#include <iostream>
#include "CSndHandler.h"
#include "CVideoHandler.h"
#include "SDL.h"
#include <SDL.h>
#ifdef WIN32
void DLLHandler::Instantiate(const char *filename)
{
@ -195,4 +198,243 @@ void CBIKHandler::open(std::string name)
// b.PixelFormat:=pf24bit;
// end
//
//end;
//end;
#else
#include "SDL_Extensions.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
static const char *protocol_name = "lod";
// Open a pseudo file. Name is something like 'lod:0x56432ab6c43df8fe'
static int lod_open(URLContext *context, const char *filename, int flags)
{
CVideoPlayer *video;
// Retrieve pointer to CVideoPlayer object
filename += strlen(protocol_name) + 1;
video = (CVideoPlayer *)(uintptr_t)strtoull(filename, NULL, 16);
// TODO: check flags ?
context->priv_data = video;
return 0;
}
static int lod_close(URLContext* h)
{
return 0;
}
// Define a set of functions to read data
static int lod_read(URLContext *context, unsigned char *buf, int size)
{
CVideoPlayer *video = (CVideoPlayer *)context->priv_data;
amin(size, video->length - video->offset);
if (size < 0)
return -1;
// TODO: can we avoid that copy ?
memcpy(buf, video->data + video->offset, size);
video->offset += size;
return size;
}
static URLProtocol lod_protocol = {
protocol_name,
lod_open,
lod_read,
NULL, // no write
NULL, // no seek
lod_close
};
CVideoPlayer::CVideoPlayer()
{
format = NULL;
frame = NULL;
codec = NULL;
sws = NULL;
overlay = NULL;
// Register codecs. TODO: May be overkill. Should call a
// combination of av_register_input_format() /
// av_register_output_format() / av_register_protocol() instead.
av_register_all();
// Register our protocol 'lod' so we can directly read from mmaped memory
av_register_protocol(&lod_protocol);
vidh = new CVidHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "VIDEO.VID"));
}
bool CVideoPlayer::open(std::string fname, int x, int y)
{
char url[100];
close();
data = vidh->extract(fname, length);
if (data == NULL)
return false;
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)this);
if (av_open_input_file(&format, url, NULL, 0, NULL)!=0)
return false;
// Retrieve stream information
if (av_find_stream_info(format) < 0)
return false;
// Dump information about file onto standard error
dump_format(format, 0, url, 0);
// Find the first video stream
stream = -1;
for(unsigned int i=0; i<format->nb_streams; i++) {
if (format->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
stream = i;
break;
}
}
if (stream < 0)
// No video stream in that file
return false;
// Get a pointer to the codec context for the video stream
codecContext = format->streams[stream]->codec;
// Find the decoder for the video stream
codec = avcodec_find_decoder(codecContext->codec_id);
if (codec == NULL) {
// Unsupported codec
return false;
}
// Open codec
if (avcodec_open(codecContext, codec) <0 ) {
// Could not open codec
codec = NULL;
return false;
}
// Allocate video frame
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);
// 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 (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.
bool CVideoPlayer::nextFrame()
{
AVPacket packet;
int frameFinished = 0;
while(!frameFinished && av_read_frame(format, &packet)>=0) {
// 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);
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);
}
}
av_free_packet(&packet);
}
return frameFinished != 0;
}
void CVideoPlayer::close()
{
if (sws) {
sws_freeContext(sws);
sws = NULL;
}
if (overlay) {
SDL_FreeYUVOverlay(overlay);
overlay = NULL;
}
if (frame) {
av_free(frame);
frame = NULL;
}
if (codec) {
avcodec_close(codecContext);
codec = NULL;
codecContext = NULL;
}
if (format) {
av_close_input_file(format);
format = NULL;
}
}
CVideoPlayer::~CVideoPlayer()
{
close();
}
#endif

View File

@ -1,6 +1,8 @@
#ifndef __CVIDEOHANDLER_H__
#define __CVIDEOHANDLER_H__
#ifdef WIN32
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
@ -147,4 +149,48 @@ public:
void open(std::string name);
void close();
};
#else
#include <SDL/SDL_video.h>
typedef struct AVFormatContext AVFormatContext;
typedef struct AVCodecContext AVCodecContext;
typedef struct AVCodec AVCodec;
typedef struct AVFrame AVFrame;
struct SwsContext;
class CVidHandler;
class CVideoPlayer
{
private:
int stream; // stream index in video
AVFormatContext *format;
AVCodecContext *codecContext; // codec context for stream
AVCodec *codec;
AVFrame *frame;
struct SwsContext *sws;
SDL_Overlay *overlay;
SDL_Rect pos; // overlay position
CVidHandler *vidh;
public:
CVideoPlayer();
~CVideoPlayer();
bool init();
bool open(std::string fname, int x, int y);
void close();
bool nextFrame(); // display next frame
const char *data; // video buffer
int length; // video size
unsigned int offset; // current data offset
};
#endif
#endif // __CVIDEOHANDLER_H__