diff --git a/configuration.c b/configuration.c index 7abcbc70e4..2b619bbff2 100644 --- a/configuration.c +++ b/configuration.c @@ -3041,6 +3041,7 @@ static bool config_load_file(const char *path, bool set_defaults, } frontend_driver_set_sustained_performance_mode(settings->bools.sustained_performance_mode); + recording_driver_update_streaming_url(); ret = true; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 9eca05ff91..bab44cb644 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -2656,6 +2656,7 @@ static int menu_displaylist_parse_load_content_settings( MENU_ENUM_LABEL_ADD_TO_FAVORITES, FILE_TYPE_PLAYLIST_ENTRY, 0, 0); } +#ifdef HAVE_FFMPEG if (!recording_is_enabled()) { menu_entries_append_enum(info->list, @@ -2680,8 +2681,8 @@ static int menu_displaylist_parse_load_content_settings( msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QUICK_MENU_STOP_RECORDING), msg_hash_to_str(MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING), MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING, MENU_SETTING_ACTION, 0, 0); - } +#endif if (settings->bools.quick_menu_show_options && !settings->bools.kiosk_mode_enable) { @@ -7050,43 +7051,37 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) info->need_push = true; break; case DISPLAYLIST_RECORDING_SETTINGS_LIST: + { + settings_t *settings = config_get_ptr(); menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_RECORD_ENABLE, - PARSE_ONLY_BOOL, false) == 0) + MENU_ENUM_LABEL_VIDEO_RECORD_QUALITY, + PARSE_ONLY_UINT, false) == 0) count++; if (menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_RECORD_CONFIG, PARSE_ONLY_PATH, false) == 0) count++; if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_STREAM_CONFIG, - PARSE_ONLY_PATH, false) == 0) + MENU_ENUM_LABEL_VIDEO_STREAM_QUALITY, + PARSE_ONLY_UINT, false) == 0) count++; if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_RECORD_PATH, - PARSE_ONLY_STRING, false) == 0) + MENU_ENUM_LABEL_STREAM_CONFIG, + PARSE_ONLY_PATH, false) == 0) count++; if (menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_STREAMING_MODE, PARSE_ONLY_UINT, false) == 0) count++; - if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_RECORD_USE_OUTPUT_DIRECTORY, - PARSE_ONLY_BOOL, false) == 0) - count++; - if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_UDP_STREAM_PORT, - PARSE_ONLY_UINT, false) == 0) - count++; - if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_VIDEO_RECORD_QUALITY, - PARSE_ONLY_UINT, false) == 0) - count++; - if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_VIDEO_STREAM_QUALITY, - PARSE_ONLY_UINT, false) == 0) - count++; + if (settings->uints.streaming_mode == STREAMING_MODE_LOCAL) + { + /* To-Do: Refresh on settings->uints.streaming_mode change to show this parameter */ + if (menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_UDP_STREAM_PORT, + PARSE_ONLY_UINT, false) == 0) + count++; + } if (menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_STREAMING_URL, PARSE_ONLY_STRING, false) == 0) @@ -7108,6 +7103,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) 0, 0, 0); info->need_push = true; + } break; case DISPLAYLIST_MAIN_MENU: menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 0981042b42..6557d98bf6 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -305,8 +305,11 @@ static void setting_get_string_representation_streaming_mode( case STREAMING_MODE_YOUTUBE: strlcpy(s, "YouTube", len); break; - case STREAMING_MODE_UDP: - strlcpy(s, "UDP", len); + case STREAMING_MODE_LOCAL: + strlcpy(s, "Local", len); + break; + case STREAMING_MODE_CUSTOM: + strlcpy(s, "Custom", len); break; } } @@ -2950,6 +2953,13 @@ static void achievement_hardcore_mode_write_handler(rarch_setting_t *setting) } #endif +#ifdef HAVE_FFMPEG +static void update_streaming_url_write_handler(rarch_setting_t *setting) +{ + recording_driver_update_streaming_url(); +} +#endif + #ifdef HAVE_LAKKA static void systemd_service_toggle(const char *path, char *unit, bool enable) { @@ -6485,99 +6495,100 @@ static bool setting_append_list( parent_group = msg_hash_to_str(MENU_ENUM_LABEL_RECORDING_SETTINGS); START_SUB_GROUP(list, list_info, "State", &group_info, &subgroup_info, parent_group); - CONFIG_PATH( - list, list_info, - settings->paths.path_record_config, - sizeof(settings->paths.path_record_config), - MENU_ENUM_LABEL_RECORD_CONFIG, - MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "", - &group_info, - &subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - menu_settings_list_current_add_values(list, list_info, "cfg"); + + CONFIG_UINT( + list, list_info, + &settings->uints.video_record_quality, + MENU_ENUM_LABEL_VIDEO_RECORD_QUALITY, + MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_QUALITY, + RECORD_CONFIG_TYPE_RECORDING_MED_QUALITY, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_video_record_quality; + menu_settings_list_current_add_range(list, list_info, RECORD_CONFIG_TYPE_RECORDING_CUSTOM, RECORD_CONFIG_TYPE_RECORDING_LOSSLESS_QUALITY, 1, true, true); CONFIG_PATH( - list, list_info, - settings->paths.path_stream_config, - sizeof(settings->paths.path_stream_config), - MENU_ENUM_LABEL_STREAM_CONFIG, - MENU_ENUM_LABEL_VALUE_STREAM_CONFIG, - "", - &group_info, - &subgroup_info, - parent_group, - general_write_handler, - general_read_handler); + list, list_info, + settings->paths.path_record_config, + sizeof(settings->paths.path_record_config), + MENU_ENUM_LABEL_RECORD_CONFIG, + MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, + "", + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); menu_settings_list_current_add_values(list, list_info, "cfg"); - CONFIG_UINT( - list, list_info, - &settings->uints.streaming_mode, - MENU_ENUM_LABEL_STREAMING_MODE, - MENU_ENUM_LABEL_VALUE_STREAMING_MODE, - STREAMING_MODE_TWITCH, - &group_info, - &subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; - (*list)[list_info->index - 1].get_string_representation = - &setting_get_string_representation_streaming_mode; - menu_settings_list_current_add_range(list, list_info, 0, 2, 1, true, true); + CONFIG_UINT( + list, list_info, + &settings->uints.streaming_mode, + MENU_ENUM_LABEL_STREAMING_MODE, + MENU_ENUM_LABEL_VALUE_STREAMING_MODE, + STREAMING_MODE_TWITCH, + &group_info, + &subgroup_info, + parent_group, + update_streaming_url_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_streaming_mode; + menu_settings_list_current_add_range(list, list_info, 0, STREAMING_MODE_CUSTOM, 1, true, true); - CONFIG_UINT( - list, list_info, - &settings->uints.video_stream_port, - MENU_ENUM_LABEL_UDP_STREAM_PORT, - MENU_ENUM_LABEL_VALUE_UDP_STREAM_PORT, - 1, - &group_info, - &subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; - (*list)[list_info->index - 1].offset_by = 1; - menu_settings_list_current_add_range(list, list_info, 1, 65536, 1, true, true); + CONFIG_UINT( + list, list_info, + &settings->uints.video_stream_port, + MENU_ENUM_LABEL_UDP_STREAM_PORT, + MENU_ENUM_LABEL_VALUE_UDP_STREAM_PORT, + 1, + &group_info, + &subgroup_info, + parent_group, + update_streaming_url_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].offset_by = 1; + menu_settings_list_current_add_range(list, list_info, 1, 65536, 1, true, true); - CONFIG_UINT( - list, list_info, - &settings->uints.video_record_quality, - MENU_ENUM_LABEL_VIDEO_RECORD_QUALITY, - MENU_ENUM_LABEL_VALUE_VIDEO_RECORD_QUALITY, - 1, - &group_info, - &subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; - (*list)[list_info->index - 1].get_string_representation = - &setting_get_string_representation_video_record_quality; - menu_settings_list_current_add_range(list, list_info, 0, 4, 1, true, true); - - CONFIG_UINT( - list, list_info, - &settings->uints.video_stream_quality, - MENU_ENUM_LABEL_VIDEO_STREAM_QUALITY, - MENU_ENUM_LABEL_VALUE_VIDEO_STREAM_QUALITY, - 1, - &group_info, - &subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; - (*list)[list_info->index - 1].get_string_representation = - &setting_get_string_representation_video_stream_quality; - (*list)[list_info->index - 1].offset_by = 5; - menu_settings_list_current_add_range(list, list_info, 5, 8, 1, true, true); + CONFIG_UINT( + list, list_info, + &settings->uints.video_stream_quality, + MENU_ENUM_LABEL_VIDEO_STREAM_QUALITY, + MENU_ENUM_LABEL_VALUE_VIDEO_STREAM_QUALITY, + RECORD_CONFIG_TYPE_STREAMING_MED_QUALITY, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_video_stream_quality; + (*list)[list_info->index - 1].offset_by = 5; + menu_settings_list_current_add_range(list, list_info, RECORD_CONFIG_TYPE_STREAMING_CUSTOM, RECORD_CONFIG_TYPE_STREAMING_HIGH_QUALITY, 1, true, true); - CONFIG_STRING( + CONFIG_PATH( + list, list_info, + settings->paths.path_stream_config, + sizeof(settings->paths.path_stream_config), + MENU_ENUM_LABEL_STREAM_CONFIG, + MENU_ENUM_LABEL_VALUE_STREAM_CONFIG, + "", + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + menu_settings_list_current_add_values(list, list_info, "cfg"); + + CONFIG_STRING( list, list_info, settings->paths.path_stream_url, sizeof(settings->paths.path_stream_url), @@ -6589,9 +6600,9 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); - settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); + settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); - CONFIG_DIR( + CONFIG_DIR( list, list_info, global->record.output_dir, sizeof(global->record.output_dir), @@ -6604,7 +6615,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); - (*list)[list_info->index - 1].action_start = directory_action_start_generic; + (*list)[list_info->index - 1].action_start = directory_action_start_generic; END_SUB_GROUP(list, list_info, parent_group); @@ -9646,7 +9657,7 @@ static bool setting_append_list( &group_info, &subgroup_info, parent_group, - general_write_handler, + update_streaming_url_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); @@ -9672,7 +9683,7 @@ static bool setting_append_list( &group_info, &subgroup_info, parent_group, - general_write_handler, + update_streaming_url_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); diff --git a/record/drivers/record_ffmpeg.c b/record/drivers/record_ffmpeg.c index d7831962b3..a4c332ac45 100644 --- a/record/drivers/record_ffmpeg.c +++ b/record/drivers/record_ffmpeg.c @@ -597,7 +597,7 @@ static bool ffmpeg_init_config_common(struct ff_config_param *params, unsigned p strlcpy(params->vcodec, "libx264", sizeof(params->vcodec)); strlcpy(params->acodec, "libmp3lame", sizeof(params->acodec)); - av_dict_set(¶ms->video_opts, "preset", "medium", 0); + av_dict_set(¶ms->video_opts, "preset", "superfast", 0); av_dict_set(¶ms->video_opts, "tune", "animation", 0); av_dict_set(¶ms->video_opts, "crf", "15", 0); av_dict_set(¶ms->audio_opts, "audio_global_quality", "100", 0); @@ -652,12 +652,15 @@ static bool ffmpeg_init_config_common(struct ff_config_param *params, unsigned p settings->uints.video_stream_scale_factor : 1; else params->scale_factor = 1; - strlcpy(params->format, "flv", sizeof(params->format)); + if (settings->uints.streaming_mode == STREAMING_MODE_YOUTUBE || settings->uints.streaming_mode == STREAMING_MODE_TWITCH) + strlcpy(params->format, "flv", sizeof(params->format)); + else + strlcpy(params->format, "mpegts", sizeof(params->format)); } - else + else if (preset == RECORD_CONFIG_TYPE_STREAMING_NETPLAY) { params->scale_factor = 1; - strlcpy(params->format, "flv", sizeof(params->format)); + strlcpy(params->format, "mpegts", sizeof(params->format)); } return true; @@ -698,9 +701,10 @@ static bool ffmpeg_init_config(struct ff_config_param *params, return true; params->conf = config_file_new(config); + RARCH_LOG("[FFmpeg] Loading FFmpeg config \"%s\".\n", config); if (!params->conf) { - RARCH_ERR("Failed to load FFmpeg config \"%s\".\n", config); + RARCH_ERR("[FFmpeg] Failed to load FFmpeg config \"%s\".\n", config); return false; } @@ -735,7 +739,7 @@ static bool ffmpeg_init_config(struct ff_config_param *params, params->out_pix_fmt = av_get_pix_fmt(pix_fmt); if (params->out_pix_fmt == PIX_FMT_NONE) { - RARCH_ERR("Cannot find pix_fmt \"%s\".\n", pix_fmt); + RARCH_ERR("[FFmpeg] Cannot find pix_fmt \"%s\".\n", pix_fmt); return false; } } @@ -938,7 +942,7 @@ static void *ffmpeg_new(const struct record_params *params) handle->params = *params; - if (params->preset == RECORD_CONFIG_TYPE_RECORDING_CUSTOM) + if (params->preset == RECORD_CONFIG_TYPE_RECORDING_CUSTOM || params->preset == RECORD_CONFIG_TYPE_STREAMING_CUSTOM) { if (!ffmpeg_init_config(&handle->config, params->config)) goto error; diff --git a/record/record_driver.c b/record/record_driver.c index 6f02833859..32896df950 100644 --- a/record/record_driver.c +++ b/record/record_driver.c @@ -37,7 +37,6 @@ #include "../list_special.h" #include "../paths.h" - static const record_driver_t *record_drivers[] = { #ifdef HAVE_FFMPEG &record_ffmpeg, @@ -119,12 +118,12 @@ void find_record_driver(void) { unsigned d; - RARCH_ERR("Couldn't find any record driver named \"%s\"\n", + RARCH_ERR("[recording] Couldn't find any record driver named \"%s\"\n", settings->arrays.record_driver); RARCH_LOG_OUTPUT("Available record drivers are:\n"); for (d = 0; record_driver_find_handle(d); d++) RARCH_LOG_OUTPUT("\t%s\n", record_driver_find_ident(d)); - RARCH_WARN("Going to default to first record driver...\n"); + RARCH_WARN("[recording] Going to default to first record driver...\n"); } recording_driver = (const record_driver_t*)record_driver_find_handle(0); @@ -217,7 +216,7 @@ void recording_dump_frame(const void *data, unsigned width, if (!vp.width || !vp.height) { - RARCH_WARN("%s \n", + RARCH_WARN("[recording] %s \n", msg_hash_to_str(MSG_VIEWPORT_SIZE_CALCULATION_FAILED)); command_event(CMD_EVENT_GPU_RECORD_DEINIT, NULL); @@ -229,7 +228,7 @@ void recording_dump_frame(const void *data, unsigned width, if ( vp.width != recording_gpu_width || vp.height != recording_gpu_height) { - RARCH_WARN("%s\n", msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE)); + RARCH_WARN("[recording] %s\n", msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE)); runloop_msg_queue_push( msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE), @@ -336,7 +335,7 @@ bool recording_init(void) if (rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { - RARCH_WARN("%s\n", + RARCH_WARN("[recording] %s\n", msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED)); return false; } @@ -344,12 +343,12 @@ bool recording_init(void) if (!settings->bools.video_gpu_record && video_driver_is_hw_context()) { - RARCH_WARN("%s.\n", + RARCH_WARN("[recording] %s.\n", msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING)); return false; } - RARCH_LOG("%s: FPS: %.4f, Sample rate: %.4f\n", + RARCH_LOG("[recording] %s: FPS: %.4f, Sample rate: %.4f\n", msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN), (float)av_info->timing.fps, (float)av_info->timing.sample_rate); @@ -362,7 +361,7 @@ bool recording_init(void) if (!string_is_empty(settings->paths.path_stream_url)) strlcpy(output, settings->paths.path_stream_url, sizeof(output)); else - /* to-do determine the local interface, this won't work for connecting over the internet*/ + /* Fallback, stream locally to 127.0.0.1 */ snprintf(output, sizeof(output), "udp://127.0.0.1:%u", settings->uints.video_stream_port); else { @@ -418,7 +417,7 @@ bool recording_init(void) if (!vp.width || !vp.height) { - RARCH_ERR("Failed to get viewport information from video driver. " + RARCH_ERR("[recording] Failed to get viewport information from video driver. " "Cannot start recording ...\n"); return false; } @@ -438,7 +437,7 @@ bool recording_init(void) recording_gpu_width = vp.width; recording_gpu_height = vp.height; - RARCH_LOG("%s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF), + RARCH_LOG("[recording] %s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF), vp.width, vp.height); gpu_size = vp.width * vp.height * 3; @@ -478,7 +477,7 @@ bool recording_init(void) } } - RARCH_LOG("%s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n", + 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, @@ -487,7 +486,7 @@ bool recording_init(void) if (!record_driver_init_first(&recording_driver, &recording_data, ¶ms)) { - RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_RECORDING)); + RARCH_ERR("[recording] %s\n", msg_hash_to_str(MSG_FAILED_TO_START_RECORDING)); command_event(CMD_EVENT_GPU_RECORD_DEINIT, NULL); return false; @@ -521,6 +520,55 @@ unsigned *recording_driver_get_height(void) return &recording_height; } +void recording_driver_update_streaming_url() +{ + 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/"; + + if (!settings) + return; + + switch (settings->uints.streaming_mode) + { + case STREAMING_MODE_TWITCH: + { + if (!string_is_empty(settings->arrays.twitch_stream_key)) + snprintf(settings->paths.path_stream_url, sizeof(settings->paths.path_stream_url), + "%s%s", twitch_url, settings->arrays.twitch_stream_key); + else + { + /* To-Do: Show input box for twitch_stream_key*/ + RARCH_LOG("[recording] twitch streaming key empty"); + } + break; + } + case STREAMING_MODE_YOUTUBE: + { + if (!string_is_empty(settings->arrays.youtube_stream_key)) + { + snprintf(settings->paths.path_stream_url, sizeof(settings->paths.path_stream_url), + "%s%s", youtube_url, settings->arrays.youtube_stream_key); + } + else + { + /* To-Do: Show input box for youtube_stream_key*/ + RARCH_LOG("[recording] youtube streaming key empty"); + } + break; + } + case STREAMING_MODE_LOCAL: + /* To-Do: 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; + } +} + void recording_driver_free_state(void) { recording_gpu_width = 0; diff --git a/record/record_driver.h b/record/record_driver.h index cf1a4c112c..539cb50698 100644 --- a/record/record_driver.h +++ b/record/record_driver.h @@ -35,7 +35,8 @@ enum streaming_mode { STREAMING_MODE_TWITCH = 0, STREAMING_MODE_YOUTUBE, - STREAMING_MODE_UDP + STREAMING_MODE_LOCAL, + STREAMING_MODE_CUSTOM }; enum record_config_type @@ -207,6 +208,8 @@ bool recording_is_enabled(void); bool streaming_is_enabled(void); +void recording_driver_update_streaming_url(); + extern void *recording_data; RETRO_END_DECLS