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:
sonicfind 2020-09-20 23:26:02 -05:00 committed by refractionpcsx2
parent 1e5e742601
commit c60cdbba07
18 changed files with 125 additions and 127 deletions

View File

@ -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

View File

@ -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 },

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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)

View File

@ -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);

View File

@ -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();
} }
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);
} }
} }

View File

@ -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)

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -34,6 +34,7 @@ EXPORTS
GSreadFIFO2 GSreadFIFO2
GSirqCallback GSirqCallback
GSsetupRecording GSsetupRecording
GSendRecording
GSsetGameCRC GSsetGameCRC
GSsetFrameSkip GSsetFrameSkip
GSsetVsync GSsetVsync

View File

@ -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()

View File

@ -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();

View File

@ -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);
} }