diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c
index 097b4708ec..745e45001e 100644
--- a/cheevos/cheevos.c
+++ b/cheevos/cheevos.c
@@ -398,15 +398,15 @@ static void rcheevos_show_mastery_placard(void)
#if defined (HAVE_GFX_WIDGETS)
if (gfx_widgets_ready())
{
+ char msg[128];
+ char badge_name[32];
const char* displayname = rc_client_get_user_info(rcheevos_locals.client)->display_name;
const bool content_runtime_log = settings->bools.content_runtime_log;
const bool content_runtime_log_aggr = settings->bools.content_runtime_log_aggregate;
- char badge_name[32];
- char msg[128];
size_t len = strlcpy(msg, displayname, sizeof(msg));
- if (len < sizeof(msg) - 12 &&
- (content_runtime_log || content_runtime_log_aggr))
+ if (len < sizeof(msg) - 12
+ && (content_runtime_log || content_runtime_log_aggr))
{
const char* content_path = path_get(RARCH_PATH_CONTENT);
const char* core_path = path_get(RARCH_PATH_CORE);
@@ -422,7 +422,7 @@ static void rcheevos_show_mastery_placard(void)
runtime_log_add_runtime_usec(runtime_log,
runloop_state->core_runtime_usec);
- len += snprintf(msg + len, sizeof(msg) - len, " | ");
+ len += strlcpy(msg + len, " | ", sizeof(msg) - len);
runtime_log_get_runtime_str(runtime_log, msg + len, sizeof(msg) - len);
msg[sizeof(msg) - 1] = '\0';
@@ -430,7 +430,8 @@ static void rcheevos_show_mastery_placard(void)
}
}
- snprintf(badge_name, sizeof(badge_name), "i%s", game->badge_name);
+ len = strlcpy(badge_name, "i", sizeof(badge_name));
+ strlcpy(badge_name + len, game->badge_name, sizeof(badge_name) - len);
gfx_widgets_push_achievement(title, msg, badge_name);
}
else
@@ -474,8 +475,10 @@ static void rcheevos_award_achievement(const rc_client_achievement_t* cheevo)
#endif
{
char buffer[256];
- snprintf(buffer, sizeof(buffer), "%s: %s",
- msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), cheevo->title);
+ size_t _len = strlcpy(buffer, msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED),
+ sizeof(buffer));
+ _len += strlcpy(buffer + _len, ": ", sizeof(buffer) - _len);
+ strlcpy(buffer + _len, cheevo->title, sizeof(buffer) - _len);
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false, NULL,
@@ -558,12 +561,13 @@ static void rcheevos_lboard_started(const rc_client_leaderboard_t* lboard)
if (settings->bools.cheevos_visibility_lboard_start)
{
char buffer[256];
+ size_t _len = strlcpy(buffer, msg_hash_to_str(MSG_LEADERBOARD_STARTED),
+ sizeof(buffer));
+ _len += strlcpy(buffer + _len, ": ", sizeof(buffer) - _len);
+ _len += strlcpy(buffer + _len, lboard->title, sizeof(buffer) - _len);
if (lboard->description && *lboard->description)
- snprintf(buffer, sizeof(buffer), "%s: %s - %s",
- msg_hash_to_str(MSG_LEADERBOARD_STARTED), lboard->title, lboard->description);
- else
- snprintf(buffer, sizeof(buffer), "%s: %s",
- msg_hash_to_str(MSG_LEADERBOARD_STARTED), lboard->title);
+ snprintf(buffer + _len, sizeof(buffer) - _len, "- %s",
+ lboard->description);
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
@@ -623,8 +627,9 @@ static void rcheevos_client_log_message(const char* message, const rc_client_t*
static void rcheevos_server_error(const char* api_name, const char* message)
{
char buffer[256];
- snprintf(buffer, sizeof(buffer), "%s failed: %s", api_name, message);
-
+ size_t _len = strlcpy(buffer, api_name, sizeof(buffer));
+ _len += strlcpy(buffer + _len, " failed: ", sizeof(buffer) - _len);
+ _len += strlcpy(buffer + _len, message, sizeof(buffer) - _len);
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
}
@@ -786,8 +791,10 @@ void rcheevos_award_achievement(rcheevos_locals_t* locals,
#endif
{
char buffer[256];
- snprintf(buffer, sizeof(buffer), "%s: %s",
- msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), cheevo->title);
+ size_t _len = strlcpy(buffer, msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED),
+ sizeof(buffer));
+ _len += strlcpy(buffer + _len, ": ", sizeof(buffer) - _len);
+ _len += strlcpy(buffer + _len, cheevo->title, sizeof(buffer) - _len);
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false, NULL,
@@ -867,7 +874,8 @@ static void rcheevos_assign_leaderboard_tracker_ids(rcheevos_locals_t* locals)
unsigned tracker_id;
char buffer[32];
- for (; lboard < end; ++lboard) {
+ for (; lboard < end; ++lboard)
+ {
if (lboard->active_tracker_id != 0xFF)
continue;
@@ -875,7 +883,8 @@ static void rcheevos_assign_leaderboard_tracker_ids(rcheevos_locals_t* locals)
if (locals->active_lboard_trackers != 0 && lboard->value_hash != 0)
{
scan = locals->game.leaderboards;
- for (; scan < end; ++scan) {
+ for (; scan < end; ++scan)
+ {
if (scan->active_tracker_id == 0 || scan->active_tracker_id == 0xFF)
continue;
@@ -983,7 +992,6 @@ static void rcheevos_lboard_canceled(rcheevos_ralboard_t * lboard,
bool widgets_ready)
{
const settings_t *settings = config_get_ptr();
- char buffer[256];
if (!lboard)
return;
@@ -997,8 +1005,11 @@ static void rcheevos_lboard_canceled(rcheevos_ralboard_t * lboard,
if (settings->bools.cheevos_visibility_lboard_cancel)
{
- snprintf(buffer, sizeof(buffer), "%s: %s",
- msg_hash_to_str(MSG_LEADERBOARD_FAILED), lboard->title);
+ char buffer[256];
+ size_t _len = strlcpy(buffer, msg_hash_to_str(MSG_LEADERBOARD_FAILED),
+ sizeof(buffer));
+ _len += strlcpy(buffer + _len, ": ", sizeof(buffer) - _len);
+ strlcpy(buffer + _len, lboard->title, sizeof(buffer) - _len);
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
@@ -1032,12 +1043,13 @@ static void rcheevos_lboard_started(
if (settings->bools.cheevos_visibility_lboard_start)
{
+ size_t _len = strlcpy(buffer, msg_hash_to_str(MSG_LEADERBOARD_STARTED),
+ sizeof(buffer));
+ _len += strlcpy(buffer + _len, ": ", sizeof(buffer) - _len);
+ _len += strlcpy(buffer + _len, lboard->title, sizeof(buffer) - _len);
if (lboard->description && *lboard->description)
- snprintf(buffer, sizeof(buffer), "%s: %s - %s",
- msg_hash_to_str(MSG_LEADERBOARD_STARTED), lboard->title, lboard->description);
- else
- snprintf(buffer, sizeof(buffer), "%s: %s",
- msg_hash_to_str(MSG_LEADERBOARD_STARTED), lboard->title);
+ snprintf(buffer + _len, sizeof(buffer) - _len, "- %s",
+ lboard->description);
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
@@ -1782,6 +1794,7 @@ void rcheevos_validate_config_settings(void)
if (!rc_libretro_is_setting_allowed(disallowed_settings, key, val))
{
char buffer[128];
+ /* TODO/FIXME - localize */
snprintf(buffer, sizeof(buffer), "Hardcore paused. Setting not allowed: %s=%s", key, val);
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", buffer);
rcheevos_pause_hardcore();
@@ -2344,7 +2357,8 @@ static void rcheevos_show_game_placard(void)
if (gfx_widgets_ready())
{
char badge_name[32];
- snprintf(badge_name, sizeof(badge_name), "i%s", game->badge_name);
+ size_t _len = strlcpy(badge_name, "i", sizeof(badge_name));
+ _len += strlcpy(badge_name + _len, game->badge_name, sizeof(badge_name) - _len);
gfx_widgets_push_achievement(game->title, msg, badge_name);
}
else
@@ -2407,12 +2421,13 @@ static void rcheevos_client_login_callback(int result,
const char* error_message, rc_client_t* client, void* userdata)
{
const rc_client_user_t* user;
- char msg[256] = "";
if (result != RC_OK)
{
- snprintf(msg, sizeof(msg), "RetroAchievements login failed: %s",
- error_message);
+ char msg[256];
+ size_t _len = strlcpy(msg, "RetroAchievements login failed: ",
+ sizeof(msg));
+ _len += strlcpy(msg + _len, error_message, sizeof(msg) - _len);
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", msg);
runloop_msg_queue_push(msg, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
@@ -2444,6 +2459,7 @@ static void rcheevos_client_login_callback(int result,
if (settings->bools.cheevos_visibility_account)
{
/* TODO/FIXME - localize */
+ char msg[256];
snprintf(msg, sizeof(msg),
"RetroAchievements: Logged in as \"%s\".",
user->display_name);
@@ -2595,9 +2611,9 @@ void rcheevos_show_mastery_placard(void)
#if defined (HAVE_GFX_WIDGETS)
if (gfx_widgets_ready())
{
+ char msg[128];
const bool content_runtime_log = settings->bools.content_runtime_log;
const bool content_runtime_log_aggr = settings->bools.content_runtime_log_aggregate;
- char msg[128];
size_t len = strlcpy(msg, rcheevos_locals.displayname, sizeof(msg));
if (len < sizeof(msg) - 12 &&
diff --git a/frontend/drivers/platform_ctr.c b/frontend/drivers/platform_ctr.c
index ee4841cf43..cb37b99b27 100644
--- a/frontend/drivers/platform_ctr.c
+++ b/frontend/drivers/platform_ctr.c
@@ -79,7 +79,7 @@ static void get_first_valid_core(char* path_return, size_t len)
{
if (!ent)
break;
- if (strlen(ent->d_name) > strlen(extension)
+ if (strlen(ent->d_name) > strlen(extension)
&& !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension))
{
size_t _len = strlcpy(path_return, "sdmc:/retroarch/cores/", len);
@@ -244,8 +244,8 @@ static void frontend_ctr_exec(const char *path, bool should_load_game)
is corrupt so we have to quit */
{
char error[PATH_MAX + 32];
-
- snprintf(error, sizeof(error), "Can't launch core: %s", path);
+ size_t _len = strlcpy(error, "Can't launch core: ", sizeof(error));
+ strlcpy(error + _len, path, sizeof(error) - _len);
error_and_quit(error);
}
}
@@ -335,7 +335,7 @@ static void ctr_check_dspfirm(void)
{
size_t dspfirm_size = ptr[1];
ptr -= 0x40;
- if ((ptr + (dspfirm_size >> 2)) >
+ if ((ptr + (dspfirm_size >> 2)) >
(code_buffer + (code_size >> 2)))
break;
@@ -480,7 +480,7 @@ static void frontend_ctr_init(void* data)
static int frontend_ctr_get_rating(void)
{
u8 device_model = 0xFF;
-
+
/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
CFGU_GetSystemModel(&device_model);
@@ -592,7 +592,7 @@ static void frontend_ctr_get_os(char* s, size_t len, int* major, int* minor)
static void frontend_ctr_get_name(char* s, size_t len)
{
u8 device_model = 0xFF;
-
+
/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
CFGU_GetSystemModel(&device_model);
diff --git a/frontend/drivers/platform_emscripten.c b/frontend/drivers/platform_emscripten.c
index 3856bdf08b..5c0511e35d 100644
--- a/frontend/drivers/platform_emscripten.c
+++ b/frontend/drivers/platform_emscripten.c
@@ -79,12 +79,10 @@ static void frontend_emscripten_get_env(int *argc, char *argv[],
if (home)
{
- base_path[0] = '\0';
- user_path[0] = '\0';
- snprintf(base_path, sizeof(base_path),
- "%s/retroarch", home);
- snprintf(user_path, sizeof(user_path),
- "%s/retroarch/userdata", home);
+ size_t _len = strlcpy(base_path, home, sizeof(base_path));
+ strlcpy(base_path + _len, "/retroarch", sizeof(base_path) - _len);
+ _len = strlcpy(user_path, home, sizeof(user_path));
+ strlcpy(user_path + _len, "/retroarch/userdata", sizeof(user_path) - _len);
}
else
{
diff --git a/frontend/drivers/platform_win32.c b/frontend/drivers/platform_win32.c
index 5a4487fa38..47e7ebd421 100644
--- a/frontend/drivers/platform_win32.c
+++ b/frontend/drivers/platform_win32.c
@@ -453,7 +453,7 @@ static void frontend_win32_init(void *data)
static void init_nvda(void)
{
#ifdef HAVE_DYLIB
- if ( (g_plat_win32_flags & PLAT_WIN32_FLAG_USE_NVDA)
+ if ( (g_plat_win32_flags & PLAT_WIN32_FLAG_USE_NVDA)
&& !nvda_lib)
{
if ((nvda_lib = dylib_load("nvdaControllerClient64.dll")))
@@ -750,8 +750,8 @@ static void frontend_win32_respawn(char *s, size_t len, char *args)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
+ char executable_args[PATH_MAX_LENGTH];
char executable_path[PATH_MAX_LENGTH] = {0};
- char executable_args[PATH_MAX_LENGTH] = {0};
if (win32_fork_mode != FRONTEND_FORK_RESTART)
return;
@@ -761,7 +761,7 @@ static void frontend_win32_respawn(char *s, size_t len, char *args)
path_set(RARCH_PATH_CORE, executable_path);
/* Remove executable path from arguments given to CreateProcess */
- snprintf(executable_args, sizeof(executable_args), "%s", strstr(args, ".exe") + 4);
+ strlcpy(executable_args, strstr(args, ".exe") + 4, sizeof(executable_args));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
@@ -853,7 +853,7 @@ static const char *accessibility_win_language_id(const char* language)
return "412";
else if (string_is_equal(language,"pl"))
return "415";
- else if (string_is_equal(language,"cs"))
+ else if (string_is_equal(language,"cs"))
return "405";
return "";
}
@@ -966,12 +966,12 @@ static bool create_win32_process(char* cmd, const char * input)
size_t input_len = strlen(input);
if (!CreatePipe(&rd, &wr, NULL, input_len))
return false;
-
+
SetHandleInformation(rd, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
-
+
WriteFile(wr, input, input_len, &dummy, NULL);
CloseHandle(wr);
-
+
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = rd;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -1006,7 +1006,7 @@ static bool is_narrator_running_windows(void)
{
long res = nvdaController_testIfRunning_func();
- if (res != 0)
+ if (res != 0)
{
/* The running nvda service wasn't found, so revert
back to the powershell method
@@ -1057,7 +1057,7 @@ static bool accessibility_speak_windows(int speed,
#ifdef HAVE_NVDA
init_nvda();
#endif
-
+
if (g_plat_win32_flags & PLAT_WIN32_FLAG_USE_POWERSHELL)
{
const char * template_lang = "powershell.exe -NoProfile -WindowStyle Hidden -Command \"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.SelectVoice(\\\"%s\\\"); $synth.Rate = %s; $synth.Speak($input);\"";
@@ -1079,7 +1079,7 @@ static bool accessibility_speak_windows(int speed,
wchar_t *wc = utf8_to_utf16_string_alloc(speak_text);
long res = nvdaController_testIfRunning_func();
- if (!wc || res != 0)
+ if (!wc || res != 0)
{
RARCH_ERR("Error communicating with NVDA\n");
if (wc)
diff --git a/frontend/drivers/platform_xdk.c b/frontend/drivers/platform_xdk.c
index fbe04b3b3e..3ccfb75f6d 100644
--- a/frontend/drivers/platform_xdk.c
+++ b/frontend/drivers/platform_xdk.c
@@ -269,7 +269,7 @@ static void frontend_xdk_exec(const char *path, bool should_load_content)
memset(&ptr, 0, sizeof(ptr));
if (should_load_content && !path_is_empty(RARCH_PATH_CONTENT))
- snprintf((char*)ptr.Data, sizeof(ptr.Data), "%s", path_get(RARCH_PATH_CONTENT));
+ strlcpy((char*)ptr.Data, path_get(RARCH_PATH_CONTENT), sizeof(ptr.Data));
if (!string_is_empty(path))
XLaunchNewImage(path, !string_is_empty((const char*)ptr.Data) ? &ptr : NULL);
diff --git a/record/record_driver.c b/record/record_driver.c
index 89491665ad..5270ca2607 100644
--- a/record/record_driver.c
+++ b/record/record_driver.c
@@ -1,512 +1,522 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
- * Copyright (C) 2011-2021 - Daniel De Matteis
- * Copyright (C) 2016-2019 - Andr�s Su�rez
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see .
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "../configuration.h"
-#include "../list_special.h"
-#include "../gfx/video_driver.h"
-#include "../paths.h"
-#include "../retroarch.h"
-#include "../runloop.h"
-#include "../verbosity.h"
-#include "../defaults.h"
-
-#include "record_driver.h"
-
-static recording_state_t recording_state = {0};
-
-static const record_driver_t record_null = {
- NULL, /* new */
- NULL, /* free */
- NULL, /* push_video */
- NULL, /* push_audio */
- NULL, /* finalize */
- "null",
-};
-
-const record_driver_t *record_drivers[] = {
-#ifdef HAVE_FFMPEG
- &record_ffmpeg,
-#endif
- &record_null,
- NULL,
-};
-
-recording_state_t *recording_state_get_ptr(void)
-{
- return &recording_state;
-}
-
-/**
- * config_get_record_driver_options:
- *
- * Get an enumerated list of all record driver names, separated by '|'.
- *
- * @return string listing of all record driver names, separated by '|'.
- **/
-const char* config_get_record_driver_options(void)
-{
- return char_list_new_special(STRING_LIST_RECORD_DRIVERS, NULL);
-}
-
-#if 0
-/* TODO/FIXME - not used apparently */
-static void find_record_driver(const char *prefix,
- bool verbosity_enabled)
-{
- settings_t *settings = config_get_ptr();
- int i = (int)driver_find_index(
- "record_driver",
- settings->arrays.record_driver);
-
- if (i >= 0)
- recording_state.driver = (const record_driver_t*)record_drivers[i];
- else
- {
- if (verbosity_enabled)
- {
- unsigned d;
-
- RARCH_ERR("[Recording]: Couldn't find any %s named \"%s\".\n", prefix,
- settings->arrays.record_driver);
- RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
- for (d = 0; record_drivers[d]; d++)
- RARCH_LOG_OUTPUT("\t%s\n", record_drivers[d].ident);
- RARCH_WARN("[Recording]: Going to default to first %s...\n", prefix);
- }
-
- recording_state.driver = (const record_driver_t*)record_drivers[0];
-
- if (!recording_state.driver)
- retroarch_fail(1, "find_record_driver()");
- }
-}
-
-/**
- * ffemu_find_backend:
- * @ident : Identifier of driver to find.
- *
- * Finds a recording driver with the name @ident.
- *
- * Returns: recording driver handle if successful, otherwise
- * NULL.
- **/
-static const record_driver_t *ffemu_find_backend(const char *ident)
-{
- unsigned i;
-
- for (i = 0; record_drivers[i]; i++)
- {
- if (string_is_equal(record_drivers[i]->ident, ident))
- return record_drivers[i];
- }
-
- return NULL;
-}
-
-static void recording_driver_free_state(void)
-{
- /* TODO/FIXME - this is not being called anywhere */
- recording_state.gpu_width = 0;
- recording_state.gpu_height = 0;
- recording_state.width = 0;
- recording_stte.height = 0;
-}
-#endif
-
-/**
- * gfx_ctx_init_first:
- * @param backend
- * Recording backend handle.
- * @param data
- * Recording data handle.
- * @param params
- * Recording info parameters.
- *
- * Finds first suitable recording context driver and initializes.
- *
- * @return true if successful, otherwise false.
- **/
-static bool record_driver_init_first(
- const record_driver_t **backend, void **data,
- const struct record_params *params)
-{
- unsigned i;
-
- for (i = 0; record_drivers[i]; i++)
- {
- void *handle = NULL;
- if (!record_drivers[i]->init)
- continue;
- if (!(handle = record_drivers[i]->init(params)))
- continue;
-
- *backend = record_drivers[i];
- *data = handle;
- return true;
- }
-
- return false;
-}
-
-bool recording_deinit(void)
-{
- recording_state_t *recording_st = &recording_state;
-#ifdef HAVE_FFMPEG
- settings_t *settings = config_get_ptr();
- bool history_list_enable = settings->bools.history_list_enable;
-#endif
-
- if ( !recording_st->data
- || !recording_st->driver)
- return false;
-
- if (recording_st->driver->finalize)
- recording_st->driver->finalize(recording_st->data);
-
- if (recording_st->driver->free)
- recording_st->driver->free(recording_st->data);
-
- recording_st->data = NULL;
- recording_st->driver = NULL;
-
- video_driver_gpu_record_deinit();
-
- /* Push recording to video history playlist */
-#ifdef HAVE_FFMPEG
- if ( history_list_enable
- && !string_is_empty(recording_st->path))
- {
- struct playlist_entry entry = {0};
-
- /* the push function reads our entry as const, so these casts are safe */
- entry.path = recording_st->path;
- entry.core_path = (char*)"builtin";
- entry.core_name = (char*)"movieplayer";
-
- command_playlist_push_write(g_defaults.video_history, &entry);
- }
-#endif
-
- /* Forget cached path to create a new one next */
- recording_st->path[0] = '\0';
-
- return true;
-}
-
-void streaming_set_state(bool state)
-{
- recording_state_t *recording_st = &recording_state;
- recording_st->streaming_enable = state;
-}
-
-bool recording_init(void)
-{
- char output[PATH_MAX_LENGTH];
- char buf[PATH_MAX_LENGTH];
- struct record_params params = {0};
- settings_t *settings = config_get_ptr();
- video_driver_state_t *video_st = video_state_get_ptr();
- struct retro_system_av_info *av_info = &video_st->av_info;
- runloop_state_t *runloop_st = runloop_state_get_ptr();
- bool video_gpu_record = settings->bools.video_gpu_record;
- bool video_force_aspect = settings->bools.video_force_aspect;
- const enum rarch_core_type
- current_core_type = runloop_st->current_core_type;
- const enum retro_pixel_format
- video_driver_pix_fmt = video_st->pix_fmt;
- recording_state_t *recording_st = &recording_state;
- bool recording_enable = recording_st->enable;
-
- if (!recording_enable)
- return false;
-
- output[0] = '\0';
-
- if (current_core_type == CORE_TYPE_DUMMY)
- {
- RARCH_WARN("[Recording]: %s\n",
- msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED));
- return false;
- }
-
- if (!video_gpu_record && video_driver_is_hw_context())
- {
- RARCH_WARN("[Recording]: %s.\n",
- msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING));
- return false;
- }
-
- RARCH_LOG("[Recording]: %s: FPS: %.2f, Sample rate: %.2f\n",
- msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN),
- (float)av_info->timing.fps,
- (float)av_info->timing.sample_rate);
-
- if (!string_is_empty(recording_st->path))
- strlcpy(output, recording_st->path, sizeof(output));
- else
- {
- const char *stream_url = settings->paths.path_stream_url;
- unsigned video_record_quality = settings->uints.video_record_quality;
- unsigned video_stream_port = settings->uints.video_stream_port;
- if (recording_st->streaming_enable)
- if (!string_is_empty(stream_url))
- strlcpy(output, stream_url, sizeof(output));
- else
- /* Fallback, stream locally to 127.0.0.1 */
- snprintf(output, sizeof(output), "udp://127.0.0.1:%u",
- video_stream_port);
- else
- {
- const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME));
- /* Fallback to core name if started without content */
- if (string_is_empty(game_name))
- game_name = runloop_st->system.info.library_name;
-
- if (video_record_quality < RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST)
- {
- fill_str_dated_filename(buf, game_name,
- "mkv", sizeof(buf));
- fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
- }
- else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST
- && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_GIF)
- {
- fill_str_dated_filename(buf, game_name,
- "webm", sizeof(buf));
- fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
- }
- else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_GIF
- && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_APNG)
- {
- fill_str_dated_filename(buf, game_name,
- "gif", sizeof(buf));
- fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
- }
- else
- {
- fill_str_dated_filename(buf, game_name,
- "png", sizeof(buf));
- fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
- }
-
- /* Cache path for playlist saving */
- if (!string_is_empty(output))
- strlcpy(recording_st->path, output, sizeof(recording_st->path));
- }
- }
-
- params.audio_resampler = settings->arrays.audio_resampler;
- params.video_gpu_record = settings->bools.video_gpu_record;
- params.video_record_scale_factor = settings->uints.video_record_scale_factor;
- params.video_stream_scale_factor = settings->uints.video_stream_scale_factor;
- params.video_record_threads = settings->uints.video_record_threads;
- params.streaming_mode = settings->uints.streaming_mode;
-
- params.out_width = av_info->geometry.base_width;
- params.out_height = av_info->geometry.base_height;
- params.fb_width = av_info->geometry.max_width;
- params.fb_height = av_info->geometry.max_height;
- params.channels = 2;
- params.filename = output;
- params.fps = av_info->timing.fps;
- params.samplerate = av_info->timing.sample_rate;
- params.pix_fmt =
- (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
- ? FFEMU_PIX_ARGB8888
- : FFEMU_PIX_RGB565;
- params.config = NULL;
-
- if (!string_is_empty(recording_st->config))
- params.config = recording_st->config;
- else
- {
- if (recording_st->streaming_enable)
- {
- params.config = settings->paths.path_stream_config;
- params.preset = (enum record_config_type)
- settings->uints.video_stream_quality;
- }
- else
- {
- params.config = settings->paths.path_record_config;
- params.preset = (enum record_config_type)
- settings->uints.video_record_quality;
- }
- }
-
- if (settings->bools.video_gpu_record
- && video_st->current_video->read_viewport)
- {
- unsigned gpu_size;
- struct video_viewport vp;
-
- vp.x = 0;
- vp.y = 0;
- vp.width = 0;
- vp.height = 0;
- vp.full_width = 0;
- vp.full_height = 0;
-
- video_driver_get_viewport_info(&vp);
-
- if (!vp.width || !vp.height)
- {
- RARCH_ERR("[Recording]: Failed to get viewport information from video driver. "
- "Cannot start recording ...\n");
- return false;
- }
-
- params.out_width = vp.width;
- params.out_height = vp.height;
- params.fb_width = next_pow2(vp.width);
- params.fb_height = next_pow2(vp.height);
-
- if (video_force_aspect &&
- (video_st->aspect_ratio > 0.0f))
- params.aspect_ratio = video_st->aspect_ratio;
- else
- params.aspect_ratio = (float)vp.width / vp.height;
-
- params.pix_fmt = FFEMU_PIX_BGR24;
- recording_st->gpu_width = vp.width;
- recording_st->gpu_height = vp.height;
-
- RARCH_LOG("[Recording]: %s %ux%u.\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF),
- vp.width, vp.height);
-
- gpu_size = vp.width * vp.height * 3;
- if (!(video_st->record_gpu_buffer = (uint8_t*)malloc(gpu_size)))
- return false;
- }
- else
- {
- if (recording_state.width || recording_state.height)
- {
- params.out_width = recording_state.width;
- params.out_height = recording_state.height;
- }
-
- if (video_force_aspect &&
- (video_st->aspect_ratio > 0.0f))
- params.aspect_ratio = video_st->aspect_ratio;
- else
- params.aspect_ratio = (float)params.out_width / params.out_height;
-
-#ifdef HAVE_VIDEO_FILTER
- if (settings->bools.video_post_filter_record
- && !!video_st->state_filter)
- {
- unsigned max_width = 0;
- unsigned max_height = 0;
-
- params.pix_fmt = FFEMU_PIX_RGB565;
-
- if (video_st->flags & VIDEO_FLAG_STATE_OUT_RGB32)
- params.pix_fmt = FFEMU_PIX_ARGB8888;
-
- rarch_softfilter_get_max_output_size(
- video_st->state_filter,
- &max_width, &max_height);
- params.fb_width = next_pow2(max_width);
- params.fb_height = next_pow2(max_height);
- }
-#endif
- }
-
- RARCH_LOG("[Recording]: %s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n",
- msg_hash_to_str(MSG_RECORDING_TO),
- output,
- params.out_width, params.out_height,
- params.fb_width, params.fb_height,
- (unsigned)params.pix_fmt);
-
- if (!record_driver_init_first(
- &recording_state.driver,
- &recording_state.data, ¶ms))
- {
- RARCH_ERR("[Recording]: %s\n",
- msg_hash_to_str(MSG_FAILED_TO_START_RECORDING));
- video_driver_gpu_record_deinit();
-
- return false;
- }
-
- return true;
-}
-
-void recording_driver_update_streaming_url(void)
-{
- settings_t *settings = config_get_ptr();
- const char *youtube_url = "rtmp://a.rtmp.youtube.com/live2/";
- const char *twitch_url = "rtmp://live.twitch.tv/app/";
- const char *facebook_url = "rtmps://live-api-s.facebook.com:443/rtmp/";
-
- if (!settings)
- return;
-
- switch (settings->uints.streaming_mode)
- {
- case STREAMING_MODE_TWITCH:
- if (!string_is_empty(settings->arrays.twitch_stream_key))
- {
- size_t _len = strlcpy(settings->paths.path_stream_url,
- twitch_url,
- sizeof(settings->paths.path_stream_url));
- strlcpy(settings->paths.path_stream_url + _len,
- settings->arrays.twitch_stream_key,
- sizeof(settings->paths.path_stream_url) - _len);
- }
- break;
- case STREAMING_MODE_YOUTUBE:
- if (!string_is_empty(settings->arrays.youtube_stream_key))
- {
- size_t _len = strlcpy(settings->paths.path_stream_url,
- youtube_url,
- sizeof(settings->paths.path_stream_url));
- strlcpy(settings->paths.path_stream_url + _len,
- settings->arrays.youtube_stream_key,
- sizeof(settings->paths.path_stream_url) - _len);
- }
- break;
- case STREAMING_MODE_LOCAL:
- /* TODO: figure out default interface and bind to that instead */
- snprintf(settings->paths.path_stream_url, sizeof(settings->paths.path_stream_url),
- "udp://%s:%u", "127.0.0.1", settings->uints.video_stream_port);
- break;
- case STREAMING_MODE_CUSTOM:
- default:
- /* Do nothing, let the user input the URL */
- break;
- case STREAMING_MODE_FACEBOOK:
- if (!string_is_empty(settings->arrays.facebook_stream_key))
- {
- size_t _len = strlcpy(settings->paths.path_stream_url,
- facebook_url,
- sizeof(settings->paths.path_stream_url));
- strlcpy(settings->paths.path_stream_url + _len,
- settings->arrays.facebook_stream_key,
- sizeof(settings->paths.path_stream_url) - _len);
- }
- break;
- }
-}
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2021 - Daniel De Matteis
+ * Copyright (C) 2016-2019 - Andr�s Su�rez
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "../configuration.h"
+#include "../list_special.h"
+#include "../gfx/video_driver.h"
+#include "../paths.h"
+#include "../retroarch.h"
+#include "../runloop.h"
+#include "../verbosity.h"
+#include "../defaults.h"
+
+#include "record_driver.h"
+
+static recording_state_t recording_state = {0};
+
+static const record_driver_t record_null = {
+ NULL, /* new */
+ NULL, /* free */
+ NULL, /* push_video */
+ NULL, /* push_audio */
+ NULL, /* finalize */
+ "null",
+};
+
+const record_driver_t *record_drivers[] = {
+#ifdef HAVE_FFMPEG
+ &record_ffmpeg,
+#endif
+ &record_null,
+ NULL,
+};
+
+recording_state_t *recording_state_get_ptr(void)
+{
+ return &recording_state;
+}
+
+/**
+ * config_get_record_driver_options:
+ *
+ * Get an enumerated list of all record driver names, separated by '|'.
+ *
+ * @return string listing of all record driver names, separated by '|'.
+ **/
+const char* config_get_record_driver_options(void)
+{
+ return char_list_new_special(STRING_LIST_RECORD_DRIVERS, NULL);
+}
+
+#if 0
+/* TODO/FIXME - not used apparently */
+static void find_record_driver(const char *prefix,
+ bool verbosity_enabled)
+{
+ settings_t *settings = config_get_ptr();
+ int i = (int)driver_find_index(
+ "record_driver",
+ settings->arrays.record_driver);
+
+ if (i >= 0)
+ recording_state.driver = (const record_driver_t*)record_drivers[i];
+ else
+ {
+ if (verbosity_enabled)
+ {
+ unsigned d;
+
+ RARCH_ERR("[Recording]: Couldn't find any %s named \"%s\".\n", prefix,
+ settings->arrays.record_driver);
+ RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
+ for (d = 0; record_drivers[d]; d++)
+ RARCH_LOG_OUTPUT("\t%s\n", record_drivers[d].ident);
+ RARCH_WARN("[Recording]: Going to default to first %s...\n", prefix);
+ }
+
+ recording_state.driver = (const record_driver_t*)record_drivers[0];
+
+ if (!recording_state.driver)
+ retroarch_fail(1, "find_record_driver()");
+ }
+}
+
+/**
+ * ffemu_find_backend:
+ * @ident : Identifier of driver to find.
+ *
+ * Finds a recording driver with the name @ident.
+ *
+ * Returns: recording driver handle if successful, otherwise
+ * NULL.
+ **/
+static const record_driver_t *ffemu_find_backend(const char *ident)
+{
+ unsigned i;
+
+ for (i = 0; record_drivers[i]; i++)
+ {
+ if (string_is_equal(record_drivers[i]->ident, ident))
+ return record_drivers[i];
+ }
+
+ return NULL;
+}
+
+static void recording_driver_free_state(void)
+{
+ /* TODO/FIXME - this is not being called anywhere */
+ recording_state.gpu_width = 0;
+ recording_state.gpu_height = 0;
+ recording_state.width = 0;
+ recording_stte.height = 0;
+}
+#endif
+
+/**
+ * gfx_ctx_init_first:
+ * @param backend
+ * Recording backend handle.
+ * @param data
+ * Recording data handle.
+ * @param params
+ * Recording info parameters.
+ *
+ * Finds first suitable recording context driver and initializes.
+ *
+ * @return true if successful, otherwise false.
+ **/
+static bool record_driver_init_first(
+ const record_driver_t **backend, void **data,
+ const struct record_params *params)
+{
+ unsigned i;
+
+ for (i = 0; record_drivers[i]; i++)
+ {
+ void *handle = NULL;
+ if (!record_drivers[i]->init)
+ continue;
+ if (!(handle = record_drivers[i]->init(params)))
+ continue;
+
+ *backend = record_drivers[i];
+ *data = handle;
+ return true;
+ }
+
+ return false;
+}
+
+bool recording_deinit(void)
+{
+ recording_state_t *recording_st = &recording_state;
+#ifdef HAVE_FFMPEG
+ settings_t *settings = config_get_ptr();
+ bool history_list_enable = settings->bools.history_list_enable;
+#endif
+
+ if ( !recording_st->data
+ || !recording_st->driver)
+ return false;
+
+ if (recording_st->driver->finalize)
+ recording_st->driver->finalize(recording_st->data);
+
+ if (recording_st->driver->free)
+ recording_st->driver->free(recording_st->data);
+
+ recording_st->data = NULL;
+ recording_st->driver = NULL;
+
+ video_driver_gpu_record_deinit();
+
+ /* Push recording to video history playlist */
+#ifdef HAVE_FFMPEG
+ if ( history_list_enable
+ && !string_is_empty(recording_st->path))
+ {
+ struct playlist_entry entry = {0};
+
+ /* the push function reads our entry as const, so these casts are safe */
+ entry.path = recording_st->path;
+ entry.core_path = (char*)"builtin";
+ entry.core_name = (char*)"movieplayer";
+
+ command_playlist_push_write(g_defaults.video_history, &entry);
+ }
+#endif
+
+ /* Forget cached path to create a new one next */
+ recording_st->path[0] = '\0';
+
+ return true;
+}
+
+void streaming_set_state(bool state)
+{
+ recording_state_t *recording_st = &recording_state;
+ recording_st->streaming_enable = state;
+}
+
+bool recording_init(void)
+{
+ char output[PATH_MAX_LENGTH];
+ char buf[PATH_MAX_LENGTH];
+ struct record_params params = {0};
+ settings_t *settings = config_get_ptr();
+ video_driver_state_t *video_st = video_state_get_ptr();
+ struct retro_system_av_info *av_info = &video_st->av_info;
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+ bool video_gpu_record = settings->bools.video_gpu_record;
+ bool video_force_aspect = settings->bools.video_force_aspect;
+ const enum rarch_core_type
+ current_core_type = runloop_st->current_core_type;
+ const enum retro_pixel_format
+ video_driver_pix_fmt = video_st->pix_fmt;
+ recording_state_t *recording_st = &recording_state;
+ bool recording_enable = recording_st->enable;
+
+ if (!recording_enable)
+ return false;
+
+ output[0] = '\0';
+
+ if (current_core_type == CORE_TYPE_DUMMY)
+ {
+ RARCH_WARN("[Recording]: %s\n",
+ msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED));
+ return false;
+ }
+
+ if (!video_gpu_record && video_driver_is_hw_context())
+ {
+ RARCH_WARN("[Recording]: %s.\n",
+ msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING));
+ return false;
+ }
+
+ RARCH_LOG("[Recording]: %s: FPS: %.2f, Sample rate: %.2f\n",
+ msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN),
+ (float)av_info->timing.fps,
+ (float)av_info->timing.sample_rate);
+
+ if (!string_is_empty(recording_st->path))
+ strlcpy(output, recording_st->path, sizeof(output));
+ else
+ {
+ const char *stream_url = settings->paths.path_stream_url;
+ unsigned video_record_quality = settings->uints.video_record_quality;
+ unsigned video_stream_port = settings->uints.video_stream_port;
+ if (recording_st->streaming_enable)
+ {
+ if (!string_is_empty(stream_url))
+ strlcpy(output, stream_url, sizeof(output));
+ else
+ {
+ /* Fallback, stream locally to 127.0.0.1 */
+ size_t _len = strlcpy(output, "udp://127.0.0.1:", sizeof(output));
+ snprintf(output + _len, sizeof(output) - _len, "%u",
+ video_stream_port);
+ }
+ }
+ else
+ {
+ const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME));
+ /* Fallback to core name if started without content */
+ if (string_is_empty(game_name))
+ game_name = runloop_st->system.info.library_name;
+
+ if (video_record_quality < RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST)
+ {
+ fill_str_dated_filename(buf, game_name,
+ "mkv", sizeof(buf));
+ fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
+ }
+ else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_WEBM_FAST
+ && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_GIF)
+ {
+ fill_str_dated_filename(buf, game_name,
+ "webm", sizeof(buf));
+ fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
+ }
+ else if (video_record_quality >= RECORD_CONFIG_TYPE_RECORDING_GIF
+ && video_record_quality < RECORD_CONFIG_TYPE_RECORDING_APNG)
+ {
+ fill_str_dated_filename(buf, game_name,
+ "gif", sizeof(buf));
+ fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
+ }
+ else
+ {
+ fill_str_dated_filename(buf, game_name,
+ "png", sizeof(buf));
+ fill_pathname_join_special(output, recording_st->output_dir, buf, sizeof(output));
+ }
+
+ /* Cache path for playlist saving */
+ if (!string_is_empty(output))
+ strlcpy(recording_st->path, output, sizeof(recording_st->path));
+ }
+ }
+
+ params.audio_resampler = settings->arrays.audio_resampler;
+ params.video_gpu_record = settings->bools.video_gpu_record;
+ params.video_record_scale_factor = settings->uints.video_record_scale_factor;
+ params.video_stream_scale_factor = settings->uints.video_stream_scale_factor;
+ params.video_record_threads = settings->uints.video_record_threads;
+ params.streaming_mode = settings->uints.streaming_mode;
+
+ params.out_width = av_info->geometry.base_width;
+ params.out_height = av_info->geometry.base_height;
+ params.fb_width = av_info->geometry.max_width;
+ params.fb_height = av_info->geometry.max_height;
+ params.channels = 2;
+ params.filename = output;
+ params.fps = av_info->timing.fps;
+ params.samplerate = av_info->timing.sample_rate;
+ params.pix_fmt =
+ (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
+ ? FFEMU_PIX_ARGB8888
+ : FFEMU_PIX_RGB565;
+ params.config = NULL;
+
+ if (!string_is_empty(recording_st->config))
+ params.config = recording_st->config;
+ else
+ {
+ if (recording_st->streaming_enable)
+ {
+ params.config = settings->paths.path_stream_config;
+ params.preset = (enum record_config_type)
+ settings->uints.video_stream_quality;
+ }
+ else
+ {
+ params.config = settings->paths.path_record_config;
+ params.preset = (enum record_config_type)
+ settings->uints.video_record_quality;
+ }
+ }
+
+ if (settings->bools.video_gpu_record
+ && video_st->current_video->read_viewport)
+ {
+ unsigned gpu_size;
+ struct video_viewport vp;
+
+ vp.x = 0;
+ vp.y = 0;
+ vp.width = 0;
+ vp.height = 0;
+ vp.full_width = 0;
+ vp.full_height = 0;
+
+ video_driver_get_viewport_info(&vp);
+
+ if (!vp.width || !vp.height)
+ {
+ RARCH_ERR("[Recording]: Failed to get viewport information from video driver. "
+ "Cannot start recording ...\n");
+ return false;
+ }
+
+ params.out_width = vp.width;
+ params.out_height = vp.height;
+ params.fb_width = next_pow2(vp.width);
+ params.fb_height = next_pow2(vp.height);
+
+ if (video_force_aspect &&
+ (video_st->aspect_ratio > 0.0f))
+ params.aspect_ratio = video_st->aspect_ratio;
+ else
+ params.aspect_ratio = (float)vp.width / vp.height;
+
+ params.pix_fmt = FFEMU_PIX_BGR24;
+ recording_st->gpu_width = vp.width;
+ recording_st->gpu_height = vp.height;
+
+ RARCH_LOG("[Recording]: %s %ux%u.\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF),
+ vp.width, vp.height);
+
+ gpu_size = vp.width * vp.height * 3;
+ if (!(video_st->record_gpu_buffer = (uint8_t*)malloc(gpu_size)))
+ return false;
+ }
+ else
+ {
+ if (recording_state.width || recording_state.height)
+ {
+ params.out_width = recording_state.width;
+ params.out_height = recording_state.height;
+ }
+
+ if (video_force_aspect &&
+ (video_st->aspect_ratio > 0.0f))
+ params.aspect_ratio = video_st->aspect_ratio;
+ else
+ params.aspect_ratio = (float)params.out_width / params.out_height;
+
+#ifdef HAVE_VIDEO_FILTER
+ if (settings->bools.video_post_filter_record
+ && !!video_st->state_filter)
+ {
+ unsigned max_width = 0;
+ unsigned max_height = 0;
+
+ params.pix_fmt = FFEMU_PIX_RGB565;
+
+ if (video_st->flags & VIDEO_FLAG_STATE_OUT_RGB32)
+ params.pix_fmt = FFEMU_PIX_ARGB8888;
+
+ rarch_softfilter_get_max_output_size(
+ video_st->state_filter,
+ &max_width, &max_height);
+ params.fb_width = next_pow2(max_width);
+ params.fb_height = next_pow2(max_height);
+ }
+#endif
+ }
+
+ RARCH_LOG("[Recording]: %s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n",
+ msg_hash_to_str(MSG_RECORDING_TO),
+ output,
+ params.out_width, params.out_height,
+ params.fb_width, params.fb_height,
+ (unsigned)params.pix_fmt);
+
+ if (!record_driver_init_first(
+ &recording_state.driver,
+ &recording_state.data, ¶ms))
+ {
+ RARCH_ERR("[Recording]: %s\n",
+ msg_hash_to_str(MSG_FAILED_TO_START_RECORDING));
+ video_driver_gpu_record_deinit();
+
+ return false;
+ }
+
+ return true;
+}
+
+void recording_driver_update_streaming_url(void)
+{
+ settings_t *settings = config_get_ptr();
+ const char *youtube_url = "rtmp://a.rtmp.youtube.com/live2/";
+ const char *twitch_url = "rtmp://live.twitch.tv/app/";
+ const char *facebook_url = "rtmps://live-api-s.facebook.com:443/rtmp/";
+
+ if (!settings)
+ return;
+
+ switch (settings->uints.streaming_mode)
+ {
+ case STREAMING_MODE_TWITCH:
+ if (!string_is_empty(settings->arrays.twitch_stream_key))
+ {
+ size_t _len = strlcpy(settings->paths.path_stream_url,
+ twitch_url,
+ sizeof(settings->paths.path_stream_url));
+ strlcpy(settings->paths.path_stream_url + _len,
+ settings->arrays.twitch_stream_key,
+ sizeof(settings->paths.path_stream_url) - _len);
+ }
+ break;
+ case STREAMING_MODE_YOUTUBE:
+ if (!string_is_empty(settings->arrays.youtube_stream_key))
+ {
+ size_t _len = strlcpy(settings->paths.path_stream_url,
+ youtube_url,
+ sizeof(settings->paths.path_stream_url));
+ strlcpy(settings->paths.path_stream_url + _len,
+ settings->arrays.youtube_stream_key,
+ sizeof(settings->paths.path_stream_url) - _len);
+ }
+ break;
+ case STREAMING_MODE_LOCAL:
+ {
+ /* TODO: figure out default interface and bind to that instead */
+ size_t _len = strlcpy(settings->paths.path_stream_url, "udp://127.0.0.1:",
+ sizeof(settings->paths.path_stream_url));
+ snprintf(settings->paths.path_stream_url + _len,
+ sizeof(settings->paths.path_stream_url) - _len,
+ "%u", settings->uints.video_stream_port);
+ }
+ break;
+ case STREAMING_MODE_FACEBOOK:
+ if (!string_is_empty(settings->arrays.facebook_stream_key))
+ {
+ size_t _len = strlcpy(settings->paths.path_stream_url,
+ facebook_url,
+ sizeof(settings->paths.path_stream_url));
+ strlcpy(settings->paths.path_stream_url + _len,
+ settings->arrays.facebook_stream_key,
+ sizeof(settings->paths.path_stream_url) - _len);
+ }
+ break;
+ case STREAMING_MODE_CUSTOM:
+ default:
+ /* Do nothing, let the user input the URL */
+ break;
+ }
+}
diff --git a/retroarch.c b/retroarch.c
index c6e075587d..f3dec5dd32 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -8171,7 +8171,7 @@ int retroarch_get_capabilities(enum rarch_capabilities type,
_MSC_VER);
#elif defined(__SNC__)
_len = strlcpy(str_out, msg_hash_to_str(MSG_COMPILER), str_len);
- _len += snprintf(str_out + _len, str_len - _Len, ": SNC (%d)",
+ _len += snprintf(str_out + _len, str_len - _len, ": SNC (%d)",
__SN_VER__);
#elif defined(_WIN32) && defined(__GNUC__)
_len = strlcpy(str_out, msg_hash_to_str(MSG_COMPILER), str_len);