summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/AVIDump.cpp
diff options
context:
space:
mode:
authorFog <christhecoolist@gmail.com>2015-01-17 13:47:07 -0500
committerFog <christhecoolist@gmail.com>2015-01-21 19:47:45 -0500
commit6cad635bd887634b1908c61ef6039420890b2ba2 (patch)
tree270a4732080bb71e846b98931bccbf6815d97ca2 /Source/Core/VideoCommon/AVIDump.cpp
parente7f2a04699c0e7e622028b4feba07fb6f46142bf (diff)
Use ffmpeg for Windows Video Dumping instead of VFW
Diffstat (limited to 'Source/Core/VideoCommon/AVIDump.cpp')
-rw-r--r--Source/Core/VideoCommon/AVIDump.cpp322
1 files changed, 23 insertions, 299 deletions
diff --git a/Source/Core/VideoCommon/AVIDump.cpp b/Source/Core/VideoCommon/AVIDump.cpp
index 1dcbbe4d9c..e70189eb94 100644
--- a/Source/Core/VideoCommon/AVIDump.cpp
+++ b/Source/Core/VideoCommon/AVIDump.cpp
@@ -8,11 +8,19 @@
#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
@@ -25,299 +33,9 @@
#include <cstdio>
#include <cstring>
-#include <vfw.h>
#include <winerror.h>
-#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>
-}
+#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1)
#define av_frame_alloc avcodec_alloc_frame
@@ -336,6 +54,7 @@ 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()
{
@@ -355,6 +74,11 @@ 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)
@@ -383,7 +107,8 @@ 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 = (AVRational){1, static_cast<int>(VideoInterface::TargetRefreshRate)};
+ s_stream->codec->time_base.num = 1;
+ s_stream->codec->time_base.den = s_frame_rate;
s_stream->codec->gop_size = 12;
s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P;
@@ -531,10 +256,9 @@ void AVIDump::CloseFile()
s_sws_context = nullptr;
}
}
-
-#endif
-
-void AVIDump::DoState()
-{
- s_last_frame = CoreTiming::GetTicks();
-}
+#if defined(HAVE_LIBAV) || defined (WIN32)
+ void AVIDump::DoState()
+ {
+ s_last_frame = CoreTiming::GetTicks();
+ }
+#endif \ No newline at end of file