diff options
| author | Fog <christhecoolist@gmail.com> | 2015-01-17 13:47:07 -0500 |
|---|---|---|
| committer | Fog <christhecoolist@gmail.com> | 2015-01-21 19:47:45 -0500 |
| commit | 6cad635bd887634b1908c61ef6039420890b2ba2 (patch) | |
| tree | 270a4732080bb71e846b98931bccbf6815d97ca2 /Source/Core/VideoCommon/AVIDump.cpp | |
| parent | e7f2a04699c0e7e622028b4feba07fb6f46142bf (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.cpp | 322 |
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 |
