summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2015-01-26 02:40:52 +0100
committerPierre Bourdon <delroth@gmail.com>2015-01-26 02:40:52 +0100
commit648a676ab511efa7d95c8beea7463d04037a4df0 (patch)
tree485b5470882b50245dc444eb502d470dadc31c49 /Source
parent34079a00379d8fb773e570c2d6fbf8750c0cd7b2 (diff)
parent1e809d9c11079be3ed8985dae42f36595767dcb5 (diff)
Merge pull request #1964 from delroth/master
Revert "Merge pull request #1903 from RisingFog/libav"
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/DolphinQt/DolphinQt.vcxproj2
-rw-r--r--Source/Core/DolphinWX/DolphinWX.vcxproj6
-rw-r--r--Source/Core/DolphinWX/VideoConfigDiag.cpp10
-rw-r--r--Source/Core/VideoBackends/D3D/Render.cpp15
-rw-r--r--Source/Core/VideoBackends/D3D/Render.h1
-rw-r--r--Source/Core/VideoBackends/OGL/Render.cpp63
-rw-r--r--Source/Core/VideoCommon/AVIDump.cpp322
-rw-r--r--Source/Core/VideoCommon/AVIDump.h4
-rw-r--r--Source/Core/VideoCommon/CMakeLists.txt6
-rw-r--r--Source/Core/VideoCommon/RenderBase.cpp5
-rw-r--r--Source/Core/VideoCommon/RenderBase.h3
-rw-r--r--Source/Core/VideoCommon/VideoCommon.vcxproj20
-rw-r--r--Source/UnitTests/UnitTests.vcxproj2
13 files changed, 379 insertions, 80 deletions
diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj
index 81a8312850..d60849aeae 100644
--- a/Source/Core/DolphinQt/DolphinQt.vcxproj
+++ b/Source/Core/DolphinQt/DolphinQt.vcxproj
@@ -162,7 +162,7 @@
<!--Copy Exe, Data directory and DLLs which should be located in the executable directory-->
<ItemGroup>
<DataDirFiles Include="$(DolphinRootDir)Data\**\*.*" />
- <ExternalDlls Include="$(ExternalsDir)OpenAL\$(PlatformName)\*.dll;$(ExternalsDir)ffmpeg\shared\bin\*.dll;$(ExternalsDir)msvcrt\$(PlatformName)\*.dll" />
+ <ExternalDlls Include="$(ExternalsDir)OpenAL\$(PlatformName)\*.dll;$(ExternalsDir)msvcrt\$(PlatformName)\*.dll" />
<BinaryFiles Include="$(TargetPath)" />
<AllInputFiles Include="@(DataDirFiles);@(ExternalDlls);@(BinaryFiles)" />
</ItemGroup>
diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj
index bc14dde23f..033c70e7d3 100644
--- a/Source/Core/DolphinWX/DolphinWX.vcxproj
+++ b/Source/Core/DolphinWX/DolphinWX.vcxproj
@@ -40,14 +40,12 @@
<BaseAddress>0x00400000</BaseAddress>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<FixedBaseAddress>true</FixedBaseAddress>
- <AdditionalLibraryDirectories>$(ExternalsDir)ffmpeg\dev\lib\;$(ExternalsDir)OpenAL\$(PlatformName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>$(ExternalsDir)OpenAL\$(PlatformName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>iphlpapi.lib;winmm.lib;setupapi.lib;vfw32.lib;opengl32.lib;glu32.lib;rpcrt4.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>$(ExternalsDir)wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
- <ClCompile />
- <ClCompile />
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AboutDolphin.cpp" />
@@ -218,7 +216,7 @@
<!--Copy Exe, Data directory and DLLs which should be located in the executable directory-->
<ItemGroup>
<DataDirFiles Include="$(DolphinRootDir)Data\**\*.*" />
- <ExternalDlls Include="$(ExternalsDir)OpenAL\$(PlatformName)\*.dll;$(ExternalsDir)ffmpeg\shared\bin\*.dll;$(ExternalsDir)msvcrt\$(PlatformName)\*.dll" />
+ <ExternalDlls Include="$(ExternalsDir)OpenAL\$(PlatformName)\*.dll;$(ExternalsDir)msvcrt\$(PlatformName)\*.dll" />
<BinaryFiles Include="$(TargetPath)" />
<AllInputFiles Include="@(DataDirFiles);@(ExternalDlls);@(BinaryFiles)" />
</ItemGroup>
diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp
index 8661c08948..93cf7b1078 100644
--- a/Source/Core/DolphinWX/VideoConfigDiag.cpp
+++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp
@@ -138,10 +138,10 @@ static wxString efb_copy_regions_desc = wxTRANSLATE("[BROKEN]\nHighlight regions
static wxString xfb_desc = wxTRANSLATE("Disable any XFB emulation.\nSpeeds up emulation a lot but causes heavy glitches in many games which rely on them (especially homebrew applications).\n\nIf unsure, leave this checked.");
static wxString xfb_virtual_desc = wxTRANSLATE("Emulate XFBs using GPU texture objects.\nFixes many games which don't work without XFB emulation while not being as slow as real XFB emulation. However, it may still fail for a lot of other games (especially homebrew applications).\n\nIf unsure, leave this checked.");
static wxString xfb_real_desc = wxTRANSLATE("Emulate XFBs accurately.\nSlows down emulation a lot and prohibits high-resolution rendering but is necessary to emulate a number of games properly.\n\nIf unsure, check virtual XFB emulation instead.");
-static wxString dump_textures_desc = wxTRANSLATE("Dump decoded game textures to User/Dump/Textures/<game_id>/\n\nIf unsure, leave this unchecked.");
-static wxString load_hires_textures_desc = wxTRANSLATE("Load custom textures from User/Load/Textures/<game_id>/\n\nIf unsure, leave this unchecked.");
-static wxString dump_efb_desc = wxTRANSLATE("Dump the contents of EFB copies to User/Dump/Textures/\n\nIf unsure, leave this unchecked.");
-#if defined(HAVE_LIBAV) || defined (WIN32)
+static wxString dump_textures_desc = wxTRANSLATE("Dump decoded game textures to User/Dump/Textures/<game_id>/.\n\nIf unsure, leave this unchecked.");
+static wxString load_hires_textures_desc = wxTRANSLATE("Load custom textures from User/Load/Textures/<game_id>/.\n\nIf unsure, leave this unchecked.");
+static wxString dump_efb_desc = wxTRANSLATE("Dump the contents of EFB copies to User/Dump/Textures/.\n\nIf unsure, leave this unchecked.");
+#if !defined WIN32 && defined HAVE_LIBAV
static wxString use_ffv1_desc = wxTRANSLATE("Encode frame dumps using the FFV1 codec.\n\nIf unsure, leave this unchecked.");
#endif
static wxString free_look_desc = wxTRANSLATE("This feature allows you to change the game's camera.\nMove the mouse while holding the right mouse button to pan and while holding the middle button to move.\nHold SHIFT and press one of the WASD keys to move the camera by a certain step distance (SHIFT+2 to move faster and SHIFT+1 to move slower). Press SHIFT+R to reset the camera and SHIFT+F to reset the speed.\n\nIf unsure, leave this unchecked.");
@@ -594,7 +594,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
szr_utility->Add(CreateCheckBox(page_advanced, _("Load Custom Textures"), wxGetTranslation(load_hires_textures_desc), vconfig.bHiresTextures));
szr_utility->Add(CreateCheckBox(page_advanced, _("Dump EFB Target"), wxGetTranslation(dump_efb_desc), vconfig.bDumpEFBTarget));
szr_utility->Add(CreateCheckBox(page_advanced, _("Free Look"), wxGetTranslation(free_look_desc), vconfig.bFreeLook));
-#if defined(HAVE_LIBAV) || defined (WIN32)
+#if !defined WIN32 && defined HAVE_LIBAV
szr_utility->Add(CreateCheckBox(page_advanced, _("Frame Dumps use FFV1"), wxGetTranslation(use_ffv1_desc), vconfig.bUseFFV1));
#endif
diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp
index c3a0aba4f2..23f9ceae2d 100644
--- a/Source/Core/VideoBackends/D3D/Render.cpp
+++ b/Source/Core/VideoBackends/D3D/Render.cpp
@@ -802,7 +802,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
{
s_recordWidth = GetTargetRectangle().GetWidth();
s_recordHeight = GetTargetRectangle().GetHeight();
- bAVIDumping = AVIDump::Start(s_recordWidth, s_recordHeight);
+ bAVIDumping = AVIDump::Start(D3D::hWnd, s_recordWidth, s_recordHeight);
if (!bAVIDumping)
{
PanicAlert("Error dumping frames to AVI.");
@@ -827,7 +827,6 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
h = s_recordHeight;
}
formatBufferDump((u8*)map.pData, &frame_data[0], s_recordWidth, s_recordHeight, map.RowPitch);
- FlipImageData(&frame_data[0], w, h);
AVIDump::AddFrame(&frame_data[0], GetTargetRectangle().GetWidth(), GetTargetRectangle().GetHeight());
D3D::context->Unmap(s_screenshot_texture, 0);
}
@@ -1280,16 +1279,4 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D
}
}
-void Renderer::FlipImageData(u8 *data, int w, int h, int pixel_width)
-{
- for (int y = 0; y < h / 2; ++y)
- {
- for (int x = 0; x < w; ++x)
- {
- for (int delta = 0; delta < pixel_width; ++delta)
- std::swap(data[(y * w + x) * pixel_width + delta], data[((h - 1 - y) * w + x) * pixel_width + delta]);
- }
- }
-}
-
} // namespace DX11
diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h
index 47984f6e6b..020dc9d85a 100644
--- a/Source/Core/VideoBackends/D3D/Render.h
+++ b/Source/Core/VideoBackends/D3D/Render.h
@@ -31,7 +31,6 @@ public:
void RestoreCull();
void RenderText(const std::string& text, int left, int top, u32 color) override;
- void FlipImageData(u8 *data, int w, int h, int pixel_width = 3);
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
u16 BBoxRead(int index) override;
diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp
index d3abafcfc0..019f5d2556 100644
--- a/Source/Core/VideoBackends/OGL/Render.cpp
+++ b/Source/Core/VideoBackends/OGL/Render.cpp
@@ -35,9 +35,6 @@
#include "VideoBackends/OGL/TextureConverter.h"
#include "VideoBackends/OGL/VertexManager.h"
-#if defined(HAVE_LIBAV) || defined (WIN32)
-#include "VideoCommon/AVIDump.h"
-#endif
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/BPStructs.h"
#include "VideoCommon/DriverDetails.h"
@@ -53,6 +50,10 @@
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h"
+#if defined _WIN32 || defined HAVE_LIBAV
+#include "VideoCommon/AVIDump.h"
+#endif
+
void VideoConfig::UpdateProjectionHack()
{
@@ -1417,7 +1418,7 @@ void Renderer::SetBlendMode(bool forceUpdate)
static void DumpFrame(const std::vector<u8>& data, int w, int h)
{
-#if defined(HAVE_LIBAV) || defined (WIN32)
+#if defined(HAVE_LIBAV) || defined(_WIN32)
if (SConfig::GetInstance().m_DumpFrames && !data.empty())
{
AVIDump::AddFrame(&data[0], w, h);
@@ -1537,7 +1538,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
// Frame dumping disabled entirely on GLES3
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
{
-#if defined(HAVE_LIBAV) || defined (WIN32)
+#if defined _WIN32 || defined HAVE_LIBAV
if (SConfig::GetInstance().m_DumpFrames)
{
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
@@ -1554,7 +1555,11 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
{
if (!bLastFrameDumped)
{
- bAVIDumping = AVIDump::Start(w, h);
+ #ifdef _WIN32
+ bAVIDumping = AVIDump::Start(nullptr, w, h);
+ #else
+ bAVIDumping = AVIDump::Start(w, h);
+ #endif
if (!bAVIDumping)
{
OSD::AddMessage("AVIDump Start failed", 2000);
@@ -1568,8 +1573,11 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
}
if (bAVIDumping)
{
- FlipImageData(&frame_data[0], w, h);
- AVIDump::AddFrame(&frame_data[0], w, h);
+ #ifndef _WIN32
+ FlipImageData(&frame_data[0], w, h);
+ #endif
+
+ AVIDump::AddFrame(&frame_data[0], w, h);
}
bLastFrameDumped = true;
@@ -1591,6 +1599,45 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
}
bLastFrameDumped = false;
}
+#else
+ if (SConfig::GetInstance().m_DumpFrames)
+ {
+ std::lock_guard<std::mutex> lk(s_criticalScreenshot);
+ std::string movie_file_name;
+ w = GetTargetRectangle().GetWidth();
+ h = GetTargetRectangle().GetHeight();
+ frame_data.resize(3 * w * h);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glReadPixels(GetTargetRectangle().left, GetTargetRectangle().bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, &frame_data[0]);
+
+ if (!bLastFrameDumped)
+ {
+ movie_file_name = File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump.raw";
+ File::CreateFullPath(movie_file_name);
+ pFrameDump.Open(movie_file_name, "wb");
+ if (!pFrameDump)
+ {
+ OSD::AddMessage("Error opening framedump.raw for writing.", 2000);
+ }
+ else
+ {
+ OSD::AddMessage(StringFromFormat("Dumping Frames to \"%s\" (%dx%d RGB24)", movie_file_name.c_str(), w, h), 2000);
+ }
+ }
+ if (pFrameDump)
+ {
+ FlipImageData(&frame_data[0], w, h);
+ pFrameDump.WriteBytes(&frame_data[0], w * 3 * h);
+ pFrameDump.Flush();
+ }
+ bLastFrameDumped = true;
+ }
+ else
+ {
+ if (bLastFrameDumped)
+ pFrameDump.Close();
+ bLastFrameDumped = false;
+ }
#endif
}
// Finish up the current frame, print some stats
diff --git a/Source/Core/VideoCommon/AVIDump.cpp b/Source/Core/VideoCommon/AVIDump.cpp
index e70189eb94..1dcbbe4d9c 100644
--- a/Source/Core/VideoCommon/AVIDump.cpp
+++ b/Source/Core/VideoCommon/AVIDump.cpp
@@ -8,19 +8,11 @@
#include <string>
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libavutil/mathematics.h>
-#include <libswscale/swscale.h>
-}
-
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Common/Logging/Log.h"
-#include "Core/ConfigManager.h" // for PAL60
#include "Core/CoreTiming.h"
#include "Core/HW/SystemTimers.h"
#include "Core/HW/VideoInterface.h" //for TargetRefreshRate
@@ -33,9 +25,299 @@ extern "C" {
#include <cstdio>
#include <cstring>
+#include <vfw.h>
#include <winerror.h>
-#endif
+#include "Core/ConfigManager.h" // for PAL60
+#include "Core/CoreTiming.h"
+
+static HWND s_emu_wnd;
+static LONG s_byte_buffer;
+static LONG s_frame_count;
+static LONG s_total_bytes;
+static PAVIFILE s_file;
+static int s_width;
+static int s_height;
+static int s_file_count;
+static u64 s_last_frame;
+static PAVISTREAM s_stream;
+static PAVISTREAM s_stream_compressed;
+static int s_frame_rate;
+static AVISTREAMINFO s_header;
+static AVICOMPRESSOPTIONS s_options;
+static AVICOMPRESSOPTIONS* s_array_options[1];
+static BITMAPINFOHEADER s_bitmap;
+// the CFR dump design doesn't let you dump until you know the NEXT timecode.
+// so we have to save a frame and always be behind
+static void* s_stored_frame = nullptr;
+static u64 s_stored_frame_size = 0;
+static bool s_start_dumping = false;
+
+bool AVIDump::Start(HWND hWnd, int w, int h)
+{
+ s_emu_wnd = hWnd;
+ s_file_count = 0;
+
+ s_width = w;
+ s_height = h;
+
+ s_last_frame = CoreTiming::GetTicks();
+
+ if (SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.E60"))
+ s_frame_rate = 60; // always 60, for either pal60 or ntsc
+ else
+ s_frame_rate = VideoInterface::TargetRefreshRate; // 50 or 60, depending on region
+
+ // clear CFR frame cache on start, not on file create (which is also segment switch)
+ SetBitmapFormat();
+ StoreFrame(nullptr);
+
+ return CreateFile();
+}
+
+bool AVIDump::CreateFile()
+{
+ s_total_bytes = 0;
+ s_frame_count = 0;
+
+ std::string movie_file_name = StringFromFormat("%sframedump%d.avi", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), s_file_count);
+
+ // Create path
+ File::CreateFullPath(movie_file_name);
+
+ // Ask to delete file
+ if (File::Exists(movie_file_name))
+ {
+ if (AskYesNoT("Delete the existing file '%s'?", movie_file_name.c_str()))
+ File::Delete(movie_file_name);
+ }
+
+ AVIFileInit();
+ NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name.c_str());
+ // TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG
+ HRESULT hr = AVIFileOpenA(&s_file, movie_file_name.c_str(), OF_WRITE | OF_CREATE, nullptr);
+ if (FAILED(hr))
+ {
+ if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format.");
+ if (hr == AVIERR_MEMORY) NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory.");
+ if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file.");
+ if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file.");
+ if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered");
+ Stop();
+ return false;
+ }
+
+ SetBitmapFormat();
+ NOTICE_LOG(VIDEO, "Setting video format...");
+ if (!SetVideoFormat())
+ {
+ NOTICE_LOG(VIDEO, "Setting video format failed");
+ Stop();
+ return false;
+ }
+
+ if (!s_file_count)
+ {
+ if (!SetCompressionOptions())
+ {
+ NOTICE_LOG(VIDEO, "SetCompressionOptions failed");
+ Stop();
+ return false;
+ }
+ }
+
+ if (FAILED(AVIMakeCompressedStream(&s_stream_compressed, s_stream, &s_options, nullptr)))
+ {
+ NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed");
+ Stop();
+ return false;
+ }
+
+ if (FAILED(AVIStreamSetFormat(s_stream_compressed, 0, &s_bitmap, s_bitmap.biSize)))
+ {
+ NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed");
+ Stop();
+ return false;
+ }
+
+ return true;
+}
+
+void AVIDump::CloseFile()
+{
+ if (s_stream_compressed)
+ {
+ AVIStreamClose(s_stream_compressed);
+ s_stream_compressed = nullptr;
+ }
+
+ if (s_stream)
+ {
+ AVIStreamClose(s_stream);
+ s_stream = nullptr;
+ }
+
+ if (s_file)
+ {
+ AVIFileRelease(s_file);
+ s_file = nullptr;
+ }
+
+ AVIFileExit();
+}
+
+void AVIDump::Stop()
+{
+ // store one copy of the last video frame, CFR case
+ if (s_stream_compressed)
+ AVIStreamWrite(s_stream_compressed, s_frame_count++, 1, GetFrame(), s_bitmap.biSizeImage, AVIIF_KEYFRAME, nullptr, &s_byte_buffer);
+ s_start_dumping = false;
+ CloseFile();
+ s_file_count = 0;
+ NOTICE_LOG(VIDEO, "Stop");
+}
+
+void AVIDump::StoreFrame(const void* data)
+{
+ if (s_bitmap.biSizeImage > s_stored_frame_size)
+ {
+ void* temp_stored_frame = realloc(s_stored_frame, s_bitmap.biSizeImage);
+ if (temp_stored_frame)
+ {
+ s_stored_frame = temp_stored_frame;
+ }
+ else
+ {
+ free(s_stored_frame);
+ PanicAlert("Something has gone seriously wrong.\n"
+ "Stopping video recording.\n"
+ "Your video will likely be broken.");
+ Stop();
+ }
+ s_stored_frame_size = s_bitmap.biSizeImage;
+ memset(s_stored_frame, 0, s_bitmap.biSizeImage);
+ }
+ if (s_stored_frame)
+ {
+ if (data)
+ memcpy(s_stored_frame, data, s_bitmap.biSizeImage);
+ else // pitch black frame
+ memset(s_stored_frame, 0, s_bitmap.biSizeImage);
+ }
+}
+
+void* AVIDump::GetFrame()
+{
+ return s_stored_frame;
+}
+
+void AVIDump::AddFrame(const u8* data, int w, int h)
+{
+ static bool shown_error = false;
+ if ((w != s_bitmap.biWidth || h != s_bitmap.biHeight) && !shown_error)
+ {
+ 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.");
+ shown_error = true;
+
+ s_bitmap.biWidth = w;
+ s_bitmap.biHeight = h;
+ }
+ // no timecodes, instead dump each frame as many/few times as needed to keep sync
+ u64 one_cfr = SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
+ int nplay = 0;
+ s64 delta;
+ if (!s_start_dumping && s_last_frame <= SystemTimers::GetTicksPerSecond())
+ {
+ delta = CoreTiming::GetTicks();
+ s_start_dumping = true;
+ }
+ else
+ {
+ delta = CoreTiming::GetTicks() - s_last_frame;
+ }
+ bool b_frame_dumped = false;
+ // try really hard to place one copy of frame in stream (otherwise it's dropped)
+ if (delta > (s64)one_cfr * 3 / 10) // place if 3/10th of a frame space
+ {
+ delta -= one_cfr;
+ nplay++;
+ }
+ // try not nearly so hard to place additional copies of the frame
+ while (delta > (s64)one_cfr * 8 / 10) // place if 8/10th of a frame space
+ {
+ delta -= one_cfr;
+ nplay++;
+ }
+ while (nplay--)
+ {
+ if (!b_frame_dumped)
+ {
+ AVIStreamWrite(s_stream_compressed, s_frame_count++, 1, GetFrame(), s_bitmap.biSizeImage, AVIIF_KEYFRAME, nullptr, &s_byte_buffer);
+ b_frame_dumped = true;
+ }
+ else
+ {
+ AVIStreamWrite(s_stream, s_frame_count++, 1, nullptr, 0, 0, nullptr, nullptr);
+ }
+ s_total_bytes += s_byte_buffer;
+ // Close the recording if the file is larger than 2gb
+ // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb.
+ if (s_total_bytes >= 2000000000)
+ {
+ CloseFile();
+ s_file_count++;
+ CreateFile();
+ }
+ }
+ StoreFrame(data);
+ s_last_frame = CoreTiming::GetTicks();
+}
+
+void AVIDump::SetBitmapFormat()
+{
+ memset(&s_bitmap, 0, sizeof(s_bitmap));
+ s_bitmap.biSize = 0x28;
+ s_bitmap.biPlanes = 1;
+ s_bitmap.biBitCount = 24;
+ s_bitmap.biWidth = s_width;
+ s_bitmap.biHeight = s_height;
+ s_bitmap.biSizeImage = 3 * s_width * s_height;
+}
+
+bool AVIDump::SetCompressionOptions()
+{
+ memset(&s_options, 0, sizeof(s_options));
+ s_array_options[0] = &s_options;
+
+ return (AVISaveOptions(s_emu_wnd, 0, 1, &s_stream, s_array_options) != 0);
+}
+
+bool AVIDump::SetVideoFormat()
+{
+ memset(&s_header, 0, sizeof(s_header));
+ s_header.fccType = streamtypeVIDEO;
+ s_header.dwScale = 1;
+ s_header.dwRate = s_frame_rate;
+ s_header.dwSuggestedBufferSize = s_bitmap.biSizeImage;
+
+ return SUCCEEDED(AVIFileCreateStream(s_file, &s_stream, &s_header));
+}
+
+#else
+
+#include "Common/CommonPaths.h"
+#include "Common/FileUtil.h"
+#include "Common/StringUtil.h"
+#include "Common/Logging/Log.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
+#include <libavutil/mathematics.h>
+}
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1)
#define av_frame_alloc avcodec_alloc_frame
@@ -54,7 +336,6 @@ static int s_size;
static u64 s_last_frame;
static bool s_start_dumping = false;
static u64 s_last_pts;
-static int s_frame_rate;
static void InitAVCodec()
{
@@ -74,11 +355,6 @@ bool AVIDump::Start(int w, int h)
s_last_frame = CoreTiming::GetTicks();
s_last_pts = 0;
- if (SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.E60"))
- s_frame_rate = 60; // always 60, for either pal60 or ntsc
- else
- s_frame_rate = VideoInterface::TargetRefreshRate; // 50 or 60, depending on region
-
InitAVCodec();
bool success = CreateFile();
if (!success)
@@ -107,8 +383,7 @@ bool AVIDump::CreateFile()
s_stream->codec->bit_rate = 400000;
s_stream->codec->width = s_width;
s_stream->codec->height = s_height;
- s_stream->codec->time_base.num = 1;
- s_stream->codec->time_base.den = s_frame_rate;
+ s_stream->codec->time_base = (AVRational){1, static_cast<int>(VideoInterface::TargetRefreshRate)};
s_stream->codec->gop_size = 12;
s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P;
@@ -256,9 +531,10 @@ void AVIDump::CloseFile()
s_sws_context = nullptr;
}
}
-#if defined(HAVE_LIBAV) || defined (WIN32)
- void AVIDump::DoState()
- {
- s_last_frame = CoreTiming::GetTicks();
- }
-#endif \ No newline at end of file
+
+#endif
+
+void AVIDump::DoState()
+{
+ s_last_frame = CoreTiming::GetTicks();
+}
diff --git a/Source/Core/VideoCommon/AVIDump.h b/Source/Core/VideoCommon/AVIDump.h
index d56b4185b6..be6d4eed95 100644
--- a/Source/Core/VideoCommon/AVIDump.h
+++ b/Source/Core/VideoCommon/AVIDump.h
@@ -25,7 +25,11 @@ private:
static void* GetFrame();
public:
+#ifdef _WIN32
+ static bool Start(HWND hWnd, int w, int h);
+#else
static bool Start(int w, int h);
+#endif
static void AddFrame(const u8* data, int width, int height);
static void Stop();
static void DoState();
diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt
index 7010652045..ceb83564f1 100644
--- a/Source/Core/VideoCommon/CMakeLists.txt
+++ b/Source/Core/VideoCommon/CMakeLists.txt
@@ -59,6 +59,8 @@ endif()
add_dolphin_library(videocommon "${SRCS}" "${LIBS}")
-if(LIBAV_FOUND)
- target_link_libraries(videocommon ${LIBS} ${LIBAV_LIBRARIES})
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ if(LIBAV_FOUND)
+ target_link_libraries(videocommon ${LIBS} ${LIBAV_LIBRARIES})
+ endif()
endif()
diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp
index 27d3ef5f55..3e95eca5cc 100644
--- a/Source/Core/VideoCommon/RenderBase.cpp
+++ b/Source/Core/VideoCommon/RenderBase.cpp
@@ -84,6 +84,7 @@ Renderer::Renderer()
{
UpdateActiveConfig();
TextureCache::OnConfigChanged(g_ActiveConfig);
+
#if defined _WIN32 || defined HAVE_LIBAV
bAVIDumping = false;
#endif
@@ -98,9 +99,13 @@ Renderer::~Renderer()
prev_efb_format = PEControl::INVALID_FMT;
efb_scale_numeratorX = efb_scale_numeratorY = efb_scale_denominatorX = efb_scale_denominatorY = 1;
+
#if defined _WIN32 || defined HAVE_LIBAV
if (SConfig::GetInstance().m_DumpFrames && bLastFrameDumped && bAVIDumping)
AVIDump::Stop();
+#else
+ if (pFrameDump.IsOpen())
+ pFrameDump.Close();
#endif
}
diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h
index a1276b2fb3..1f89ef828c 100644
--- a/Source/Core/VideoCommon/RenderBase.h
+++ b/Source/Core/VideoCommon/RenderBase.h
@@ -139,8 +139,9 @@ protected:
#if defined _WIN32 || defined HAVE_LIBAV
bool bAVIDumping;
+#else
+ File::IOFile pFrameDump;
#endif
-
std::vector<u8> frame_data;
bool bLastFrameDumped;
diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj
index 5af578ac88..649cd5095e 100644
--- a/Source/Core/VideoCommon/VideoCommon.vcxproj
+++ b/Source/Core/VideoCommon/VideoCommon.vcxproj
@@ -34,26 +34,6 @@
<Import Project="..\..\VSProps\PCHUse.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <AdditionalIncludeDirectories>$(ExternalsDir)ffmpeg\dev\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- </ClCompile>
- <Lib>
- <AdditionalDependencies>$(ExternalsDir)ffmpeg\dev\lib\swscale.lib;$(ExternalsDir)ffmpeg\dev\lib\avutil.lib;$(ExternalsDir)ffmpeg\dev\lib\avcodec.lib;$(ExternalsDir)ffmpeg\dev\lib\avformat.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Lib>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <AdditionalIncludeDirectories>$(ExternalsDir)ffmpeg\dev\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- </ClCompile>
- <Lib>
- <AdditionalDependencies>$(ExternalsDir)ffmpeg\dev\lib\swscale.lib;$(ExternalsDir)ffmpeg\dev\lib\avutil.lib;$(ExternalsDir)ffmpeg\dev\lib\avcodec.lib;$(ExternalsDir)ffmpeg\dev\lib\avformat.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Lib>
- </ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AVIDump.cpp" />
<ClCompile Include="BoundingBox.cpp" />
diff --git a/Source/UnitTests/UnitTests.vcxproj b/Source/UnitTests/UnitTests.vcxproj
index 472479d696..a67c8e5ac0 100644
--- a/Source/UnitTests/UnitTests.vcxproj
+++ b/Source/UnitTests/UnitTests.vcxproj
@@ -93,7 +93,7 @@
OutDir :)
-->
<ItemGroup>
- <ExternalDlls Include="$(ExternalsDir)ffmpeg\shared\bin\*.dll;$(ExternalsDir)OpenAL\$(PlatformName)\*.dll" />
+ <ExternalDlls Include="$(ExternalsDir)OpenAL\$(PlatformName)\*.dll" />
</ItemGroup>
<!--Either method of running requires the runtime deps to be copied to pwd-->
<Target Name="CopyDeps"