* 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:
smelenchuk 2011-02-11 18:59:42 +00:00
parent ca78d3639b
commit b0fa0a83f8
13 changed files with 132 additions and 30 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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