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:
parent
e874681fc0
commit
dcbf717a07
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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__
|
||||
|
Loading…
Reference in New Issue
Block a user