Fixes the bug that extra frames could be saved in the movie file, when rerecording from middle of the movie.
Also flushes the movie file more often.
This commit is contained in:
parent
b08267b84a
commit
693607f66b
167
src/movie.cpp
167
src/movie.cpp
|
@ -478,7 +478,7 @@ void MovieData::installValue(std::string& key, std::string& val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int MovieData::dump(EMUFILE *os, bool binary)
|
int MovieData::dump(EMUFILE *os, bool binary, bool seekToCurrFramePos)
|
||||||
{
|
{
|
||||||
int start = os->ftell();
|
int start = os->ftell();
|
||||||
os->fprintf("version %d\n", version);
|
os->fprintf("version %d\n", version);
|
||||||
|
@ -516,19 +516,30 @@ int MovieData::dump(EMUFILE *os, bool binary)
|
||||||
if (this->loadFrameCount >= 0)
|
if (this->loadFrameCount >= 0)
|
||||||
os->fprintf("length %d\n" , this->loadFrameCount);
|
os->fprintf("length %d\n" , this->loadFrameCount);
|
||||||
|
|
||||||
|
int currFramePos = -1;
|
||||||
if(binary)
|
if(binary)
|
||||||
{
|
{
|
||||||
//put one | to start the binary dump
|
//put one | to start the binary dump
|
||||||
os->fputc('|');
|
os->fputc('|');
|
||||||
for(int i=0;i<(int)records.size();i++)
|
for (int i = 0; i < (int)records.size(); i++)
|
||||||
|
{
|
||||||
|
if (seekToCurrFramePos && currFrameCounter == i)
|
||||||
|
currFramePos = os->ftell();
|
||||||
records[i].dumpBinary(this, os, i);
|
records[i].dumpBinary(this, os, i);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
for(int i=0;i<(int)records.size();i++)
|
for (int i = 0; i < (int)records.size(); i++)
|
||||||
|
{
|
||||||
|
if (seekToCurrFramePos && currFrameCounter == i)
|
||||||
|
currFramePos = os->ftell();
|
||||||
records[i].dump(this, os, i);
|
records[i].dump(this, os, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int end = os->ftell();
|
int end = os->ftell();
|
||||||
|
if (currFramePos >= 0)
|
||||||
|
os->fseek(currFramePos, SEEK_SET);
|
||||||
return end-start;
|
return end-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,53 +746,83 @@ bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop movie playback.
|
static EMUFILE *openRecordingMovie(const char* fname)
|
||||||
static void StopPlayback()
|
|
||||||
{
|
{
|
||||||
FCEU_DispMessageOnMovie("Movie playback stopped.");
|
if (osRecordingMovie)
|
||||||
movieMode = MOVIEMODE_INACTIVE;
|
delete osRecordingMovie;
|
||||||
}
|
|
||||||
|
|
||||||
// Stop movie playback without closing the movie.
|
osRecordingMovie = FCEUD_UTF8_fstream(fname, "wb");
|
||||||
static void FinishPlayback()
|
if (!osRecordingMovie || osRecordingMovie->fail()) {
|
||||||
{
|
FCEU_PrintError("Error opening movie output file: %s", fname);
|
||||||
extern int closeFinishedMovie;
|
return NULL;
|
||||||
if (closeFinishedMovie)
|
|
||||||
StopPlayback();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FCEU_DispMessage("Movie finished playing.",0);
|
|
||||||
movieMode = MOVIEMODE_FINISHED;
|
|
||||||
}
|
}
|
||||||
|
strcpy(curMovieFilename, fname);
|
||||||
|
|
||||||
|
return osRecordingMovie;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void closeRecordingMovie()
|
static void closeRecordingMovie()
|
||||||
{
|
{
|
||||||
if(osRecordingMovie)
|
if (osRecordingMovie)
|
||||||
{
|
{
|
||||||
delete osRecordingMovie;
|
delete osRecordingMovie;
|
||||||
osRecordingMovie = 0;
|
osRecordingMovie = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callers shall set the approriate movieMode before calling this
|
||||||
|
static void RedumpWholeMovieFile(bool justToggledRecording = false)
|
||||||
|
{
|
||||||
|
bool recording = (movieMode == MOVIEMODE_RECORD);
|
||||||
|
assert((NULL != osRecordingMovie) == (recording != justToggledRecording) && "osRecordingMovie should be consistent with movie mode!");
|
||||||
|
|
||||||
|
if (NULL == openRecordingMovie(curMovieFilename))
|
||||||
|
return;
|
||||||
|
|
||||||
|
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/, recording);
|
||||||
|
if (recording)
|
||||||
|
osRecordingMovie->fflush();
|
||||||
|
else
|
||||||
|
closeRecordingMovie();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stop movie playback.
|
||||||
|
static void StopPlayback()
|
||||||
|
{
|
||||||
|
assert(movieMode != MOVIEMODE_RECORD && NULL == osRecordingMovie);
|
||||||
|
|
||||||
|
movieMode = MOVIEMODE_INACTIVE;
|
||||||
|
FCEU_DispMessageOnMovie("Movie playback stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop movie playback without closing the movie.
|
||||||
|
static void FinishPlayback()
|
||||||
|
{
|
||||||
|
assert(movieMode != MOVIEMODE_RECORD);
|
||||||
|
|
||||||
|
extern int closeFinishedMovie;
|
||||||
|
if (closeFinishedMovie)
|
||||||
|
StopPlayback();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
movieMode = MOVIEMODE_FINISHED;
|
||||||
|
FCEU_DispMessage("Movie finished playing.",0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Stop movie recording
|
/// Stop movie recording
|
||||||
static void StopRecording()
|
static void StopRecording()
|
||||||
{
|
{
|
||||||
FCEU_DispMessage("Movie recording stopped.",0);
|
assert(movieMode == MOVIEMODE_RECORD);
|
||||||
movieMode = MOVIEMODE_INACTIVE;
|
|
||||||
|
|
||||||
closeRecordingMovie();
|
movieMode = MOVIEMODE_INACTIVE;
|
||||||
|
RedumpWholeMovieFile(true);
|
||||||
|
FCEU_DispMessage("Movie recording stopped.",0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_StopMovie()
|
static void OnMovieClosed()
|
||||||
{
|
{
|
||||||
if(suppressMovieStop)
|
assert(movieMode == MOVIEMODE_INACTIVE);
|
||||||
return;
|
|
||||||
|
|
||||||
if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED)
|
|
||||||
StopPlayback();
|
|
||||||
else if(movieMode == MOVIEMODE_RECORD)
|
|
||||||
StopRecording();
|
|
||||||
|
|
||||||
curMovieFilename[0] = 0; //No longer a current movie filename
|
curMovieFilename[0] = 0; //No longer a current movie filename
|
||||||
freshMovie = false; //No longer a fresh movie loaded
|
freshMovie = false; //No longer a fresh movie loaded
|
||||||
|
@ -794,6 +835,19 @@ void FCEUI_StopMovie()
|
||||||
|
|
||||||
bool bogorf;
|
bool bogorf;
|
||||||
|
|
||||||
|
void FCEUI_StopMovie()
|
||||||
|
{
|
||||||
|
if (suppressMovieStop)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED)
|
||||||
|
StopPlayback();
|
||||||
|
else if (movieMode == MOVIEMODE_RECORD)
|
||||||
|
StopRecording();
|
||||||
|
|
||||||
|
OnMovieClosed();
|
||||||
|
}
|
||||||
|
|
||||||
void poweron(bool shouldDisableBatteryLoading)
|
void poweron(bool shouldDisableBatteryLoading)
|
||||||
{
|
{
|
||||||
//// make a for-movie-recording power-on clear the game's save data, too
|
//// make a for-movie-recording power-on clear the game's save data, too
|
||||||
|
@ -1021,21 +1075,6 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openRecordingMovie(const char* fname)
|
|
||||||
{
|
|
||||||
osRecordingMovie = FCEUD_UTF8_fstream(fname, "wb");
|
|
||||||
if(!osRecordingMovie || osRecordingMovie->fail()) {
|
|
||||||
FCEU_PrintError("Error opening movie output file: %s",fname);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
strcpy(curMovieFilename, fname);
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
//Add to the recent movie menu
|
|
||||||
AddRecentMovieFile(fname);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//begin recording a new movie
|
//begin recording a new movie
|
||||||
//TODO - BUG - the record-from-another-savestate doesnt work.
|
//TODO - BUG - the record-from-another-savestate doesnt work.
|
||||||
|
@ -1048,11 +1087,14 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author)
|
||||||
|
|
||||||
FCEUI_StopMovie();
|
FCEUI_StopMovie();
|
||||||
|
|
||||||
openRecordingMovie(fname);
|
if (NULL == openRecordingMovie(fname))
|
||||||
|
|
||||||
if(!osRecordingMovie || osRecordingMovie->fail())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
//Add to the recent movie menu
|
||||||
|
AddRecentMovieFile(fname);
|
||||||
|
#endif
|
||||||
|
|
||||||
currFrameCounter = 0;
|
currFrameCounter = 0;
|
||||||
LagCounterReset();
|
LagCounterReset();
|
||||||
FCEUMOV_CreateCleanMovie();
|
FCEUMOV_CreateCleanMovie();
|
||||||
|
@ -1224,6 +1266,9 @@ void FCEUMOV_AddCommand(int cmd)
|
||||||
|
|
||||||
void FCEU_DrawMovies(uint8 *XBuf)
|
void FCEU_DrawMovies(uint8 *XBuf)
|
||||||
{
|
{
|
||||||
|
// not the best place, but just working
|
||||||
|
assert((NULL != osRecordingMovie) == (movieMode == MOVIEMODE_RECORD));
|
||||||
|
|
||||||
if(frame_display)
|
if(frame_display)
|
||||||
{
|
{
|
||||||
char counterbuf[32] = {0};
|
char counterbuf[32] = {0};
|
||||||
|
@ -1420,9 +1465,15 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
closeRecordingMovie();
|
|
||||||
if (movie_readonly)
|
if (movie_readonly)
|
||||||
{
|
{
|
||||||
|
if (movieMode == MOVIEMODE_RECORD)
|
||||||
|
{
|
||||||
|
movieMode = MOVIEMODE_PLAY;
|
||||||
|
RedumpWholeMovieFile(true);
|
||||||
|
closeRecordingMovie();
|
||||||
|
}
|
||||||
|
|
||||||
// currFrameCounter at this point represents the savestate framecount
|
// currFrameCounter at this point represents the savestate framecount
|
||||||
int frame_of_mismatch = CheckTimelines(tempMovieData, currMovieData);
|
int frame_of_mismatch = CheckTimelines(tempMovieData, currMovieData);
|
||||||
if (frame_of_mismatch >= 0)
|
if (frame_of_mismatch >= 0)
|
||||||
|
@ -1461,13 +1512,16 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
//Read+Write mode
|
//Read+Write mode
|
||||||
|
closeRecordingMovie();
|
||||||
|
|
||||||
if (currFrameCounter > (int)tempMovieData.records.size())
|
if (currFrameCounter > (int)tempMovieData.records.size())
|
||||||
{
|
{
|
||||||
//This is a post movie savestate, handle it differently
|
//This is a post movie savestate, handle it differently
|
||||||
//Replace movie contents but then switch to movie finished mode
|
//Replace movie contents but then switch to movie finished mode
|
||||||
currMovieData = tempMovieData;
|
currMovieData = tempMovieData;
|
||||||
openRecordingMovie(curMovieFilename);
|
movieMode = MOVIEMODE_PLAY;
|
||||||
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/);
|
FCEUMOV_IncrementRerecordCount();
|
||||||
|
RedumpWholeMovieFile();
|
||||||
FinishPlayback();
|
FinishPlayback();
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
|
@ -1477,11 +1531,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||||
tempMovieData.truncateAt(currFrameCounter);
|
tempMovieData.truncateAt(currFrameCounter);
|
||||||
|
|
||||||
currMovieData = tempMovieData;
|
currMovieData = tempMovieData;
|
||||||
FCEUMOV_IncrementRerecordCount();
|
|
||||||
openRecordingMovie(curMovieFilename);
|
|
||||||
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/);
|
|
||||||
movieMode = MOVIEMODE_RECORD;
|
movieMode = MOVIEMODE_RECORD;
|
||||||
|
FCEUMOV_IncrementRerecordCount();
|
||||||
|
RedumpWholeMovieFile(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1616,6 +1668,11 @@ void FCEUI_MoviePlayFromBeginning(void)
|
||||||
#endif
|
#endif
|
||||||
} else if (movieMode != MOVIEMODE_INACTIVE)
|
} else if (movieMode != MOVIEMODE_INACTIVE)
|
||||||
{
|
{
|
||||||
|
if (movieMode == MOVIEMODE_RECORD)
|
||||||
|
{
|
||||||
|
movieMode = MOVIEMODE_PLAY;
|
||||||
|
RedumpWholeMovieFile(true);
|
||||||
|
}
|
||||||
if (currMovieData.savestate.empty())
|
if (currMovieData.savestate.empty())
|
||||||
{
|
{
|
||||||
movie_readonly = true;
|
movie_readonly = true;
|
||||||
|
|
|
@ -234,7 +234,7 @@ public:
|
||||||
|
|
||||||
void truncateAt(int frame);
|
void truncateAt(int frame);
|
||||||
void installValue(std::string& key, std::string& val);
|
void installValue(std::string& key, std::string& val);
|
||||||
int dump(EMUFILE* os, bool binary);
|
int dump(EMUFILE* os, bool binary, bool seekToCurrFramePos = false);
|
||||||
|
|
||||||
void clearRecordRange(int start, int len);
|
void clearRecordRange(int start, int len);
|
||||||
void eraseRecords(int at, int frames = 1);
|
void eraseRecords(int at, int frames = 1);
|
||||||
|
|
Loading…
Reference in New Issue