mirror of https://github.com/PCSX2/pcsx2.git
Capture: Optimizations with filenames, audio, and capture mainFrame gui
*Resulting .wavs should get saved in the same location as the video file on linux *Keep gui capture state consistent regardless of the method used to start recording *Reworked mainFrame capture menu video options to route to a single toggleCapture_click function *Split GS & SPU2 recording into start & end functions
This commit is contained in:
parent
1e5e742601
commit
c60cdbba07
|
@ -133,10 +133,12 @@ void CALLBACK GSsetGameCRC(int crc, int gameoptions);
|
||||||
// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done
|
// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done
|
||||||
void CALLBACK GSsetFrameSkip(int frameskip);
|
void CALLBACK GSsetFrameSkip(int frameskip);
|
||||||
|
|
||||||
// if start is 1, starts recording spu2 data, else stops
|
// Starts recording GS frame data
|
||||||
// returns a non zero value if successful
|
// returns a non zero value if successful
|
||||||
// for now, pData is not used
|
int CALLBACK GSsetupRecording(std::string& filename);
|
||||||
int CALLBACK GSsetupRecording(int start, void *pData);
|
|
||||||
|
// Stops recording GS frame data
|
||||||
|
void CALLBACK GSendRecording();
|
||||||
|
|
||||||
void CALLBACK GSreset();
|
void CALLBACK GSreset();
|
||||||
//deprecated: GSgetTitleInfo was used in PCSX2 but no plugin supported it prior to r4070:
|
//deprecated: GSgetTitleInfo was used in PCSX2 but no plugin supported it prior to r4070:
|
||||||
|
@ -183,7 +185,8 @@ typedef void(CALLBACK *_GSsetGameCRC)(int, int);
|
||||||
typedef void(CALLBACK *_GSsetFrameSkip)(int frameskip);
|
typedef void(CALLBACK *_GSsetFrameSkip)(int frameskip);
|
||||||
typedef void(CALLBACK *_GSsetVsync)(int enabled);
|
typedef void(CALLBACK *_GSsetVsync)(int enabled);
|
||||||
typedef void(CALLBACK *_GSsetExclusive)(int isExclusive);
|
typedef void(CALLBACK *_GSsetExclusive)(int isExclusive);
|
||||||
typedef std::wstring*(CALLBACK *_GSsetupRecording)(int);
|
typedef int(CALLBACK* _GSsetupRecording)(std::string&);
|
||||||
|
typedef void(CALLBACK* _GSendRecording)();
|
||||||
typedef void(CALLBACK *_GSreset)();
|
typedef void(CALLBACK *_GSreset)();
|
||||||
typedef void(CALLBACK *_GSwriteCSR)(u32 value);
|
typedef void(CALLBACK *_GSwriteCSR)(u32 value);
|
||||||
typedef bool(CALLBACK *_GSmakeSnapshot)(const char *path);
|
typedef bool(CALLBACK *_GSmakeSnapshot)(const char *path);
|
||||||
|
@ -220,6 +223,7 @@ extern _GSsetGameCRC GSsetGameCRC;
|
||||||
extern _GSsetFrameSkip GSsetFrameSkip;
|
extern _GSsetFrameSkip GSsetFrameSkip;
|
||||||
extern _GSsetVsync GSsetVsync;
|
extern _GSsetVsync GSsetVsync;
|
||||||
extern _GSsetupRecording GSsetupRecording;
|
extern _GSsetupRecording GSsetupRecording;
|
||||||
|
extern _GSendRecording GSendRecording;
|
||||||
extern _GSreset GSreset;
|
extern _GSreset GSreset;
|
||||||
extern _GSwriteCSR GSwriteCSR;
|
extern _GSwriteCSR GSwriteCSR;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -177,6 +177,7 @@ _GSsetFrameSkip GSsetFrameSkip;
|
||||||
_GSsetVsync GSsetVsync;
|
_GSsetVsync GSsetVsync;
|
||||||
_GSsetExclusive GSsetExclusive;
|
_GSsetExclusive GSsetExclusive;
|
||||||
_GSsetupRecording GSsetupRecording;
|
_GSsetupRecording GSsetupRecording;
|
||||||
|
_GSendRecording GSendRecording;
|
||||||
_GSreset GSreset;
|
_GSreset GSreset;
|
||||||
_GSwriteCSR GSwriteCSR;
|
_GSwriteCSR GSwriteCSR;
|
||||||
#endif
|
#endif
|
||||||
|
@ -316,6 +317,7 @@ static const LegacyApi_OptMethod s_MethMessOpt_GS[] =
|
||||||
{ "GSopen2", (vMeth**)&GSopen2 },
|
{ "GSopen2", (vMeth**)&GSopen2 },
|
||||||
{ "GSreset", (vMeth**)&GSreset },
|
{ "GSreset", (vMeth**)&GSreset },
|
||||||
{ "GSsetupRecording", (vMeth**)&GSsetupRecording },
|
{ "GSsetupRecording", (vMeth**)&GSsetupRecording },
|
||||||
|
{ "GSendRecording", (vMeth**)&GSendRecording },
|
||||||
{ "GSmakeSnapshot2", (vMeth**)&GSmakeSnapshot2 },
|
{ "GSmakeSnapshot2", (vMeth**)&GSmakeSnapshot2 },
|
||||||
{ "GSgifSoftReset", (vMeth**)&GSgifSoftReset },
|
{ "GSgifSoftReset", (vMeth**)&GSgifSoftReset },
|
||||||
{ "GSreadFIFO", (vMeth**)&GSreadFIFO },
|
{ "GSreadFIFO", (vMeth**)&GSreadFIFO },
|
||||||
|
|
|
@ -682,7 +682,7 @@ extern SndOutModule* mods[];
|
||||||
|
|
||||||
extern bool WavRecordEnabled;
|
extern bool WavRecordEnabled;
|
||||||
|
|
||||||
extern void RecordStart(std::wstring* filename);
|
extern int RecordStart(const std::string* filename);
|
||||||
extern void RecordStop();
|
extern void RecordStop();
|
||||||
extern void RecordWrite(const StereoOut16& sample);
|
extern void RecordWrite(const StereoOut16& sample);
|
||||||
|
|
||||||
|
|
|
@ -110,28 +110,27 @@ bool WavRecordEnabled = false;
|
||||||
static WavOutFile* m_wavrecord = nullptr;
|
static WavOutFile* m_wavrecord = nullptr;
|
||||||
static Mutex WavRecordMutex;
|
static Mutex WavRecordMutex;
|
||||||
|
|
||||||
void RecordStart(std::wstring* filename)
|
int RecordStart(const std::string* filename)
|
||||||
{
|
{
|
||||||
WavRecordEnabled = false;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ScopedLock lock(WavRecordMutex);
|
ScopedLock lock(WavRecordMutex);
|
||||||
safe_delete(m_wavrecord);
|
safe_delete(m_wavrecord);
|
||||||
#ifdef _WIN32
|
|
||||||
if (filename)
|
if (filename)
|
||||||
m_wavrecord = new WavOutFile((*filename) + "wav", 48000, 16, 2);
|
m_wavrecord = new WavOutFile(filename->c_str(), 48000, 16, 2);
|
||||||
else
|
else
|
||||||
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
|
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
|
||||||
#elif defined(__unix__)
|
|
||||||
m_wavrecord = new WavOutFile("audio_recording.wav", 48000, 16, 2);
|
|
||||||
#endif
|
|
||||||
WavRecordEnabled = true;
|
WavRecordEnabled = true;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
catch (std::runtime_error&)
|
catch (std::runtime_error&)
|
||||||
{
|
{
|
||||||
m_wavrecord = nullptr; // not needed, but what the heck. :)
|
m_wavrecord = nullptr; // not needed, but what the heck. :)
|
||||||
SysMessage("SPU2 couldn't open file for recording: %s.\nRecording to wavfile disabled.", "audio_recording.wav");
|
if (filename)
|
||||||
|
SysMessage("SPU2-X couldn't open file for recording: %s.\nWavfile capture disabled.", filename->c_str());
|
||||||
|
else
|
||||||
|
SysMessage("SPU2-X couldn't open file for recording: audio_recording.wav.\nWavfile capture disabled.");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -578,17 +578,16 @@ void SPU2write(u32 rmem, u16 value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if start is 1, starts recording spu2 data, else stops
|
|
||||||
// returns a non zero value if successful
|
// returns a non zero value if successful
|
||||||
// for now, pData is not used
|
int SPU2setupRecording(const std::string* filename)
|
||||||
int SPU2setupRecording(int start, std::wstring* filename)
|
|
||||||
{
|
{
|
||||||
if (start == 0)
|
return RecordStart(filename);
|
||||||
RecordStop();
|
}
|
||||||
else if (start == 1)
|
|
||||||
RecordStart(filename);
|
|
||||||
|
|
||||||
return 0;
|
void SPU2endRecording()
|
||||||
|
{
|
||||||
|
if (WavRecordEnabled)
|
||||||
|
RecordStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 SPU2freeze(int mode, freezeData* data)
|
s32 SPU2freeze(int mode, freezeData* data)
|
||||||
|
|
|
@ -31,10 +31,9 @@ void SPU2write(u32 mem, u16 value);
|
||||||
u16 SPU2read(u32 mem);
|
u16 SPU2read(u32 mem);
|
||||||
|
|
||||||
// extended funcs
|
// extended funcs
|
||||||
// if start is 1, starts recording spu2 data, else stops
|
|
||||||
// returns a non zero value if successful
|
// returns a non zero value if successful
|
||||||
// for now, pData is not used
|
int SPU2setupRecording(const std::string* filename);
|
||||||
int SPU2setupRecording(int start, std::wstring* filename);
|
void SPU2endRecording();
|
||||||
|
|
||||||
void SPU2setClockPtr(u32* ptr);
|
void SPU2setClockPtr(u32* ptr);
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ uint renderswitch_delay = 0;
|
||||||
|
|
||||||
extern bool switchAR;
|
extern bool switchAR;
|
||||||
|
|
||||||
static int g_Pcsx2Recording = 0; // true 1 if recording video and sound
|
static bool g_Pcsx2Recording = false; // true if recording video and sound
|
||||||
|
|
||||||
|
|
||||||
KeyAcceleratorCode::KeyAcceleratorCode(const wxKeyEvent& evt)
|
KeyAcceleratorCode::KeyAcceleratorCode(const wxKeyEvent& evt)
|
||||||
|
@ -450,9 +450,14 @@ namespace Implementations
|
||||||
ScopedCoreThreadPause paused_core;
|
ScopedCoreThreadPause paused_core;
|
||||||
paused_core.AllowResume();
|
paused_core.AllowResume();
|
||||||
|
|
||||||
g_Pcsx2Recording ^= 1;
|
if (wxGetApp().HasGUI())
|
||||||
|
{
|
||||||
|
sMainFrame.VideoCaptureToggle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GetMTGS().WaitGS(); // make sure GS is in sync with the audio stream when we start.
|
GetMTGS().WaitGS(); // make sure GS is in sync with the audio stream when we start.
|
||||||
|
g_Pcsx2Recording = !g_Pcsx2Recording;
|
||||||
if (g_Pcsx2Recording)
|
if (g_Pcsx2Recording)
|
||||||
{
|
{
|
||||||
// start recording
|
// start recording
|
||||||
|
@ -469,23 +474,17 @@ namespace Implementations
|
||||||
if (GSsetupRecording)
|
if (GSsetupRecording)
|
||||||
{
|
{
|
||||||
// GSsetupRecording can be aborted/canceled by the user. Don't go on to record the audio if that happens.
|
// GSsetupRecording can be aborted/canceled by the user. Don't go on to record the audio if that happens.
|
||||||
std::wstring* filename = nullptr;
|
std::string filename;
|
||||||
if (filename = GSsetupRecording(g_Pcsx2Recording))
|
if (GSsetupRecording(filename))
|
||||||
{
|
// Note: Add a dialog box here (or in the function) that prompts the user to answer whether a failed
|
||||||
SPU2setupRecording(g_Pcsx2Recording, filename);
|
// SPU2 recording setup should still lead to the visuals being recorded.
|
||||||
delete filename;
|
SPU2setupRecording(&filename);
|
||||||
|
else // recording dialog canceled by the user. align our state
|
||||||
|
g_Pcsx2Recording = false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// recording dialog canceled by the user. align our state
|
|
||||||
g_Pcsx2Recording ^= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// the GS doesn't support recording
|
// the GS doesn't support recording
|
||||||
SPU2setupRecording(g_Pcsx2Recording, NULL);
|
else
|
||||||
}
|
g_Pcsx2Recording = SPU2setupRecording(nullptr);
|
||||||
|
|
||||||
if (GetMainFramePtr() && needsMainFrameEnable)
|
if (GetMainFramePtr() && needsMainFrameEnable)
|
||||||
GetMainFramePtr()->Enable();
|
GetMainFramePtr()->Enable();
|
||||||
|
@ -493,9 +492,9 @@ namespace Implementations
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// stop recording
|
// stop recording
|
||||||
if (GSsetupRecording)
|
if (GSendRecording)
|
||||||
GSsetupRecording(g_Pcsx2Recording);
|
GSendRecording();
|
||||||
SPU2setupRecording(g_Pcsx2Recording, NULL);
|
SPU2endRecording();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,8 +289,8 @@ void MainEmuFrame::ConnectMenus()
|
||||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Debug_Open_Click, this, MenuId_Debug_Open);
|
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Debug_Open_Click, this, MenuId_Debug_Open);
|
||||||
|
|
||||||
// Capture
|
// Capture
|
||||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Video_Record_Click, this, MenuId_Capture_Video_Record);
|
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Video_ToggleCapture_Click, this, MenuId_Capture_Video_Record);
|
||||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Video_Stop_Click, this, MenuId_Capture_Video_Stop);
|
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Video_ToggleCapture_Click, this, MenuId_Capture_Video_Stop);
|
||||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_Click, this, MenuId_Capture_Screenshot_Screenshot);
|
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_Click, this, MenuId_Capture_Screenshot_Screenshot);
|
||||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click, this, MenuId_Capture_Screenshot_Screenshot_As);
|
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click, this, MenuId_Capture_Screenshot_Screenshot_As);
|
||||||
|
|
||||||
|
@ -573,6 +573,7 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
|
||||||
|
|
||||||
{
|
{
|
||||||
m_RestartEmuOnDelete = false;
|
m_RestartEmuOnDelete = false;
|
||||||
|
m_capturingVideo = false;
|
||||||
|
|
||||||
for (int i = 0; i < PluginId_Count; ++i)
|
for (int i = 0; i < PluginId_Count; ++i)
|
||||||
m_PluginMenuPacks[i].Populate((PluginsEnum_t)i);
|
m_PluginMenuPacks[i].Populate((PluginsEnum_t)i);
|
||||||
|
|
|
@ -172,6 +172,7 @@ public:
|
||||||
void CommitPreset_noTrigger();
|
void CommitPreset_noTrigger();
|
||||||
void AppendShortcutToMenuOption(wxMenuItem& item, wxString keyCodeStr);
|
void AppendShortcutToMenuOption(wxMenuItem& item, wxString keyCodeStr);
|
||||||
void UpdateStatusBar();
|
void UpdateStatusBar();
|
||||||
|
void VideoCaptureToggle();
|
||||||
#ifndef DISABLE_RECORDING
|
#ifndef DISABLE_RECORDING
|
||||||
void initializeRecordingMenuItem(MenuIdentifiers menuId, wxString keyCodeStr, bool enable = true);
|
void initializeRecordingMenuItem(MenuIdentifiers menuId, wxString keyCodeStr, bool enable = true);
|
||||||
void enableRecordingMenuItem(MenuIdentifiers menuId, bool enable);
|
void enableRecordingMenuItem(MenuIdentifiers menuId, bool enable);
|
||||||
|
@ -252,9 +253,7 @@ protected:
|
||||||
void Menu_Wiki(wxCommandEvent& event);
|
void Menu_Wiki(wxCommandEvent& event);
|
||||||
void Menu_ShowAboutBox(wxCommandEvent& event);
|
void Menu_ShowAboutBox(wxCommandEvent& event);
|
||||||
|
|
||||||
void Menu_Capture_Video_Record_Click(wxCommandEvent& event);
|
void Menu_Capture_Video_ToggleCapture_Click(wxCommandEvent& event);
|
||||||
void Menu_Capture_Video_Stop_Click(wxCommandEvent& event);
|
|
||||||
void VideoCaptureUpdate();
|
|
||||||
void Menu_Capture_Screenshot_Screenshot_Click(wxCommandEvent& event);
|
void Menu_Capture_Screenshot_Screenshot_Click(wxCommandEvent& event);
|
||||||
void Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& event);
|
void Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& event);
|
||||||
|
|
||||||
|
|
|
@ -848,27 +848,17 @@ void MainEmuFrame::Menu_ShowAboutBox(wxCommandEvent& event)
|
||||||
AppOpenDialog<AboutBoxDialog>(this);
|
AppOpenDialog<AboutBoxDialog>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_Capture_Video_Record_Click(wxCommandEvent& event)
|
void MainEmuFrame::Menu_Capture_Video_ToggleCapture_Click(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
ScopedCoreThreadPause paused_core;
|
ScopedCoreThreadPause paused_core;
|
||||||
paused_core.AllowResume();
|
paused_core.AllowResume();
|
||||||
|
VideoCaptureToggle();
|
||||||
m_capturingVideo = true;
|
|
||||||
VideoCaptureUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_Capture_Video_Stop_Click(wxCommandEvent& event)
|
void MainEmuFrame::VideoCaptureToggle()
|
||||||
{
|
|
||||||
ScopedCoreThreadPause paused_core;
|
|
||||||
paused_core.AllowResume();
|
|
||||||
|
|
||||||
m_capturingVideo = false;
|
|
||||||
VideoCaptureUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainEmuFrame::VideoCaptureUpdate()
|
|
||||||
{
|
{
|
||||||
GetMTGS().WaitGS(); // make sure GS is in sync with the audio stream when we start.
|
GetMTGS().WaitGS(); // make sure GS is in sync with the audio stream when we start.
|
||||||
|
m_capturingVideo = !m_capturingVideo;
|
||||||
if (m_capturingVideo)
|
if (m_capturingVideo)
|
||||||
{
|
{
|
||||||
// start recording
|
// start recording
|
||||||
|
@ -876,20 +866,23 @@ void MainEmuFrame::VideoCaptureUpdate()
|
||||||
// make the recording setup dialog[s] pseudo-modal also for the main PCSX2 window
|
// make the recording setup dialog[s] pseudo-modal also for the main PCSX2 window
|
||||||
// (the GSdx dialog is already properly modal for the GS window)
|
// (the GSdx dialog is already properly modal for the GS window)
|
||||||
bool needsMainFrameEnable = false;
|
bool needsMainFrameEnable = false;
|
||||||
if (GetMainFramePtr() && GetMainFramePtr()->IsEnabled())
|
if (IsEnabled())
|
||||||
{
|
{
|
||||||
needsMainFrameEnable = true;
|
needsMainFrameEnable = true;
|
||||||
GetMainFramePtr()->Disable();
|
Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GSsetupRecording)
|
if (GSsetupRecording)
|
||||||
{
|
{
|
||||||
// GSsetupRecording can be aborted/canceled by the user. Don't go on to record the audio if that happens
|
// GSsetupRecording can be aborted/canceled by the user. Don't go on to record the audio if that happens
|
||||||
std::wstring* filename = nullptr;
|
std::string filename;
|
||||||
if (filename = GSsetupRecording(m_capturingVideo))
|
if (GSsetupRecording(filename))
|
||||||
{
|
{
|
||||||
SPU2setupRecording(m_capturingVideo, filename);
|
// Note: Add a dialog box here (or in the function) that prompts the user to answer whether a failed
|
||||||
delete filename;
|
// SPU2 recording setup should still lead to the visuals being recorded.
|
||||||
|
SPU2setupRecording(&filename);
|
||||||
|
m_submenuVideoCapture.Enable(MenuId_Capture_Video_Record, false);
|
||||||
|
m_submenuVideoCapture.Enable(MenuId_Capture_Video_Stop, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -900,29 +893,26 @@ void MainEmuFrame::VideoCaptureUpdate()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// the GS doesn't support recording.
|
// the GS doesn't support recording.
|
||||||
SPU2setupRecording(m_capturingVideo, nullptr);
|
if (SPU2setupRecording(nullptr))
|
||||||
|
{
|
||||||
|
m_submenuVideoCapture.Enable(MenuId_Capture_Video_Record, false);
|
||||||
|
m_submenuVideoCapture.Enable(MenuId_Capture_Video_Stop, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_capturingVideo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetMainFramePtr() && needsMainFrameEnable)
|
if (needsMainFrameEnable)
|
||||||
GetMainFramePtr()->Enable();
|
Enable();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// stop recording
|
// stop recording
|
||||||
if (GSsetupRecording)
|
if (GSendRecording)
|
||||||
GSsetupRecording(m_capturingVideo);
|
GSendRecording();
|
||||||
SPU2setupRecording(m_capturingVideo, nullptr);
|
SPU2endRecording();
|
||||||
}
|
m_submenuVideoCapture.Enable(MenuId_Capture_Video_Record, true);
|
||||||
|
m_submenuVideoCapture.Enable(MenuId_Capture_Video_Stop, false);
|
||||||
if (m_capturingVideo)
|
|
||||||
{
|
|
||||||
m_submenuVideoCapture.FindItem(MenuId_Capture_Video_Record)->Enable(false);
|
|
||||||
m_submenuVideoCapture.FindItem(MenuId_Capture_Video_Stop)->Enable(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_submenuVideoCapture.FindItem(MenuId_Capture_Video_Record)->Enable(true);
|
|
||||||
m_submenuVideoCapture.FindItem(MenuId_Capture_Video_Stop)->Enable(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -677,7 +677,11 @@ EXPORT_C_(uint32) GSmakeSnapshot(char* path)
|
||||||
{
|
{
|
||||||
// Allows for providing a complete path
|
// Allows for providing a complete path
|
||||||
std::string extension = s.substr(s.size() - 4, 4);
|
std::string extension = s.substr(s.size() - 4, 4);
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::transform(extension.begin(), extension.end(), extension.begin(), (char(_cdecl*)(int))tolower);
|
||||||
|
#else
|
||||||
std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
|
std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
|
||||||
|
#endif
|
||||||
if (extension == ".png")
|
if (extension == ".png")
|
||||||
return s_gs->MakeSnapshot(s);
|
return s_gs->MakeSnapshot(s);
|
||||||
else if (s[s.length() - 1] != DIRECTORY_SEPARATOR)
|
else if (s[s.length() - 1] != DIRECTORY_SEPARATOR)
|
||||||
|
@ -807,41 +811,36 @@ void pt(const char* str){
|
||||||
printf("%02i:%02i:%02i%s", current->tm_hour, current->tm_min, current->tm_sec, str);
|
printf("%02i:%02i:%02i%s", current->tm_hour, current->tm_min, current->tm_sec, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_C_(std::wstring*) GSsetupRecording(int start)
|
EXPORT_C_(int) GSsetupRecording(std::string& filename)
|
||||||
{
|
{
|
||||||
if (s_gs == NULL) {
|
if (s_gs == NULL) {
|
||||||
printf("GSdx: no s_gs for recording\n");
|
printf("GSdx: no s_gs for recording\n");
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
#if defined(__unix__) || defined(__APPLE__)
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
if (!theApp.GetConfigB("capture_enabled")) {
|
if (!theApp.GetConfigB("capture_enabled")) {
|
||||||
printf("GSdx: Recording is disabled\n");
|
printf("GSdx: Recording is disabled\n");
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
std::wstring* filename = nullptr;
|
|
||||||
if(start & 1)
|
|
||||||
{
|
|
||||||
printf("GSdx: Recording start command\n");
|
printf("GSdx: Recording start command\n");
|
||||||
filename = s_gs->BeginCapture();
|
if (s_gs->BeginCapture(filename))
|
||||||
if (filename)
|
|
||||||
{
|
{
|
||||||
pt(" - Capture started\n");
|
pt(" - Capture started\n");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pt(" - Capture cancelled\n");
|
pt(" - Capture cancelled\n");
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
EXPORT_C_(void) GSendRecording()
|
||||||
|
{
|
||||||
printf("GSdx: Recording end command\n");
|
printf("GSdx: Recording end command\n");
|
||||||
s_gs->EndCapture();
|
s_gs->EndCapture();
|
||||||
pt(" - Capture ended\n");
|
pt(" - Capture ended\n");
|
||||||
}
|
|
||||||
|
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_C GSsetGameCRC(uint32 crc, int options)
|
EXPORT_C GSsetGameCRC(uint32 crc, int options)
|
||||||
|
|
|
@ -404,7 +404,7 @@ GSCapture::~GSCapture()
|
||||||
EndCapture();
|
EndCapture();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring* GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float aspect)
|
int GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float aspect, std::string& filename)
|
||||||
{
|
{
|
||||||
printf("Recommended resolution: %d x %d, DAR for muxing: %.4f\n", recommendedResolution.x, recommendedResolution.y, aspect);
|
printf("Recommended resolution: %d x %d, DAR for muxing: %.4f\n", recommendedResolution.x, recommendedResolution.y, aspect);
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||||
|
@ -418,10 +418,10 @@ std::wstring* GSCapture::BeginCapture(float fps, GSVector2i recommendedResolutio
|
||||||
GSCaptureDlg dlg;
|
GSCaptureDlg dlg;
|
||||||
|
|
||||||
if (IDOK != dlg.DoModal())
|
if (IDOK != dlg.DoModal())
|
||||||
return nullptr;
|
return 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
int start = dlg.m_filename.length() - 4;
|
const int start = dlg.m_filename.length() - 4;
|
||||||
if (start > 0)
|
if (start > 0)
|
||||||
{
|
{
|
||||||
std::string test = dlg.m_filename.substr(start);
|
std::string test = dlg.m_filename.substr(start);
|
||||||
|
@ -438,11 +438,11 @@ std::wstring* GSCapture::BeginCapture(float fps, GSVector2i recommendedResolutio
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dlg.InvalidFile();
|
dlg.InvalidFile();
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring fn{dlg.m_filename.begin(), dlg.m_filename.end()};
|
;
|
||||||
|
|
||||||
m_size.x = (dlg.m_width + 7) & ~7;
|
m_size.x = (dlg.m_width + 7) & ~7;
|
||||||
m_size.y = (dlg.m_height + 7) & ~7;
|
m_size.y = (dlg.m_height + 7) & ~7;
|
||||||
|
@ -456,9 +456,9 @@ std::wstring* GSCapture::BeginCapture(float fps, GSVector2i recommendedResolutio
|
||||||
if(FAILED(hr = m_graph.CoCreateInstance(CLSID_FilterGraph))
|
if(FAILED(hr = m_graph.CoCreateInstance(CLSID_FilterGraph))
|
||||||
|| FAILED(hr = cgb.CoCreateInstance(CLSID_CaptureGraphBuilder2))
|
|| FAILED(hr = cgb.CoCreateInstance(CLSID_CaptureGraphBuilder2))
|
||||||
|| FAILED(hr = cgb->SetFiltergraph(m_graph))
|
|| FAILED(hr = cgb->SetFiltergraph(m_graph))
|
||||||
|| FAILED(hr = cgb->SetOutputFileName(&MEDIASUBTYPE_Avi, fn.c_str(), &mux, NULL)))
|
|| FAILED(hr = cgb->SetOutputFileName(&MEDIASUBTYPE_Avi, std::wstring(dlg.m_filename.begin(), dlg.m_filename.end()).c_str(), &mux, NULL)))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_src = new GSSource(m_size.x, m_size.y, fps, NULL, hr, dlg.m_colorspace);
|
m_src = new GSSource(m_size.x, m_size.y, fps, NULL, hr, dlg.m_colorspace);
|
||||||
|
@ -466,22 +466,22 @@ std::wstring* GSCapture::BeginCapture(float fps, GSVector2i recommendedResolutio
|
||||||
if (dlg.m_enc==0)
|
if (dlg.m_enc==0)
|
||||||
{
|
{
|
||||||
if (FAILED(hr = m_graph->AddFilter(m_src, L"Source")))
|
if (FAILED(hr = m_graph->AddFilter(m_src, L"Source")))
|
||||||
return nullptr;
|
return 0;
|
||||||
if (FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
|
if (FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(FAILED(hr = m_graph->AddFilter(m_src, L"Source"))
|
if(FAILED(hr = m_graph->AddFilter(m_src, L"Source"))
|
||||||
|| FAILED(hr = m_graph->AddFilter(dlg.m_enc, L"Encoder")))
|
|| FAILED(hr = m_graph->AddFilter(dlg.m_enc, L"Encoder")))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(dlg.m_enc, PINDIR_INPUT), NULL))
|
if(FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(dlg.m_enc, PINDIR_INPUT), NULL))
|
||||||
|| FAILED(hr = m_graph->ConnectDirect(GetFirstPin(dlg.m_enc, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
|
|| FAILED(hr = m_graph->ConnectDirect(GetFirstPin(dlg.m_enc, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,7 +509,8 @@ std::wstring* GSCapture::BeginCapture(float fps, GSVector2i recommendedResolutio
|
||||||
CComQIPtr<IGSSource>(m_src)->DeliverNewSegment();
|
CComQIPtr<IGSSource>(m_src)->DeliverNewSegment();
|
||||||
|
|
||||||
m_capturing = true;
|
m_capturing = true;
|
||||||
return new std::wstring(dlg.m_filename.begin(), dlg.m_filename.end() - 3);
|
filename = dlg.m_filename.erase(dlg.m_filename.length() - 3, 3) + "wav";
|
||||||
|
return 1;
|
||||||
#elif defined(__unix__)
|
#elif defined(__unix__)
|
||||||
// Note I think it doesn't support multiple depth creation
|
// Note I think it doesn't support multiple depth creation
|
||||||
GSmkdir(m_out_dir.c_str());
|
GSmkdir(m_out_dir.c_str());
|
||||||
|
@ -525,7 +526,8 @@ std::wstring* GSCapture::BeginCapture(float fps, GSVector2i recommendedResolutio
|
||||||
}
|
}
|
||||||
|
|
||||||
m_capturing = true;
|
m_capturing = true;
|
||||||
return new std::wstring();
|
filename = m_out_dir + "/audio_recording.wav";
|
||||||
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,6 +566,9 @@ bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba)
|
||||||
|
|
||||||
bool GSCapture::EndCapture()
|
bool GSCapture::EndCapture()
|
||||||
{
|
{
|
||||||
|
if (!m_capturing)
|
||||||
|
return false;
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
std::lock_guard<std::recursive_mutex> lock(m_lock);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
GSCapture();
|
GSCapture();
|
||||||
virtual ~GSCapture();
|
virtual ~GSCapture();
|
||||||
|
|
||||||
std::wstring* BeginCapture(float fps, GSVector2i recommendedResolution, float aspect);
|
int BeginCapture(float fps, GSVector2i recommendedResolution, float aspect, std::string& filename);
|
||||||
bool DeliverFrame(const void* bits, int pitch, bool rgba);
|
bool DeliverFrame(const void* bits, int pitch, bool rgba);
|
||||||
bool EndCapture();
|
bool EndCapture();
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,7 @@ void GSmkdir(const wchar_t* dir)
|
||||||
if (!CreateDirectory(dir, nullptr)) {
|
if (!CreateDirectory(dir, nullptr)) {
|
||||||
DWORD errorID = ::GetLastError();
|
DWORD errorID = ::GetLastError();
|
||||||
if (errorID != ERROR_ALREADY_EXISTS) {
|
if (errorID != ERROR_ALREADY_EXISTS) {
|
||||||
fprintf(stderr, "Failed to create directory: %s error %u\n", dir, errorID);
|
fprintf(stderr, "Failed to create directory: %ls error %u\n", dir, errorID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -34,6 +34,7 @@ EXPORTS
|
||||||
GSreadFIFO2
|
GSreadFIFO2
|
||||||
GSirqCallback
|
GSirqCallback
|
||||||
GSsetupRecording
|
GSsetupRecording
|
||||||
|
GSendRecording
|
||||||
GSsetGameCRC
|
GSsetGameCRC
|
||||||
GSsetFrameSkip
|
GSsetFrameSkip
|
||||||
GSsetVsync
|
GSsetVsync
|
||||||
|
|
|
@ -533,12 +533,12 @@ bool GSRenderer::MakeSnapshot(const std::string& path)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring* GSRenderer::BeginCapture()
|
int GSRenderer::BeginCapture(std::string& filename)
|
||||||
{
|
{
|
||||||
GSVector4i disp = m_wnd->GetClientRect().fit(m_aspectratio);
|
GSVector4i disp = m_wnd->GetClientRect().fit(m_aspectratio);
|
||||||
float aspect = (float)disp.width() / std::max(1, disp.height());
|
float aspect = (float)disp.width() / std::max(1, disp.height());
|
||||||
|
|
||||||
return m_capture.BeginCapture(GetTvRefreshRate(), GetInternalResolution(), aspect);
|
return m_capture.BeginCapture(GetTvRefreshRate(), GetInternalResolution(), aspect, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSRenderer::EndCapture()
|
void GSRenderer::EndCapture()
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
void SetAspectRatio(int aspect) {m_aspectratio = aspect;}
|
void SetAspectRatio(int aspect) {m_aspectratio = aspect;}
|
||||||
void SetVSync(int vsync);
|
void SetVSync(int vsync);
|
||||||
|
|
||||||
virtual std::wstring* BeginCapture();
|
virtual int BeginCapture(std::string& filename);
|
||||||
virtual void EndCapture();
|
virtual void EndCapture();
|
||||||
|
|
||||||
void PurgePool();
|
void PurgePool();
|
||||||
|
|
|
@ -40,7 +40,8 @@
|
||||||
void GSCaptureDlg::InvalidFile()
|
void GSCaptureDlg::InvalidFile()
|
||||||
{
|
{
|
||||||
wchar_t tmp[512];
|
wchar_t tmp[512];
|
||||||
swprintf_s(tmp, L"GSdx couldn't open file for capturing: %s.\nCapture aborted.", m_filename.c_str());
|
std::wstring tmpstr(m_filename.begin(), m_filename.end());
|
||||||
|
swprintf_s(tmp, L"GSdx couldn't open file for capturing: %ls.\nCapture aborted.", tmpstr.c_str());
|
||||||
MessageBox(GetActiveWindow(), tmp, L"GSdx System Message", MB_OK | MB_SETFOREGROUND);
|
MessageBox(GetActiveWindow(), tmp, L"GSdx System Message", MB_OK | MB_SETFOREGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue