aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp167
1 files changed, 136 insertions, 31 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 22ad190..2126e61 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -140,9 +140,6 @@ static double notification_timeout_seconds = 0.0;
static double notification_start_seconds = 0.0;
static AppIndicator *app_indicator;
-static const char *tray_idle_icon_name = "com.dec05eba.gpu_screen_recorder.tray-idle";
-static const char *tray_recording_icon_name = "com.dec05eba.gpu_screen_recorder.tray-recording";
-static const char *tray_paused_icon_name = "com.dec05eba.gpu_screen_recorder.tray-paused";
struct AudioInput {
std::string name;
@@ -185,10 +182,12 @@ struct SupportedVideoCodecs {
bool h264;
bool hevc;
bool av1;
+ bool vp8;
+ bool vp9;
};
static SupportedVideoCodecs supported_video_codecs;
-static bool got_supported_video_codecs = false;
+static int supported_video_codecs_exit_status = 0;
struct Container {
const char *container_name;
@@ -222,6 +221,28 @@ typedef struct {
static gpu_info gpu_inf;
+// Dumb hacks below!! why dont these fking paths work outside flatpak.. except in kde. TODO: fix this!
+static const char* get_tray_idle_icon_name() {
+ if(flatpak)
+ return "com.dec05eba.gpu_screen_recorder.tray-idle";
+ else
+ return "/usr/share/icons/hicolor/32x32/status/com.dec05eba.gpu_screen_recorder.tray-idle.png";
+}
+
+static const char* get_tray_recording_icon_name() {
+ if(flatpak)
+ return "com.dec05eba.gpu_screen_recorder.tray-recording";
+ else
+ return "/usr/share/icons/hicolor/32x32/status/com.dec05eba.gpu_screen_recorder.tray-recording.png";
+}
+
+static const char* get_tray_paused_icon_name() {
+ if(flatpak)
+ return "com.dec05eba.gpu_screen_recorder.tray-paused";
+ else
+ return "/usr/share/icons/hicolor/32x32/status/com.dec05eba.gpu_screen_recorder.tray-paused.png";
+}
+
static bool is_program_installed(const StringView program_name) {
const char *path = getenv("PATH");
if(!path)
@@ -391,7 +412,7 @@ static GtkMenuShell* create_systray_menu(GtkApplication *app, SystrayPage systra
static void setup_systray(GtkApplication *app) {
app_indicator = app_indicator_new("com.dec05eba.gpu_screen_recorder", "", APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
- app_indicator_set_icon_full(app_indicator, tray_idle_icon_name, "Idle");
+ app_indicator_set_icon_full(app_indicator, get_tray_idle_icon_name(), "Idle");
// This triggers Gdk assert: gdk_window_thaw_toplevel_updates: assertion 'window->update_and_descendants_freeze_count > 0' failed,
// dont know why but it works anyways
app_indicator_set_title(app_indicator, "GPU Screen Recorder");
@@ -1716,7 +1737,7 @@ static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdat
gtk_menu_item_set_label(GTK_MENU_ITEM(start_stop_replay_menu_item), "Start replay");
gtk_widget_set_sensitive(save_replay_menu_item, false);
- app_indicator_set_icon_full(app_indicator, tray_idle_icon_name, "Idle");
+ app_indicator_set_icon_full(app_indicator, get_tray_idle_icon_name(), "Idle");
if(exit_status == 10) {
show_notification(app, "GPU Screen Recorder",
@@ -1766,6 +1787,18 @@ static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdat
const gchar* framerate_mode_input_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(framerate_mode_input_menu));
const bool record_cursor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(record_cursor_button));
+ if(strcmp(video_codec_input_str, "vp8") == 0 || strcmp(video_codec_input_str, "vp9") == 0) {
+ if(strcmp(container_str, "webm") != 0 && strcmp(container_str, "matroska") != 0) {
+ fprintf(stderr, "Warning: container '%s' is not compatible with video codec '%s', using webm container instead\n", container_str, video_codec_input_str);
+ container_str = "webm";
+ }
+ } else {
+ if(strcmp(container_str, "webm") == 0) {
+ fprintf(stderr, "Warning: container webm is not compatible with video codec '%s', using mp4 container instead\n", video_codec_input_str);
+ container_str = "mp4";
+ }
+ }
+
char area[64];
snprintf(area, sizeof(area), "%dx%d", record_width, record_height);
@@ -1823,7 +1856,7 @@ static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdat
gtk_menu_item_set_label(GTK_MENU_ITEM(start_stop_replay_menu_item), "Stop replay");
gtk_widget_set_sensitive(save_replay_menu_item, true);
- app_indicator_set_icon_full(app_indicator, tray_recording_icon_name, "Recording");
+ app_indicator_set_icon_full(app_indicator, get_tray_recording_icon_name(), "Recording");
record_start_time_sec = clock_get_monotonic_seconds();
return true;
@@ -1850,13 +1883,13 @@ static gboolean on_pause_unpause_button_click(GtkButton*, gpointer) {
gtk_button_set_label(pause_recording_button, "Unpause recording");
gtk_image_set_from_icon_name(GTK_IMAGE(recording_record_icon), "media-playback-pause", GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_menu_item_set_label(GTK_MENU_ITEM(pause_recording_menu_item), "Unpause recording");
- app_indicator_set_icon_full(app_indicator, tray_paused_icon_name, "Paused");
+ app_indicator_set_icon_full(app_indicator, get_tray_paused_icon_name(), "Paused");
pause_start_sec = clock_get_monotonic_seconds();
} else {
gtk_button_set_label(pause_recording_button, "Pause recording");
gtk_image_set_from_icon_name(GTK_IMAGE(recording_record_icon), "media-record", GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_menu_item_set_label(GTK_MENU_ITEM(pause_recording_menu_item), "Pause recording");
- app_indicator_set_icon_full(app_indicator, tray_recording_icon_name, "Recording");
+ app_indicator_set_icon_full(app_indicator, get_tray_recording_icon_name(), "Recording");
paused_time_offset_sec += (clock_get_monotonic_seconds() - pause_start_sec);
}
return true;
@@ -1886,7 +1919,7 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
gtk_menu_item_set_label(GTK_MENU_ITEM(start_stop_recording_menu_item), "Start recording");
gtk_menu_item_set_label(GTK_MENU_ITEM(pause_recording_menu_item), "Pause recording");
gtk_widget_set_sensitive(pause_recording_menu_item, false);
- app_indicator_set_icon_full(app_indicator, tray_idle_icon_name, "Idle");
+ app_indicator_set_icon_full(app_indicator, get_tray_idle_icon_name(), "Idle");
if(exit_status == 10) {
show_notification(app, "GPU Screen Recorder",
@@ -1908,16 +1941,6 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
int record_width = wayland ? 0 : gtk_spin_button_get_value_as_int(area_width_entry);
int record_height = wayland ? 0 : gtk_spin_button_get_value_as_int(area_height_entry);
- char dir_tmp[PATH_MAX];
- strcpy(dir_tmp, dir);
- if(create_directory_recursive(dir_tmp) != 0) {
- std::string notification_body = std::string("Failed to start recording. Failed to create ") + dir_tmp;
- show_notification(app, "GPU Screen Recorder", notification_body.c_str(), G_NOTIFICATION_PRIORITY_URGENT);
- return true;
- }
-
- record_file_current_filename = std::string(dir_tmp) + "/Video_" + get_date_str() + "." + gtk_combo_box_text_get_active_text(record_container);
-
bool follow_focused = false;
std::string window_str = record_area_selection_menu_get_active_id();
if(window_str == "window") {
@@ -1933,6 +1956,7 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
std::string fps_str = std::to_string(fps);
const gchar* container_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(record_container));
+ const gchar* container_name = gtk_combo_box_text_get_active_text(record_container);
const gchar* color_range_input_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(color_range_input_menu));
const gchar* quality_input_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(quality_input_menu));
const gchar* video_codec_input_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(video_codec_input_menu));
@@ -1940,6 +1964,30 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
const gchar* framerate_mode_input_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(framerate_mode_input_menu));
const bool record_cursor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(record_cursor_button));
+ if(strcmp(video_codec_input_str, "vp8") == 0 || strcmp(video_codec_input_str, "vp9") == 0) {
+ if(strcmp(container_str, "webm") != 0 && strcmp(container_str, "matroska") != 0) {
+ fprintf(stderr, "Warning: container '%s' is not compatible with video codec '%s', using webm container instead\n", container_str, video_codec_input_str);
+ container_str = "webm";
+ container_name = "webm";
+ }
+ } else {
+ if(strcmp(container_str, "webm") == 0) {
+ fprintf(stderr, "Warning: container webm is not compatible with video codec '%s', using mp4 container instead\n", video_codec_input_str);
+ container_str = "mp4";
+ container_name = "mp4";
+ }
+ }
+
+ char dir_tmp[PATH_MAX];
+ strcpy(dir_tmp, dir);
+ if(create_directory_recursive(dir_tmp) != 0) {
+ std::string notification_body = std::string("Failed to start recording. Failed to create ") + dir_tmp;
+ show_notification(app, "GPU Screen Recorder", notification_body.c_str(), G_NOTIFICATION_PRIORITY_URGENT);
+ return true;
+ }
+
+ record_file_current_filename = std::string(dir_tmp) + "/Video_" + get_date_str() + "." + container_name;
+
char area[64];
snprintf(area, sizeof(area), "%dx%d", record_width, record_height);
@@ -1996,7 +2044,7 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
gtk_menu_item_set_label(GTK_MENU_ITEM(start_stop_recording_menu_item), "Stop recording");
gtk_widget_set_sensitive(pause_recording_menu_item, true);
- app_indicator_set_icon_full(app_indicator, tray_recording_icon_name, "recording");
+ app_indicator_set_icon_full(app_indicator, get_tray_recording_icon_name(), "Recording");
record_start_time_sec = clock_get_monotonic_seconds();
paused_time_offset_sec = 0.0;
@@ -2019,7 +2067,7 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user
gtk_label_set_text(GTK_LABEL(streaming_record_time_label), "00:00:00");
gtk_menu_item_set_label(GTK_MENU_ITEM(start_stop_streaming_menu_item), "Start streaming");
- app_indicator_set_icon_full(app_indicator, tray_idle_icon_name, "Idle");
+ app_indicator_set_icon_full(app_indicator, get_tray_idle_icon_name(), "Idle");
if(exit_status == 10) {
show_notification(app, "GPU Screen Recorder",
@@ -2068,12 +2116,18 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user
{}
else if(stream_url.size() >= 8 && strncmp(stream_url.c_str(), "rtmps://", 8) == 0)
{}
+ else if(stream_url.size() >= 7 && strncmp(stream_url.c_str(), "rtsp://", 7) == 0)
+ {}
else if(stream_url.size() >= 6 && strncmp(stream_url.c_str(), "srt://", 6) == 0)
{}
else if(stream_url.size() >= 7 && strncmp(stream_url.c_str(), "http://", 7) == 0)
{}
else if(stream_url.size() >= 8 && strncmp(stream_url.c_str(), "https://", 8) == 0)
{}
+ else if(stream_url.size() >= 6 && strncmp(stream_url.c_str(), "tcp://", 6) == 0)
+ {}
+ else if(stream_url.size() >= 6 && strncmp(stream_url.c_str(), "udp://", 6) == 0)
+ {}
else
stream_url = "rtmp://" + stream_url;
}
@@ -2085,6 +2139,18 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user
const gchar* framerate_mode_input_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(framerate_mode_input_menu));
const bool record_cursor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(record_cursor_button));
+ if(strcmp(video_codec_input_str, "vp8") == 0 || strcmp(video_codec_input_str, "vp9") == 0) {
+ if(strcmp(container_str, "webm") != 0 && strcmp(container_str, "matroska") != 0) {
+ fprintf(stderr, "Warning: container '%s' is not compatible with video codec '%s', using webm container instead\n", container_str, video_codec_input_str);
+ container_str = "webm";
+ }
+ } else {
+ if(strcmp(container_str, "webm") == 0) {
+ fprintf(stderr, "Warning: container webm is not compatible with video codec '%s', using mp4 container instead\n", video_codec_input_str);
+ container_str = "mp4";
+ }
+ }
+
char area[64];
snprintf(area, sizeof(area), "%dx%d", record_width, record_height);
@@ -2140,7 +2206,7 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user
gtk_widget_set_opacity(GTK_WIDGET(streaming_bottom_panel_grid), 1.0);
gtk_menu_item_set_label(GTK_MENU_ITEM(start_stop_streaming_menu_item), "Stop streaming");
- app_indicator_set_icon_full(app_indicator, tray_recording_icon_name, "Recording");
+ app_indicator_set_icon_full(app_indicator, get_tray_recording_icon_name(), "Recording");
record_start_time_sec = clock_get_monotonic_seconds();
return true;
@@ -2460,15 +2526,18 @@ static gsr_connection_type get_connection_type() {
}
}
-static bool get_supported_video_codecs(SupportedVideoCodecs *supported_video_codecs) {
+// Returns the exit status
+static int get_supported_video_codecs(SupportedVideoCodecs *supported_video_codecs) {
supported_video_codecs->h264 = false;
supported_video_codecs->hevc = false;
supported_video_codecs->av1 = false;
+ supported_video_codecs->vp8 = false;
+ supported_video_codecs->vp9 = false;
FILE *f = popen("gpu-screen-recorder --list-supported-video-codecs", "r");
if(!f) {
fprintf(stderr, "error: 'gpu-screen-recorder --list-supported-video-codecs' failed\n");
- return false;
+ return -1;
}
char output[1024];
@@ -2476,7 +2545,7 @@ static bool get_supported_video_codecs(SupportedVideoCodecs *supported_video_cod
if(bytes_read < 0 || ferror(f)) {
fprintf(stderr, "error: failed to read 'gpu-screen-recorder --list-supported-video-codecs' output\n");
pclose(f);
- return false;
+ return -1;
}
output[bytes_read] = '\0';
@@ -2486,9 +2555,15 @@ static bool get_supported_video_codecs(SupportedVideoCodecs *supported_video_cod
supported_video_codecs->hevc = true;
if(strstr(output, "av1"))
supported_video_codecs->av1 = true;
+ if(strstr(output, "vp8"))
+ supported_video_codecs->vp8 = true;
+ if(strstr(output, "vp9"))
+ supported_video_codecs->vp9 = true;
- pclose(f);
- return true;
+ int status = pclose(f);
+ if(WIFEXITED(status))
+ return WEXITSTATUS(status);
+ return 0;
}
static void record_area_set_sensitive(GtkCellLayout *cell_layout, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) {
@@ -2735,13 +2810,17 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_grid_attach(video_codec_grid, gtk_label_new("Video codec: "), 0, 0, 1, 1);
video_codec_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
gtk_combo_box_text_append(video_codec_input_menu, "auto", "Auto (Recommended)");
- if(got_supported_video_codecs) {
+ if(supported_video_codecs_exit_status == 0) {
if(supported_video_codecs.h264)
gtk_combo_box_text_append(video_codec_input_menu, "h264", "H264");
if(supported_video_codecs.hevc)
gtk_combo_box_text_append(video_codec_input_menu, "hevc", "HEVC");
if(supported_video_codecs.av1)
gtk_combo_box_text_append(video_codec_input_menu, "av1", "AV1");
+ if(supported_video_codecs.vp8)
+ gtk_combo_box_text_append(video_codec_input_menu, "vp8", "VP8");
+ if(supported_video_codecs.vp9)
+ gtk_combo_box_text_append(video_codec_input_menu, "vp9", "VP9");
if(wayland) {
if(supported_video_codecs.hevc)
@@ -2960,6 +3039,9 @@ static GtkWidget* create_replay_page(GtkApplication *app, GtkStack *stack) {
for(auto &supported_container : supported_containers) {
gtk_combo_box_text_append(replay_container, supported_container.container_name, supported_container.file_extension);
}
+ if(supported_video_codecs.vp8 || supported_video_codecs.vp9) {
+ gtk_combo_box_text_append(replay_container, "webm", "webm");
+ }
gtk_widget_set_hexpand(GTK_WIDGET(replay_container), true);
gtk_grid_attach(container_grid, GTK_WIDGET(replay_container), 1, 0, 1, 1);
gtk_combo_box_set_active(GTK_COMBO_BOX(replay_container), 0); // TODO:
@@ -3093,6 +3175,9 @@ static GtkWidget* create_recording_page(GtkApplication *app, GtkStack *stack) {
for(auto &supported_container : supported_containers) {
gtk_combo_box_text_append(record_container, supported_container.container_name, supported_container.file_extension);
}
+ if(supported_video_codecs.vp8 || supported_video_codecs.vp9) {
+ gtk_combo_box_text_append(record_container, "webm", "webm");
+ }
gtk_widget_set_hexpand(GTK_WIDGET(record_container), true);
gtk_grid_attach(container_grid, GTK_WIDGET(record_container), 1, 0, 1, 1);
gtk_combo_box_set_active(GTK_COMBO_BOX(record_container), 0); // TODO:
@@ -3215,6 +3300,9 @@ static GtkWidget* create_streaming_page(GtkApplication *app, GtkStack *stack) {
for(auto &supported_container : supported_containers) {
gtk_combo_box_text_append(custom_stream_container, supported_container.container_name, supported_container.file_extension);
}
+ if(supported_video_codecs.vp8 || supported_video_codecs.vp9) {
+ gtk_combo_box_text_append(custom_stream_container, "webm", "webm");
+ }
gtk_widget_set_hexpand(GTK_WIDGET(custom_stream_container), true);
gtk_grid_attach(custom_stream_container_grid, GTK_WIDGET(custom_stream_container), 1, 0, 1, 1);
gtk_combo_box_set_active(GTK_COMBO_BOX(custom_stream_container), 1);
@@ -3418,8 +3506,13 @@ static void load_config(const gpu_info &gpu_inf) {
if(config.main_config.quality != "medium" && config.main_config.quality != "high" && config.main_config.quality != "very_high" && config.main_config.quality != "ultra")
config.main_config.quality = "very_high";
- if(config.main_config.codec != "auto" && config.main_config.codec != "h264" && config.main_config.codec != "h265" && config.main_config.codec != "hevc" && config.main_config.codec != "av1" && config.main_config.codec != "hevc_hdr" && config.main_config.codec != "av1_hdr")
+ if(config.main_config.codec != "auto" && config.main_config.codec != "h264" && config.main_config.codec != "h265"
+ && config.main_config.codec != "hevc" && config.main_config.codec != "av1"
+ && config.main_config.codec != "hevc_hdr" && config.main_config.codec != "av1_hdr"
+ && config.main_config.codec != "vp8" && config.main_config.codec != "vp9")
+ {
config.main_config.codec = "auto";
+ }
if(!wayland && (config.main_config.codec == "hevc_hdr" || config.main_config.codec == "av1_hdr"))
config.main_config.codec = "auto";
@@ -3520,6 +3613,18 @@ static void load_config(const gpu_info &gpu_inf) {
enable_stream_record_button_if_info_filled();
stream_service_item_change_callback(GTK_COMBO_BOX(stream_service_input_menu), nullptr);
+ if(supported_video_codecs_exit_status != 0) {
+ const char *cmd = flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder -w screen -f 60 -o video.mp4" : "gpu-screen-recorder -w screen -f 60 -o video.mp4";
+ GtkWidget *dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "Failed to run 'gpu-screen-recorder' command. If you are using gpu-screen-recorder flatpak then this is a bug. Otherwise you need to make sure gpu-screen-recorder is installed on your system and working properly (install necessary depedencies depending on your GPU, such as libva-mesa-driver, libva-intel-driver, intel-media-driver and linux-firmware). Run:\n"
+ "%s\n"
+ "in a terminal to see more information about the issue.", cmd);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ g_application_quit(G_APPLICATION(select_window_userdata.app));
+ return;
+ }
+
if(!supported_video_codecs.h264 && !supported_video_codecs.hevc && gpu_inf.vendor != GPU_VENDOR_NVIDIA && config.main_config.codec != "av1") {
if(supported_video_codecs.av1) {
GtkWidget *dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
@@ -3691,7 +3796,7 @@ static void activate(GtkApplication *app, gpointer) {
}
}
- got_supported_video_codecs = get_supported_video_codecs(&supported_video_codecs);
+ supported_video_codecs_exit_status = get_supported_video_codecs(&supported_video_codecs);
std::string window_title = "GPU Screen Recorder | Running on ";
window_title += gpu_vendor_to_name(gpu_inf.vendor);