mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
Update to handle new gsr --info output, remove general section from streaming
This commit is contained in:
10
TODO
10
TODO
@@ -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 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.
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ namespace gsr {
|
|||||||
bool png = false;
|
bool png = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SupportedCameraPixelFormats {
|
enum GsrCameraPixelFormat {
|
||||||
bool yuyv = false;
|
YUYV,
|
||||||
bool mjpeg = false;
|
MJPEG
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GsrMonitor {
|
struct GsrMonitor {
|
||||||
@@ -35,10 +35,16 @@ namespace gsr {
|
|||||||
mgl::vec2i size;
|
mgl::vec2i size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GsrCameraSetup {
|
||||||
|
mgl::vec2i resolution;
|
||||||
|
int fps;
|
||||||
|
//GsrCameraPixelFormat pixel_format;
|
||||||
|
};
|
||||||
|
|
||||||
struct GsrCamera {
|
struct GsrCamera {
|
||||||
std::string path;
|
std::string path;
|
||||||
mgl::vec2i size;
|
std::vector<GsrCameraSetup> yuyv_setups;
|
||||||
SupportedCameraPixelFormats supported_pixel_formats;
|
std::vector<GsrCameraSetup> mjpeg_setups;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GsrVersion {
|
struct GsrVersion {
|
||||||
|
|||||||
@@ -237,5 +237,6 @@ namespace gsr {
|
|||||||
mgl::vec2f webcam_box_size_resize_start;
|
mgl::vec2f webcam_box_size_resize_start;
|
||||||
|
|
||||||
std::optional<GsrCamera> selected_camera;
|
std::optional<GsrCamera> selected_camera;
|
||||||
|
std::optional<GsrCameraSetup> selected_camera_setup;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -310,32 +310,34 @@ namespace gsr {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static SupportedCameraPixelFormats parse_supported_camera_pixel_formats(std::string_view line) {
|
static bool parse_camera_pixel_format(std::string_view line, GsrCameraPixelFormat &pixel_format) {
|
||||||
SupportedCameraPixelFormats result;
|
if(line == "yuyv") {
|
||||||
string_split_char(line, ',', [&](std::string_view column) {
|
pixel_format = YUYV;
|
||||||
if(column == "yuyv")
|
|
||||||
result.yuyv = true;
|
|
||||||
else if(column == "mjpeg")
|
|
||||||
result.mjpeg = true;
|
|
||||||
return true;
|
return true;
|
||||||
});
|
} else if(line == "mjpeg") {
|
||||||
return result;
|
pixel_format = MJPEG;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<GsrCamera> capture_option_line_to_camera(std::string_view line) {
|
static bool capture_option_line_to_camera(std::string_view line, std::string &path, GsrCameraSetup &camera_setup, GsrCameraPixelFormat &pixel_format) {
|
||||||
std::optional<GsrCamera> camera;
|
|
||||||
const std::optional<KeyValue3> key_value3 = parse_3(line);
|
const std::optional<KeyValue3> key_value3 = parse_3(line);
|
||||||
if(!key_value3)
|
if(!key_value3)
|
||||||
return camera;
|
return false;
|
||||||
|
|
||||||
|
path = key_value3->value1;
|
||||||
|
|
||||||
mgl::vec2i size;
|
|
||||||
char value_buffer[256];
|
char value_buffer[256];
|
||||||
snprintf(value_buffer, sizeof(value_buffer), "%.*s", (int)key_value3->value2.size(), key_value3->value2.data());
|
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)
|
if(sscanf(value_buffer, "%dx%d@%dhz", &camera_setup.resolution.x, &camera_setup.resolution.y, &camera_setup.fps) != 3)
|
||||||
return camera;
|
return false;
|
||||||
|
|
||||||
camera = GsrCamera{std::string(key_value3->value1), size, parse_supported_camera_pixel_formats(key_value3->value3)};
|
if(!parse_camera_pixel_format(key_value3->value3, pixel_format))
|
||||||
return camera;
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<GsrMonitor> capture_option_line_to_monitor(std::string_view line) {
|
static std::optional<GsrMonitor> capture_option_line_to_monitor(std::string_view line) {
|
||||||
@@ -354,6 +356,37 @@ namespace gsr {
|
|||||||
return monitor;
|
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) {
|
static void parse_capture_options_line(SupportedCaptureOptions &capture_options, std::string_view line) {
|
||||||
if(line == "window") {
|
if(line == "window") {
|
||||||
capture_options.window = true;
|
capture_options.window = true;
|
||||||
@@ -364,9 +397,7 @@ namespace gsr {
|
|||||||
} else if(line == "portal") {
|
} else if(line == "portal") {
|
||||||
capture_options.portal = true;
|
capture_options.portal = true;
|
||||||
} else if(!line.empty() && line[0] == '/') {
|
} else if(!line.empty() && line[0] == '/') {
|
||||||
std::optional<GsrCamera> camera = capture_option_line_to_camera(line);
|
parse_camera_line(line, capture_options.cameras);
|
||||||
if(camera)
|
|
||||||
capture_options.cameras.push_back(std::move(camera.value()));
|
|
||||||
} else {
|
} else {
|
||||||
std::optional<GsrMonitor> monitor = capture_option_line_to_monitor(line);
|
std::optional<GsrMonitor> monitor = capture_option_line_to_monitor(line);
|
||||||
if(monitor)
|
if(monitor)
|
||||||
@@ -414,9 +445,7 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string_split_char(stdout_str, '\n', [&](std::string_view line) {
|
string_split_char(stdout_str, '\n', [&](std::string_view line) {
|
||||||
std::optional<GsrCamera> camera = capture_option_line_to_camera(line);
|
parse_camera_line(line, cameras);
|
||||||
if(camera)
|
|
||||||
cameras.push_back(std::move(camera.value()));
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ namespace gsr {
|
|||||||
|
|
||||||
webcam_sources_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) {
|
webcam_sources_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) {
|
||||||
selected_camera = std::nullopt;
|
selected_camera = std::nullopt;
|
||||||
|
selected_camera_setup = std::nullopt;
|
||||||
webcam_video_format_box_ptr->clear_items();
|
webcam_video_format_box_ptr->clear_items();
|
||||||
if(id == "") {
|
if(id == "") {
|
||||||
webcam_body_list_ptr->set_visible(false);
|
webcam_body_list_ptr->set_visible(false);
|
||||||
@@ -220,14 +221,26 @@ namespace gsr {
|
|||||||
webcam_body_list_ptr->set_visible(true);
|
webcam_body_list_ptr->set_visible(true);
|
||||||
webcam_video_format_box_ptr->add_item("Auto (recommended)", "auto");
|
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");
|
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->add_item("Motion-JPEG", "mjpeg");
|
||||||
|
|
||||||
webcam_video_format_box_ptr->set_selected_item(get_current_record_options().webcam_video_format);
|
webcam_video_format_box_ptr->set_selected_item(get_current_record_options().webcam_video_format);
|
||||||
selected_camera = *it;
|
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));
|
ll->add_widget(std::move(combobox));
|
||||||
@@ -261,13 +274,13 @@ namespace gsr {
|
|||||||
|
|
||||||
auto camera_location_widget = std::make_unique<CustomRendererWidget>(camera_screen_size);
|
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) {
|
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;
|
return;
|
||||||
|
|
||||||
pos = pos.floor();
|
pos = pos.floor();
|
||||||
size = size.floor();
|
size = size.floor();
|
||||||
const mgl::vec2i mouse_pos = window.get_mouse_position();
|
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) {
|
if(moving_webcam_box) {
|
||||||
webcam_box_pos = mouse_pos.to_vec2f() - screen_border_size - webcam_box_grab_offset - pos;
|
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 = 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)
|
if(webcam_box_pos.x < 0.0f)
|
||||||
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)
|
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.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);
|
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();
|
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);
|
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());
|
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)));
|
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)));
|
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) {
|
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.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);
|
webcam_box_size.y = ((float)record_options.webcam_height / 100.0f * screen_inner_size.y);
|
||||||
|
|
||||||
if(selected_camera.has_value())
|
if(selected_camera_setup.has_value())
|
||||||
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(record_options.record_area_width == 0)
|
if(record_options.record_area_width == 0)
|
||||||
record_options.record_area_width = 1920;
|
record_options.record_area_width = 1920;
|
||||||
@@ -1569,8 +1577,8 @@ namespace gsr {
|
|||||||
record_options.show_notifications = show_notification_checkbox_ptr->is_checked();
|
record_options.show_notifications = show_notification_checkbox_ptr->is_checked();
|
||||||
record_options.use_led_indicator = led_indicator_checkbox_ptr->is_checked();
|
record_options.use_led_indicator = led_indicator_checkbox_ptr->is_checked();
|
||||||
|
|
||||||
if(selected_camera.has_value())
|
if(selected_camera_setup.has_value())
|
||||||
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);
|
||||||
|
|
||||||
record_options.webcam_source = webcam_sources_box_ptr->get_selected_id();
|
record_options.webcam_source = webcam_sources_box_ptr->get_selected_id();
|
||||||
record_options.webcam_flip_horizontally = flip_camera_horizontally_checkbox_ptr->is_checked();
|
record_options.webcam_flip_horizontally = flip_camera_horizontally_checkbox_ptr->is_checked();
|
||||||
|
|||||||
Reference in New Issue
Block a user