aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/Config.hpp20
-rw-r--r--include/Overlay.hpp8
-rw-r--r--include/gui/SettingsPage.hpp2
-rw-r--r--src/Overlay.cpp289
-rw-r--r--src/gui/SettingsPage.cpp6
5 files changed, 204 insertions, 121 deletions
diff --git a/include/Config.hpp b/include/Config.hpp
index 63e7984..549696e 100644
--- a/include/Config.hpp
+++ b/include/Config.hpp
@@ -13,17 +13,17 @@ namespace gsr {
};
struct RecordOptions {
- std::string record_area_option;
+ std::string record_area_option = "screen";
int32_t record_area_width = 0;
int32_t record_area_height = 0;
int32_t fps = 60;
bool merge_audio_tracks = true;
std::vector<std::string> audio_tracks;
- std::string color_range;
- std::string video_quality;
- std::string video_codec;
- std::string audio_codec;
- std::string framerate_mode;
+ std::string color_range = "limited";
+ std::string video_quality = "very_high";
+ std::string video_codec = "auto";
+ std::string audio_codec = "opus";
+ std::string framerate_mode = "vfr";
bool advanced_view = false;
bool overclock = false;
bool record_cursor = true;
@@ -45,14 +45,14 @@ namespace gsr {
struct CustomStreamConfig {
std::string url;
- std::string container;
+ std::string container = "flv";
};
struct StreamingConfig {
RecordOptions record_options;
bool show_streaming_started_notifications = true;
bool show_streaming_stopped_notifications = true;
- std::string streaming_service;
+ std::string streaming_service = "twitch";
YoutubeStreamConfig youtube;
TwitchStreamConfig twitch;
CustomStreamConfig custom;
@@ -64,7 +64,7 @@ namespace gsr {
bool show_recording_started_notifications = true;
bool show_video_saved_notifications = true;
std::string save_directory;
- std::string container;
+ std::string container = "mp4";
ConfigHotkey start_stop_recording_hotkey;
ConfigHotkey pause_unpause_recording_hotkey;
};
@@ -75,7 +75,7 @@ namespace gsr {
bool show_replay_stopped_notifications = true;
bool show_replay_saved_notifications = true;
std::string save_directory;
- std::string container;
+ std::string container = "mp4";
int32_t replay_time = 60;
ConfigHotkey start_stop_recording_hotkey;
ConfigHotkey save_recording_hotkey;
diff --git a/include/Overlay.hpp b/include/Overlay.hpp
index de5fa79..bb366e7 100644
--- a/include/Overlay.hpp
+++ b/include/Overlay.hpp
@@ -13,6 +13,8 @@
#include <mglpp/graphics/Text.hpp>
namespace gsr {
+ class DropdownButton;
+
class Overlay {
public:
Overlay(mgl::Window &window, std::string resources_path, GsrInfo gsr_info, egl_functions egl_funcs, mgl::Color bg_color);
@@ -28,6 +30,9 @@ namespace gsr {
void toggle_show();
bool is_open() const;
private:
+ void on_press_start_replay(const std::string &id);
+ void on_press_start_record(const std::string &id);
+ void on_press_start_stream(const std::string &id);
bool update_compositor_texture(const mgl_monitor *monitor);
private:
mgl::Window &window;
@@ -52,5 +57,8 @@ namespace gsr {
uint64_t default_cursor = 0;
pid_t gpu_screen_recorder_process = -1;
std::optional<Config> config;
+ DropdownButton *replay_dropdown_button_ptr = nullptr;
+ DropdownButton *record_dropdown_button_ptr = nullptr;
+ DropdownButton *stream_dropdown_button_ptr = nullptr;
};
} \ No newline at end of file
diff --git a/include/gui/SettingsPage.hpp b/include/gui/SettingsPage.hpp
index ebbc98c..e9102da 100644
--- a/include/gui/SettingsPage.hpp
+++ b/include/gui/SettingsPage.hpp
@@ -86,7 +86,7 @@ namespace gsr {
std::unique_ptr<List> create_stream_container_section();
void add_stream_widgets();
- void load_audio_tracks();
+ void load_audio_tracks(RecordOptions &record_options);
void load_common(RecordOptions &record_options);
void load_replay();
void load_record();
diff --git a/src/Overlay.cpp b/src/Overlay.cpp
index bc51b42..5bc534f 100644
--- a/src/Overlay.cpp
+++ b/src/Overlay.cpp
@@ -303,129 +303,28 @@ namespace gsr {
{
auto button = std::make_unique<DropdownButton>(&get_theme().title_font, &get_theme().body_font, "Instant Replay", "On", "Off", &get_theme().replay_button_texture,
mgl::vec2f(button_width, button_height));
+ replay_dropdown_button_ptr = button.get();
button->add_item("Start", "start");
button->add_item("Settings", "settings");
- button->on_click = [&](const std::string &id) {
- if(id == "settings") {
- auto replay_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::REPLAY, gsr_info, audio_devices, config, &page_stack);
- page_stack.push(std::move(replay_settings_page));
- return;
- }
- /*
- char window_to_record_str[32];
- snprintf(window_to_record_str, sizeof(window_to_record_str), "%ld", target_window);
-
- const char *args[] = {
- "gpu-screen-recorder", "-w", window_to_record_str,
- "-c", "mp4",
- "-f", "60",
- "-o", "/home/dec05eba/Videos/gpu-screen-recorder.mp4",
- nullptr
- };
- exec_program_daemonized(args);
- */
- };
+ button->on_click = std::bind(&Overlay::on_press_start_replay, this, std::placeholders::_1);
main_buttons_list->add_widget(std::move(button));
}
{
auto button = std::make_unique<DropdownButton>(&get_theme().title_font, &get_theme().body_font, "Record", "Recording", "Not recording", &get_theme().record_button_texture,
mgl::vec2f(button_width, button_height));
- DropdownButton *button_ptr = button.get();
+ record_dropdown_button_ptr = button.get();
button->add_item("Start", "start");
button->add_item("Settings", "settings");
- button->on_click = [&, button_ptr](const std::string &id) {
- if(id == "settings") {
- auto record_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::RECORD, gsr_info, audio_devices, config, &page_stack);
- page_stack.push(std::move(record_settings_page));
- return;
- }
-
- if(id != "start")
- return;
-
- // window.close();
- // usleep(1000 * 50); // 50 milliseconds
-
- const std::string tint_color_as_hex = color_to_hex_str(get_theme().tint_color);
-
- if(gpu_screen_recorder_process > 0) {
- kill(gpu_screen_recorder_process, SIGINT);
- int status;
- if(waitpid(gpu_screen_recorder_process, &status, 0) == -1) {
- perror("waitpid failed");
- /* Ignore... */
- }
- // window.set_visible(false);
- // window.close();
- // return;
- //exit(0);
- gpu_screen_recorder_process = -1;
- button_ptr->set_item_label(id, "Start");
-
- // TODO: Show this with a slight delay to make sure it doesn't show up in the video
- const std::string record_image_filepath = resources_path + "images/record.png";
- const char *notification_args[] = {
- "gsr-notify", "--text", "Recording has been saved", "--timeout", "3.0",
- "--icon", record_image_filepath.c_str(),
- "--icon-color", "ffffff", "--bg-color", tint_color_as_hex.c_str(),
- nullptr
- };
- exec_program_daemonized(notification_args);
- return;
- }
-
- const char *args[] = {
- "gpu-screen-recorder", "-w", "screen",
- "-c", "mp4",
- "-f", "60",
- "-o", "/home/dec05eba/Videos/gpu-screen-recorder.mp4",
- nullptr
- };
- gpu_screen_recorder_process = exec_program(args);
- if(gpu_screen_recorder_process == -1) {
- // TODO: Show notification failed to start
- } else {
- button_ptr->set_item_label(id, "Stop");
- }
-
- // TODO: Start recording after this notification has disappeared to make sure it doesn't show up in the video.
- // Make clear to the user that the recording starts after the notification is gone.
- // Maybe have the option in notification to show timer until its getting hidden, then the notification can say:
- // Starting recording in 3...
- // 2...
- // 1...
- // TODO: Do not run this is a daemon. Instead get the pid and when launching another notification close the current notification
- // program and start another one. This can also be used to check when the notification has finished by checking with waitpid NOWAIT
- // to see when the program has exit.
- const std::string record_image_filepath = resources_path + "images/record.png";
- const char *notification_args[] = {
- "gsr-notify", "--text", "Recording has started", "--timeout", "3.0",
- "--icon", record_image_filepath.c_str(),
- "--icon-color", tint_color_as_hex.c_str(), "--bg-color", tint_color_as_hex.c_str(),
- nullptr
- };
- exec_program_daemonized(notification_args);
- //exit(0);
- // window.set_visible(false);
- // window.close();
-
- // TODO: Show notification with args:
- // "Recording has started" 3.0 ./images/record.png 76b900
- };
+ button->on_click = std::bind(&Overlay::on_press_start_record, this, std::placeholders::_1);
main_buttons_list->add_widget(std::move(button));
}
{
auto button = std::make_unique<DropdownButton>(&get_theme().title_font, &get_theme().body_font, "Livestream", "Streaming", "Not streaming", &get_theme().stream_button_texture,
mgl::vec2f(button_width, button_height));
+ stream_dropdown_button_ptr = button.get();
button->add_item("Start", "start");
button->add_item("Settings", "settings");
- button->on_click = [&](const std::string &id) {
- if(id == "settings") {
- auto stream_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::STREAM, gsr_info, audio_devices, config, &page_stack);
- page_stack.push(std::move(stream_settings_page));
- return;
- }
- };
+ button->on_click = std::bind(&Overlay::on_press_start_replay, this, std::placeholders::_1);
main_buttons_list->add_widget(std::move(button));
}
@@ -528,6 +427,182 @@ namespace gsr {
return visible;
}
+ void Overlay::on_press_start_replay(const std::string &id) {
+ if(id == "settings") {
+ auto replay_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::REPLAY, gsr_info, audio_devices, config, &page_stack);
+ page_stack.push(std::move(replay_settings_page));
+ return;
+ }
+ /*
+ char window_to_record_str[32];
+ snprintf(window_to_record_str, sizeof(window_to_record_str), "%ld", target_window);
+
+ const char *args[] = {
+ "gpu-screen-recorder", "-w", window_to_record_str,
+ "-c", "mp4",
+ "-f", "60",
+ "-o", "/home/dec05eba/Videos/gpu-screen-recorder.mp4",
+ nullptr
+ };
+ exec_program_daemonized(args);
+ */
+ }
+
+ static std::string get_date_str() {
+ char str[128];
+ time_t now = time(NULL);
+ struct tm *t = localtime(&now);
+ strftime(str, sizeof(str)-1, "%Y-%m-%d_%H-%M-%S", t);
+ return str;
+ }
+
+ static std::string container_to_file_extension(const std::string &container) {
+ if(container == "matroska")
+ return "mkv";
+ else if(container == "mpegts")
+ return "ts";
+ else if(container == "hls")
+ return "m3u8";
+ else
+ return container;
+ }
+
+ static std::string merge_audio_tracks(const std::vector<std::string> &audio_tracks) {
+ std::string result;
+ for(size_t i = 0; i < audio_tracks.size(); ++i) {
+ if(i > 0)
+ result += "|";
+ result += audio_tracks[i];
+ }
+ return result;
+ }
+
+ void Overlay::on_press_start_record(const std::string &id) {
+ if(id == "settings") {
+ auto record_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::RECORD, gsr_info, audio_devices, config, &page_stack);
+ page_stack.push(std::move(record_settings_page));
+ return;
+ }
+
+ if(id != "start")
+ return;
+
+ if(!config)
+ config = Config();
+
+ // window.close();
+ // usleep(1000 * 50); // 50 milliseconds
+
+ const std::string tint_color_as_hex = color_to_hex_str(get_theme().tint_color);
+
+ if(gpu_screen_recorder_process > 0) {
+ kill(gpu_screen_recorder_process, SIGINT);
+ int status;
+ if(waitpid(gpu_screen_recorder_process, &status, 0) == -1) {
+ perror("waitpid failed");
+ /* Ignore... */
+ }
+ // window.set_visible(false);
+ // window.close();
+ // return;
+ //exit(0);
+ gpu_screen_recorder_process = -1;
+ record_dropdown_button_ptr->set_item_label(id, "Start");
+ record_dropdown_button_ptr->set_activated(false);
+
+ // TODO: Show this with a slight delay to make sure it doesn't show up in the video
+ if(config->record_config.show_video_saved_notifications) {
+ const char *notification_args[] = {
+ "gsr-notify", "--text", "Recording has been saved", "--timeout", "3.0",
+ "--icon", "record",
+ "--icon-color", "ffffff", "--bg-color", tint_color_as_hex.c_str(),
+ nullptr
+ };
+ exec_program_daemonized(notification_args);
+ }
+ return;
+ }
+
+ // TODO: Validate input, fallback to valid values
+ const std::string fps = std::to_string(config->record_config.record_options.fps);
+ const std::string output_file = config->record_config.save_directory + "/Video_" + get_date_str() + "." + container_to_file_extension(config->record_config.container.c_str());
+ const std::string audio_tracks_merged = merge_audio_tracks(config->record_config.record_options.audio_tracks);
+ const std::string framerate_mode = config->record_config.record_options.framerate_mode == "auto" ? "vfr" : config->record_config.record_options.framerate_mode;
+ char region[64];
+ snprintf(region, sizeof(region), "%dx%d", (int)config->record_config.record_options.record_area_width, (int)config->record_config.record_options.record_area_height);
+
+ std::vector<const char*> args = {
+ "gpu-screen-recorder", "-w", config->record_config.record_options.record_area_option.c_str(),
+ "-c", config->record_config.container.c_str(),
+ "-ac", config->record_config.record_options.audio_codec.c_str(),
+ "-cursor", config->record_config.record_options.record_cursor ? "yes" : "no",
+ "-cr", config->record_config.record_options.color_range.c_str(),
+ "-fm", framerate_mode.c_str(),
+ "-q", config->record_config.record_options.video_quality.c_str(),
+ "-k", config->record_config.record_options.video_codec.c_str(),
+ "-f", fps.c_str(),
+ "-o", output_file.c_str()
+ };
+
+ if(config->record_config.record_options.record_area_option == "window" || config->record_config.record_options.record_area_option == "focused") {
+ args.push_back("-s");
+ args.push_back(region);
+ }
+
+ if(config->record_config.record_options.merge_audio_tracks) {
+ args.push_back("-a");
+ args.push_back(audio_tracks_merged.c_str());
+ } else {
+ for(const std::string &audio_track : config->record_config.record_options.audio_tracks) {
+ args.push_back("-a");
+ args.push_back(audio_track.c_str());
+ }
+ }
+
+ args.push_back(nullptr);
+
+ gpu_screen_recorder_process = exec_program(args.data());
+ if(gpu_screen_recorder_process == -1) {
+ // TODO: Show notification failed to start
+ } else {
+ record_dropdown_button_ptr->set_item_label(id, "Stop");
+ record_dropdown_button_ptr->set_activated(true);
+ }
+
+ // TODO: Start recording after this notification has disappeared to make sure it doesn't show up in the video.
+ // Make clear to the user that the recording starts after the notification is gone.
+ // Maybe have the option in notification to show timer until its getting hidden, then the notification can say:
+ // Starting recording in 3...
+ // 2...
+ // 1...
+ // TODO: Do not run this is a daemon. Instead get the pid and when launching another notification close the current notification
+ // program and start another one. This can also be used to check when the notification has finished by checking with waitpid NOWAIT
+ // to see when the program has exit.
+ if(config->record_config.show_recording_started_notifications) {
+ const char *notification_args[] = {
+ "gsr-notify", "--text", "Recording has started", "--timeout", "3.0",
+ "--icon", "record",
+ "--icon-color", tint_color_as_hex.c_str(), "--bg-color", tint_color_as_hex.c_str(),
+ nullptr
+ };
+ exec_program_daemonized(notification_args);
+ }
+ //exit(0);
+ // window.set_visible(false);
+ // window.close();
+
+ // TODO: Show notification with args:
+ // "Recording has started" 3.0 ./images/record.png 76b900
+ }
+
+ void Overlay::on_press_start_stream(const std::string &id) {
+ if(id == "settings") {
+ auto stream_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::STREAM, gsr_info, audio_devices, config, &page_stack);
+ page_stack.push(std::move(stream_settings_page));
+ return;
+ }
+ }
+
bool Overlay::update_compositor_texture(const mgl_monitor *monitor) {
window_texture_deinit(&window_texture);
window_texture_sprite.set_texture(nullptr);
diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp
index b7e87d2..a38aa45 100644
--- a/src/gui/SettingsPage.cpp
+++ b/src/gui/SettingsPage.cpp
@@ -678,9 +678,9 @@ namespace gsr {
save_config(config.value());
}
- void SettingsPage::load_audio_tracks() {
+ void SettingsPage::load_audio_tracks(RecordOptions &record_options) {
audio_devices_list_ptr->clear();
- for(const std::string &audio_track : config->replay_config.record_options.audio_tracks) {
+ for(const std::string &audio_track : record_options.audio_tracks) {
std::unique_ptr<List> audio_track_widget = create_audio_track();
ComboBox *audio_device_box = static_cast<ComboBox*>(audio_track_widget->get_child_widget_by_index(0));
audio_device_box->set_selected_item(audio_track);
@@ -695,7 +695,7 @@ namespace gsr {
framerate_entry_ptr->set_text(std::to_string(record_options.fps));
merge_audio_tracks_checkbox_ptr->set_checked(record_options.merge_audio_tracks);
- load_audio_tracks();
+ load_audio_tracks(record_options);
color_range_box_ptr->set_selected_item(record_options.color_range);
video_quality_box_ptr->set_selected_item(record_options.video_quality);
video_codec_box_ptr->set_selected_item(record_options.video_codec);