GBA RR: Add way to play movies from startup
@@ -17,6 +17,8 @@ enum {
INVALID_INPUT = 0x8000 }; +static void GBAMGMContextDestroy(struct GBARRContext*); + static bool GBAMGMStartPlaying(struct GBARRContext*, bool autorecord); static void GBAMGMStopPlaying(struct GBARRContext*); static bool GBAMGMStartRecording(struct GBARRContext*);@@ -56,6 +58,8 @@
void GBAMGMContextCreate(struct GBAMGMContext* mgm) { memset(mgm, 0, sizeof(*mgm)); + mgm->d.destroy = GBAMGMContextDestroy; + mgm->d.startPlaying = GBAMGMStartPlaying; mgm->d.stopPlaying = GBAMGMStopPlaying; mgm->d.startRecording = GBAMGMStartRecording;@@ -75,19 +79,10 @@ mgm->d.openSavedata = GBAMGMOpenSavedata;
mgm->d.openSavestate = GBAMGMOpenSavestate; } -void GBAMGMContextDestroy(struct GBAMGMContext* mgm) { - if (mgm->d.isPlaying(&mgm->d)) { - mgm->d.stopPlaying(&mgm->d); - } - if (mgm->d.isRecording(&mgm->d)) { - mgm->d.stopRecording(&mgm->d); - } +void GBAMGMContextDestroy(struct GBARRContext* rr) { + struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; if (mgm->metadataFile) { mgm->metadataFile->close(mgm->metadataFile); - } - if (mgm->d.savedata) { - mgm->d.savedata->close(mgm->d.savedata); - mgm->d.savedata = 0; } }
@@ -75,7 +75,6 @@ uint32_t previously;
}; void GBAMGMContextCreate(struct GBAMGMContext*); -void GBAMGMContextDestroy(struct GBAMGMContext*); bool GBAMGMSetStream(struct GBAMGMContext* mgm, struct VDir* stream); bool GBAMGMCreateStream(struct GBAMGMContext* mgm, enum GBARRInitFrom initFrom);
@@ -7,7 +7,7 @@ #include "rr.h"
#include "util/vfs.h" -void GBARRSaveState(struct GBA* gba) { +void GBARRInitRecord(struct GBA* gba) { if (!gba || !gba->rr) { return; }@@ -34,7 +34,7 @@ ARMReset(gba->cpu);
} } -void GBARRLoadState(struct GBA* gba) { +void GBARRInitPlay(struct GBA* gba) { if (!gba || !gba->rr) { return; }@@ -57,3 +57,17 @@ } else {
ARMReset(gba->cpu); } } + +void GBARRDestroy(struct GBARRContext* rr) { + if (rr->isPlaying(rr)) { + rr->stopPlaying(rr); + } + if (rr->isRecording(rr)) { + rr->stopRecording(rr); + } + if (rr->savedata) { + rr->savedata->close(rr->savedata); + rr->savedata = 0; + } + rr->destroy(rr); +}
@@ -20,6 +20,8 @@ INIT_FROM_BOTH = 3,
}; struct GBARRContext { + void (*destroy)(struct GBARRContext*); + bool (*startPlaying)(struct GBARRContext*, bool autorecord); void (*stopPlaying)(struct GBARRContext*); bool (*startRecording)(struct GBARRContext*);@@ -46,5 +48,10 @@ uint32_t rrCount;
struct VFile* savedata; }; + +void GBARRDestroy(struct GBARRContext*); + +void GBARRInitRecord(struct GBA*); +void GBARRInitPlay(struct GBA*); #endif
@@ -10,6 +10,7 @@ #include "gba/gba.h"
#include "gba/cheats.h" #include "gba/serialize.h" #include "gba/supervisor/config.h" +#include "gba/rr/mgm.h" #include "debugger/debugger.h"@@ -117,6 +118,7 @@ struct Patch patch;
struct GBACheatDevice cheatDevice; struct GBAThread* threadContext = context; struct ARMComponent* components[GBA_COMPONENT_MAX] = {}; + struct GBARRContext* movie = 0; int numComponents = GBA_COMPONENT_MAX; #if !defined(_WIN32) && defined(USE_PTHREADS)@@ -170,7 +172,32 @@ GBAApplyPatch(&gba, &patch);
} } + if (threadContext->movie) { + struct VDir* movieDir = VDirOpen(threadContext->movie); +#ifdef ENABLE_LIBZIP + if (!movieDir) { + movieDir = VDirOpenZip(threadContext->movie, 0); + } +#endif + if (movieDir) { + struct GBAMGMContext* mgm = malloc(sizeof(*mgm)); + GBAMGMContextCreate(mgm); + if (!GBAMGMSetStream(mgm, movieDir)) { + mgm->d.destroy(&mgm->d); + } else { + movie = &mgm->d; + } + } + } + ARMReset(&cpu); + + if (movie) { + gba.rr = movie; + movie->startPlaying(movie, false); + GBARRInitPlay(&gba); + } + if (threadContext->skipBios) { GBASkipBIOS(&cpu); }@@ -256,6 +283,11 @@ if (&cheatDevice == threadContext->cheats) {
GBACheatDeviceDestroy(&cheatDevice); } + if (movie) { + movie->destroy(movie); + free(movie); + } + threadContext->sync.videoFrameOn = false; ConditionWake(&threadContext->sync.videoFrameAvailableCond); ConditionWake(&threadContext->sync.audioRequiredCond);@@ -309,6 +341,7 @@ }
threadContext->fname = args->fname; threadContext->patch = VFileOpen(args->patch, O_RDONLY); threadContext->cheatsFile = VFileOpen(args->cheatsFile, O_RDONLY); + threadContext->movie = args->movie; } bool GBAThreadStart(struct GBAThread* threadContext) {
@@ -72,6 +72,7 @@ struct VFile* bios;
struct VFile* patch; struct VFile* cheatsFile; const char* fname; + const char* movie; int activeKeys; struct GBAAVStream* stream; struct Configuration* overrides;
@@ -34,8 +34,8 @@ " -f Start full-screen"
static const struct option _options[] = { { "bios", required_argument, 0, 'b' }, - { "cheats", required_argument, 0, 'c' }, - { "dirmode", required_argument, 0, 'D' }, + { "cheats", required_argument, 0, 'c' }, + { "dirmode", required_argument, 0, 'D' }, { "frameskip", required_argument, 0, 's' }, #ifdef USE_CLI_DEBUGGER { "debug", no_argument, 0, 'd' },@@ -43,6 +43,7 @@ #endif
#ifdef USE_GDB_STUB { "gdb", no_argument, 0, 'g' }, #endif + { "movie", required_argument, 0, 'v' }, { "patch", required_argument, 0, 'p' }, { 0, 0, 0, 0 } };@@ -52,7 +53,7 @@
bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) { int ch; char options[64] = - "b:c:Dl:p:s:" + "b:c:Dl:p:s:v:" #ifdef USE_CLI_DEBUGGER "d" #endif@@ -101,6 +102,9 @@ break;
case 's': GBAConfigSetDefaultValue(config, "frameskip", optarg); break; + case 'v': + opts->movie = strdup(optarg); + break; default: if (subparser) { if (!subparser->parse(subparser, config, ch, optarg)) {@@ -125,6 +129,9 @@ opts->fname = 0;
free(opts->patch); opts->patch = 0; + + free(opts->movie); + opts->movie = 0; } void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) {@@ -211,6 +218,7 @@ #endif
#ifdef USE_GDB_STUB puts(" -g, --gdb Start GDB session (default port 2345)"); #endif + puts(" -v, --movie FILE Play back a movie of recorded input"); puts(" -p, --patch FILE Apply a specified patch file when running"); puts(" -s, --frameskip N Skip every N frames"); if (extraOptions) {
@@ -26,6 +26,7 @@ char* fname;
char* patch; char* cheatsFile; bool dirmode; + char* movie; enum DebuggerType debuggerType; bool debugAtStart;