(Recording) Bake in HAVE_RECORD implicitly

This commit is contained in:
twinaphex 2014-08-12 05:28:43 +02:00
parent 717def1717
commit fcbbf08109
11 changed files with 39 additions and 64 deletions

View File

@ -356,10 +356,12 @@ ifeq ($(HAVE_ZLIB), 1)
DEFINES += $(ZLIB_CFLAGS) -DHAVE_ZLIB_DEFLATE DEFINES += $(ZLIB_CFLAGS) -DHAVE_ZLIB_DEFLATE
endif endif
OBJ += record/ffemu.o
ifeq ($(HAVE_FFMPEG), 1) ifeq ($(HAVE_FFMPEG), 1)
OBJ += record/ffemu.o record/ffmpeg.o OBJ += record/ffmpeg.o
LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS)
DEFINES += $(AVCODEC_CFLAGS) $(AVFORMAT_CFLAGS) $(AVUTIL_CFLAGS) $(SWSCALE_CFLAGS) -DHAVE_RECORD DEFINES += $(AVCODEC_CFLAGS) $(AVFORMAT_CFLAGS) $(AVUTIL_CFLAGS) $(SWSCALE_CFLAGS)
endif endif
ifeq ($(HAVE_DYNAMIC), 1) ifeq ($(HAVE_DYNAMIC), 1)

View File

@ -259,10 +259,12 @@ ifeq ($(HAVE_DINPUT), 1)
OBJ += input/dinput.o OBJ += input/dinput.o
endif endif
OBJ += record/ffemu.o
ifeq ($(HAVE_FFMPEG), 1) ifeq ($(HAVE_FFMPEG), 1)
LIBS += -lavformat -lavcodec -lavutil -lswscale -lws2_32 -lz LIBS += -lavformat -lavcodec -lavutil -lswscale -lws2_32 -lz
DEFINES += -DHAVE_FFMPEG -DHAVE_RECORD -Iffmpeg DEFINES += -DHAVE_FFMPEG -Iffmpeg
OBJ += record/ffemu.o record/ffmpeg.o OBJ += record/ffmpeg.o
endif endif
ifneq ($(V), 1) ifneq ($(V), 1)

View File

@ -45,7 +45,7 @@ It is designed to be very portable and features a gamepad-centric UI.
It also has a full-featured command-line interface. It also has a full-featured command-line interface.
In some areas, RetroArch goes beyond and emphasizes on not-so-common technical features such as multi-pass shader support, In some areas, RetroArch goes beyond and emphasizes on not-so-common technical features such as multi-pass shader support,
real-time rewind (Braid-style), FFmpeg video recording, etc. real-time rewind (Braid-style), video recording (using FFmpeg), etc.
RetroArch also emphasizes on being easy to integrate into various launcher frontends. RetroArch also emphasizes on being easy to integrate into various launcher frontends.

View File

@ -142,11 +142,11 @@ Codecs used are (FFV1 or H264 RGB lossless (x264))/FLAC, suitable for processing
.TP .TP
\fB--recordconfig PATH\fR \fB--recordconfig PATH\fR
Sets path to a config file for use during FFmpeg recording. Sets path to a config file for use during recording.
.TP .TP
\fB--size WIDTHxHEIGHT\fR \fB--size WIDTHxHEIGHT\fR
Allows specifying the exact output width and height of FFmpeg recording. This option will override any configuration settings. Allows specifying the exact output width and height of recording. This option will override any configuration settings.
The video input is scaled with point filtering before being encoded at the correct size. The video input is scaled with point filtering before being encoded at the correct size.
.TP .TP

View File

@ -502,16 +502,15 @@ bool driver_update_system_av_info(const struct retro_system_av_info *info)
// Cannot continue recording with different parameters. // Cannot continue recording with different parameters.
// Take the easiest route out and just restart the recording. // Take the easiest route out and just restart the recording.
#ifdef HAVE_RECORD
if (g_extern.rec) if (g_extern.rec)
{ {
static const char *msg = "Restarting FFmpeg recording due to driver reinit."; static const char *msg = "Restarting recording due to driver reinit.";
msg_queue_push(g_extern.msg_queue, msg, 2, 180); msg_queue_push(g_extern.msg_queue, msg, 2, 180);
RARCH_WARN("%s\n", msg); RARCH_WARN("%s\n", msg);
rarch_main_command(RARCH_CMD_RECORD_DEINIT); rarch_main_command(RARCH_CMD_RECORD_DEINIT);
rarch_main_command(RARCH_CMD_RECORD_INIT); rarch_main_command(RARCH_CMD_RECORD_INIT);
} }
#endif
return true; return true;
} }

View File

@ -767,10 +767,8 @@ bool rarch_environment_cb(unsigned cmd, void *data)
RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n"); RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n");
const struct retro_audio_callback *info = (const struct retro_audio_callback*)data; const struct retro_audio_callback *info = (const struct retro_audio_callback*)data;
#ifdef HAVE_RECORD
if (g_extern.rec) // A/V sync is a must. if (g_extern.rec) // A/V sync is a must.
return false; return false;
#endif
#ifdef HAVE_NETPLAY #ifdef HAVE_NETPLAY
if (g_extern.netplay_enable) if (g_extern.netplay_enable)

View File

@ -638,21 +638,19 @@ struct global
uint16_t netplay_port; uint16_t netplay_port;
#endif #endif
// FFmpeg record. // Recording.
#ifdef HAVE_RECORD
const ffemu_backend_t *rec_driver; const ffemu_backend_t *rec_driver;
void *rec; void *rec;
char record_path[PATH_MAX]; char record_path[PATH_MAX];
char record_config[PATH_MAX]; char record_config[PATH_MAX];
bool recording; bool recording_enable;
unsigned record_width; unsigned record_width;
unsigned record_height; unsigned record_height;
uint8_t *record_gpu_buffer; uint8_t *record_gpu_buffer;
size_t record_gpu_width; size_t record_gpu_width;
size_t record_gpu_height; size_t record_gpu_height;
#endif
struct struct
{ {

View File

@ -1928,9 +1928,9 @@ static inline void gl_set_texture_fmts(gl_t *gl, bool rgb32)
static void gl_init_pbo_readback(gl_t *gl) static void gl_init_pbo_readback(gl_t *gl)
{ {
unsigned i; unsigned i;
// Only bother with this if we're doing FFmpeg GPU recording. // Only bother with this if we're doing GPU recording.
// Check g_extern.recording and not g_extern.rec, because recording is not initialized yet. // Check g_extern.recording_enable and not g_extern.rec, because recording is not initialized yet.
gl->pbo_readback_enable = g_settings.video.gpu_record && g_extern.recording; gl->pbo_readback_enable = g_settings.video.gpu_record && g_extern.recording_enable;
if (!gl->pbo_readback_enable) if (!gl->pbo_readback_enable)
return; return;

View File

@ -58,7 +58,7 @@
gl->ctx_driver->write_egl_image(gl, frame, width, height, pitch, base_size, tex_index,img) gl->ctx_driver->write_egl_image(gl, frame, width, height, pitch, base_size, tex_index,img)
#endif #endif
#if defined(HAVE_RECORD) && (!defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3)) #if (!defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3))
#define HAVE_GL_ASYNC_READBACK #define HAVE_GL_ASYNC_READBACK
#endif #endif

View File

@ -568,6 +568,11 @@ RETROARCH
============================================================ */ ============================================================ */
#include "../retroarch.c" #include "../retroarch.c"
/*============================================================
RECORDING
============================================================ */
#include "../record/ffemu.c"
/*============================================================ /*============================================================
THREAD THREAD
============================================================ */ ============================================================ */

View File

@ -217,12 +217,11 @@ static void readjust_audio_input_rate(void)
// g_extern.audio_data.src_ratio, g_extern.audio_data.orig_src_ratio); // g_extern.audio_data.src_ratio, g_extern.audio_data.orig_src_ratio);
} }
#ifdef HAVE_RECORD
static void init_recording(void) static void init_recording(void)
{ {
struct ffemu_params params = {0}; struct ffemu_params params = {0};
if (!g_extern.recording) if (!g_extern.recording_enable)
return; return;
if (g_extern.libretro_dummy) if (g_extern.libretro_dummy)
@ -233,7 +232,7 @@ static void init_recording(void)
if (!g_settings.video.gpu_record && g_extern.system.hw_render_callback.context_type) if (!g_settings.video.gpu_record && g_extern.system.hw_render_callback.context_type)
{ {
RARCH_WARN("Libretro core is hardware rendered. Must use post-shaded FFmpeg recording as well.\n"); RARCH_WARN("Libretro core is hardware rendered. Must use post-shaded recording as well.\n");
return; return;
} }
@ -313,7 +312,7 @@ static void init_recording(void)
} }
} }
RARCH_LOG("Recording with FFmpeg to %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n", RARCH_LOG("Recording to %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n",
g_extern.record_path, g_extern.record_path,
params.out_width, params.out_height, params.out_width, params.out_height,
params.fb_width, params.fb_height, params.fb_width, params.fb_height,
@ -321,7 +320,7 @@ static void init_recording(void)
if (!ffemu_init_first(&g_extern.rec_driver, &g_extern.rec, &params)) if (!ffemu_init_first(&g_extern.rec_driver, &g_extern.rec, &params))
{ {
RARCH_ERR("Failed to start FFmpeg recording.\n"); RARCH_ERR("Failed to start recording.\n");
free(g_extern.record_gpu_buffer); free(g_extern.record_gpu_buffer);
g_extern.record_gpu_buffer = NULL; g_extern.record_gpu_buffer = NULL;
} }
@ -332,8 +331,10 @@ static void deinit_recording(void)
if (!g_extern.rec || !g_extern.rec_driver) if (!g_extern.rec || !g_extern.rec_driver)
return; return;
g_extern.rec_driver->finalize(g_extern.rec); if (g_extern.rec_driver->finalize)
g_extern.rec_driver->free(g_extern.rec); g_extern.rec_driver->finalize(g_extern.rec);
if (g_extern.rec_driver->free)
g_extern.rec_driver->free(g_extern.rec);
g_extern.rec = NULL; g_extern.rec = NULL;
g_extern.rec_driver = NULL; g_extern.rec_driver = NULL;
@ -396,9 +397,9 @@ static void recording_dump_frame(const void *data, unsigned width, unsigned heig
if (!g_extern.record_gpu_buffer) if (!g_extern.record_gpu_buffer)
ffemu_data.is_dupe = !data; ffemu_data.is_dupe = !data;
g_extern.rec_driver->push_video(g_extern.rec, &ffemu_data); if (g_extern.rec_driver && g_extern.rec_driver->push_video)
g_extern.rec_driver->push_video(g_extern.rec, &ffemu_data);
} }
#endif
static void video_frame(const void *data, unsigned width, unsigned height, size_t pitch) static void video_frame(const void *data, unsigned width, unsigned height, size_t pitch)
{ {
@ -431,10 +432,8 @@ static void video_frame(const void *data, unsigned width, unsigned height, size_
// Slightly messy code, // Slightly messy code,
// but we really need to do processing before blocking on VSync for best possible scheduling. // but we really need to do processing before blocking on VSync for best possible scheduling.
#ifdef HAVE_RECORD
if (g_extern.rec && (!g_extern.filter.filter || !g_settings.video.post_filter_record || !data || g_extern.record_gpu_buffer)) if (g_extern.rec && (!g_extern.filter.filter || !g_settings.video.post_filter_record || !data || g_extern.record_gpu_buffer))
recording_dump_frame(data, width, height, pitch); recording_dump_frame(data, width, height, pitch);
#endif
msg = msg_queue_pull(g_extern.msg_queue); msg = msg_queue_pull(g_extern.msg_queue);
driver.current_msg = msg; driver.current_msg = msg;
@ -455,10 +454,8 @@ static void video_frame(const void *data, unsigned width, unsigned height, size_
data, width, height, pitch); data, width, height, pitch);
RARCH_PERFORMANCE_STOP(softfilter_process); RARCH_PERFORMANCE_STOP(softfilter_process);
#ifdef HAVE_RECORD
if (g_extern.rec && g_settings.video.post_filter_record) if (g_extern.rec && g_settings.video.post_filter_record)
recording_dump_frame(g_extern.filter.buffer, owidth, oheight, opitch); recording_dump_frame(g_extern.filter.buffer, owidth, oheight, opitch);
#endif
data = g_extern.filter.buffer; data = g_extern.filter.buffer;
width = owidth; width = owidth;
@ -473,11 +470,10 @@ static void video_frame(const void *data, unsigned width, unsigned height, size_
void rarch_render_cached_frame(void) void rarch_render_cached_frame(void)
{ {
const void *frame = g_extern.frame_cache.data; const void *frame = g_extern.frame_cache.data;
#ifdef HAVE_RECORD
// Cannot allow recording when pushing duped frames. // Cannot allow recording when pushing duped frames.
void *recording = g_extern.rec; void *recording = g_extern.rec;
g_extern.rec = NULL; g_extern.rec = NULL;
#endif
if (frame == RETRO_HW_FRAME_BUFFER_VALID) if (frame == RETRO_HW_FRAME_BUFFER_VALID)
frame = NULL; // Dupe frame = NULL; // Dupe
@ -490,9 +486,7 @@ void rarch_render_cached_frame(void)
g_extern.frame_cache.height, g_extern.frame_cache.height,
g_extern.frame_cache.pitch); g_extern.frame_cache.pitch);
#ifdef HAVE_RECORD
g_extern.rec = recording; g_extern.rec = recording;
#endif
} }
static bool audio_flush(const int16_t *data, size_t samples) static bool audio_flush(const int16_t *data, size_t samples)
@ -503,16 +497,15 @@ static bool audio_flush(const int16_t *data, size_t samples)
struct resampler_data src_data = {0}; struct resampler_data src_data = {0};
struct rarch_dsp_data dsp_data = {0}; struct rarch_dsp_data dsp_data = {0};
#ifdef HAVE_RECORD
if (g_extern.rec) if (g_extern.rec)
{ {
struct ffemu_audio_data ffemu_data = {0}; struct ffemu_audio_data ffemu_data = {0};
ffemu_data.data = data; ffemu_data.data = data;
ffemu_data.frames = samples / 2; ffemu_data.frames = samples / 2;
g_extern.rec_driver->push_audio(g_extern.rec, &ffemu_data); if (g_extern.rec_driver && g_extern.rec_driver->push_audio)
g_extern.rec_driver->push_audio(g_extern.rec, &ffemu_data);
} }
#endif
if (g_extern.is_paused || g_extern.audio_data.mute) if (g_extern.is_paused || g_extern.audio_data.mute)
return true; return true;
@ -931,11 +924,9 @@ static void print_help(void)
puts("\t\tAvailable commands are listed if command is invalid."); puts("\t\tAvailable commands are listed if command is invalid.");
#endif #endif
#ifdef HAVE_RECORD
puts("\t-r/--record: Path to record video file.\n\t\tUsing .mkv extension is recommended."); puts("\t-r/--record: Path to record video file.\n\t\tUsing .mkv extension is recommended.");
puts("\t--recordconfig: Path to settings used during recording."); puts("\t--recordconfig: Path to settings used during recording.");
puts("\t--size: Overrides output video size when recording with FFmpeg (format: WIDTHxHEIGHT)."); puts("\t--size: Overrides output video size when recording (format: WIDTHxHEIGHT).");
#endif
puts("\t-v/--verbose: Verbose logging."); puts("\t-v/--verbose: Verbose logging.");
puts("\t-U/--ups: Specifies path for UPS patch that will be applied to content."); puts("\t-U/--ups: Specifies path for UPS patch that will be applied to content.");
puts("\t--bps: Specifies path for BPS patch that will be applied to content."); puts("\t--bps: Specifies path for BPS patch that will be applied to content.");
@ -1059,11 +1050,9 @@ static void parse_input(int argc, char *argv[])
{ "help", 0, NULL, 'h' }, { "help", 0, NULL, 'h' },
{ "save", 1, NULL, 's' }, { "save", 1, NULL, 's' },
{ "fullscreen", 0, NULL, 'f' }, { "fullscreen", 0, NULL, 'f' },
#ifdef HAVE_RECORD
{ "record", 1, NULL, 'r' }, { "record", 1, NULL, 'r' },
{ "recordconfig", 1, &val, 'R' }, { "recordconfig", 1, &val, 'R' },
{ "size", 1, &val, 's' }, { "size", 1, &val, 's' },
#endif
{ "verbose", 0, NULL, 'v' }, { "verbose", 0, NULL, 'v' },
{ "config", 1, NULL, 'c' }, { "config", 1, NULL, 'c' },
{ "appendconfig", 1, &val, 'C' }, { "appendconfig", 1, &val, 'C' },
@ -1095,11 +1084,7 @@ static void parse_input(int argc, char *argv[])
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
#ifdef HAVE_RECORD
#define FFMPEG_RECORD_ARG "r:" #define FFMPEG_RECORD_ARG "r:"
#else
#define FFMPEG_RECORD_ARG
#endif
#ifdef HAVE_DYNAMIC #ifdef HAVE_DYNAMIC
#define DYNAMIC_ARG "L:" #define DYNAMIC_ARG "L:"
@ -1201,12 +1186,10 @@ static void parse_input(int argc, char *argv[])
strlcpy(g_extern.config_path, optarg, sizeof(g_extern.config_path)); strlcpy(g_extern.config_path, optarg, sizeof(g_extern.config_path));
break; break;
#ifdef HAVE_RECORD
case 'r': case 'r':
strlcpy(g_extern.record_path, optarg, sizeof(g_extern.record_path)); strlcpy(g_extern.record_path, optarg, sizeof(g_extern.record_path));
g_extern.recording = true; g_extern.recording_enable = true;
break; break;
#endif
#ifdef HAVE_DYNAMIC #ifdef HAVE_DYNAMIC
case 'L': case 'L':
@ -1333,7 +1316,6 @@ static void parse_input(int argc, char *argv[])
g_extern.block_patch = true; g_extern.block_patch = true;
break; break;
#ifdef HAVE_RECORD
case 's': case 's':
{ {
if (sscanf(optarg, "%ux%u", &g_extern.record_width, &g_extern.record_height) != 2) if (sscanf(optarg, "%ux%u", &g_extern.record_width, &g_extern.record_height) != 2)
@ -1348,7 +1330,6 @@ static void parse_input(int argc, char *argv[])
case 'R': case 'R':
strlcpy(g_extern.record_config, optarg, sizeof(g_extern.record_config)); strlcpy(g_extern.record_config, optarg, sizeof(g_extern.record_config));
break; break;
#endif
case 'f': case 'f':
print_features(); print_features();
exit(0); exit(0);
@ -3018,9 +2999,7 @@ int rarch_main_init(int argc, char *argv[])
init_rewind(); init_rewind();
init_controllers(); init_controllers();
#ifdef HAVE_RECORD
init_recording(); init_recording();
#endif
init_sram(); init_sram();
@ -3070,9 +3049,7 @@ static inline void update_frame_time(void)
time = rarch_get_time_usec(); time = rarch_get_time_usec();
is_locked_fps = g_extern.is_paused || driver.nonblock_state; is_locked_fps = g_extern.is_paused || driver.nonblock_state;
#ifdef HAVE_RECORD
is_locked_fps |= !!g_extern.rec; is_locked_fps |= !!g_extern.rec;
#endif
if (!g_extern.system.frame_time_last || is_locked_fps) if (!g_extern.system.frame_time_last || is_locked_fps)
delta = g_extern.system.frame_time.reference; delta = g_extern.system.frame_time.reference;
@ -3221,14 +3198,10 @@ void rarch_main_command(unsigned action)
g_extern.audio_data.dsp = NULL; g_extern.audio_data.dsp = NULL;
break; break;
case RARCH_CMD_RECORD_INIT: case RARCH_CMD_RECORD_INIT:
#ifdef HAVE_RECORD
init_recording(); init_recording();
#endif
break; break;
case RARCH_CMD_RECORD_DEINIT: case RARCH_CMD_RECORD_DEINIT:
#ifdef HAVE_RECORD
deinit_recording(); deinit_recording();
#endif
break; break;
case RARCH_CMD_HISTORY_INIT: case RARCH_CMD_HISTORY_INIT:
if (g_extern.history) if (g_extern.history)
@ -3367,9 +3340,7 @@ void rarch_main_deinit(void)
deinit_autosave(); deinit_autosave();
#endif #endif
#ifdef HAVE_RECORD
deinit_recording(); deinit_recording();
#endif
save_files(); save_files();