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