Make video dumping to go through generic A/V snooping interface
This commit is contained in:
parent
b015451c38
commit
6877c2f63b
9 changed files with 420 additions and 188 deletions
9
Makefile
9
Makefile
|
@ -1,13 +1,18 @@
|
|||
FONT_SRC := unifontfull-5.1.20080820.hex
|
||||
CC := g++-4.5
|
||||
HOSTCC = $(CC)
|
||||
OBJECTS = controllerdata.o fieldsplit.o memorymanip.o misc.o movie.o moviefile.o render.o rom.o zip.o fonts/font.o videodumper.o videodumper2.o keymapper.o window.o window-sdl.o settings.o framerate.o mainloop.o rrdata.o specialframes.o png.o lsnesrc.o memorywatch.o command.o
|
||||
OBJECTS = controllerdata.o fieldsplit.o memorymanip.o misc.o movie.o moviefile.o render.o rom.o zip.o fonts/font.o keymapper.o window.o window-sdl.o settings.o framerate.o mainloop.o rrdata.o specialframes.o png.o lsnesrc.o memorywatch.o command.o avsnoop.o
|
||||
|
||||
#AVI dumper
|
||||
OBJECTS += avidump/avidump-control.o avidump/avidump.o
|
||||
|
||||
PROGRAMS = lsnes.exe movietrunctest.exe
|
||||
|
||||
CFLAGS = $(shell sdl-config --cflags) $(USER_CFLAGS)
|
||||
CFLAGS = -I. $(shell sdl-config --cflags) $(USER_CFLAGS)
|
||||
HOSTCCFLAGS = $(USER_HOSTCCFLAGS)
|
||||
LDFLAGS = $(shell sdl-config --libs) $(USER_LDFLAGS)
|
||||
|
||||
#Lua.
|
||||
ifdef NO_LUA
|
||||
OBJECTS += lua-dummy.o
|
||||
else
|
||||
|
|
|
@ -1,28 +1,94 @@
|
|||
#include "videodumper.hpp"
|
||||
#include "lua.hpp"
|
||||
#include "avidump.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "videodumper2.hpp"
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <zlib.h>
|
||||
#include "misc.hpp"
|
||||
#include "fieldsplit.hpp"
|
||||
#include "avsnoop.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
avidumper* vid_dumper = NULL;
|
||||
|
||||
void update_movie_state();
|
||||
|
||||
namespace
|
||||
{
|
||||
screen dscr;
|
||||
boolean_setting dump_large("large-video", false);
|
||||
|
||||
class avi_avsnoop : public av_snooper
|
||||
{
|
||||
public:
|
||||
avi_avsnoop(const std::string& prefix, struct avi_info parameters) throw(std::bad_alloc)
|
||||
{
|
||||
vid_dumper = new avidumper(prefix, parameters);
|
||||
}
|
||||
|
||||
~avi_avsnoop() throw()
|
||||
{
|
||||
delete vid_dumper;
|
||||
}
|
||||
|
||||
void frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d, window* win, bool dummy)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
vid_dumper->wait_idle();
|
||||
uint32_t hscl = 1;
|
||||
uint32_t vscl = 1;
|
||||
if(dump_large && _frame.width < 400)
|
||||
hscl = 2;
|
||||
if(dump_large && _frame.height < 400)
|
||||
vscl = 2;
|
||||
uint32_t _magic = 403703808;
|
||||
uint8_t* magic = reinterpret_cast<uint8_t*>(&_magic);
|
||||
dscr.set_palette(magic[2], magic[1], magic[0]);
|
||||
|
||||
struct lua_render_context lrc;
|
||||
render_queue rq;
|
||||
lrc.left_gap = 0;
|
||||
lrc.right_gap = 0;
|
||||
lrc.bottom_gap = 0;
|
||||
lrc.top_gap = 0;
|
||||
lrc.queue = &rq;
|
||||
lrc.width = _frame.width * hscl;
|
||||
lrc.height = _frame.height * vscl;
|
||||
lrc.rshift = magic[2];
|
||||
lrc.gshift = magic[1];
|
||||
lrc.bshift = magic[0];
|
||||
lua_callback_do_video(&lrc, win);
|
||||
|
||||
dscr.reallocate(lrc.left_gap + hscl * _frame.width + lrc.right_gap, lrc.top_gap + vscl *
|
||||
_frame.height + lrc.bottom_gap, lrc.left_gap, lrc.top_gap, true);
|
||||
dscr.copy_from(_frame, hscl, vscl);
|
||||
rq.run(dscr);
|
||||
vid_dumper->on_frame(dscr.memory, dscr.width, dscr.height, fps_n, fps_d);
|
||||
}
|
||||
|
||||
void sample(short l, short r) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
vid_dumper->on_sample(l, r);
|
||||
}
|
||||
|
||||
void end() throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
vid_dumper->on_end();
|
||||
}
|
||||
|
||||
void gameinfo(const std::string& gamename, const std::list<std::pair<std::string, std::string>>&
|
||||
authors, double gametime, const std::string& rerecords) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
//We don't have place for this info and thus ignore it.
|
||||
}
|
||||
private:
|
||||
avidumper* vid_dumper;
|
||||
screen dscr;
|
||||
};
|
||||
|
||||
avi_avsnoop* vid_dumper;
|
||||
|
||||
class dump_video_command : public command
|
||||
{
|
||||
public:
|
||||
dump_video_command() throw(std::bad_alloc) : command("dump-video") {}
|
||||
dump_video_command() throw(std::bad_alloc) : command("dump-avi") {}
|
||||
void invoke(const std::string& args, window* win) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
tokensplitter t(args);
|
||||
|
@ -31,7 +97,7 @@ namespace
|
|||
if(prefix == "")
|
||||
throw std::runtime_error("Expected prefix");
|
||||
if(vid_dumper)
|
||||
throw std::runtime_error("Video dumping already in progress");
|
||||
throw std::runtime_error("AVI dumping already in progress");
|
||||
unsigned long level2;
|
||||
try {
|
||||
level2 = parse_value<unsigned long>(level);
|
||||
|
@ -40,7 +106,7 @@ namespace
|
|||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
} catch(std::runtime_error& e) {
|
||||
throw std::runtime_error("Bad video compression level '" + level + "': " + e.what());
|
||||
throw std::runtime_error("Bad AVI compression level '" + level + "': " + e.what());
|
||||
}
|
||||
struct avi_info parameters;
|
||||
parameters.compression_level = (level2 > 9) ? (level2 - 9) : level2;
|
||||
|
@ -50,7 +116,7 @@ namespace
|
|||
parameters.audio_native_sampling_rate = 32040.5;
|
||||
parameters.keyframe_interval = (level2 > 9) ? 300 : 1;
|
||||
try {
|
||||
vid_dumper = new avidumper(prefix, parameters);
|
||||
vid_dumper = new avi_avsnoop(prefix, parameters);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
} catch(std::exception& e) {
|
||||
|
@ -59,13 +125,12 @@ namespace
|
|||
throw std::runtime_error(x.str());
|
||||
}
|
||||
out(win) << "Dumping to " << prefix << " at level " << level2 << std::endl;
|
||||
update_movie_state();
|
||||
}
|
||||
std::string get_short_help() throw(std::bad_alloc) { return "Start video capture"; }
|
||||
std::string get_short_help() throw(std::bad_alloc) { return "Start AVI capture"; }
|
||||
std::string get_long_help() throw(std::bad_alloc)
|
||||
{
|
||||
return "Syntax: dump-video <level> <prefix>\n"
|
||||
"Start video capture to <prefix> using compression\n"
|
||||
return "Syntax: dump-avi <level> <prefix>\n"
|
||||
"Start AVI capture to <prefix> using compression\n"
|
||||
"level <level> (0-18).\n";
|
||||
}
|
||||
} dump_video;
|
||||
|
@ -73,7 +138,7 @@ namespace
|
|||
class end_video_command : public command
|
||||
{
|
||||
public:
|
||||
end_video_command() throw(std::bad_alloc) : command("end-video") {}
|
||||
end_video_command() throw(std::bad_alloc) : command("end-avi") {}
|
||||
void invoke(const std::string& args, window* win) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(args != "")
|
||||
|
@ -81,7 +146,7 @@ namespace
|
|||
if(!vid_dumper)
|
||||
throw std::runtime_error("No video dump in progress");
|
||||
try {
|
||||
vid_dumper->on_end();
|
||||
vid_dumper->end();
|
||||
out(win) << "Dump finished" << std::endl;
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
|
@ -90,89 +155,12 @@ namespace
|
|||
}
|
||||
delete vid_dumper;
|
||||
vid_dumper = NULL;
|
||||
update_movie_state();
|
||||
}
|
||||
std::string get_short_help() throw(std::bad_alloc) { return "End video capture"; }
|
||||
std::string get_short_help() throw(std::bad_alloc) { return "End AVI capture"; }
|
||||
std::string get_long_help() throw(std::bad_alloc)
|
||||
{
|
||||
return "Syntax: end-video\n"
|
||||
"End a video capture.\n";
|
||||
return "Syntax: end-avi\n"
|
||||
"End a AVI capture.\n";
|
||||
}
|
||||
} end_vieo;
|
||||
|
||||
}
|
||||
|
||||
void end_vid_dump() throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(vid_dumper)
|
||||
try {
|
||||
vid_dumper->on_end();
|
||||
} catch(std::bad_alloc& e) {
|
||||
throw;
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "Error ending dump: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void dump_frame(lcscreen& ls, render_queue* rq, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom,
|
||||
bool region, window* win) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(vid_dumper)
|
||||
try {
|
||||
vid_dumper->wait_idle();
|
||||
uint32_t hscl = 1;
|
||||
uint32_t vscl = 1;
|
||||
if(dump_large && ls.width < 400)
|
||||
hscl = 2;
|
||||
if(dump_large && ls.height < 400)
|
||||
vscl = 2;
|
||||
uint32_t _magic = 403703808;
|
||||
uint8_t* magic = reinterpret_cast<uint8_t*>(&_magic);
|
||||
dscr.reallocate(left + hscl * ls.width + right, top + vscl * ls.height + bottom, left, top,
|
||||
true);
|
||||
dscr.set_palette(magic[2], magic[1], magic[0]);
|
||||
dscr.copy_from(ls, hscl, vscl);
|
||||
if(rq)
|
||||
rq->run(dscr);
|
||||
assert(dscr.memory);
|
||||
assert(dscr.width);
|
||||
assert(dscr.height);
|
||||
uint32_t fps_n = 10738636;
|
||||
uint32_t fps_d = 178683;
|
||||
if(region) {
|
||||
fps_n = 322445;
|
||||
fps_d = 6448;
|
||||
}
|
||||
vid_dumper->on_frame(dscr.memory, dscr.width, dscr.height, fps_n, fps_d);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
} catch(std::exception& e) {
|
||||
out(win) << "Error sending video frame: " << e.what() << std::endl;
|
||||
}
|
||||
if(rq)
|
||||
rq->clear();
|
||||
}
|
||||
|
||||
void dump_audio_sample(int16_t l_sample, int16_t r_sample, window* win) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(vid_dumper)
|
||||
try {
|
||||
vid_dumper->on_sample(l_sample, r_sample);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
} catch(std::exception& e) {
|
||||
out(win) << "Error sending audio sample: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool dump_in_progress() throw()
|
||||
{
|
||||
return (vid_dumper != NULL);
|
||||
}
|
||||
|
||||
void video_fill_shifts(uint32_t& r, uint32_t& g, uint32_t& b)
|
||||
{
|
||||
r = dscr.active_rshift;
|
||||
g = dscr.active_gshift;
|
||||
b = dscr.active_bshift;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#include "videodumper.hpp"
|
||||
#include "avidump.hpp"
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _videodumper__hpp__included__
|
||||
#define _videodumper__hpp__included__
|
||||
#ifndef _avidump__hpp__included__
|
||||
#define _avidump__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
140
avsnoop.cpp
Normal file
140
avsnoop.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include "avsnoop.hpp"
|
||||
#include "misc.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::list<av_snooper*>* snoopers;
|
||||
std::list<av_snooper::dump_notification*> notifiers;
|
||||
std::string s_gamename;
|
||||
std::string s_rerecords;
|
||||
double s_gametime;
|
||||
std::list<std::pair<std::string, std::string>> s_authors;
|
||||
bool gameinfo_set;
|
||||
}
|
||||
|
||||
av_snooper::av_snooper() throw(std::bad_alloc)
|
||||
{
|
||||
if(!snoopers)
|
||||
snoopers = new std::list<av_snooper*>();
|
||||
snoopers->push_back(this);
|
||||
for(auto i = notifiers.begin(); i != notifiers.end(); i++)
|
||||
(*i)->dump_starting();
|
||||
}
|
||||
|
||||
av_snooper::~av_snooper() throw()
|
||||
{
|
||||
if(!snoopers)
|
||||
return;
|
||||
for(auto i = snoopers->begin(); i != snoopers->end(); i++)
|
||||
if(*i == this) {
|
||||
snoopers->erase(i);
|
||||
break;
|
||||
}
|
||||
for(auto i = notifiers.begin(); i != notifiers.end(); i++)
|
||||
(*i)->dump_ending();
|
||||
}
|
||||
|
||||
void av_snooper::frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d, window* win) throw()
|
||||
{
|
||||
if(!snoopers)
|
||||
return;
|
||||
for(auto i = snoopers->begin(); i != snoopers->end(); i++)
|
||||
try {
|
||||
(*i)->frame(_frame, fps_n, fps_d, win, true);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
} catch(std::exception& e) {
|
||||
try {
|
||||
win->message(std::string("Error dumping frame: ") + e.what());
|
||||
} catch(...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av_snooper::sample(short l, short r, window* win) throw()
|
||||
{
|
||||
if(!snoopers)
|
||||
return;
|
||||
for(auto i = snoopers->begin(); i != snoopers->end(); i++)
|
||||
try {
|
||||
(*i)->sample(l, r);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
} catch(std::exception& e) {
|
||||
try {
|
||||
win->message(std::string("Error dumping sample: ") + e.what());
|
||||
} catch(...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av_snooper::end(window* win) throw()
|
||||
{
|
||||
if(!snoopers)
|
||||
return;
|
||||
for(auto i = snoopers->begin(); i != snoopers->end(); i++)
|
||||
try {
|
||||
(*i)->end();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic(win);
|
||||
} catch(std::exception& e) {
|
||||
try {
|
||||
win->message(std::string("Error ending dump: ") + e.what());
|
||||
} catch(...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void av_snooper::gameinfo(const std::string& gamename, const std::list<std::pair<std::string, std::string>>&
|
||||
authors, double gametime, const std::string& rerecords, window* win) throw(std::bad_alloc)
|
||||
{
|
||||
if(!snoopers)
|
||||
return;
|
||||
s_gamename = gamename;
|
||||
s_authors = authors;
|
||||
s_gametime = gametime;
|
||||
s_rerecords = rerecords;
|
||||
gameinfo_set = true;
|
||||
for(auto i = snoopers->begin(); i != snoopers->end(); i++)
|
||||
(*i)->send_gameinfo();
|
||||
}
|
||||
|
||||
void av_snooper::send_gameinfo() throw()
|
||||
{
|
||||
if(gameinfo_set)
|
||||
try {
|
||||
gameinfo(s_gamename, s_authors, s_gametime, s_rerecords);
|
||||
} catch(...) {
|
||||
}
|
||||
}
|
||||
|
||||
bool av_snooper::dump_in_progress() throw()
|
||||
{
|
||||
return (snoopers && !snoopers->empty());
|
||||
}
|
||||
|
||||
av_snooper::dump_notification::~dump_notification() throw()
|
||||
{
|
||||
}
|
||||
|
||||
void av_snooper::dump_notification::dump_starting() throw()
|
||||
{
|
||||
}
|
||||
|
||||
void av_snooper::dump_notification::dump_ending() throw()
|
||||
{
|
||||
}
|
||||
|
||||
void av_snooper::add_dump_notifier(av_snooper::dump_notification& notifier) throw(std::bad_alloc)
|
||||
{
|
||||
notifiers.push_back(¬ifier);
|
||||
}
|
||||
|
||||
void av_snooper::remove_dump_notifier(av_snooper::dump_notification& notifier) throw()
|
||||
{
|
||||
for(auto i = notifiers.begin(); i != notifiers.end(); i++)
|
||||
if(*i == ¬ifier) {
|
||||
notifiers.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
157
avsnoop.hpp
Normal file
157
avsnoop.hpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
#ifndef _avsnoop__hpp__included__
|
||||
#define _avsnoop__hpp__included__
|
||||
|
||||
#include "render.hpp"
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include "window.hpp"
|
||||
|
||||
/**
|
||||
* A/V snooper.
|
||||
*/
|
||||
class av_snooper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create new A/V snooper.
|
||||
*
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
*/
|
||||
av_snooper() throw(std::bad_alloc);
|
||||
|
||||
/**
|
||||
* Destroy A/V snooper. This will not call end method.
|
||||
*/
|
||||
~av_snooper() throw();
|
||||
|
||||
/**
|
||||
* Dump a frame.
|
||||
*
|
||||
* parameter _frame: The frame to dump.
|
||||
* parameter fps_n: Current fps numerator.
|
||||
* parameter fps_d: Current fps denomerator.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Error dumping frame.
|
||||
*/
|
||||
virtual void frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d, window* win, bool dummy)
|
||||
throw(std::bad_alloc, std::runtime_error) = 0;
|
||||
|
||||
/**
|
||||
* Dump a frame.
|
||||
*
|
||||
* parameter _frame: The frame to dump.
|
||||
* parameter fps_n: Current fps numerator.
|
||||
* parameter fps_d: Current fps denomerator.
|
||||
* parameter win: Graphics system handle.
|
||||
*/
|
||||
static void frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d, window* win) throw();
|
||||
|
||||
/**
|
||||
* Dump a sample.
|
||||
*
|
||||
* parameter l: Left channel sample.
|
||||
* parameter r: Right channel sample.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Error dumping sample.
|
||||
*/
|
||||
virtual void sample(short l, short r) throw(std::bad_alloc, std::runtime_error) = 0;
|
||||
|
||||
/**
|
||||
* Dump a sample.
|
||||
*
|
||||
* parameter l: Left channel sample.
|
||||
* parameter r: Right channel sample.
|
||||
* parameter win: Graphics system handle.
|
||||
*/
|
||||
static void sample(short l, short r, window* win) throw();
|
||||
|
||||
/**
|
||||
* End dump.
|
||||
*
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Error dumping sample.
|
||||
*/
|
||||
virtual void end() throw(std::bad_alloc, std::runtime_error) = 0;
|
||||
|
||||
/**
|
||||
* End dump.
|
||||
*
|
||||
* parameter win: Graphics system handle.
|
||||
*/
|
||||
static void end(window* win) throw();
|
||||
|
||||
/**
|
||||
* Notify game information.
|
||||
*
|
||||
* parameter gamename: Name of the game.
|
||||
* parameter authors: Authors of the run.
|
||||
* parameter gametime: Game time.
|
||||
* parameter rercords: Rerecord count.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Error recording this info.
|
||||
*/
|
||||
virtual void gameinfo(const std::string& gamename, const std::list<std::pair<std::string, std::string>>&
|
||||
authors, double gametime, const std::string& rerecords) throw(std::bad_alloc, std::runtime_error) = 0;
|
||||
|
||||
/**
|
||||
* Notify game information.
|
||||
*
|
||||
* parameter gamename: Name of the game.
|
||||
* parameter authors: Authors of the run.
|
||||
* parameter gametime: Game time.
|
||||
* parameter rercords: Rerecord count.
|
||||
* parameter win: Graphics system handle.
|
||||
* throws std::bad_alloc Not enough memory.
|
||||
*/
|
||||
static void gameinfo(const std::string& gamename, const std::list<std::pair<std::string, std::string>>&
|
||||
authors, double gametime, const std::string& rerecords, window* win) throw(std::bad_alloc);
|
||||
|
||||
/**
|
||||
* Send game info. This causes gameinfo method to be called on object this method is called on.
|
||||
*/
|
||||
void send_gameinfo() throw();
|
||||
|
||||
/**
|
||||
* Is there dump in progress?
|
||||
*
|
||||
* returns: True if dump is in progress, false if not.
|
||||
*/
|
||||
static bool dump_in_progress() throw();
|
||||
|
||||
/**
|
||||
* Notifier for dumps starting/ending.
|
||||
*/
|
||||
class dump_notification
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~dump_notification() throw();
|
||||
/**
|
||||
* New dump starting.
|
||||
*/
|
||||
virtual void dump_starting() throw();
|
||||
/**
|
||||
* Dump ending.
|
||||
*/
|
||||
virtual void dump_ending() throw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a notifier.
|
||||
*
|
||||
* parameter notifier: New notifier to add.
|
||||
*/
|
||||
static void add_dump_notifier(dump_notification& notifier) throw(std::bad_alloc);
|
||||
|
||||
/**
|
||||
* Remove a notifier.
|
||||
*
|
||||
* parameter notifier: Existing notifier to remove.
|
||||
*/
|
||||
static void remove_dump_notifier(dump_notification& notifier) throw();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -5,7 +5,6 @@
|
|||
#include <map>
|
||||
#include <set>
|
||||
#include "misc.hpp"
|
||||
#include "videodumper2.hpp"
|
||||
#include "memorymanip.hpp"
|
||||
#include "fieldsplit.hpp"
|
||||
#include "command.hpp"
|
||||
|
|
46
mainloop.cpp
46
mainloop.cpp
|
@ -1,4 +1,5 @@
|
|||
#include "mainloop.hpp"
|
||||
#include "avsnoop.hpp"
|
||||
#include "command.hpp"
|
||||
#include <iomanip>
|
||||
#include "framerate.hpp"
|
||||
|
@ -20,7 +21,6 @@
|
|||
#include "memorymanip.hpp"
|
||||
#include "keymapper.hpp"
|
||||
#include "render.hpp"
|
||||
#include "videodumper2.hpp"
|
||||
#include <iostream>
|
||||
#include "lsnes.hpp"
|
||||
#include <sys/time.h>
|
||||
|
@ -710,6 +710,18 @@ namespace
|
|||
queued_saves.insert(filename);
|
||||
win->message("Pending save on '" + filename + "'");
|
||||
}
|
||||
|
||||
class dump_watch : public av_snooper::dump_notification
|
||||
{
|
||||
void dump_starting() throw()
|
||||
{
|
||||
update_movie_state();
|
||||
}
|
||||
void dump_ending() throw()
|
||||
{
|
||||
update_movie_state();
|
||||
}
|
||||
} dumpwatch;
|
||||
}
|
||||
|
||||
std::vector<char>& get_host_memory()
|
||||
|
@ -745,7 +757,7 @@ void update_movie_state()
|
|||
x << "PLAY ";
|
||||
else
|
||||
x << "REC ";
|
||||
if(dump_in_progress())
|
||||
if(av_snooper::dump_in_progress())
|
||||
x << "CAP ";
|
||||
_status["Flags"] = x.str();
|
||||
}
|
||||
|
@ -833,19 +845,15 @@ class my_interface : public SNES::Interface
|
|||
location_special = SPECIAL_FRAME_VIDEO;
|
||||
update_movie_state();
|
||||
redraw_framebuffer();
|
||||
|
||||
struct lua_render_context lrc;
|
||||
render_queue rq;
|
||||
lrc.left_gap = 0;
|
||||
lrc.right_gap = 0;
|
||||
lrc.bottom_gap = 0;
|
||||
lrc.top_gap = 0;
|
||||
lrc.queue = &rq;
|
||||
lrc.width = framebuffer.width;
|
||||
lrc.height = framebuffer.height;
|
||||
video_fill_shifts(lrc.rshift, lrc.gshift, lrc.bshift);
|
||||
lua_callback_do_video(&lrc, win);
|
||||
dump_frame(framebuffer, &rq, lrc.left_gap, lrc.right_gap, lrc.top_gap, lrc.bottom_gap, region, win);
|
||||
uint32_t fps_n, fps_d;
|
||||
if(region) {
|
||||
fps_n = 322445;
|
||||
fps_d = 6448;
|
||||
} else {
|
||||
fps_n = 10738636;
|
||||
fps_d = 178683;
|
||||
}
|
||||
av_snooper::frame(ls, fps_n, fps_d, win);
|
||||
}
|
||||
|
||||
void audio_sample(int16_t l_sample, int16_t r_sample)
|
||||
|
@ -853,14 +861,14 @@ class my_interface : public SNES::Interface
|
|||
uint16_t _l = l_sample;
|
||||
uint16_t _r = r_sample;
|
||||
win->play_audio_sample(_l + 32768, _r + 32768);
|
||||
dump_audio_sample(_l, _r, win);
|
||||
av_snooper::sample(_l, _r, win);
|
||||
}
|
||||
|
||||
void audio_sample(uint16_t l_sample, uint16_t r_sample)
|
||||
{
|
||||
//Yes, this interface is broken. The samples are signed but are passed as unsigned!
|
||||
win->play_audio_sample(l_sample + 32768, r_sample + 32768);
|
||||
dump_audio_sample(l_sample, r_sample, win);
|
||||
av_snooper::sample(l_sample, r_sample, win);
|
||||
}
|
||||
|
||||
int16_t input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id)
|
||||
|
@ -1639,7 +1647,7 @@ void main_loop(window* _win, struct loaded_rom& rom, struct moviefile& initial)
|
|||
lua_callback_startup(win);
|
||||
|
||||
//print_controller_mappings();
|
||||
|
||||
av_snooper::add_dump_notifier(dumpwatch);
|
||||
win->set_main_surface(scr);
|
||||
redraw_framebuffer();
|
||||
win->paused(false);
|
||||
|
@ -1689,6 +1697,6 @@ void main_loop(window* _win, struct loaded_rom& rom, struct moviefile& initial)
|
|||
win->wait_msec(to_wait_frame(get_ticks_msec()));
|
||||
first_round = false;
|
||||
}
|
||||
end_vid_dump();
|
||||
av_snooper::end(win);
|
||||
SNES::system.interface = old_inteface;
|
||||
}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
#ifndef _videodumper2__hpp__included__
|
||||
#define _videodumper2__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include "window.hpp"
|
||||
#include "videodumper.hpp"
|
||||
|
||||
/**
|
||||
* Forcibly ends dumping. Mainly useful for quitting.
|
||||
*
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Failed to end dump.
|
||||
*/
|
||||
void end_vid_dump() throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Dumps a frame. Does nothing if dumping is not in progress.
|
||||
*
|
||||
* parameter ls: Screen to dump.
|
||||
* parameter rq: Render queue to run.
|
||||
* parameter left: Left border.
|
||||
* parameter right: Right border.
|
||||
* parameter top: Top border.
|
||||
* parameter bottom: Bottom border.
|
||||
* parameter region: True if PAL, false if NTSC.
|
||||
* parameter win: Graphics system handle.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Failed to dump frame.
|
||||
*/
|
||||
void dump_frame(lcscreen& ls, render_queue* rq, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom,
|
||||
bool region, window* win) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Dumps one sample of audio. Does nothing if dumping is not in progress.
|
||||
*
|
||||
* parameter l_sample Left channel sample (-32768-32767)
|
||||
* parameter r_sample Right channel sample (-32768-32767)
|
||||
* parameter win Graphics System handle.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Failed to dump sample.
|
||||
*/
|
||||
void dump_audio_sample(int16_t l_sample, int16_t r_sample, window* win) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Is the dump in progress?
|
||||
*
|
||||
* returns: True if dump is in progress, false if not.
|
||||
*/
|
||||
bool dump_in_progress() throw();
|
||||
|
||||
/**
|
||||
* Fill rendering shifts.
|
||||
*
|
||||
* parameter r: Shift for red component is written here.
|
||||
* parameter g: Shift for green component is written here.
|
||||
* parameter b: Shift for blue component is written here.
|
||||
*/
|
||||
void video_fill_shifts(uint32_t& r, uint32_t& g, uint32_t& b);
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue