Unattended dumping support

This commit is contained in:
Ilari Liusvaara 2011-09-20 22:05:49 +03:00
parent 83e2d655ed
commit 66fcf13980
10 changed files with 389 additions and 28 deletions

View file

@ -3,12 +3,15 @@ CC := g++-4.5
HOSTCC = $(CC)
OBJECTS = $(patsubst %.cpp,%.o,$(wildcard generic/*.cpp)) $(patsubst %.cpp,%.o,$(wildcard avidump/*.cpp)) fonts/font.o
GENERIC_LIBS = -ldl -lboost_iostreams -lboost_filesystem -lboost_system -lz
PROGRAMS = lsnes.exe movieinfo.exe
CFLAGS = $(USER_CFLAGS)
HOSTCCFLAGS = $(USER_HOSTCCFLAGS)
LDFLAGS = $(GENERIC_LIBS) $(USER_LDFLAGS)
PLATFORM = SDL
PLATFORM_CFLAGS = $(CFLAGS)
PLATFORM_LDFLAGS = $(LDFLAGS)
PROGRAMS = lsnes.exe movieinfo.exe lsnes-dumpavi.exe
#Lua.
ifdef NO_LUA
@ -19,26 +22,47 @@ CFLAGS += $(shell pkg-config lua5.1 --cflags)
LDFLAGS += $(shell pkg-config lua5.1 --libs)
endif
#Platform stuff (SDL).
OBJECTS += $(patsubst %.cpp,%.o,$(wildcard SDL/*.cpp))
CFLAGS += $(shell sdl-config --cflags)
LDFLAGS += $(shell sdl-config --libs)
#Some misc defines.
ifdef NO_THREADS
CFLAGS += -DNO_THREADS
endif
ifdef USE_THREADS
CFLAGS += -DUSE_THREADS
endif
ifdef TEST_WIN32
CFLAGS += -DTEST_WIN32_CODE
endif
ifdef BSNES_IS_COMPAT
CFLAGS += -DBSNES_IS_COMPAT
endif
all: $(PROGRAMS)
.PRECIOUS: %.exe %.o
%.exe: %.o $(OBJECTS)
#Platform stuff.
ifeq ($(PLATFORM), SDL)
LSNES_MAIN = lsnes.o
PLATFORM_OBJECTS += $(patsubst %.cpp,%.o,$(wildcard SDL/*.cpp))
PLATFORM_CFLAGS += $(shell sdl-config --cflags)
PLATFORM_LDFLAGS += $(shell sdl-config --libs)
ifdef TEST_WIN32
PLATFORM_LDFLAGS += -lSDLmain
endif
SDL/%.o: SDL/%.cpp
$(CC) -I. -Igeneric -g -std=c++0x -I$(BSNES_PATH) -c -o $@ $< $(CFLAGS) $(PLATFORM_CFLAGS)
lsnes.o: lsnes.cpp
$(CC) -I. -Igeneric -g -std=c++0x -I$(BSNES_PATH) -c -o $@ $< $(CFLAGS) $(PLATFORM_CFLAGS)
lsnes.exe: lsnes.o $(OBJECTS) $(PLATFORM_OBJECTS)
$(CC) -o $@ $^ $(BSNES_PATH)/out/libsnes.a $(LDFLAGS) $(PLATFORM_LDFLAGS)
else
lsnes.o:
echo "Unsupported platform" $(PLATFORM)
false
endif
%.exe: %.o $(OBJECTS) dummy/window-dummy.o
$(CC) -o $@ $^ $(BSNES_PATH)/out/libsnes.a $(LDFLAGS)
%.o: %.cpp

View file

@ -8,8 +8,16 @@
#include <list>
#include <stdexcept>
#ifdef USE_THREADS
#define REALLY_USE_THREADS 1
#endif
#ifndef NO_THREADS
#ifdef __linux__
#define REALLY_USE_THREADS 1
#endif
#endif
#ifdef REALLY_USE_THREADS
#include <thread>
#include <condition_variable>
#include <mutex>

51
dummy/window-dummy.cpp Normal file
View file

@ -0,0 +1,51 @@
#include "window.hpp"
#include <cstdlib>
#include <iostream>
namespace
{
std::map<std::string, std::string> status;
}
void window::init() {}
void window::quit() {}
void window::poll_inputs() throw(std::bad_alloc) {}
void window::notify_screen_update(bool full) throw() {}
void window::set_main_surface(screen& scr) throw() {}
void window::paused(bool enable) throw() {}
void window::wait_msec(uint64_t msec) throw(std::bad_alloc) {}
void window::cancel_wait() throw() {}
void window::sound_enable(bool enable) throw() {}
void window::play_audio_sample(uint16_t left, uint16_t right) throw() {}
void window::set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl) {}
bool window::modal_message(const std::string& msg, bool confirm) throw(std::bad_alloc)
{
std::cerr << "Modal message: " << msg << std::endl;
return confirm;
}
void window::fatal_error() throw()
{
std::cerr << "Exiting on fatal error." << std::endl;
exit(1);
}
void window::message(const std::string& msg) throw(std::bad_alloc)
{
if(msg[msg.length() - 1] == '\n')
std::cout << msg;
else
std::cout << msg << std::endl;
}
std::map<std::string, std::string>& window::get_emustatus() throw()
{
return status;
}
uint64_t get_ticks_msec() throw()
{
static uint64_t c = 0;
return c++;
}

View file

@ -976,7 +976,7 @@ namespace
}
}
void main_loop(struct loaded_rom& rom, struct moviefile& initial) throw(std::bad_alloc,
void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_to_succeed) throw(std::bad_alloc,
std::runtime_error)
{
//Basic initialization.
@ -1001,6 +1001,10 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial) throw(std::bad
OOM_panic();
} catch(std::exception& e) {
messages << "ERROR: Can't load initial state: " << e.what() << std::endl;
if(load_has_to_succeed) {
messages << "FATAL: Can't load movie" << std::endl;
window::fatal_error();
}
system_corrupt = true;
update_movie_state();
framebuffer = screen_corrupt;

View file

@ -8,7 +8,7 @@
/**
* \brief Emulator main loop.
*/
void main_loop(struct loaded_rom& rom, struct moviefile& settings) throw(std::bad_alloc,
std::runtime_error);
void main_loop(struct loaded_rom& rom, struct moviefile& settings, bool load_has_to_succeed = false)
throw(std::bad_alloc, std::runtime_error);
#endif

View file

@ -1,7 +1,6 @@
#ifndef _window__hpp__included__
#define _window__hpp__included__
#include "SDL.h"
#include "render.hpp"
#include <string>
#include <map>

View file

@ -439,7 +439,7 @@ void zip_writer::commit() throw(std::bad_alloc, std::logic_error, std::runtime_e
throw std::runtime_error("Failed to write central directory end marker to output file");
zipstream.close();
std::string backup = zipfile_path + ".backup";
#if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
//Grumble, Windows seemingly can't do this atomically.
remove(backup.c_str());
#endif
@ -513,7 +513,7 @@ void zip_writer::close_file() throw(std::bad_alloc, std::logic_error, std::runti
namespace
{
#if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
const char* path_splitters = "\\/";
bool drives_allowed = true;
#else

213
lsnes-dumpavi.cpp Normal file
View file

@ -0,0 +1,213 @@
#include <sstream>
#include "mainloop.hpp"
#include "command.hpp"
#include "lua.hpp"
#include "moviedata.hpp"
#include "rrdata.hpp"
#include "lsnes.hpp"
#include "rom.hpp"
#include "keymapper.hpp"
#include "misc.hpp"
#include "window.hpp"
#include <sys/time.h>
#include <snes/snes.hpp>
#include <ui-libsnes/libsnes.hpp>
#include "framerate.hpp"
#include "avsnoop.hpp"
namespace
{
class myavsnoop : public av_snooper
{
public:
myavsnoop(uint64_t frames_to_dump)
{
frames_dumped = 0;
total = frames_to_dump;
}
~myavsnoop()
{
}
void frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc,
std::runtime_error)
{
frames_dumped++;
if(frames_dumped % 100 == 0) {
std::cout << "Dumping frame " << frames_dumped << "/" << total << " ("
<< (100 * frames_dumped / total) << "%)" << std::endl;
}
if(frames_dumped == total) {
//Rough way to end it.
av_snooper::end(true);
exit(1);
}
}
void sample(short l, short r) throw(std::bad_alloc, std::runtime_error)
{
}
void end() throw(std::bad_alloc, std::runtime_error)
{
std::cout << "Finished!" << std::endl;
}
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)
{
}
private:
uint64_t frames_dumped;
uint64_t total;
};
void dumper_startup(const std::vector<std::string>& cmdline)
{
unsigned level = 7;
std::string prefix = "avidump";
uint64_t length = 0;
for(auto i = cmdline.begin(); i != cmdline.end(); i++) {
std::string a = *i;
if(a.length() > 9 && a.substr(0, 9) == "--prefix=")
prefix = a.substr(9);
if(a.length() > 8 && a.substr(0, 8) == "--level=")
try {
level = boost::lexical_cast<unsigned>(a.substr(8));
if(level < 0 || level > 18)
throw std::runtime_error("Level out of range (0-18)");
} catch(std::exception& e) {
std::cerr << "Bad --level: " << e.what() << std::endl;
exit(1);
}
if(a.length() > 9 && a.substr(0, 9) == "--length=")
try {
length = boost::lexical_cast<uint64_t>(a.substr(9));
if(!length)
throw std::runtime_error("Length out of range (1-)");
} catch(std::exception& e) {
std::cerr << "Bad --length: " << e.what() << std::endl;
exit(1);
}
}
if(!length) {
std::cerr << "--length=<frames> has to be specified" << std::endl;
exit(1);
}
std::cout << "Invoking dumper" << std::endl;
std::ostringstream cmd;
cmd << "dump-avi " << level << " " << prefix;
command::invokeC(cmd.str());
if(av_snooper::dump_in_progress()) {
std::cout << "Dumper attach confirmed" << std::endl;
} else {
std::cout << "Can't start dumper!" << std::endl;
exit(1);
}
myavsnoop* s = new myavsnoop(length);
}
void startup_lua_scripts(const std::vector<std::string>& cmdline)
{
for(auto i = cmdline.begin(); i != cmdline.end(); i++) {
std::string a = *i;
if(a.length() > 6 && a.substr(0, 6) == "--lua=") {
command::invokeC("run-lua " + a.substr(6));
}
}
}
}
class my_interfaced : public SNES::Interface
{
string path(SNES::Cartridge::Slot slot, const string &hint)
{
return "./";
}
};
int main(int argc, char** argv)
{
std::vector<std::string> cmdline;
for(int i = 1; i < argc; i++)
cmdline.push_back(argv[i]);
my_interfaced intrf;
SNES::system.interface = &intrf;
set_random_seed();
{
std::ostringstream x;
x << snes_library_id() << " (" << SNES::Info::Profile << " core)";
bsnes_core_version = x.str();
}
init_lua();
messages << "BSNES version: " << bsnes_core_version << std::endl;
messages << "lsnes version: lsnes rr" << lsnes_version << std::endl;
messages << "Command line is: ";
for(auto k = cmdline.begin(); k != cmdline.end(); k++)
messages << "\"" << *k << "\" ";
messages << std::endl;
std::string cfgpath = get_config_path();
messages << "--- Loading ROM ---" << std::endl;
struct loaded_rom r;
try {
r = load_rom_from_commandline(cmdline);
r.load();
} catch(std::bad_alloc& e) {
OOM_panic();
} catch(std::exception& e) {
messages << "FATAL: Can't load ROM: " << e.what() << std::endl;
fatal_error();
exit(1);
}
messages << "Detected region: " << gtype::tostring(r.rtype, r.region) << std::endl;
if(r.region == REGION_PAL)
set_nominal_framerate(322445.0/6448.0);
else if(r.region == REGION_NTSC)
set_nominal_framerate(10738636.0/178683.0);
messages << "--- Internal memory mappings ---" << std::endl;
dump_region_map();
messages << "--- End of Startup --- " << std::endl;
dumper_startup(cmdline);
startup_lua_scripts(cmdline);
moviefile movie;
try {
bool tried = false;
bool loaded = false;
for(auto i = cmdline.begin(); i != cmdline.end(); i++)
if(i->length() > 0 && (*i)[0] != '-') {
try {
tried = true;
movie = moviefile(*i);
loaded = true;
} catch(std::bad_alloc& e) {
OOM_panic();
} catch(std::exception& e) {
messages << "Error loading '" << *i << "': " << e.what() << std::endl;
}
}
if(!tried)
throw std::runtime_error("Specifying movie is required");
if(!loaded)
throw std::runtime_error("Can't load any of the movies specified");
main_loop(r, movie, true);
} catch(std::bad_alloc& e) {
OOM_panic();
} catch(std::exception& e) {
messages << "FATAL: " << e.what() << std::endl;
fatal_error();
return 1;
}
rrdata::close();
return 0;
}

View file

@ -1,4 +1,3 @@
#ifndef PLATFORM_STARTUP
#include <sstream>
#include "mainloop.hpp"
#include "command.hpp"
@ -14,7 +13,7 @@
#include <snes/snes.hpp>
#include <ui-libsnes/libsnes.hpp>
#include "framerate.hpp"
#if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
#include "SDL_main.h"
#endif
@ -74,11 +73,7 @@ namespace
}
}
#if defined(_WIN32) || defined(_WIN64)
int SDL_main(int argc, char** argv)
#else
int main(int argc, char** argv)
#endif
{
std::vector<std::string> cmdline;
for(int i = 1; i < argc; i++)
@ -164,4 +159,3 @@ int main(int argc, char** argv)
window::quit();
return 0;
}
#endif

View file

@ -158,7 +158,7 @@ Force ROM to be considered NTSC-only (default for everything except SNES
\end_layout
\begin_layout Subsection
New session options
New session options (not for lsnes-avidump.exe)
\end_layout
\begin_layout Standard
@ -227,6 +227,70 @@ If filename is specified on command line, it is loaded as initial state
(instead of constructing one).
\end_layout
\begin_layout Standard
Mandatory for lsnes-avidump.exe
\end_layout
\begin_layout Subsection
lsnes-avidump.exe options
\end_layout
\begin_layout Subsubsection
--prefix=<prefix>
\end_layout
\begin_layout Standard
Set dump prefix.
Default is
\begin_inset Quotes eld
\end_inset
avidump
\begin_inset Quotes erd
\end_inset
.
\end_layout
\begin_layout Subsubsection
--level=<level>
\end_layout
\begin_layout Standard
Set compression level (0-18).
Default is 7.
\end_layout
\begin_layout Subsubsection
--length=<length>
\end_layout
\begin_layout Standard
Set number of frames to dump.
Mandatory.
\end_layout
\begin_layout Subsubsection
--lua=<script>
\end_layout
\begin_layout Standard
Run specified lua script.
\end_layout
\begin_layout Section
Movieinfo.exe
\end_layout
\begin_layout Itemize
Syntax: Movieinfo.exe <file>
\end_layout
\begin_layout Standard
Opens <file> and parses it as a movie, giving all sorts of information about
it.
\end_layout
\begin_layout Section
Startup file lsnes.rc
\end_layout
@ -2968,7 +3032,11 @@ Fix rerecord counting
\end_layout
\begin_layout Itemize
Add movieinfo program
\end_layout
\begin_layout Itemize
Fix loading movies starting from SRAM.
\end_layout
\end_body