mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-04-02 01:36:06 +09:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10165977f6 | ||
|
|
62509a4b60 | ||
|
|
eb602b9b53 | ||
|
|
19d77b8a96 | ||
|
|
601219febb | ||
|
|
3e199f241a | ||
|
|
a5895b775d | ||
|
|
2c4b077f43 |
@@ -168,4 +168,6 @@ Try recording to an SSD and make sure it's not using NTFS file system. Also reco
|
||||
## The colors look washed out when recording a monitor with HDR enabled
|
||||
You have to either record in hdr mode (-k `hevc_hdr` or -k `av1_hdr` option) to record a HDR video or record with desktop portal option (`-w portal`) to turn the HDR recording into SDR.
|
||||
## GPU Screen Recorder records night light when recording in HDR mode
|
||||
You can record with desktop portal option (`-w portal`) instead which ignores night light, if you are ok with recording without HDR.
|
||||
You can record with desktop portal option (`-w portal`) instead which ignores night light, if you are ok with recording without HDR.
|
||||
## Kdenlive says that the video is not usable for editing because it has variable frame rate
|
||||
To fix this you can either record the video in .mkv format or constant frame rate (-fm cfr).
|
||||
|
||||
11
TODO
11
TODO
@@ -156,9 +156,6 @@ Restart replay/update video resolution if monitor resolution changes.
|
||||
|
||||
Fix pure vaapi copy on intel.
|
||||
|
||||
ffmpeg supports vulkan encoding now (h264!). Doesn't work on amd yet because mesa is missing VK_KHR_video_maintenance1, see https://gitlab.freedesktop.org/mesa/mesa/-/issues/11857. Test on nvidia!
|
||||
|
||||
Test vaapi low latency mode (setenv("AMD_DEBUG", "lowlatencyenc", true);), added in mesa 24.1.4, released on july 17, 2024. Note that this forces gpu power usage to max at all times, even when recording at 2 fps.
|
||||
Use nvidia low latency options for better encoding times.
|
||||
|
||||
Test ideal async_depth value. Increasing async_depth also increased gpu memory usage a lot (from 100mb to 500mb when moving from async_depth 2 to 16) at 4k resolution. Setting it to 8 increases it by 200mb which might be ok.
|
||||
@@ -175,4 +172,10 @@ Support recording while in replay mode. This will be needed when enabling replay
|
||||
|
||||
Dynamically change bitrate/resolution to match desired fps. This would be helpful when streaming for example, where the encode output speed also depends on upload speed to the streaming service.
|
||||
Implement opengl injection to capture texture. This fixes VRR without having to use NvFBC direct capture and also allows perfect frame timing.
|
||||
Always use direct capture with NvFBC once the capture issue in mpv fullscreen has been resolved (maybe detect if direct capture fails in nvfbc and switch to non-direct recording. NvFBC says if direct capture fails).
|
||||
Always use direct capture with NvFBC once the capture issue in mpv fullscreen has been resolved (maybe detect if direct capture fails in nvfbc and switch to non-direct recording. NvFBC says if direct capture fails).
|
||||
|
||||
Support ROI (AV_FRAME_DATA_REGIONS_OF_INTEREST).
|
||||
|
||||
Default to hevc if capture size is larger than 4096 in width or height.
|
||||
|
||||
Set low latency mode on vulkan encoding.
|
||||
@@ -183,6 +183,40 @@ static void file_get_directory(char *filepath) {
|
||||
*end = '\0';
|
||||
}
|
||||
|
||||
static bool find_program_in_path(const char *program_name, char *filepath, int filepath_len) {
|
||||
const char *path = getenv("PATH");
|
||||
if(!path)
|
||||
return false;
|
||||
|
||||
int program_name_len = strlen(program_name);
|
||||
const char *end = path + strlen(path);
|
||||
while(path != end) {
|
||||
const char *part_end = strchr(path, ':');
|
||||
const char *next = part_end;
|
||||
if(part_end) {
|
||||
next = part_end + 1;
|
||||
} else {
|
||||
part_end = end;
|
||||
next = end;
|
||||
}
|
||||
|
||||
int len = part_end - path;
|
||||
if(len + 1 + program_name_len < filepath_len) {
|
||||
memcpy(filepath, path, len);
|
||||
filepath[len] = '/';
|
||||
memcpy(filepath + len + 1, program_name, program_name_len);
|
||||
filepath[len + 1 + program_name_len] = '\0';
|
||||
|
||||
if(access(filepath, F_OK) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
path = next;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int gsr_kms_client_init(gsr_kms_client *self, const char *card_path) {
|
||||
int result = -1;
|
||||
self->kms_server_pid = -1;
|
||||
@@ -212,8 +246,11 @@ int gsr_kms_client_init(gsr_kms_client *self, const char *card_path) {
|
||||
}
|
||||
|
||||
if(access(server_filepath, F_OK) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_kms_client_init: gsr-kms-server is not installed (%s not found)\n", server_filepath);
|
||||
return -1;
|
||||
fprintf(stderr, "gsr info: gsr_kms_client_init: gsr-kms-server is not installed in the same directory as gpu-screen-recorder (%s not found), looking for gsr-kms-server in PATH instead\n", server_filepath);
|
||||
if(!find_program_in_path("gsr-kms-server", server_filepath, sizeof(server_filepath)) || access(server_filepath, F_OK) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_kms_client_init: gsr-kms-server was not found in PATH. Please install gpu-screen-recorder properly\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "gsr info: gsr_kms_client_init: setting up connection to %s\n", server_filepath);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '4.2.0', default_options : ['warning_level=2'])
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '4.2.3', default_options : ['warning_level=2'])
|
||||
|
||||
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
|
||||
if get_option('buildtype') == 'debug'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "gpu-screen-recorder"
|
||||
type = "executable"
|
||||
version = "4.2.0"
|
||||
version = "4.2.3"
|
||||
platforms = ["posix"]
|
||||
|
||||
[config]
|
||||
|
||||
44
src/main.cpp
44
src/main.cpp
@@ -810,10 +810,9 @@ static void open_video_software(AVCodecContext *codec_context, VideoQuality vide
|
||||
if(bitrate_mode == BitrateMode::QP)
|
||||
video_software_set_qp(codec_context, video_quality, hdr, &options);
|
||||
|
||||
av_dict_set(&options, "preset", "medium", 0);
|
||||
av_dict_set(&options, "preset", "fast", 0);
|
||||
dict_set_profile(codec_context, GSR_GPU_VENDOR_INTEL, color_depth, &options);
|
||||
// TODO: If streaming or piping output set this to zerolatency
|
||||
av_dict_set(&options, "tune", "fastdecode", 0);
|
||||
av_dict_set(&options, "tune", "zerolatency", 0);
|
||||
|
||||
if(codec_context->codec_id == AV_CODEC_ID_H264) {
|
||||
av_dict_set(&options, "coder", "cabac", 0); // TODO: cavlc is faster than cabac but worse compression. Which to use?
|
||||
@@ -990,6 +989,14 @@ static void open_video_hardware(AVCodecContext *codec_context, VideoQuality vide
|
||||
// TODO: Enable multipass
|
||||
|
||||
if(vendor == GSR_GPU_VENDOR_NVIDIA) {
|
||||
// TODO: Test these, if they are needed, if they should be used
|
||||
// av_dict_set_int(&options, "zerolatency", 1, 0);
|
||||
// if(codec_context->codec_id == AV_CODEC_ID_AV1) {
|
||||
// av_dict_set(&options, "tune", "ll", 0);
|
||||
// } else if(codec_context->codec_id == AV_CODEC_ID_H264 || codec_context->codec_id == AV_CODEC_ID_HEVC) {
|
||||
// av_dict_set(&options, "preset", "llhq", 0);
|
||||
// av_dict_set(&options, "tune", "ll", 0);
|
||||
// }
|
||||
av_dict_set(&options, "tune", "hq", 0);
|
||||
|
||||
dict_set_profile(codec_context, vendor, color_depth, &options);
|
||||
@@ -1155,7 +1162,7 @@ static void usage_full() {
|
||||
fprintf(stderr, " Note: the directory to the portal session token file is created automatically if it doesn't exist.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -encoder\n");
|
||||
fprintf(stderr, " Which device should be used for video encoding. Should either be 'gpu' or 'cpu'. Does currently only work with h264 codec option (-k).\n");
|
||||
fprintf(stderr, " Which device should be used for video encoding. Should either be 'gpu' or 'cpu'. 'cpu' option currently only work with h264 codec option (-k).\n");
|
||||
fprintf(stderr, " Optional, set to 'gpu' by default.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " --info\n");
|
||||
@@ -1170,6 +1177,7 @@ static void usage_full() {
|
||||
fprintf(stderr, " For example:\n");
|
||||
fprintf(stderr, " bluez_input.88:C9:E8:66:A2:27|WH-1000XM4\n");
|
||||
fprintf(stderr, " The <audio_device_name> is the name to pass to GPU Screen Recorder in a -a option.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " --version\n");
|
||||
fprintf(stderr, " Print version (%s) and exit\n", GSR_VERSION);
|
||||
fprintf(stderr, "\n");
|
||||
@@ -1178,7 +1186,7 @@ static void usage_full() {
|
||||
fprintf(stderr, " In replay mode this has to be a directory instead of a file.\n");
|
||||
fprintf(stderr, " Note: the directory to the file is created automatically if it doesn't already exist.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -v Prints per second, fps updates. Optional, set to 'yes' by default.\n");
|
||||
fprintf(stderr, " -v Prints fps and damage info once per second. Optional, set to 'yes' by default.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -h, --help\n");
|
||||
fprintf(stderr, " Show this help.\n");
|
||||
@@ -2600,6 +2608,13 @@ int main(int argc, char **argv) {
|
||||
// If this is set to 1 then cuGraphicsGLRegisterImage will fail for egl context with error: invalid OpenGL or DirectX context,
|
||||
// so we overwrite it
|
||||
setenv("__GL_THREADED_OPTIMIZATIONS", "0", true);
|
||||
// Forces low latency encoding mode. Use this environment variable until vaapi supports setting this as a parameter.
|
||||
// The downside of this is that it always uses maximum power, which is not ideal for replay mode that runs on system startup.
|
||||
// This option was added in mesa 24.1.4, released in july 17, 2024.
|
||||
// TODO: Add an option to enable/disable this?
|
||||
// Seems like the performance issue is not in encoding, but rendering the frame.
|
||||
// Some frames end up taking 10 times longer. Seems to be an issue with amd gpu power management when letting the application sleep on the cpu side?
|
||||
setenv("AMD_DEBUG", "lowlatencyenc", true);
|
||||
// Some people set this to nvidia (for nvdec) or vdpau (for nvidia vdpau), which breaks gpu screen recorder since
|
||||
// nvidia doesn't support vaapi and nvidia-vaapi-driver doesn't support encoding yet.
|
||||
// Let vaapi find the match vaapi driver instead of forcing a specific one.
|
||||
@@ -3400,7 +3415,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
double fps_start_time = clock_get_monotonic_seconds();
|
||||
double frame_timer_start = fps_start_time;
|
||||
//double frame_timer_start = fps_start_time;
|
||||
int fps_counter = 0;
|
||||
int damage_fps_counter = 0;
|
||||
|
||||
@@ -3638,7 +3653,7 @@ int main(int argc, char **argv) {
|
||||
bool wait_until_frame_time_elapsed = false;
|
||||
|
||||
while(running) {
|
||||
//const double frame_start = clock_get_monotonic_seconds();
|
||||
const double frame_start = clock_get_monotonic_seconds();
|
||||
|
||||
while(gsr_egl_process_event(&egl)) {
|
||||
gsr_damage_on_event(&damage, gsr_egl_get_event_data(&egl));
|
||||
@@ -3780,7 +3795,8 @@ int main(int argc, char **argv) {
|
||||
save_replay_async(video_codec_context, VIDEO_STREAM_INDEX, audio_tracks, frame_data_queue, frames_erased, filename, container_format, file_extension, write_output_mutex, date_folders, hdr, capture);
|
||||
}
|
||||
|
||||
const double time_at_frame_end = clock_get_monotonic_seconds() - paused_time_offset;
|
||||
const double frame_end = clock_get_monotonic_seconds();
|
||||
const double time_at_frame_end = frame_end - paused_time_offset;
|
||||
const double time_elapsed_total = time_at_frame_end - record_start_time;
|
||||
const int64_t frames_elapsed = (int64_t)(time_elapsed_total / target_fps);
|
||||
const double time_at_next_frame = (frames_elapsed + 1) * target_fps;
|
||||
@@ -3788,16 +3804,18 @@ int main(int argc, char **argv) {
|
||||
if(time_to_next_frame > target_fps*1.1)
|
||||
time_to_next_frame = target_fps;
|
||||
|
||||
//const double frame_end = clock_get_monotonic_seconds();
|
||||
//const double frame_time = frame_end - frame_start;
|
||||
if(time_to_next_frame > 0.0)
|
||||
const double frame_time = frame_end - frame_start;
|
||||
const bool frame_deadline_missed = frame_time > target_fps;
|
||||
if(time_to_next_frame > 0.0 && !frame_deadline_missed && frame_captured)
|
||||
av_usleep(time_to_next_frame * 1000.0 * 1000.0);
|
||||
else {
|
||||
if(paused)
|
||||
av_usleep(20.0 * 1000.0); // 10 milliseconds
|
||||
av_usleep(20.0 * 1000.0); // 20 milliseconds
|
||||
else if(frame_deadline_missed)
|
||||
{}
|
||||
else if(framerate_mode == FramerateMode::CONTENT || !frame_captured)
|
||||
av_usleep(2.8 * 1000.0); // 2.8 milliseconds
|
||||
else if(!damaged)
|
||||
else if(!frame_captured)
|
||||
av_usleep(1.0 * 1000.0); // 1 milliseconds
|
||||
wait_until_frame_time_elapsed = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user