Yell at the user if they change window size while dumping frames, and some other avi dumping stuff.

This commit is contained in:
Jordan Woyak
2013-02-26 20:47:48 -05:00
committed by Rachel Bryk
parent 46adbfa9ed
commit f1c990069c
7 changed files with 73 additions and 78 deletions

View File

@ -157,9 +157,21 @@ void AVIDump::Stop()
NOTICE_LOG(VIDEO, "Stop"); NOTICE_LOG(VIDEO, "Stop");
} }
void AVIDump::AddFrame(char *data) void AVIDump::AddFrame(const u8* data, int w, int h)
{ {
AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, (LPVOID) data, m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer); static bool bShownError = false;
if ((w != m_bitmap.biWidth || h != m_bitmap.biHeight) && !bShownError)
{
PanicAlert("You have resized the window while dumping frames.\n"
"Nothing sane can be done to handle this.\n"
"Your video will likely be broken.");
bShownError=true;
m_bitmap.biWidth = w;
m_bitmap.biHeight = h;
}
AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, const_cast<u8*>(data), m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer);
m_totalBytes += m_byteBuffer; m_totalBytes += m_byteBuffer;
// Close the recording if the file is more than 2gb // Close the recording if the file is more than 2gb
// VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb. // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb.
@ -298,7 +310,7 @@ bool AVIDump::CreateFile()
return true; return true;
} }
void AVIDump::AddFrame(uint8_t *data, int width, int height) void AVIDump::AddFrame(const u8* data, int width, int height)
{ {
avpicture_fill((AVPicture *)s_BGRFrame, data, PIX_FMT_BGR24, width, height); avpicture_fill((AVPicture *)s_BGRFrame, data, PIX_FMT_BGR24, width, height);

View File

@ -24,6 +24,8 @@
#include <stdint.h> #include <stdint.h>
#endif #endif
#include "CommonTypes.h"
class AVIDump class AVIDump
{ {
private: private:
@ -36,11 +38,11 @@ class AVIDump
public: public:
#ifdef _WIN32 #ifdef _WIN32
static bool Start(HWND hWnd, int w, int h); static bool Start(HWND hWnd, int w, int h);
static void AddFrame(char *data);
#else #else
static bool Start(int w, int h); static bool Start(int w, int h);
static void AddFrame(uint8_t *data, int width, int height);
#endif #endif
static void AddFrame(const u8* data, int width, int height);
static void Stop(); static void Stop();
}; };

View File

@ -83,7 +83,9 @@ unsigned int Renderer::efb_scale_denominatorY = 1;
unsigned int Renderer::ssaa_multiplier = 1; unsigned int Renderer::ssaa_multiplier = 1;
Renderer::Renderer() : frame_data(NULL), bLastFrameDumped(false) Renderer::Renderer()
: frame_data()
, bLastFrameDumped(false)
{ {
UpdateActiveConfig(); UpdateActiveConfig();
TextureCache::OnConfigChanged(g_ActiveConfig); TextureCache::OnConfigChanged(g_ActiveConfig);
@ -110,7 +112,6 @@ Renderer::~Renderer()
if (pFrameDump.IsOpen()) if (pFrameDump.IsOpen())
pFrameDump.Close(); pFrameDump.Close();
#endif #endif
delete[] frame_data;
} }
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma)

View File

@ -147,7 +147,7 @@ protected:
#else #else
File::IOFile pFrameDump; File::IOFile pFrameDump;
#endif #endif
char* frame_data; std::vector<u8> frame_data;
bool bLastFrameDumped; bool bLastFrameDumped;
// The framebuffer size // The framebuffer size

View File

@ -761,11 +761,11 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle
return SUCCEEDED(hr); return SUCCEEDED(hr);
} }
void formatBufferDump(const char *in, char *out, int w, int h, int p) void formatBufferDump(const u8* in, u8* out, int w, int h, int p)
{ {
for (int y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
const u8 *line = (u8*)(in + (h - y - 1) * p); auto line = (in + (h - y - 1) * p);
for (int x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
out[0] = line[2]; out[0] = line[2];
@ -782,8 +782,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{ {
if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
{ {
if (g_ActiveConfig.bDumpFrames && frame_data) if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(frame_data); AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false); Core::Callback_VideoCopiedToXFB(false);
return; return;
@ -794,8 +794,8 @@ 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 && frame_data) if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(frame_data); AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false); Core::Callback_VideoCopiedToXFB(false);
return; return;
@ -934,16 +934,15 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
D3D11_MAPPED_SUBRESOURCE map; D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map);
if (!frame_data || w != s_recordWidth || h != s_recordHeight) if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight)
{ {
delete[] frame_data; frame_data.resize(3 * s_recordWidth * s_recordHeight);
frame_data = new char[3 * s_recordWidth * s_recordHeight];
w = s_recordWidth; w = s_recordWidth;
h = s_recordHeight; h = s_recordHeight;
} }
char* source_ptr = (char*)map.pData + GetTargetRectangle().left*4 + GetTargetRectangle().top*map.RowPitch; auto source_ptr = (const u8*)map.pData + GetTargetRectangle().left*4 + GetTargetRectangle().top*map.RowPitch;
formatBufferDump(source_ptr, frame_data, s_recordWidth, s_recordHeight, map.RowPitch); formatBufferDump(source_ptr, &frame_data[0], s_recordWidth, s_recordHeight, map.RowPitch);
AVIDump::AddFrame(frame_data); AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
D3D::context->Unmap(s_screenshot_texture, 0); D3D::context->Unmap(s_screenshot_texture, 0);
} }
bLastFrameDumped = true; bLastFrameDumped = true;
@ -952,7 +951,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{ {
if (bLastFrameDumped && bAVIDumping) if (bLastFrameDumped && bAVIDumping)
{ {
SAFE_DELETE_ARRAY(frame_data); std::vector<u8>().swap(frame_data);
w = h = 0; w = h = 0;
AVIDump::Stop(); AVIDump::Stop();

View File

@ -216,11 +216,11 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
} }
void formatBufferDump(const char *in, char *out, int w, int h, int p) void formatBufferDump(const u8* in, u8* out, int w, int h, int p)
{ {
for (int y = 0; y < h; y++) for (int y = 0; y < h; y++)
{ {
const char *line = in + (h - y - 1) * p; auto line = in + (h - y - 1) * p;
for (int x = 0; x < w; x++) for (int x = 0; x < w; x++)
{ {
memcpy(out, line, 3); memcpy(out, line, 3);
@ -725,8 +725,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{ {
if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
{ {
if (g_ActiveConfig.bDumpFrames && frame_data) if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(frame_data); AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false); Core::Callback_VideoCopiedToXFB(false);
return; return;
@ -737,8 +737,8 @@ 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 && frame_data) if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(frame_data); AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false); Core::Callback_VideoCopiedToXFB(false);
return; return;
@ -935,15 +935,14 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
D3DLOCKED_RECT rect; D3DLOCKED_RECT rect;
if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, GetTargetRectangle().AsRECT(), D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))) if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, GetTargetRectangle().AsRECT(), D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY)))
{ {
if (!frame_data || w != s_recordWidth || h != s_recordHeight) if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight)
{ {
delete[] frame_data; frame_data.resize(3 * s_recordWidth * s_recordHeight);
frame_data = new char[3 * s_recordWidth * s_recordHeight];
w = s_recordWidth; w = s_recordWidth;
h = s_recordHeight; h = s_recordHeight;
} }
formatBufferDump((const char*)rect.pBits, frame_data, s_recordWidth, s_recordHeight, rect.Pitch); formatBufferDump((const u8*)rect.pBits, &frame_data[0], s_recordWidth, s_recordHeight, rect.Pitch);
AVIDump::AddFrame(frame_data); AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
ScreenShootMEMSurface->UnlockRect(); ScreenShootMEMSurface->UnlockRect();
} }
} }
@ -953,12 +952,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{ {
if (bLastFrameDumped && bAVIDumping) if (bLastFrameDumped && bAVIDumping)
{ {
if (frame_data) std::vector<u8>().swap(frame_data);
{ w = h = 0;
delete[] frame_data;
frame_data = 0;
w = h = 0;
}
AVIDump::Stop(); AVIDump::Stop();
bAVIDumping = false; bAVIDumping = false;
OSD::AddMessage("Stop dumping frames to AVI", 2000); OSD::AddMessage("Stop dumping frames to AVI", 2000);

View File

@ -956,20 +956,23 @@ void Renderer::SetBlendMode(bool forceUpdate)
s_blendMode = newval; s_blendMode = newval;
} }
void DumpFrame(const std::vector<u8>& data, int w, int h)
{
#if defined(HAVE_LIBAV) || defined(_WIN32)
if (g_ActiveConfig.bDumpFrames && !data.empty())
{
AVIDump::AddFrame(&data[0], w, h);
}
#endif
}
// 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 int w = 0, h = 0; static int w = 0, h = 0;
if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
{ {
if (g_ActiveConfig.bDumpFrames && frame_data) DumpFrame(frame_data, w, h);
{
#ifdef _WIN32
AVIDump::AddFrame(frame_data);
#elif defined HAVE_LIBAV
AVIDump::AddFrame((u8*)frame_data, w, h);
#endif
}
Core::Callback_VideoCopiedToXFB(false); Core::Callback_VideoCopiedToXFB(false);
return; return;
} }
@ -979,14 +982,7 @@ 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 (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0)) if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0))
{ {
if (g_ActiveConfig.bDumpFrames && frame_data) DumpFrame(frame_data, w, h);
{
#ifdef _WIN32
AVIDump::AddFrame(frame_data);
#elif defined HAVE_LIBAV
AVIDump::AddFrame((u8*)frame_data, w, h);
#endif
}
Core::Callback_VideoCopiedToXFB(false); Core::Callback_VideoCopiedToXFB(false);
return; return;
} }
@ -1149,16 +1145,15 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
if (g_ActiveConfig.bDumpFrames) if (g_ActiveConfig.bDumpFrames)
{ {
std::lock_guard<std::mutex> lk(s_criticalScreenshot); std::lock_guard<std::mutex> lk(s_criticalScreenshot);
if (!frame_data || w != flipped_trc.GetWidth() || if (frame_data.empty() || w != flipped_trc.GetWidth() ||
h != flipped_trc.GetHeight()) h != flipped_trc.GetHeight())
{ {
if (frame_data) delete[] frame_data;
w = flipped_trc.GetWidth(); w = flipped_trc.GetWidth();
h = flipped_trc.GetHeight(); h = flipped_trc.GetHeight();
frame_data = new char[3 * w * h]; frame_data.resize(3 * w * h);
} }
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(flipped_trc.left, flipped_trc.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, frame_data); glReadPixels(flipped_trc.left, flipped_trc.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, &frame_data[0]);
if (GL_REPORT_ERROR() == GL_NO_ERROR && w > 0 && h > 0) if (GL_REPORT_ERROR() == GL_NO_ERROR && w > 0 && h > 0)
{ {
if (!bLastFrameDumped) if (!bLastFrameDumped)
@ -1179,12 +1174,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
} }
if (bAVIDumping) if (bAVIDumping)
{ {
#ifdef _WIN32 #ifndef _WIN32
AVIDump::AddFrame(frame_data); FlipImageData(&frame_data[0], w, h);
#else
FlipImageData((u8*)frame_data, w, h);
AVIDump::AddFrame((u8*)frame_data, w, h);
#endif #endif
AVIDump::AddFrame(&frame_data[0], w, h);
} }
bLastFrameDumped = true; bLastFrameDumped = true;
@ -1196,12 +1190,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{ {
if (bLastFrameDumped && bAVIDumping) if (bLastFrameDumped && bAVIDumping)
{ {
if (frame_data) std::vector<u8>().swap(frame_data);
{ w = h = 0;
delete[] frame_data;
frame_data = NULL;
w = h = 0;
}
AVIDump::Stop(); AVIDump::Stop();
bAVIDumping = false; bAVIDumping = false;
OSD::AddMessage("Stop dumping frames", 2000); OSD::AddMessage("Stop dumping frames", 2000);
@ -1215,9 +1205,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
std::string movie_file_name; std::string movie_file_name;
w = GetTargetRectangle().GetWidth(); w = GetTargetRectangle().GetWidth();
h = GetTargetRectangle().GetHeight(); h = GetTargetRectangle().GetHeight();
frame_data = new char[3 * w * h]; frame_data.resize(3 * w * h);
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(GetTargetRectangle().left, GetTargetRectangle().bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, frame_data); glReadPixels(GetTargetRectangle().left, GetTargetRectangle().bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, &frame_data[0]);
if (GL_REPORT_ERROR() == GL_NO_ERROR) if (GL_REPORT_ERROR() == GL_NO_ERROR)
{ {
if (!bLastFrameDumped) if (!bLastFrameDumped)
@ -1228,21 +1218,17 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
OSD::AddMessage("Error opening framedump.raw for writing.", 2000); OSD::AddMessage("Error opening framedump.raw for writing.", 2000);
else else
{ {
char msg [255]; OSD::AddMessage(StromFromFormat("Dumping Frames to \"%s\" (%dx%d RGB24)", movie_file_name.c_str(), w, h), 2000);
sprintf(msg, "Dumping Frames to \"%s\" (%dx%d RGB24)", movie_file_name.c_str(), w, h);
OSD::AddMessage(msg, 2000);
} }
} }
if (pFrameDump) if (pFrameDump)
{ {
FlipImageData((u8*)frame_data, w, h); FlipImageData(&frame_data[0], w, h);
pFrameDump.WriteBytes(frame_data, w * 3 * h); pFrameDump.WriteBytes(&frame_data[0], w * 3 * h);
pFrameDump.Flush(); pFrameDump.Flush();
} }
bLastFrameDumped = true; bLastFrameDumped = true;
} }
delete[] frame_data;
} }
else else
{ {