mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-25 07:21:14 +01:00
* Dump AVI output on every VI (fixes issue #4064).
* Add audio dumping (fixes issue #1638). git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7131 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
ca78d3639b
commit
b0fa0a83f8
@ -16,6 +16,7 @@
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "AudioCommon.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Mixer.h"
|
||||
#include "NullSoundStream.h"
|
||||
#include "DSoundStream.h"
|
||||
@ -53,11 +54,13 @@ namespace AudioCommon
|
||||
ac_Config.Update();
|
||||
if (soundStream->Start())
|
||||
{
|
||||
#if 0
|
||||
// Start the sound recording
|
||||
if (ac_Config.record)
|
||||
soundStream->StartLogAudio(FULL_DUMP_DIR g_Config.recordFile);
|
||||
#endif
|
||||
if (ac_Config.m_DumpAudio) {
|
||||
char audio_file_name[255];
|
||||
snprintf(audio_file_name, 255, "%saudiodump.wav", File::GetUserPath(D_DUMPAUDIO_IDX));
|
||||
mixer->StartLogAudio(audio_file_name);
|
||||
//soundStream->StartLogAudio(audio_file_name);
|
||||
}
|
||||
|
||||
return soundStream;
|
||||
}
|
||||
PanicAlertT("Could not initialize backend %s.", backend.c_str());
|
||||
@ -76,10 +79,9 @@ namespace AudioCommon
|
||||
if (soundStream)
|
||||
{
|
||||
soundStream->Stop();
|
||||
#if 0
|
||||
if (ac_Config.record)
|
||||
soundStream->StopLogAudio();
|
||||
#endif
|
||||
if (ac_Config.m_DumpAudio)
|
||||
soundStream->GetMixer()->StopLogAudio();
|
||||
//soundStream->StopLogAudio();
|
||||
delete soundStream;
|
||||
soundStream = NULL;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ void AudioCommonConfig::Load()
|
||||
file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true);
|
||||
file.Get("Config", "EnableThrottle", &m_EnableThrottle, true);
|
||||
file.Get("Config", "EnableJIT", &m_EnableJIT, true);
|
||||
file.Get("Config", "DumpAudio", &m_DumpAudio, false);
|
||||
#if defined __linux__ && HAVE_ALSA
|
||||
file.Get("Config", "Backend", &sBackend, BACKEND_ALSA);
|
||||
#elif defined __APPLE__
|
||||
@ -55,6 +56,7 @@ void AudioCommonConfig::SaveSettings()
|
||||
file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic);
|
||||
file.Set("Config", "EnableThrottle", m_EnableThrottle);
|
||||
file.Set("Config", "EnableJIT", m_EnableJIT);
|
||||
file.Set("Config", "DumpAudio", m_DumpAudio);
|
||||
file.Set("Config", "Backend", sBackend);
|
||||
file.Set("Config", "Frequency", sFrequency);
|
||||
file.Set("Config", "Volume", m_Volume);
|
||||
|
@ -36,6 +36,7 @@ struct AudioCommonConfig
|
||||
bool m_EnableDTKMusic;
|
||||
bool m_EnableThrottle;
|
||||
bool m_EnableJIT;
|
||||
bool m_DumpAudio;
|
||||
int m_Volume;
|
||||
std::string sBackend;
|
||||
int sFrequency;
|
||||
|
@ -125,15 +125,29 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||
if (numSamples > numLeft)
|
||||
memset(&samples[numLeft * 2], 0, (numSamples - numLeft) * 4);
|
||||
|
||||
// Add the DSPHLE sound, re-sampling is done inside
|
||||
Premix(samples, numSamples);
|
||||
//when logging, also throttle HLE audio
|
||||
if (m_logAudio) {
|
||||
if (m_AIplaying) {
|
||||
Premix(samples, numLeft);
|
||||
|
||||
// Add the DTK Music
|
||||
if (m_EnableDTKMusic)
|
||||
{
|
||||
// Re-sampling is done inside
|
||||
AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate);
|
||||
if (m_EnableDTKMusic)
|
||||
AudioInterface::Callback_GetStreaming(samples, numLeft, m_sampleRate);
|
||||
|
||||
g_wave_writer.AddStereoSamples(samples, numLeft);
|
||||
}
|
||||
}
|
||||
else { //or mix as usual
|
||||
// Add the DSPHLE sound, re-sampling is done inside
|
||||
Premix(samples, numSamples);
|
||||
|
||||
// Add the DTK Music
|
||||
if (m_EnableDTKMusic)
|
||||
{
|
||||
// Re-sampling is done inside
|
||||
AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Common::AtomicAdd(m_numSamples, -(s32)numLeft);
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#ifndef _MIXER_H_
|
||||
#define _MIXER_H_
|
||||
|
||||
#include "WaveFile.h"
|
||||
|
||||
// 16 bit Stereo
|
||||
#define MAX_SAMPLES (1024 * 8)
|
||||
#define INDEX_MASK (MAX_SAMPLES * 2 - 1)
|
||||
@ -36,6 +38,7 @@ public:
|
||||
, m_indexW(0)
|
||||
, m_indexR(0)
|
||||
, m_AIplaying(true)
|
||||
, m_logAudio(0)
|
||||
{
|
||||
// AyuanX: The internal (Core & DSP) sample rate is fixed at 32KHz
|
||||
// So when AI/DAC sample rate differs than 32KHz, we have to do re-sampling
|
||||
@ -63,14 +66,40 @@ public:
|
||||
void SetHLEReady(bool ready) { m_HLEready = ready;}
|
||||
// ---------------------
|
||||
|
||||
|
||||
virtual void StartLogAudio(const char *filename) {
|
||||
if (! m_logAudio) {
|
||||
m_logAudio = true;
|
||||
g_wave_writer.Start(filename);
|
||||
g_wave_writer.SetSkipSilence(false);
|
||||
NOTICE_LOG(DSPHLE, "Starting Audio logging");
|
||||
} else {
|
||||
WARN_LOG(DSPHLE, "Audio logging already started");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void StopLogAudio() {
|
||||
if (m_logAudio) {
|
||||
m_logAudio = false;
|
||||
g_wave_writer.Stop();
|
||||
NOTICE_LOG(DSPHLE, "Stopping Audio logging");
|
||||
} else {
|
||||
WARN_LOG(DSPHLE, "Audio logging already stopped");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
unsigned int m_sampleRate;
|
||||
unsigned int m_aiSampleRate;
|
||||
unsigned int m_dacSampleRate;
|
||||
int m_bits;
|
||||
int m_channels;
|
||||
|
||||
WaveFileWriter g_wave_writer;
|
||||
|
||||
bool m_HLEready;
|
||||
bool m_logAudio;
|
||||
|
||||
bool m_EnableDTKMusic;
|
||||
bool m_throttle;
|
||||
|
@ -83,6 +83,7 @@
|
||||
#define DUMP_DIR "Dump"
|
||||
#define DUMP_TEXTURES_DIR DUMP_DIR DIR_SEP "Textures"
|
||||
#define DUMP_FRAMES_DIR DUMP_DIR DIR_SEP "Frames"
|
||||
#define DUMP_AUDIO_DIR DUMP_DIR DIR_SEP "Audio"
|
||||
#define DUMP_DSP_DIR DUMP_DIR DIR_SEP "DSP"
|
||||
#define LOGS_DIR "Logs"
|
||||
#define MAIL_LOGS_DIR LOGS_DIR DIR_SEP "Mail"
|
||||
|
@ -640,6 +640,7 @@ const char *GetUserPath(int DirIDX)
|
||||
static char HiresTexturesDir[MAX_PATH] = {0};
|
||||
static char DumpDir[MAX_PATH] = {0};
|
||||
static char DumpFramesDir[MAX_PATH] = {0};
|
||||
static char DumpAudioDir[MAX_PATH] = {0};
|
||||
static char DumpTexturesDir[MAX_PATH] = {0};
|
||||
static char DumpDSPDir[MAX_PATH] = {0};
|
||||
static char LogsDir[MAX_PATH] = {0};
|
||||
@ -684,6 +685,7 @@ const char *GetUserPath(int DirIDX)
|
||||
snprintf(HiresTexturesDir, sizeof(HiresTexturesDir), "%s" HIRES_TEXTURES_DIR DIR_SEP, UserDir);
|
||||
snprintf(DumpDir, sizeof(DumpDir), "%s" DUMP_DIR DIR_SEP, UserDir);
|
||||
snprintf(DumpFramesDir, sizeof(DumpFramesDir), "%s" DUMP_FRAMES_DIR DIR_SEP, UserDir);
|
||||
snprintf(DumpAudioDir, sizeof(DumpAudioDir), "%s" DUMP_AUDIO_DIR DIR_SEP, UserDir);
|
||||
snprintf(DumpTexturesDir, sizeof(DumpTexturesDir), "%s" DUMP_TEXTURES_DIR DIR_SEP, UserDir);
|
||||
snprintf(DumpDSPDir, sizeof(DumpDSPDir), "%s" DUMP_DSP_DIR DIR_SEP, UserDir);
|
||||
snprintf(LogsDir, sizeof(LogsDir), "%s" LOGS_DIR DIR_SEP, UserDir);
|
||||
@ -733,6 +735,8 @@ const char *GetUserPath(int DirIDX)
|
||||
return DumpDir;
|
||||
case D_DUMPFRAMES_IDX:
|
||||
return DumpFramesDir;
|
||||
case D_DUMPAUDIO_IDX:
|
||||
return DumpAudioDir;
|
||||
case D_DUMPTEXTURES_IDX:
|
||||
return DumpTexturesDir;
|
||||
case D_DUMPDSP_IDX:
|
||||
|
@ -42,6 +42,7 @@ enum {
|
||||
D_HIRESTEXTURES_IDX,
|
||||
D_DUMP_IDX,
|
||||
D_DUMPFRAMES_IDX,
|
||||
D_DUMPAUDIO_IDX,
|
||||
D_DUMPTEXTURES_IDX,
|
||||
D_DUMPDSP_IDX,
|
||||
D_LOGS_IDX,
|
||||
|
@ -127,6 +127,7 @@ EVT_CHECKBOX(ID_DISPLAY_NTSCJ, CConfigMain::DisplaySettingsChanged)
|
||||
EVT_RADIOBOX(ID_DSPENGINE, CConfigMain::AudioSettingsChanged)
|
||||
EVT_CHECKBOX(ID_ENABLE_DTK_MUSIC, CConfigMain::AudioSettingsChanged)
|
||||
EVT_CHECKBOX(ID_ENABLE_THROTTLE, CConfigMain::AudioSettingsChanged)
|
||||
EVT_CHECKBOX(ID_DUMP_AUDIO, CConfigMain::AudioSettingsChanged)
|
||||
EVT_CHOICE(ID_FREQUENCY, CConfigMain::AudioSettingsChanged)
|
||||
EVT_CHOICE(ID_BACKEND, CConfigMain::AudioSettingsChanged)
|
||||
EVT_SLIDER(ID_VOLUME, CConfigMain::AudioSettingsChanged)
|
||||
@ -399,6 +400,7 @@ void CConfigMain::InitializeGUIValues()
|
||||
VolumeText->SetLabel(wxString::Format(wxT("%d %%"), ac_Config.m_Volume));
|
||||
EnableDTKMusic->SetValue(ac_Config.m_EnableDTKMusic ? true : false);
|
||||
EnableThrottle->SetValue(ac_Config.m_EnableThrottle ? true : false);
|
||||
DumpAudio->SetValue(ac_Config.m_DumpAudio ? true : false);
|
||||
FrequencySelection->SetSelection(
|
||||
FrequencySelection->FindString(wxString::Format(_("%d Hz"), ac_Config.sFrequency)));
|
||||
// add backends to the list
|
||||
@ -713,6 +715,8 @@ void CConfigMain::CreateGUIControls()
|
||||
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
EnableThrottle = new wxCheckBox(AudioPage, ID_ENABLE_THROTTLE, _("Enable Audio Throttle"),
|
||||
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
DumpAudio = new wxCheckBox(AudioPage, ID_DUMP_AUDIO, _("Dump Audio"),
|
||||
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
VolumeSlider = new wxSlider(AudioPage, ID_VOLUME, 0, 1, 100,
|
||||
wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL|wxSL_INVERSE);
|
||||
VolumeText = new wxStaticText(AudioPage, wxID_ANY, wxT(""),
|
||||
@ -728,6 +732,7 @@ void CConfigMain::CreateGUIControls()
|
||||
sbAudioSettings->Add(DSPEngine, 0, wxALL | wxEXPAND, 5);
|
||||
sbAudioSettings->Add(EnableDTKMusic, 0, wxALL, 5);
|
||||
sbAudioSettings->Add(EnableThrottle, 0, wxALL, 5);
|
||||
sbAudioSettings->Add(DumpAudio, 0, wxALL, 5);
|
||||
|
||||
wxStaticBoxSizer *sbVolume = new wxStaticBoxSizer(wxVERTICAL, AudioPage, _("Volume"));
|
||||
sbVolume->Add(VolumeSlider, 1, wxLEFT|wxRIGHT, 13);
|
||||
@ -1069,6 +1074,7 @@ void CConfigMain::AudioSettingsChanged(wxCommandEvent& event)
|
||||
default:
|
||||
ac_Config.m_EnableDTKMusic = EnableDTKMusic->GetValue();
|
||||
ac_Config.m_EnableThrottle = EnableThrottle->GetValue();
|
||||
ac_Config.m_DumpAudio = DumpAudio->GetValue();
|
||||
ac_Config.sBackend = BackendSelection->GetStringSelection().mb_str();
|
||||
long int frequency;
|
||||
FrequencySelection->GetStringSelection().ToLong(&frequency);
|
||||
|
@ -89,6 +89,7 @@ private:
|
||||
ID_ENABLE_HLE_AUDIO,
|
||||
ID_ENABLE_DTK_MUSIC,
|
||||
ID_ENABLE_THROTTLE,
|
||||
ID_DUMP_AUDIO,
|
||||
ID_FREQUENCY,
|
||||
ID_BACKEND,
|
||||
ID_VOLUME,
|
||||
@ -183,6 +184,7 @@ private:
|
||||
wxStaticText* VolumeText;
|
||||
wxCheckBox* EnableDTKMusic;
|
||||
wxCheckBox* EnableThrottle;
|
||||
wxCheckBox* DumpAudio;
|
||||
wxArrayString wxArrayBackends;
|
||||
wxChoice* BackendSelection;
|
||||
wxChoice* FrequencySelection;
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "CommonPaths.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "HW/VideoInterface.h" //for TargetRefreshRate
|
||||
|
||||
HWND m_emuWnd;
|
||||
LONG m_byteBuffer;
|
||||
LONG m_frameCount;
|
||||
@ -189,8 +191,7 @@ bool AVIDump::SetVideoFormat()
|
||||
memset(&m_header, 0, sizeof(m_header));
|
||||
m_header.fccType = streamtypeVIDEO;
|
||||
m_header.dwScale = 1;
|
||||
// TODO: Decect FPS using NTSC/PAL
|
||||
m_header.dwRate = 60;
|
||||
m_header.dwRate = VideoInterface::TargetRefreshRate;
|
||||
m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage;
|
||||
|
||||
return SUCCEEDED(AVIFileCreateStream(m_file, &m_stream, &m_header));
|
||||
@ -202,6 +203,8 @@ bool AVIDump::SetVideoFormat()
|
||||
#include "StringUtil.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "HW/VideoInterface.h" //for TargetRefreshRate
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
@ -253,14 +256,14 @@ bool AVIDump::CreateFile()
|
||||
return false;
|
||||
}
|
||||
|
||||
s_Stream->codec->codec_id = s_FormatContext->oformat->video_codec;
|
||||
s_Stream->codec->codec_id = CODEC_ID_FFV1; //s_FormatContext->oformat->video_codec;
|
||||
s_Stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
s_Stream->codec->bit_rate = 400000;
|
||||
s_Stream->codec->width = s_width;
|
||||
s_Stream->codec->height = s_height;
|
||||
s_Stream->codec->time_base = (AVRational){1, 30};
|
||||
s_Stream->codec->time_base = (AVRational){1, VideoInterface::TargetRefreshRate};
|
||||
s_Stream->codec->gop_size = 12;
|
||||
s_Stream->codec->pix_fmt = PIX_FMT_YUV420P;
|
||||
s_Stream->codec->pix_fmt = PIX_FMT_BGRA;
|
||||
|
||||
av_set_parameters(s_FormatContext, NULL);
|
||||
|
||||
@ -272,7 +275,7 @@ bool AVIDump::CreateFile()
|
||||
}
|
||||
|
||||
if(!(s_SwsContext = sws_getContext(s_width, s_height, PIX_FMT_BGR24, s_width, s_height,
|
||||
PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL)))
|
||||
PIX_FMT_BGRA, SWS_BICUBIC, NULL, NULL, NULL)))
|
||||
{
|
||||
CloseFile();
|
||||
return false;
|
||||
@ -281,10 +284,10 @@ bool AVIDump::CreateFile()
|
||||
s_BGRFrame = avcodec_alloc_frame();
|
||||
s_YUVFrame = avcodec_alloc_frame();
|
||||
|
||||
s_size = avpicture_get_size(PIX_FMT_YUV420P, s_width, s_height);
|
||||
s_size = avpicture_get_size(PIX_FMT_BGRA, s_width, s_height);
|
||||
|
||||
s_YUVBuffer = new uint8_t[s_size];
|
||||
avpicture_fill((AVPicture *)s_YUVFrame, s_YUVBuffer, PIX_FMT_YUV420P, s_width, s_height);
|
||||
avpicture_fill((AVPicture *)s_YUVFrame, s_YUVBuffer, PIX_FMT_BGRA, s_width, s_height);
|
||||
|
||||
s_OutBuffer = new uint8_t[s_size];
|
||||
|
||||
|
@ -920,6 +920,8 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle
|
||||
// This function has the final picture. We adjust the aspect ratio here.
|
||||
void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma)
|
||||
{
|
||||
static char* data = 0;
|
||||
static int w = 0, h = 0;
|
||||
if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight)
|
||||
{
|
||||
Core::Callback_VideoCopiedToXFB(false);
|
||||
@ -1120,10 +1122,15 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
D3DLOCKED_RECT rect;
|
||||
if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, dst_rect.AsRECT(), D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY)))
|
||||
{
|
||||
char* data = (char*)malloc(3 * s_recordWidth * s_recordHeight);
|
||||
if (!data || w != s_recordWidth || h != s_recordHeight)
|
||||
{
|
||||
free(data);
|
||||
data = (char*)malloc(3 * s_recordWidth * s_recordHeight);
|
||||
w = s_recordWidth;
|
||||
h = s_recordHeight;
|
||||
}
|
||||
formatBufferDump((const char*)rect.pBits, data, s_recordWidth, s_recordHeight, rect.Pitch);
|
||||
AVIDump::AddFrame(data);
|
||||
free(data);
|
||||
ScreenShootMEMSurface->UnlockRect();
|
||||
}
|
||||
}
|
||||
@ -1133,6 +1140,12 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
{
|
||||
if (s_bLastFrameDumped && s_bAVIDumping)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
data = 0;
|
||||
w = h = 0;
|
||||
}
|
||||
AVIDump::Stop();
|
||||
s_bAVIDumping = false;
|
||||
OSD::AddMessage("Stop dumping frames to AVI", 2000);
|
||||
|
@ -961,8 +961,16 @@ void Renderer::SetBlendMode(bool forceUpdate)
|
||||
// This function has the final picture. We adjust the aspect ratio here.
|
||||
void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma)
|
||||
{
|
||||
static u8 *data = 0;
|
||||
static int w = 0, h = 0;
|
||||
if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight)
|
||||
{
|
||||
if (g_ActiveConfig.bDumpFrames && data)
|
||||
#ifdef _WIN32
|
||||
AVIDump::AddFrame((char *) data);
|
||||
#else
|
||||
AVIDump::AddFrame(data);
|
||||
#endif
|
||||
Core::Callback_VideoCopiedToXFB(false);
|
||||
return;
|
||||
}
|
||||
@ -975,6 +983,12 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
||||
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
if (g_ActiveConfig.bDumpFrames && data)
|
||||
#ifdef _WIN32
|
||||
AVIDump::AddFrame((char *) data);
|
||||
#else
|
||||
AVIDump::AddFrame(data);
|
||||
#endif
|
||||
Core::Callback_VideoCopiedToXFB(false);
|
||||
return;
|
||||
}
|
||||
@ -1134,9 +1148,14 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
if (g_ActiveConfig.bDumpFrames)
|
||||
{
|
||||
s_criticalScreenshot.Enter();
|
||||
int w = dst_rect.GetWidth();
|
||||
int h = dst_rect.GetHeight();
|
||||
u8 *data = new u8[3 * w * h];
|
||||
if (!data || w != dst_rect.GetWidth() ||
|
||||
h != dst_rect.GetHeight())
|
||||
{
|
||||
if (data) delete[] data;
|
||||
w = dst_rect.GetWidth();
|
||||
h = dst_rect.GetHeight();
|
||||
data = new u8[3 * w * h];
|
||||
}
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
|
||||
if (GL_REPORT_ERROR() == GL_NO_ERROR && w > 0 && h > 0)
|
||||
@ -1172,13 +1191,18 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
else
|
||||
NOTICE_LOG(VIDEO, "Error reading framebuffer");
|
||||
|
||||
delete[] data;
|
||||
s_criticalScreenshot.Leave();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_bLastFrameDumped && s_bAVIDumping)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
delete[] data;
|
||||
data = 0;
|
||||
w = h = 0;
|
||||
}
|
||||
AVIDump::Stop();
|
||||
s_bAVIDumping = false;
|
||||
OSD::AddMessage("Stop dumping frames", 2000);
|
||||
|
Loading…
x
Reference in New Issue
Block a user