diff --git a/CMakeLists.txt b/CMakeLists.txt index bfd8eb4212..12b7b7874c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1193,7 +1193,9 @@ endif() if (NOT MOBILE_DEVICE) set(CoreExtra ${CoreExtra} Core/AVIDump.cpp - Core/AVIDump.h) + Core/AVIDump.h + Core/WaveFile.cpp + Core/WaveFile.h) endif() if(ARMV7) @@ -1218,8 +1220,6 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HDRemaster.cpp Core/HDRemaster.h Core/ThreadEventQueue.h - Core/WaveFile.cpp - Core/WaveFile.h Core/Debugger/Breakpoints.cpp Core/Debugger/Breakpoints.h Core/Debugger/DebugInterface.h diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 25ab77a940..16095915c6 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -26,10 +26,6 @@ extern "C" { #include "Core/Screenshot.h" #include "GPU/Common/GPUDebugInterface.h" -#ifdef _WIN32 -#include "GPU/Directx9/GPU_DX9.h" -#endif -#include "GPU/GLES/GPU_GLES.h" #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1) #define av_frame_alloc avcodec_alloc_frame @@ -48,6 +44,7 @@ static bool s_start_dumping = false; static int s_current_width; static int s_current_height; static int s_file_index = 0; +static GPUDebugBuffer buf; static void InitAVCodec() { @@ -80,10 +77,10 @@ bool AVIDump::CreateAVI() s_format_context = avformat_alloc_context(); std::stringstream s_file_index_str; s_file_index_str << s_file_index; - snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", (GetSysDirectory(DIRECTORY_VIDEO_DUMP) + "framedump" + s_file_index_str.str() + ".avi").c_str()); + snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", (GetSysDirectory(DIRECTORY_VIDEO) + "framedump" + s_file_index_str.str() + ".avi").c_str()); // Make sure that the path exists - if (!File::Exists(GetSysDirectory(DIRECTORY_VIDEO_DUMP))) - File::CreateDir(GetSysDirectory(DIRECTORY_VIDEO_DUMP)); + if (!File::Exists(GetSysDirectory(DIRECTORY_VIDEO))) + File::CreateDir(GetSysDirectory(DIRECTORY_VIDEO)); if (File::Exists(s_format_context->filename)) File::Delete(s_format_context->filename); @@ -150,101 +147,8 @@ static void PreparePacket(AVPacket* pkt) pkt->stream_index = s_stream->index; } -static const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u32 &h) { - // The temp buffer will be freed by the caller if set, and can be the return value. - temp = nullptr; - - w = std::min(w, buf.GetStride()); - h = std::min(h, buf.GetHeight()); - - const u8 *buffer = buf.GetData(); - if (buf.GetFlipped() && buf.GetFormat() == GPU_DBG_FORMAT_888_RGB) { - // Silly OpenGL reads upside down, we flip to another buffer for simplicity. - temp = new u8[3 * w * h]; - for (u32 y = 0; y < h; y++) { - memcpy(temp + y * w * 3, buffer + (buf.GetHeight() - y - 1) * buf.GetStride() * 3, w * 3); - } - buffer = temp; - } - else if (buf.GetFormat() != GPU_DBG_FORMAT_888_RGB) { - // Let's boil it down to how we need to interpret the bits. - int baseFmt = buf.GetFormat() & ~(GPU_DBG_FORMAT_REVERSE_FLAG | GPU_DBG_FORMAT_BRSWAP_FLAG); - bool rev = (buf.GetFormat() & GPU_DBG_FORMAT_REVERSE_FLAG) != 0; - bool brswap = (buf.GetFormat() & GPU_DBG_FORMAT_BRSWAP_FLAG) != 0; - bool flip = buf.GetFlipped(); - - temp = new u8[3 * w * h]; - - // This is pretty inefficient. - const u16 *buf16 = (const u16 *)buffer; - const u32 *buf32 = (const u32 *)buffer; - for (u32 y = 0; y < h; y++) { - for (u32 x = 0; x < w; x++) { - u8 *dst; - if (flip) { - dst = &temp[(h - y - 1) * w * 3 + x * 3]; - } - else { - dst = &temp[y * w * 3 + x * 3]; - } - - u8 &r = brswap ? dst[2] : dst[0]; - u8 &g = dst[1]; - u8 &b = brswap ? dst[0] : dst[2]; - - u32 src; - switch (baseFmt) { - case GPU_DBG_FORMAT_565: - src = buf16[y * buf.GetStride() + x]; - if (rev) { - src = bswap16(src); - } - r = Convert5To8((src >> 0) & 0x1F); - g = Convert6To8((src >> 5) & 0x3F); - b = Convert5To8((src >> 11) & 0x1F); - break; - case GPU_DBG_FORMAT_5551: - src = buf16[y * buf.GetStride() + x]; - if (rev) { - src = bswap16(src); - } - r = Convert5To8((src >> 0) & 0x1F); - g = Convert5To8((src >> 5) & 0x1F); - b = Convert5To8((src >> 10) & 0x1F); - break; - case GPU_DBG_FORMAT_4444: - src = buf16[y * buf.GetStride() + x]; - if (rev) { - src = bswap16(src); - } - r = Convert4To8((src >> 0) & 0xF); - g = Convert4To8((src >> 4) & 0xF); - b = Convert4To8((src >> 8) & 0xF); - break; - case GPU_DBG_FORMAT_8888: - src = buf32[y * buf.GetStride() + x]; - if (rev) { - src = bswap32(src); - } - r = (src >> 0) & 0xFF; - g = (src >> 8) & 0xFF; - b = (src >> 16) & 0xFF; - break; - default: - ERROR_LOG(COMMON, "Unsupported framebuffer format for screenshot: %d", buf.GetFormat()); - return nullptr; - } - } - } - buffer = temp; - } - - return buffer; -} - void AVIDump::AddFrame() { - GPUDebugBuffer buf; gpuDebug->GetCurrentFramebuffer(buf); u32 w = buf.GetStride(); u32 h = buf.GetHeight(); @@ -257,14 +161,10 @@ void AVIDump::AddFrame() s_src_frame->width = s_width; s_src_frame->height = s_height; - // Convert image from BGR24 to desired pixel format, and scale to initial - // width and height - if ((s_sws_context = - sws_getCachedContext(s_sws_context, w, h, AV_PIX_FMT_RGB24, s_width, s_height, - s_stream->codec->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr))) + // Convert image from BGR24 to desired pixel format, and scale to initial width and height + if ((s_sws_context = sws_getCachedContext(s_sws_context, w, h, AV_PIX_FMT_RGB24, s_width, s_height, s_stream->codec->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr))) { - sws_scale(s_sws_context, s_src_frame->data, s_src_frame->linesize, 0, h, - s_scaled_frame->data, s_scaled_frame->linesize); + sws_scale(s_sws_context, s_src_frame->data, s_src_frame->linesize, 0, h, s_scaled_frame->data, s_scaled_frame->linesize); } s_scaled_frame->format = s_stream->codec->pix_fmt; @@ -344,10 +244,9 @@ void AVIDump::CloseFile() void AVIDump::CheckResolution(int width, int height) { // We check here to see if the requested width and height have changed since the last frame which - // was dumped, then create a new file accordingly. However, is it possible for the height - // (possibly width as well, but no examples known) to have a value of zero. This can occur as the - // VI is able to be set to a zero value for height/width to disable output. If this is the case, - // simply keep the last known resolution of the video for the added frame. + // was dumped, then create a new file accordingly. However, is it possible for the width and height + // to have a value of zero. If this is the case, simply keep the last known resolution of the video + // for the added frame. if ((width != s_current_width || height != s_current_height) && (width > 0 && height > 0)) { int temp_file_index = s_file_index; diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 951498ef61..7999cb18ad 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -240,11 +240,6 @@ u64 GetTicks() return (u64)globalTimer + slicelength - currentMIPS->downcount; } -u64 GetTicksPerSecond() -{ - return CPU_HZ; -} - u64 GetIdleTicks() { return (u64)idledCycles; diff --git a/Core/CoreTiming.h b/Core/CoreTiming.h index 82f28aa8f7..ee7a26a714 100644 --- a/Core/CoreTiming.h +++ b/Core/CoreTiming.h @@ -82,7 +82,6 @@ namespace CoreTiming u64 GetIdleTicks(); u64 GetGlobalTimeUs(); u64 GetGlobalTimeUsScaled(); - u64 GetTicksPerSecond(); // Returns the event_type identifier. int RegisterEvent(const char *name, TimedCallback callback); diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 1ffc92800d..84483a0350 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -33,6 +33,9 @@ #include "Core/MemMapHelpers.h" #include "Core/Reporting.h" #include "Core/System.h" +#ifndef MOBILE_DEVICE +#include "Core/WaveFile.h" +#endif #include "Core/HLE/__sceAudio.h" #include "Core/HLE/sceAudio.h" #include "Core/HLE/sceKernel.h" @@ -67,9 +70,11 @@ static int audioIntervalCycles; static int audioHostIntervalCycles; static s32 *mixBuffer; - +static s16 *clampedMixBuffer; +#ifndef MOBILE_DEVICE WaveFileWriter g_wave_writer; -bool m_logAudio; +static bool m_logAudio; +#endif // High and low watermarks, basically. For perfect emulation, the correct values are 0 and 1, respectively. // TODO: Tweak. Hm, there aren't actually even used currently... @@ -134,17 +139,21 @@ void __AudioInit() { chans[i].clear(); mixBuffer = new s32[hwBlockSize * 2]; + clampedMixBuffer = new s16[hwBlockSize * 2]; memset(mixBuffer, 0, hwBlockSize * 2 * sizeof(s32)); resampler.Clear(); CoreTiming::RegisterMHzChangeCallback(&__AudioCPUMHzChange); - +#ifndef MOBILE_DEVICE if (g_Config.bDumpAudio) { - std::string audio_file_name = GetSysDirectory(DIRECTORY_VIDEO_DUMP) + "audiodump.wav"; + std::string audio_file_name = GetSysDirectory(DIRECTORY_AUDIO) + "audiodump.wav"; + // Create the path just in case it doesn't exist + File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); File::CreateEmptyFile(audio_file_name); __StartLogAudio(audio_file_name); } +#endif } void __AudioDoState(PointerWrap &p) { @@ -184,15 +193,18 @@ void __AudioDoState(PointerWrap &p) { void __AudioShutdown() { delete [] mixBuffer; + delete [] clampedMixBuffer; mixBuffer = 0; for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) chans[i].clear(); +#ifndef MOBILE_DEVICE if (g_Config.bDumpAudio) { __StopLogAudio(); } +#endif } u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) { @@ -380,15 +392,15 @@ void __AudioUpdate() { if (g_Config.bEnableSound) { resampler.PushSamples(mixBuffer, hwBlockSize); +#ifndef MOBILE_DEVICE if (m_logAudio) { - s16 *clamped_data = new s16[hwBlockSize * 2]; - for (int i = 0; i < hwBlockSize * 2; i++) { - clamped_data[i] = clamp_s16(mixBuffer[i]); + clampedMixBuffer[i] = clamp_s16(mixBuffer[i]); } - g_wave_writer.AddStereoSamples(clamped_data, hwBlockSize); + g_wave_writer.AddStereoSamples(clampedMixBuffer, hwBlockSize); } +#endif } } @@ -410,7 +422,7 @@ void __PushExternalAudio(const s32 *audio, int numSamples) { resampler.Clear(); } } - +#ifndef MOBILE_DEVICE void __StartLogAudio(const std::string& filename) { if (!m_logAudio) @@ -439,3 +451,4 @@ void __StopLogAudio() WARN_LOG(SCEAUDIO, "Audio logging has already been stopped"); } } +#endif diff --git a/Core/HLE/__sceAudio.h b/Core/HLE/__sceAudio.h index 99dcabd130..87365fb361 100644 --- a/Core/HLE/__sceAudio.h +++ b/Core/HLE/__sceAudio.h @@ -18,7 +18,6 @@ #pragma once #include "sceAudio.h" -#include "Core/WaveFile.h" struct AudioDebugStats { int buffered; diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index 93acd0a1f5..cdbc811e47 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -211,7 +211,7 @@ static u32 sceAudioChReserve(int chan, u32 sampleCount, u32 format) { ERROR_LOG(SCEAUDIO, "sceAudioChReserve - no channels remaining"); return SCE_ERROR_AUDIO_NO_CHANNELS_AVAILABLE; } - } + } if ((u32)chan >= PSP_AUDIO_CHANNEL_MAX) { ERROR_LOG(SCEAUDIO, "sceAudioChReserve(%08x, %08x, %08x) - bad channel", chan, sampleCount, format); return SCE_ERROR_AUDIO_INVALID_CHANNEL; @@ -457,7 +457,7 @@ static u32 sceAudioRoutingGetVolumeMode() { return defaultRoutingVolMode; } -const HLEFunction sceAudio[] = +const HLEFunction sceAudio[] = { // Newer simplified single channel audio output. Presumably for games that use Atrac3 // directly from Sas instead of playing it on a separate audio channel. diff --git a/Core/HW/StereoResampler.h b/Core/HW/StereoResampler.h index b0f44de313..77b55c7e28 100644 --- a/Core/HW/StereoResampler.h +++ b/Core/HW/StereoResampler.h @@ -25,7 +25,6 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Core/WaveFile.h" struct AudioDebugStats; diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index f949426e24..74a698b58a 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -25,7 +25,6 @@ #include "Common/FileUtil.h" #include "Common/ChunkFile.h" -#include "Core/AVIDump.h" #include "Core/SaveState.h" #include "Core/Config.h" #include "Core/Core.h" diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp index e2175d3bd4..35cd517c9f 100644 --- a/Core/Screenshot.cpp +++ b/Core/Screenshot.cpp @@ -125,7 +125,7 @@ static bool WriteScreenshotToPNG(png_imagep image, const char *filename, int con } #endif -static const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u32 &h) { +const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u32 &h) { // The temp buffer will be freed by the caller if set, and can be the return value. temp = nullptr; diff --git a/Core/Screenshot.h b/Core/Screenshot.h index 3cecc4547e..1f4bdd6d28 100644 --- a/Core/Screenshot.h +++ b/Core/Screenshot.h @@ -17,6 +17,8 @@ #pragma once +class GPUDebugBuffer; + enum ScreenshotFormat { SCREENSHOT_PNG, SCREENSHOT_JPG, @@ -30,4 +32,6 @@ enum ScreenshotType { SCREENSHOT_RENDER, }; +const u8 * ConvertBufferTo888RGB(const GPUDebugBuffer & buf, u8 *& temp, u32 & w, u32 & h); + bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type, int *width = nullptr, int *height = nullptr, int maxRes = -1); diff --git a/Core/System.cpp b/Core/System.cpp index 7f03be1263..03976499c9 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -593,8 +593,10 @@ std::string GetSysDirectory(PSPDirectories directoryType) { return g_Config.appCacheDirectory; } return g_Config.memStickDirectory + "PSP/SYSTEM/CACHE/"; - case DIRECTORY_VIDEO_DUMP: - return g_Config.memStickDirectory + "PSP/FRAMEDUMP/"; + case DIRECTORY_VIDEO: + return g_Config.memStickDirectory + "PSP/VIDEO/"; + case DIRECTORY_AUDIO: + return g_Config.memStickDirectory + "PSP/AUDIO/"; // Just return the memory stick root if we run into some sort of problem. default: ERROR_LOG(FILESYS, "Unknown directory type."); diff --git a/Core/System.h b/Core/System.h index 2aef7c21e8..b9c5feadf6 100644 --- a/Core/System.h +++ b/Core/System.h @@ -47,7 +47,8 @@ enum PSPDirectories { DIRECTORY_CACHE, DIRECTORY_TEXTURES, DIRECTORY_APP_CACHE, // Use the OS app cache if available - DIRECTORY_VIDEO_DUMP + DIRECTORY_VIDEO, + DIRECTORY_AUDIO }; class GraphicsContext; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 5f2ddeac0c..ffa28b3be9 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -676,9 +676,9 @@ void GameSettingsScreen::CreateViews() { #if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE)) // Screenshot functionality is not yet available on non-Windows/non-Qt systemSettings->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, sy->T("Screenshots as PNG"))); - systemSettings->Add(new CheckBox(&g_Config.bDumpFrames, sy->T("Dump Frames"))); - systemSettings->Add(new CheckBox(&g_Config.bUseFFV1, sy->T("Use FFV1 for Frame Dumps"))); - systemSettings->Add(new CheckBox(&g_Config.bDumpAudio, sy->T("Dump Audio"))); + systemSettings->Add(new CheckBox(&g_Config.bDumpFrames, sy->T("Record Display"))); + systemSettings->Add(new CheckBox(&g_Config.bUseFFV1, sy->T("Use Lossless Video Codec (FFV1)"))); + systemSettings->Add(new CheckBox(&g_Config.bDumpAudio, sy->T("Export Audio"))); #endif systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving"))); static const char *dateFormat[] = { "YYYYMMDD", "MMDDYYYY", "DDMMYYYY"}; diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index a4129d136a..5962e1611b 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -447,9 +447,9 @@ BEGIN POPUP "Movie" BEGIN - MENUITEM "Dump Frames", ID_MOVIE_DUMPFRAMES - MENUITEM "Lossless Codec (FFV1)", ID_MOVIE_USEFFV1 - MENUITEM "Dump Audio", ID_MOVIE_DUMPAUDIO + MENUITEM "Record Display", ID_MOVIE_DUMPFRAMES + MENUITEM "Use Lossless Video Codec (FFV1)", ID_MOVIE_USEFFV1 + MENUITEM "Export Audio", ID_MOVIE_DUMPAUDIO END POPUP "Options"