| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-27 20:42:11 +02:00
										 |  |  | #if defined(__FreeBSD__)
 | 
					
						
							|  |  |  | #define __STDC_CONSTANT_MACROS 1
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-08-27 20:42:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 01:08:54 -04:00
										 |  |  | #include <string>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Common/CommonPaths.h"
 | 
					
						
							|  |  |  | #include "Common/FileUtil.h"
 | 
					
						
							|  |  |  | #include "Common/StringUtil.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:29:54 -04:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Core/HW/VideoInterface.h" //for TargetRefreshRate
 | 
					
						
							|  |  |  | #include "VideoCommon/AVIDump.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/VideoConfig.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | #include "tchar.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cstdio>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							|  |  |  | #include <vfw.h>
 | 
					
						
							|  |  |  | #include <winerror.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | HWND m_emuWnd; | 
					
						
							|  |  |  | LONG m_byteBuffer; | 
					
						
							|  |  |  | LONG m_frameCount; | 
					
						
							|  |  |  | LONG m_totalBytes; | 
					
						
							|  |  |  | PAVIFILE m_file; | 
					
						
							|  |  |  | int m_width; | 
					
						
							|  |  |  | int m_height; | 
					
						
							|  |  |  | int m_fileCount; | 
					
						
							|  |  |  | PAVISTREAM m_stream; | 
					
						
							|  |  |  | PAVISTREAM m_streamCompressed; | 
					
						
							|  |  |  | AVISTREAMINFO m_header; | 
					
						
							|  |  |  | AVICOMPRESSOPTIONS m_options; | 
					
						
							|  |  |  | AVICOMPRESSOPTIONS *m_arrayOptions[1]; | 
					
						
							|  |  |  | BITMAPINFOHEADER m_bitmap; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | bool AVIDump::Start(HWND hWnd, int w, int h) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	m_emuWnd = hWnd; | 
					
						
							|  |  |  | 	m_fileCount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_width = w; | 
					
						
							|  |  |  | 	m_height = h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return CreateFile(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AVIDump::CreateFile() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	m_totalBytes = 0; | 
					
						
							|  |  |  | 	m_frameCount = 0; | 
					
						
							| 
									
										
										
										
											2014-06-03 01:08:54 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	std::string movie_file_name = StringFromFormat("%sframedump%d.avi", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), m_fileCount); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	// Create path
 | 
					
						
							|  |  |  | 	File::CreateFullPath(movie_file_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ask to delete file
 | 
					
						
							|  |  |  | 	if (File::Exists(movie_file_name)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-03 01:08:54 -04:00
										 |  |  | 		if (AskYesNoT("Delete the existing file '%s'?", movie_file_name.c_str())) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 			File::Delete(movie_file_name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AVIFileInit(); | 
					
						
							| 
									
										
										
										
											2014-06-03 01:08:54 -04:00
										 |  |  | 	NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name.c_str()); | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	// TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG
 | 
					
						
							| 
									
										
										
										
											2014-06-03 01:08:54 -04:00
										 |  |  | 	HRESULT hr = AVIFileOpenA(&m_file, movie_file_name.c_str(), OF_WRITE | OF_CREATE, nullptr); | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 		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."); | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	SetBitmapFormat(); | 
					
						
							|  |  |  | 	NOTICE_LOG(VIDEO, "Setting video format..."); | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 	if (!SetVideoFormat()) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		NOTICE_LOG(VIDEO, "Setting video format failed"); | 
					
						
							|  |  |  | 		Stop(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-24 09:21:54 -04:00
										 |  |  | 	if (!m_fileCount) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (!SetCompressionOptions()) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 			NOTICE_LOG(VIDEO, "SetCompressionOptions failed"); | 
					
						
							|  |  |  | 			Stop(); | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, nullptr))) | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed"); | 
					
						
							|  |  |  | 		Stop(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, &m_bitmap, m_bitmap.biSize))) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed"); | 
					
						
							|  |  |  | 		Stop(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AVIDump::CloseFile() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 	if (m_streamCompressed) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		AVIStreamClose(m_streamCompressed); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		m_streamCompressed = nullptr; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (m_stream) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		AVIStreamClose(m_stream); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		m_stream = nullptr; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (m_file) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		AVIFileRelease(m_file); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		m_file = nullptr; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	AVIFileExit(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AVIDump::Stop() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CloseFile(); | 
					
						
							|  |  |  | 	m_fileCount = 0; | 
					
						
							|  |  |  | 	NOTICE_LOG(VIDEO, "Stop"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 20:47:48 -05:00
										 |  |  | void AVIDump::AddFrame(const u8* data, int w, int h) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-26 19:59:33 -06:00
										 |  |  | 	static bool shown_error = false; | 
					
						
							|  |  |  | 	if ((w != m_bitmap.biWidth || h != m_bitmap.biHeight) && !shown_error) | 
					
						
							| 
									
										
										
										
											2013-02-26 20:47:48 -05:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		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."); | 
					
						
							| 
									
										
										
										
											2013-02-26 19:59:33 -06:00
										 |  |  | 		shown_error = true; | 
					
						
							| 
									
										
										
										
											2013-02-26 20:47:48 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		m_bitmap.biWidth = w; | 
					
						
							|  |  |  | 		m_bitmap.biHeight = h; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, const_cast<u8*>(data), m_bitmap.biSizeImage, AVIIF_KEYFRAME, nullptr, &m_byteBuffer); | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	m_totalBytes += m_byteBuffer; | 
					
						
							|  |  |  | 	// 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.
 | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 	if (m_totalBytes >= 2000000000) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		CloseFile(); | 
					
						
							|  |  |  | 		m_fileCount++; | 
					
						
							|  |  |  | 		CreateFile(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AVIDump::SetBitmapFormat() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	memset(&m_bitmap, 0, sizeof(m_bitmap)); | 
					
						
							|  |  |  | 	m_bitmap.biSize = 0x28; | 
					
						
							|  |  |  | 	m_bitmap.biPlanes = 1; | 
					
						
							|  |  |  | 	m_bitmap.biBitCount = 24; | 
					
						
							|  |  |  | 	m_bitmap.biWidth = m_width; | 
					
						
							|  |  |  | 	m_bitmap.biHeight = m_height; | 
					
						
							|  |  |  | 	m_bitmap.biSizeImage = 3 * m_width * m_height; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AVIDump::SetCompressionOptions() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	memset(&m_options, 0, sizeof(m_options)); | 
					
						
							|  |  |  | 	m_arrayOptions[0] = &m_options; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (AVISaveOptions(m_emuWnd, 0, 1, &m_stream, m_arrayOptions) != 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AVIDump::SetVideoFormat() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	memset(&m_header, 0, sizeof(m_header)); | 
					
						
							|  |  |  | 	m_header.fccType = streamtypeVIDEO; | 
					
						
							|  |  |  | 	m_header.dwScale = 1; | 
					
						
							| 
									
										
										
										
											2011-02-11 18:59:42 +00:00
										 |  |  | 	m_header.dwRate = VideoInterface::TargetRefreshRate; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	m_header.dwSuggestedBufferSize  = m_bitmap.biSizeImage; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return SUCCEEDED(AVIFileCreateStream(m_file, &m_stream, &m_header)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern "C" { | 
					
						
							|  |  |  | #include <libavcodec/avcodec.h>
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | #include <libavformat/avformat.h>
 | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | #include <libswscale/swscale.h>
 | 
					
						
							| 
									
										
										
										
											2012-05-02 07:29:15 +02:00
										 |  |  | #include <libavutil/mathematics.h>
 | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-13 23:06:20 +02:00
										 |  |  | #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1)
 | 
					
						
							|  |  |  | #define av_frame_alloc avcodec_alloc_frame
 | 
					
						
							|  |  |  | #define av_frame_free avcodec_free_frame
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | static AVFormatContext* s_format_context = nullptr; | 
					
						
							|  |  |  | static AVStream* s_stream = nullptr; | 
					
						
							| 
									
										
										
										
											2014-06-24 04:12:15 +02:00
										 |  |  | static AVFrame* s_src_frame = nullptr; | 
					
						
							|  |  |  | static AVFrame* s_scaled_frame = nullptr; | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | static uint8_t* s_yuv_buffer = nullptr; | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | static SwsContext* s_sws_context = nullptr; | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | static int s_width; | 
					
						
							|  |  |  | static int s_height; | 
					
						
							|  |  |  | static int s_size; | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void InitAVCodec() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static bool first_run = true; | 
					
						
							|  |  |  | 	if (first_run) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 		av_register_all(); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 		first_run = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AVIDump::Start(int w, int h) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	s_width = w; | 
					
						
							|  |  |  | 	s_height = h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	InitAVCodec(); | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	bool success = CreateFile(); | 
					
						
							|  |  |  | 	if (!success) | 
					
						
							|  |  |  | 		CloseFile(); | 
					
						
							|  |  |  | 	return success; | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AVIDump::CreateFile() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	AVCodec* codec = nullptr; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	s_format_context = avformat_alloc_context(); | 
					
						
							|  |  |  | 	snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", | 
					
						
							|  |  |  | 	         (File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump0.avi").c_str()); | 
					
						
							|  |  |  | 	File::CreateFullPath(s_format_context->filename); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	if (!(s_format_context->oformat = av_guess_format("avi", nullptr, nullptr)) || | 
					
						
							|  |  |  | 	    !(s_stream = avformat_new_stream(s_format_context, codec))) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 	s_stream->codec->codec_id = g_Config.bUseFFV1 ? AV_CODEC_ID_FFV1 | 
					
						
							|  |  |  | 	                                              : s_format_context->oformat->video_codec; | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	s_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; | 
					
						
							|  |  |  | 	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->gop_size = 12; | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 	s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P; | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!(codec = avcodec_find_encoder(s_stream->codec->codec_id)) || | 
					
						
							|  |  |  | 	    (avcodec_open2(s_stream->codec, codec, nullptr) < 0)) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 04:12:15 +02:00
										 |  |  | 	s_src_frame = av_frame_alloc(); | 
					
						
							|  |  |  | 	s_scaled_frame = av_frame_alloc(); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	s_size = avpicture_get_size(s_stream->codec->pix_fmt, s_width, s_height); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	s_yuv_buffer = new uint8_t[s_size]; | 
					
						
							| 
									
										
										
										
											2014-06-24 04:12:15 +02:00
										 |  |  | 	avpicture_fill((AVPicture*)s_scaled_frame, s_yuv_buffer, s_stream->codec->pix_fmt, s_width, s_height); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_format_context->filename); | 
					
						
							|  |  |  | 	if (avio_open(&s_format_context->pb, s_format_context->filename, AVIO_FLAG_WRITE) < 0) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 		WARN_LOG(VIDEO, "Could not open %s", s_format_context->filename); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	avformat_write_header(s_format_context, nullptr); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | static void PreparePacket(AVPacket* pkt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	av_init_packet(pkt); | 
					
						
							|  |  |  | 	pkt->data = nullptr; | 
					
						
							|  |  |  | 	pkt->size = 0; | 
					
						
							|  |  |  | 	if (s_stream->codec->coded_frame->pts != AV_NOPTS_VALUE) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		pkt->pts = av_rescale_q(s_stream->codec->coded_frame->pts, | 
					
						
							|  |  |  | 		                        s_stream->codec->time_base, s_stream->time_base); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (s_stream->codec->coded_frame->key_frame) | 
					
						
							|  |  |  | 		pkt->flags |= AV_PKT_FLAG_KEY; | 
					
						
							|  |  |  | 	pkt->stream_index = s_stream->index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 20:47:48 -05:00
										 |  |  | void AVIDump::AddFrame(const u8* data, int width, int height) | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-24 04:12:15 +02:00
										 |  |  | 	avpicture_fill((AVPicture*)s_src_frame, const_cast<u8*>(data), AV_PIX_FMT_BGR24, width, height); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-25 18:12:40 +00:00
										 |  |  | 	// Convert image from BGR24 to desired pixel format, and scale to initial
 | 
					
						
							|  |  |  | 	// width and height
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 	if ((s_sws_context = sws_getCachedContext(s_sws_context, | 
					
						
							|  |  |  | 	                                          width, height, AV_PIX_FMT_BGR24, | 
					
						
							|  |  |  | 	                                          s_width, s_height, s_stream->codec->pix_fmt, | 
					
						
							|  |  |  | 	                                          SWS_BICUBIC, nullptr, nullptr, nullptr))) | 
					
						
							| 
									
										
										
										
											2011-03-25 18:12:40 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-24 04:12:15 +02:00
										 |  |  | 		sws_scale(s_sws_context, s_src_frame->data, s_src_frame->linesize, 0, | 
					
						
							|  |  |  | 		          height, s_scaled_frame->data, s_scaled_frame->linesize); | 
					
						
							| 
									
										
										
										
											2011-03-25 18:12:40 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-10 02:53:12 +02:00
										 |  |  | 	s_scaled_frame->format = s_stream->codec->pix_fmt; | 
					
						
							|  |  |  | 	s_scaled_frame->width = s_width; | 
					
						
							|  |  |  | 	s_scaled_frame->height = s_height; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 	// Encode and write the image.
 | 
					
						
							|  |  |  | 	AVPacket pkt; | 
					
						
							|  |  |  | 	PreparePacket(&pkt); | 
					
						
							|  |  |  | 	int got_packet; | 
					
						
							| 
									
										
										
										
											2014-06-24 04:12:15 +02:00
										 |  |  | 	int error = avcodec_encode_video2(s_stream->codec, &pkt, s_scaled_frame, &got_packet); | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 	while (!error && got_packet) | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 		// Write the compressed frame in the media file.
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 		av_interleaved_write_frame(s_format_context, &pkt); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 		// Handle delayed frames.
 | 
					
						
							|  |  |  | 		PreparePacket(&pkt); | 
					
						
							|  |  |  | 		error = avcodec_encode_video2(s_stream->codec, &pkt, nullptr, &got_packet); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		ERROR_LOG(VIDEO, "Error while encoding video: %d", error); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AVIDump::Stop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	av_write_trailer(s_format_context); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 	CloseFile(); | 
					
						
							|  |  |  | 	NOTICE_LOG(VIDEO, "Stopping frame dump"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AVIDump::CloseFile() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	if (s_stream) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 		if (s_stream->codec) | 
					
						
							|  |  |  | 			avcodec_close(s_stream->codec); | 
					
						
							|  |  |  | 		av_free(s_stream); | 
					
						
							|  |  |  | 		s_stream = nullptr; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	if (s_yuv_buffer) | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 		delete[] s_yuv_buffer; | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 		s_yuv_buffer = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 04:12:15 +02:00
										 |  |  | 	av_frame_free(&s_src_frame); | 
					
						
							|  |  |  | 	av_frame_free(&s_scaled_frame); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 	if (s_format_context) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-15 05:29:05 +02:00
										 |  |  | 		if (s_format_context->pb) | 
					
						
							|  |  |  | 			avio_close(s_format_context->pb); | 
					
						
							|  |  |  | 		av_free(s_format_context); | 
					
						
							|  |  |  | 		s_format_context = nullptr; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-15 05:16:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (s_sws_context) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		sws_freeContext(s_sws_context); | 
					
						
							|  |  |  | 		s_sws_context = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |