Update to handle new gsr --info output, remove general section from streaming

This commit is contained in:
dec05eba
2026-01-15 23:44:32 +01:00
parent fed47000ce
commit 61bbaf3728
6 changed files with 97 additions and 47 deletions

10
TODO
View File

@@ -250,6 +250,12 @@ Sometimes when opening gpu screen recorder ui gsr-global-hotkeys incorrectly det
When running replay for a long time and then stopping it it takes a while. Improve this.
When adding webcamera make replay auto start wait for camera to be available (when /dev/video device exists and can be initialized), just like audio device.
Make it possible to resize webcam box from top left, top right and bottom left as well.
Make it possible to resize webcam box from top left, top right and bottom left as well.
Add kick streaming option (add /app at the end of the url).
The flatpak version can for some get stuck at shutdown when instant replay is running. It only happens in the flatpak version and only when instant replay is running and it happens always. Manual SIGINT on gsr-ui stops gsr-ui properly, so why does it fail when shutting down the computer when the systemd stop signal is SIGINT? Maybe its related to the flatpak version being launched through gsr-gtk. I cant personally reproduce it.
Show warning in the UI (with a warning icon) when adding audio output device and application audio in the same audio track.
Redesign the UI to allow capturing multiple video sources. Move webcam to capture sources as well then. Maybe design the UI to work more like obs studio then, where you start recording and then add sources at capture time, with a preview.

View File

@@ -25,9 +25,9 @@ namespace gsr {
bool png = false;
};
struct SupportedCameraPixelFormats {
bool yuyv = false;
bool mjpeg = false;
enum GsrCameraPixelFormat {
YUYV,
MJPEG
};
struct GsrMonitor {
@@ -35,10 +35,16 @@ namespace gsr {
mgl::vec2i size;
};
struct GsrCameraSetup {
mgl::vec2i resolution;
int fps;
//GsrCameraPixelFormat pixel_format;
};
struct GsrCamera {
std::string path;
mgl::vec2i size;
SupportedCameraPixelFormats supported_pixel_formats;
std::vector<GsrCameraSetup> yuyv_setups;
std::vector<GsrCameraSetup> mjpeg_setups;
};
struct GsrVersion {

View File

@@ -237,5 +237,6 @@ namespace gsr {
mgl::vec2f webcam_box_size_resize_start;
std::optional<GsrCamera> selected_camera;
std::optional<GsrCameraSetup> selected_camera_setup;
};
}

View File

@@ -310,32 +310,34 @@ namespace gsr {
};
}
static SupportedCameraPixelFormats parse_supported_camera_pixel_formats(std::string_view line) {
SupportedCameraPixelFormats result;
string_split_char(line, ',', [&](std::string_view column) {
if(column == "yuyv")
result.yuyv = true;
else if(column == "mjpeg")
result.mjpeg = true;
static bool parse_camera_pixel_format(std::string_view line, GsrCameraPixelFormat &pixel_format) {
if(line == "yuyv") {
pixel_format = YUYV;
return true;
});
return result;
} else if(line == "mjpeg") {
pixel_format = MJPEG;
return true;
} else {
return false;
}
}
static std::optional<GsrCamera> capture_option_line_to_camera(std::string_view line) {
std::optional<GsrCamera> camera;
static bool capture_option_line_to_camera(std::string_view line, std::string &path, GsrCameraSetup &camera_setup, GsrCameraPixelFormat &pixel_format) {
const std::optional<KeyValue3> key_value3 = parse_3(line);
if(!key_value3)
return camera;
return false;
path = key_value3->value1;
mgl::vec2i size;
char value_buffer[256];
snprintf(value_buffer, sizeof(value_buffer), "%.*s", (int)key_value3->value2.size(), key_value3->value2.data());
if(sscanf(value_buffer, "%dx%d", &size.x, &size.y) != 2)
return camera;
if(sscanf(value_buffer, "%dx%d@%dhz", &camera_setup.resolution.x, &camera_setup.resolution.y, &camera_setup.fps) != 3)
return false;
camera = GsrCamera{std::string(key_value3->value1), size, parse_supported_camera_pixel_formats(key_value3->value3)};
return camera;
if(!parse_camera_pixel_format(key_value3->value3, pixel_format))
return false;
return true;
}
static std::optional<GsrMonitor> capture_option_line_to_monitor(std::string_view line) {
@@ -354,6 +356,37 @@ namespace gsr {
return monitor;
}
static GsrCamera* get_gsr_camera_by_path(std::vector<GsrCamera> &cameras, const std::string &path) {
for(GsrCamera &camera : cameras) {
if(camera.path == path)
return &camera;
}
return nullptr;
}
static void parse_camera_line(std::string_view line, std::vector<GsrCamera> &cameras) {
std::string camera_path;
GsrCameraSetup camera_setup;
GsrCameraPixelFormat pixel_format;
if(!capture_option_line_to_camera(line, camera_path, camera_setup, pixel_format))
return;
GsrCamera *existing_camera = get_gsr_camera_by_path(cameras, camera_path);
if(!existing_camera) {
cameras.push_back(GsrCamera{camera_path, std::vector<GsrCameraSetup>{}, std::vector<GsrCameraSetup>{}});
existing_camera = &cameras.back();
}
switch(pixel_format) {
case YUYV:
existing_camera->yuyv_setups.push_back(camera_setup);
break;
case MJPEG:
existing_camera->mjpeg_setups.push_back(camera_setup);
break;
}
}
static void parse_capture_options_line(SupportedCaptureOptions &capture_options, std::string_view line) {
if(line == "window") {
capture_options.window = true;
@@ -364,9 +397,7 @@ namespace gsr {
} else if(line == "portal") {
capture_options.portal = true;
} else if(!line.empty() && line[0] == '/') {
std::optional<GsrCamera> camera = capture_option_line_to_camera(line);
if(camera)
capture_options.cameras.push_back(std::move(camera.value()));
parse_camera_line(line, capture_options.cameras);
} else {
std::optional<GsrMonitor> monitor = capture_option_line_to_monitor(line);
if(monitor)
@@ -414,9 +445,7 @@ namespace gsr {
}
string_split_char(stdout_str, '\n', [&](std::string_view line) {
std::optional<GsrCamera> camera = capture_option_line_to_camera(line);
if(camera)
cameras.push_back(std::move(camera.value()));
parse_camera_line(line, cameras);
return true;
});

View File

@@ -1278,7 +1278,7 @@ namespace gsr {
if(recording_status == RecordingStatus::RECORD)
show_notification("Recording settings have been modified.\nYou may need to restart recording to apply the changes.", notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD);
update_led_indicator_after_settings_change();
update_led_indicator_after_settings_change();
};
page_stack.push(std::move(record_settings_page));
} else if(id == "pause") {

View File

@@ -205,6 +205,7 @@ namespace gsr {
webcam_sources_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) {
selected_camera = std::nullopt;
selected_camera_setup = std::nullopt;
webcam_video_format_box_ptr->clear_items();
if(id == "") {
webcam_body_list_ptr->set_visible(false);
@@ -220,14 +221,26 @@ namespace gsr {
webcam_body_list_ptr->set_visible(true);
webcam_video_format_box_ptr->add_item("Auto (recommended)", "auto");
if(it->supported_pixel_formats.yuyv)
if(!it->yuyv_setups.empty())
webcam_video_format_box_ptr->add_item("YUYV", "yuyv");
if(it->supported_pixel_formats.mjpeg)
if(!it->mjpeg_setups.empty())
webcam_video_format_box_ptr->add_item("Motion-JPEG", "mjpeg");
webcam_video_format_box_ptr->set_selected_item(get_current_record_options().webcam_video_format);
selected_camera = *it;
// TODO: Set from config
if(webcam_video_format_box_ptr->get_selected_id() == "yuyv" && !it->yuyv_setups.empty())
selected_camera_setup = selected_camera->yuyv_setups.front();
else if(webcam_video_format_box_ptr->get_selected_id() == "mjpeg" && !it->mjpeg_setups.empty())
selected_camera_setup = selected_camera->mjpeg_setups.front();
else if(webcam_video_format_box_ptr->get_selected_id() == "auto") {
if(!it->mjpeg_setups.empty())
selected_camera_setup = selected_camera->mjpeg_setups.front();
else if(!it->yuyv_setups.empty())
selected_camera_setup = selected_camera->yuyv_setups.front();
}
};
ll->add_widget(std::move(combobox));
@@ -261,13 +274,13 @@ namespace gsr {
auto camera_location_widget = std::make_unique<CustomRendererWidget>(camera_screen_size);
camera_location_widget->draw_handler = [this, screen_border_size, screen_border](mgl::Window &window, mgl::vec2f pos, mgl::vec2f size) {
if(!selected_camera.has_value())
if(!selected_camera.has_value() || !selected_camera_setup.has_value())
return;
pos = pos.floor();
size = size.floor();
const mgl::vec2i mouse_pos = window.get_mouse_position();
const mgl::vec2f webcam_box_min_size = clamp_keep_aspect_ratio(selected_camera->size.to_vec2f(), screen_inner_size * 0.2f);
const mgl::vec2f webcam_box_min_size = clamp_keep_aspect_ratio(selected_camera_setup->resolution.to_vec2f(), screen_inner_size * 0.2f);
if(moving_webcam_box) {
webcam_box_pos = mouse_pos.to_vec2f() - screen_border_size - webcam_box_grab_offset - pos;
@@ -276,7 +289,7 @@ namespace gsr {
webcam_box_size = webcam_box_size_resize_start + mouse_diff;
}
webcam_box_size = clamp_keep_aspect_ratio(selected_camera->size.to_vec2f(), webcam_box_size);
webcam_box_size = clamp_keep_aspect_ratio(selected_camera_setup->resolution.to_vec2f(), webcam_box_size);
if(webcam_box_pos.x < 0.0f)
webcam_box_pos.x = 0.0f;
@@ -300,7 +313,7 @@ namespace gsr {
else if(webcam_box_pos.y + webcam_box_size.y > screen_inner_size.y)
webcam_box_size.y = screen_inner_size.y - webcam_box_pos.y;
webcam_box_size = clamp_keep_aspect_ratio(selected_camera->size.to_vec2f(), webcam_box_size);
webcam_box_size = clamp_keep_aspect_ratio(selected_camera_setup->resolution.to_vec2f(), webcam_box_size);
{
draw_rectangle_outline(window, pos, size, mgl::Color(255, 0, 0, 255), screen_border);
@@ -310,7 +323,7 @@ namespace gsr {
}
{
webcam_box_drawn_size = clamp_keep_aspect_ratio(selected_camera->size.to_vec2f(), webcam_box_size);
webcam_box_drawn_size = clamp_keep_aspect_ratio(selected_camera_setup->resolution.to_vec2f(), webcam_box_size);
webcam_box_drawn_pos = (pos + screen_border_size + webcam_box_pos).floor();
draw_rectangle_outline(window, webcam_box_drawn_pos, webcam_box_drawn_size, mgl::Color(0, 255, 0, 255), screen_border);
@@ -1280,11 +1293,6 @@ namespace gsr {
streaming_info_list->add_widget(create_stream_custom_section());
settings_list_ptr->add_widget(std::make_unique<Subsection>("Streaming info", std::move(streaming_info_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
auto general_list = std::make_unique<List>(List::Orientation::VERTICAL);
general_list->add_widget(create_save_recording_in_game_folder());
settings_list_ptr->add_widget(std::make_unique<Subsection>("General", std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
settings_list_ptr->add_widget(std::make_unique<Subsection>("Streaming indicator", create_indicator("streaming"), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
streaming_service_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) {
@@ -1434,8 +1442,8 @@ namespace gsr {
webcam_box_size.x = ((float)record_options.webcam_width / 100.0f * screen_inner_size.x);
webcam_box_size.y = ((float)record_options.webcam_height / 100.0f * screen_inner_size.y);
if(selected_camera.has_value())
webcam_box_size = clamp_keep_aspect_ratio(selected_camera->size.to_vec2f(), webcam_box_size);
if(selected_camera_setup.has_value())
webcam_box_size = clamp_keep_aspect_ratio(selected_camera_setup->resolution.to_vec2f(), webcam_box_size);
if(record_options.record_area_width == 0)
record_options.record_area_width = 1920;
@@ -1569,8 +1577,8 @@ namespace gsr {
record_options.show_notifications = show_notification_checkbox_ptr->is_checked();
record_options.use_led_indicator = led_indicator_checkbox_ptr->is_checked();
if(selected_camera.has_value())
webcam_box_size = clamp_keep_aspect_ratio(selected_camera->size.to_vec2f(), webcam_box_size);
if(selected_camera_setup.has_value())
webcam_box_size = clamp_keep_aspect_ratio(selected_camera_setup->resolution.to_vec2f(), webcam_box_size);
record_options.webcam_source = webcam_sources_box_ptr->get_selected_id();
record_options.webcam_flip_horizontally = flip_camera_horizontally_checkbox_ptr->is_checked();