Updates to rerecording behaviour:
* Frame counter is restored properly post-load. * "Read-only mode" menu option added. Currently this either causes the movie file to be closed at the end of playback (if enabled) or continues recording past end of playback (if disabled). * Can now properly resume recording from a state saved during movie playback. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7142 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
6912f0a18c
commit
0d110c41d9
|
@ -26,12 +26,19 @@
|
|||
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
|
||||
#include "VideoBackendBase.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <io.h> //_chsize_s
|
||||
#else
|
||||
#include <unistd.h> //truncate
|
||||
#endif
|
||||
|
||||
Common::CriticalSection cs_frameSkip;
|
||||
|
||||
namespace Frame {
|
||||
|
||||
bool g_bFrameStep = false;
|
||||
bool g_bFrameStop = false;
|
||||
bool g_bReadOnly = true;
|
||||
u32 g_rerecords = 0;
|
||||
PlayMode g_playMode = MODE_NONE;
|
||||
|
||||
|
@ -39,6 +46,7 @@ unsigned int g_framesToSkip = 0, g_frameSkipCounter = 0;
|
|||
|
||||
int g_numPads = 0;
|
||||
ControllerState g_padState;
|
||||
char g_playingFile[256] = "\0";
|
||||
FILE *g_recordfd = NULL;
|
||||
|
||||
u64 g_frameCounter = 0, g_lagCounter = 0;
|
||||
|
@ -103,6 +111,11 @@ void SetFrameStopping(bool bEnabled)
|
|||
g_bFrameStop = bEnabled;
|
||||
}
|
||||
|
||||
void SetReadOnly(bool bEnabled)
|
||||
{
|
||||
g_bReadOnly = bEnabled;
|
||||
}
|
||||
|
||||
void FrameSkipping()
|
||||
{
|
||||
// Frameskipping will desync movie playback
|
||||
|
@ -242,7 +255,10 @@ bool PlayInput(const char *filename)
|
|||
|
||||
DTMHeader header;
|
||||
|
||||
g_recordfd = fopen(filename, "rb");
|
||||
File::Delete(g_recordFile.c_str());
|
||||
File::Copy(filename, g_recordFile.c_str());
|
||||
|
||||
g_recordfd = fopen(g_recordFile.c_str(), "r+b");
|
||||
if(!g_recordfd)
|
||||
return false;
|
||||
|
||||
|
@ -278,6 +294,8 @@ bool PlayInput(const char *filename)
|
|||
|
||||
g_playMode = MODE_PLAYING;
|
||||
|
||||
strncpy(g_playingFile, filename, 256);
|
||||
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
|
@ -297,6 +315,7 @@ void LoadInput(const char *filename)
|
|||
|
||||
if(header.filetype[0] != 'D' || header.filetype[1] != 'T' || header.filetype[2] != 'M' || header.filetype[3] != 0x1A) {
|
||||
PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", filename);
|
||||
strncpy(g_playingFile, "\0", 256);
|
||||
EndPlayInput();
|
||||
return;
|
||||
}
|
||||
|
@ -304,6 +323,8 @@ void LoadInput(const char *filename)
|
|||
if (g_rerecords == 0)
|
||||
g_rerecords = header.numRerecords;
|
||||
|
||||
g_frameCounter = header.frameCount;
|
||||
|
||||
g_numPads = header.numControllers;
|
||||
|
||||
ChangePads(true);
|
||||
|
@ -381,9 +402,7 @@ void PlayController(SPADStatus *PadStatus, int controllerID)
|
|||
if(feof(g_recordfd))
|
||||
{
|
||||
Core::DisplayMessage("Movie End", 2000);
|
||||
// TODO: read-only mode
|
||||
//EndPlayInput();
|
||||
g_playMode = MODE_RECORDING;
|
||||
EndPlayInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,54 +420,88 @@ void PlayWiimote(u8 *data, s8 &size)
|
|||
if(feof(g_recordfd))
|
||||
{
|
||||
Core::DisplayMessage("Movie End", 2000);
|
||||
// TODO: read-only mode
|
||||
//EndPlayInput();
|
||||
g_playMode = MODE_RECORDING;
|
||||
EndPlayInput();
|
||||
}
|
||||
}
|
||||
|
||||
void EndPlayInput() {
|
||||
if (g_recordfd)
|
||||
fclose(g_recordfd);
|
||||
g_recordfd = NULL;
|
||||
g_numPads = g_rerecords = 0;
|
||||
g_frameCounter = g_lagCounter = 0;
|
||||
g_playMode = MODE_NONE;
|
||||
|
||||
if (!g_bReadOnly && strncmp(g_playingFile, "\0", 1))
|
||||
{
|
||||
File::Delete(g_recordFile.c_str());
|
||||
File::Copy(g_playingFile, g_recordFile.c_str());
|
||||
g_recordfd = fopen(g_recordFile.c_str(), "r+b");
|
||||
fseeko(g_recordfd, 0, SEEK_END);
|
||||
g_playMode = MODE_RECORDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_recordfd = NULL;
|
||||
g_numPads = g_rerecords = 0;
|
||||
g_frameCounter = g_lagCounter = 0;
|
||||
g_playMode = MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void SaveRecording(const char *filename)
|
||||
{
|
||||
rewind(g_recordfd);
|
||||
off_t size = ftello(g_recordfd);
|
||||
|
||||
// Create the real header now and write it
|
||||
DTMHeader header;
|
||||
memset(&header, 0, sizeof(DTMHeader));
|
||||
// NOTE: Eventually this will not happen in
|
||||
// read-only mode, but we need a way for the save state to
|
||||
// store the current point in the file first.
|
||||
// if (!g_bReadOnly)
|
||||
{
|
||||
rewind(g_recordfd);
|
||||
|
||||
header.filetype[0] = 'D'; header.filetype[1] = 'T'; header.filetype[2] = 'M'; header.filetype[3] = 0x1A;
|
||||
strncpy((char *)header.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6);
|
||||
header.bWii = Core::g_CoreStartupParameter.bWii;
|
||||
header.numControllers = g_numPads & (Core::g_CoreStartupParameter.bWii ? 0xFF : 0x0F);
|
||||
// Create the real header now and write it
|
||||
DTMHeader header;
|
||||
memset(&header, 0, sizeof(DTMHeader));
|
||||
|
||||
header.bFromSaveState = false; // TODO: add the case where it's true
|
||||
header.frameCount = g_frameCounter;
|
||||
header.lagCount = g_lagCounter;
|
||||
header.numRerecords = g_rerecords;
|
||||
header.filetype[0] = 'D'; header.filetype[1] = 'T'; header.filetype[2] = 'M'; header.filetype[3] = 0x1A;
|
||||
strncpy((char *)header.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6);
|
||||
header.bWii = Core::g_CoreStartupParameter.bWii;
|
||||
header.numControllers = g_numPads & (Core::g_CoreStartupParameter.bWii ? 0xFF : 0x0F);
|
||||
|
||||
// TODO
|
||||
header.uniqueID = 0;
|
||||
// header.author;
|
||||
// header.videoPlugin;
|
||||
// header.audioPlugin;
|
||||
header.bFromSaveState = false; // TODO: add the case where it's true
|
||||
header.frameCount = g_frameCounter;
|
||||
header.lagCount = g_lagCounter;
|
||||
header.numRerecords = g_rerecords;
|
||||
|
||||
fwrite(&header, sizeof(DTMHeader), 1, g_recordfd);
|
||||
// TODO
|
||||
header.uniqueID = 0;
|
||||
// header.author;
|
||||
// header.videoPlugin;
|
||||
// header.audioPlugin;
|
||||
|
||||
fwrite(&header, sizeof(DTMHeader), 1, g_recordfd);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
fclose(g_recordfd);
|
||||
File::Delete(filename);
|
||||
success = File::Copy(g_recordFile.c_str(), filename);
|
||||
|
||||
if (File::Copy(g_recordFile.c_str(), filename))
|
||||
if (success /* && !g_bReadOnly*/)
|
||||
{
|
||||
success =
|
||||
#ifdef WIN32
|
||||
(g_recordfd = fopen(filename, "r+b")) &&
|
||||
!(_chsize_s(g_recordfd, size) == 0) &&
|
||||
fclose(g_recordfd);
|
||||
#else
|
||||
!truncate(filename, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (success)
|
||||
Core::DisplayMessage(StringFromFormat("DTM %s saved", filename).c_str(), 2000);
|
||||
else
|
||||
Core::DisplayMessage(StringFromFormat("Failed to save %s", filename).c_str(), 2000);
|
||||
|
||||
g_recordfd = fopen(g_recordFile.c_str(), "r+b");
|
||||
fseeko(g_recordfd, 0, SEEK_END);
|
||||
fseeko(g_recordfd, size, SEEK_SET);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -50,13 +50,14 @@ struct ControllerState {
|
|||
#pragma pack(pop)
|
||||
|
||||
// Global declarations
|
||||
extern bool g_bFrameStep, g_bPolled;
|
||||
extern bool g_bFrameStep, g_bPolled, g_bReadOnly;
|
||||
extern PlayMode g_playMode;
|
||||
|
||||
extern unsigned int g_framesToSkip, g_frameSkipCounter;
|
||||
|
||||
extern int g_numPads;
|
||||
extern ControllerState *g_padStates;
|
||||
extern char g_playingFile[256];
|
||||
extern FILE *g_recordfd;
|
||||
extern std::string g_recordFile;
|
||||
|
||||
|
@ -105,6 +106,7 @@ void ChangeWiiPads();
|
|||
|
||||
void SetFrameStepping(bool bEnabled);
|
||||
void SetFrameStopping(bool bEnabled);
|
||||
void SetReadOnly(bool bEnabled);
|
||||
|
||||
void SetFrameSkipping(unsigned int framesToSkip);
|
||||
int FrameSkippingFactor();
|
||||
|
|
|
@ -265,7 +265,7 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
|
|||
saveData->buffer = buffer;
|
||||
saveData->size = sz;
|
||||
|
||||
if (Frame::IsRecordingInput())
|
||||
if (Frame::IsRecordingInput() || Frame::IsPlayingInput())
|
||||
Frame::SaveRecording(StringFromFormat("%s.dtm", cur_filename.c_str()).c_str());
|
||||
|
||||
Core::DisplayMessage("Saving State...", 1000);
|
||||
|
|
|
@ -250,6 +250,7 @@ EVT_MENU(IDM_RESET, CFrame::OnReset)
|
|||
EVT_MENU(IDM_RECORD, CFrame::OnRecord)
|
||||
EVT_MENU(IDM_PLAYRECORD, CFrame::OnPlayRecording)
|
||||
EVT_MENU(IDM_RECORDEXPORT, CFrame::OnRecordExport)
|
||||
EVT_MENU(IDM_RECORDREADONLY, CFrame::OnRecordReadOnly)
|
||||
EVT_MENU(IDM_FRAMESTEP, CFrame::OnFrameStep)
|
||||
EVT_MENU(IDM_SCREENSHOT, CFrame::OnScreenshot)
|
||||
EVT_MENU(wxID_PREFERENCES, CFrame::OnConfigMain)
|
||||
|
|
|
@ -279,6 +279,7 @@ class CFrame : public CRenderFrame
|
|||
void OnRecord(wxCommandEvent& event);
|
||||
void OnPlayRecording(wxCommandEvent& event);
|
||||
void OnRecordExport(wxCommandEvent& event);
|
||||
void OnRecordReadOnly(wxCommandEvent& event);
|
||||
void OnChangeDisc(wxCommandEvent& event);
|
||||
void OnScreenshot(wxCommandEvent& event);
|
||||
void OnActive(wxActivateEvent& event);
|
||||
|
|
|
@ -140,6 +140,8 @@ void CFrame::CreateMenu()
|
|||
emulationMenu->Append(IDM_RECORD, _("Start Re&cording"));
|
||||
emulationMenu->Append(IDM_PLAYRECORD, _("P&lay Recording..."));
|
||||
emulationMenu->Append(IDM_RECORDEXPORT, _("Export Recording..."));
|
||||
emulationMenu->Append(IDM_RECORDREADONLY, _("&Read-only mode"), wxEmptyString, wxITEM_CHECK);
|
||||
emulationMenu->Check(IDM_RECORDREADONLY, true);
|
||||
emulationMenu->AppendSeparator();
|
||||
|
||||
emulationMenu->Append(IDM_FRAMESTEP, _("&Frame Advance"), wxEmptyString, wxITEM_CHECK);
|
||||
|
@ -633,6 +635,11 @@ void CFrame::DoOpen(bool Boot)
|
|||
}
|
||||
}
|
||||
|
||||
void CFrame::OnRecordReadOnly(wxCommandEvent& event)
|
||||
{
|
||||
Frame::SetReadOnly(event.IsChecked());
|
||||
}
|
||||
|
||||
void CFrame::OnFrameStep(wxCommandEvent& event)
|
||||
{
|
||||
Frame::SetFrameStepping(event.IsChecked());
|
||||
|
|
|
@ -78,6 +78,7 @@ enum
|
|||
IDM_RECORD,
|
||||
IDM_PLAYRECORD,
|
||||
IDM_RECORDEXPORT,
|
||||
IDM_RECORDREADONLY,
|
||||
IDM_FRAMESTEP,
|
||||
IDM_SCREENSHOT,
|
||||
IDM_BROWSE,
|
||||
|
|
Loading…
Reference in New Issue