| 
									
										
										
										
											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
 | 
					
						
							|  |  |  | #endif 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | #include "AVIDump.h"
 | 
					
						
							| 
									
										
										
										
											2011-02-11 21:30:53 +00:00
										 |  |  | #include "HW/VideoInterface.h" //for TargetRefreshRate
 | 
					
						
							| 
									
										
										
										
											2011-02-11 22:09:20 +00:00
										 |  |  | #include "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>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "FileUtil.h"
 | 
					
						
							|  |  |  | #include "CommonPaths.h"
 | 
					
						
							|  |  |  | #include "Log.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; | 
					
						
							|  |  |  | 	char movie_file_name[255]; | 
					
						
							| 
									
										
										
										
											2011-02-28 20:40:15 +00:00
										 |  |  | 	sprintf(movie_file_name, "%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)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-01-13 02:05:58 +00:00
										 |  |  | 		if (AskYesNoT("Delete the existing file '%s'?", movie_file_name)) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 			File::Delete(movie_file_name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AVIFileInit(); | 
					
						
							|  |  |  | 	NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name); | 
					
						
							|  |  |  | 	// TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG
 | 
					
						
							|  |  |  | 	HRESULT hr = AVIFileOpenA(&m_file, movie_file_name, OF_WRITE | OF_CREATE, NULL); | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00: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.");  | 
					
						
							|  |  |  | 		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
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  | 		m_streamCompressed = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (m_stream) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		AVIStreamClose(m_stream); | 
					
						
							|  |  |  | 		m_stream = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-26 09:52:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (m_file) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		AVIFileRelease(m_file); | 
					
						
							|  |  |  | 		m_file = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, const_cast<u8*>(data), m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &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
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "FileUtil.h"
 | 
					
						
							|  |  |  | #include "StringUtil.h"
 | 
					
						
							|  |  |  | #include "Log.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | AVFormatContext *s_FormatContext = NULL; | 
					
						
							|  |  |  | AVStream *s_Stream = NULL; | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | AVFrame *s_BGRFrame = NULL, *s_YUVFrame = NULL; | 
					
						
							|  |  |  | uint8_t *s_YUVBuffer = NULL; | 
					
						
							|  |  |  | uint8_t *s_OutBuffer = NULL; | 
					
						
							|  |  |  | int s_width; | 
					
						
							|  |  |  | int s_height; | 
					
						
							|  |  |  | int s_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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(); | 
					
						
							|  |  |  | 	return CreateFile(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AVIDump::CreateFile() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	AVCodec *codec = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s_FormatContext = avformat_alloc_context(); | 
					
						
							|  |  |  | 	snprintf(s_FormatContext->filename, sizeof(s_FormatContext->filename), "%s", | 
					
						
							| 
									
										
										
										
											2011-02-28 20:40:15 +00:00
										 |  |  | 			(File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump0.avi").c_str()); | 
					
						
							| 
									
										
										
										
											2011-02-02 04:40:27 +00:00
										 |  |  | 	File::CreateFullPath(s_FormatContext->filename); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!(s_FormatContext->oformat = av_guess_format("avi", NULL, NULL)) || | 
					
						
							| 
									
										
										
										
											2012-08-28 22:34:24 -05:00
										 |  |  | 			!(s_Stream = avformat_new_stream(s_FormatContext, codec))) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		CloseFile(); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-25 18:12:40 +00:00
										 |  |  | 	s_Stream->codec->codec_id = | 
					
						
							|  |  |  | 		g_Config.bUseFFV1 ?  CODEC_ID_FFV1 : s_FormatContext->oformat->video_codec; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00: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; | 
					
						
							| 
									
										
										
										
											2012-02-24 14:25:02 -06:00
										 |  |  | 	s_Stream->codec->time_base = (AVRational){1, static_cast<int>(VideoInterface::TargetRefreshRate)}; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	s_Stream->codec->gop_size = 12; | 
					
						
							| 
									
										
										
										
											2011-03-25 18:12:40 +00:00
										 |  |  | 	s_Stream->codec->pix_fmt = g_Config.bUseFFV1 ? PIX_FMT_BGRA : PIX_FMT_YUV420P; | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	if (!(codec = avcodec_find_encoder(s_Stream->codec->codec_id)) || | 
					
						
							| 
									
										
										
										
											2012-08-28 22:34:24 -05:00
										 |  |  | 			(avcodec_open2(s_Stream->codec, codec, NULL) < 0)) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		CloseFile(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 	s_BGRFrame = avcodec_alloc_frame(); | 
					
						
							|  |  |  | 	s_YUVFrame = avcodec_alloc_frame(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-11 22:09:20 +00:00
										 |  |  | 	s_size = avpicture_get_size(s_Stream->codec->pix_fmt, s_width, s_height); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	s_YUVBuffer = new uint8_t[s_size]; | 
					
						
							| 
									
										
										
										
											2011-02-11 22:09:20 +00:00
										 |  |  | 	avpicture_fill((AVPicture *)s_YUVFrame, s_YUVBuffer, s_Stream->codec->pix_fmt, s_width, s_height); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	s_OutBuffer = new uint8_t[s_size]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_FormatContext->filename); | 
					
						
							| 
									
										
										
										
											2011-11-22 19:24:05 -06:00
										 |  |  | 	if (avio_open(&s_FormatContext->pb, s_FormatContext->filename, AVIO_FLAG_WRITE) < 0) | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		WARN_LOG(VIDEO, "Could not open %s", s_FormatContext->filename); | 
					
						
							|  |  |  | 		CloseFile(); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:24:05 -06:00
										 |  |  | 	avformat_write_header(s_FormatContext, NULL); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-26 19:59:33 -06:00
										 |  |  | 	avpicture_fill((AVPicture *)s_BGRFrame, const_cast<u8*>(data), 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
 | 
					
						
							|  |  |  | 	struct SwsContext *s_SwsContext; | 
					
						
							|  |  |  | 	if ((s_SwsContext = sws_getContext(width, height, PIX_FMT_BGR24, s_width, s_height, | 
					
						
							|  |  |  | 					s_Stream->codec->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL))) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		sws_scale(s_SwsContext, s_BGRFrame->data, s_BGRFrame->linesize, 0, | 
					
						
							|  |  |  | 				height, s_YUVFrame->data, s_YUVFrame->linesize); | 
					
						
							|  |  |  | 		sws_freeContext(s_SwsContext); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Encode and write the image
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	int outsize = avcodec_encode_video(s_Stream->codec, s_OutBuffer, s_size, s_YUVFrame); | 
					
						
							|  |  |  | 	while (outsize > 0) | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 		AVPacket pkt; | 
					
						
							|  |  |  | 		av_init_packet(&pkt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (s_Stream->codec->coded_frame->pts != (unsigned int)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; | 
					
						
							|  |  |  | 		pkt.data = s_OutBuffer; | 
					
						
							|  |  |  | 		pkt.size = outsize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Write the compressed frame in the media file
 | 
					
						
							|  |  |  | 		av_interleaved_write_frame(s_FormatContext, &pkt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Encode delayed frames
 | 
					
						
							|  |  |  | 		outsize = avcodec_encode_video(s_Stream->codec, s_OutBuffer, s_size, NULL); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AVIDump::Stop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	av_write_trailer(s_FormatContext); | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 	CloseFile(); | 
					
						
							|  |  |  | 	NOTICE_LOG(VIDEO, "Stopping frame dump"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AVIDump::CloseFile() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	if (s_Stream) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (s_Stream->codec) | 
					
						
							|  |  |  | 			avcodec_close(s_Stream->codec); | 
					
						
							|  |  |  | 		av_free(s_Stream); | 
					
						
							|  |  |  | 		s_Stream = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (s_YUVBuffer) | 
					
						
							|  |  |  | 		delete[] s_YUVBuffer; | 
					
						
							|  |  |  | 	s_YUVBuffer = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s_OutBuffer) | 
					
						
							|  |  |  | 		delete[] s_OutBuffer; | 
					
						
							|  |  |  | 	s_OutBuffer = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s_BGRFrame) | 
					
						
							|  |  |  | 		av_free(s_BGRFrame); | 
					
						
							|  |  |  | 	s_BGRFrame = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s_YUVFrame) | 
					
						
							|  |  |  | 		av_free(s_YUVFrame); | 
					
						
							|  |  |  | 	s_YUVFrame = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	if (s_FormatContext) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (s_FormatContext->pb) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:24:05 -06:00
										 |  |  | 			avio_close(s_FormatContext->pb); | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 		av_free(s_FormatContext); | 
					
						
							| 
									
										
										
										
											2011-03-25 18:12:40 +00:00
										 |  |  | 		s_FormatContext = NULL; | 
					
						
							| 
									
										
										
										
											2010-11-18 16:46:17 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 21:14:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |