Compare commits

..

4 Commits
5.0.1 ... 5.0.2

Author SHA1 Message Date
dec05eba
802067d1df -overlapping-replay > -overlap-replay 2025-01-24 00:29:57 +01:00
dec05eba
b55096544b Add version to --info output 2025-01-23 23:56:19 +01:00
dec05eba
e87ade6ee3 Add -overlapping-replay option to clear replay buffer after a save 2025-01-23 23:52:31 +01:00
dec05eba
832052a012 m 2025-01-19 00:32:20 +01:00
4 changed files with 38 additions and 7 deletions

2
TODO
View File

@@ -219,3 +219,5 @@ Always disable prime run/dri prime and list all monitors to record from from all
Allow flv av1 if recent ffmpeg version and streaming to youtube (and twitch?) and for custom services.
Use explicit sync in pipewire video code: https://docs.pipewire.org/page_dma_buf.html.
Support vaapi rotation. Support for it is added in mesa here: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32919.

View File

@@ -1,4 +1,4 @@
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.0.1', default_options : ['warning_level=2'])
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.0.2', default_options : ['warning_level=2'])
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
if get_option('buildtype') == 'debug'

View File

@@ -1,7 +1,7 @@
[package]
name = "gpu-screen-recorder"
type = "executable"
version = "5.0.1"
version = "5.0.2"
platforms = ["posix"]
[config]

View File

@@ -1069,7 +1069,7 @@ static void open_video_hardware(AVCodecContext *codec_context, VideoQuality vide
static void usage_header() {
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
const char *program_name = inside_flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder" : "gpu-screen-recorder";
printf("usage: %s -w <window_id|monitor|focused|portal> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-q <quality>] [-r <replay_buffer_size_sec>] [-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-oc yes|no] [-fm cfr|vfr|content] [-bm auto|qp|vbr|cbr] [-cr limited|full] [-df yes|no] [-sc <script_path>] [-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] [-o <output_file>] [--list-capture-options [card_path] [vendor]] [--list-audio-devices] [--list-application-audio] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
printf("usage: %s -w <window_id|monitor|focused|portal> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-q <quality>] [-r <replay_buffer_size_sec>] [-overlap-replay yes|no] [-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-oc yes|no] [-fm cfr|vfr|content] [-bm auto|qp|vbr|cbr] [-cr limited|full] [-df yes|no] [-sc <script_path>] [-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] [-o <output_file>] [--list-capture-options [card_path] [vendor]] [--list-audio-devices] [--list-application-audio] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
fflush(stdout);
}
@@ -1130,6 +1130,12 @@ static void usage_full() {
printf(" Note that the video data is stored in RAM, so don't use too long replay buffer time and use constant bitrate option (-bm cbr) to prevent RAM usage from going too high in busy scenes.\n");
printf(" Optional, disabled by default.\n");
printf("\n");
printf(" -overlap-replay\n");
printf(" Should replays overlap. For example if this is set to 'yes' and replay time (-r) is set to 60 seconds and a replay is saved once then the first replay video is 60 seconds long\n");
printf(" and if a replay is saved 10 seconds later then the second replay video will also be 60 seconds long and contain 50 seconds of the previous video as well.\n");
printf(" If this is set to 'no' then after a replay is saved the replay buffer data is cleared and the second replay will start from that point onward.\n");
printf(" Optional, set to 'yes' by default.\n");
printf("\n");
printf(" -k Video codec to use. Should be either 'auto', 'h264', 'hevc', 'av1', 'vp8', 'vp9', 'hevc_hdr', 'av1_hdr', 'hevc_10bit' or 'av1_10bit'.\n");
printf(" Optional, set to 'auto' by default which defaults to 'h264'. Forcefully set to 'h264' if the file container type is 'flv'.\n");
printf(" 'hevc_hdr' and 'av1_hdr' option is not available on X11 nor when using the portal capture option.\n");
@@ -2148,6 +2154,7 @@ static void info_command() {
puts("is_steam_deck|yes");
else
puts("is_steam_deck|no");
printf("gsr_version|%s\n", GSR_VERSION);
puts("section=gpu_info");
list_gpu_info(&egl);
puts("section=video_codecs");
@@ -3055,6 +3062,7 @@ int main(int argc, char **argv) {
{ "-q", Arg { {}, true, false } },
{ "-o", Arg { {}, true, false } },
{ "-r", Arg { {}, true, false } },
{ "-overlap-replay", Arg { {}, true, false } },
{ "-k", Arg { {}, true, false } },
{ "-ac", Arg { {}, true, false } },
{ "-ab", Arg { {}, true, false } },
@@ -3381,6 +3389,20 @@ int main(int argc, char **argv) {
replay_buffer_size_secs += std::ceil(keyint); // Add a few seconds to account of lost packets because of non-keyframe packets skipped
}
bool overlap_replay = true;
const char *overlap_replay_str = args["-overlap-replay"].value();
if(!overlap_replay_str)
overlap_replay_str = "yes";
if(strcmp(overlap_replay_str, "yes") == 0) {
overlap_replay = true;
} else if(strcmp(overlap_replay_str, "no") == 0) {
overlap_replay = false;
} else {
fprintf(stderr, "Error: -overlap-replap should either be either 'yes' or 'no', got: '%s'\n", overlap_replay_str);
usage();
}
std::string window_str = args["-w"].value();
const bool is_portal_capture = strcmp(window_str.c_str(), "portal") == 0;
@@ -3866,6 +3888,7 @@ int main(int argc, char **argv) {
std::mutex audio_filter_mutex;
const double record_start_time = clock_get_monotonic_seconds();
std::atomic<double> replay_start_time(record_start_time);
std::deque<std::shared_ptr<PacketData>> frame_data_queue;
bool frames_erased = false;
@@ -3984,7 +4007,7 @@ int main(int argc, char **argv) {
ret = avcodec_send_frame(audio_track.codec_context, audio_device.frame);
if(ret >= 0) {
// TODO: Move to separate thread because this could write to network (for example when livestreaming)
receive_frames(audio_track.codec_context, audio_track.stream_index, audio_track.stream, audio_device.frame->pts, av_format_context, record_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
receive_frames(audio_track.codec_context, audio_track.stream_index, audio_track.stream, audio_device.frame->pts, av_format_context, replay_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
} else {
fprintf(stderr, "Failed to encode audio!\n");
}
@@ -4016,7 +4039,7 @@ int main(int argc, char **argv) {
ret = avcodec_send_frame(audio_track.codec_context, audio_device.frame);
if(ret >= 0) {
// TODO: Move to separate thread because this could write to network (for example when livestreaming)
receive_frames(audio_track.codec_context, audio_track.stream_index, audio_track.stream, audio_device.frame->pts, av_format_context, record_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
receive_frames(audio_track.codec_context, audio_track.stream_index, audio_track.stream, audio_device.frame->pts, av_format_context, replay_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
} else {
fprintf(stderr, "Failed to encode audio!\n");
}
@@ -4050,7 +4073,7 @@ int main(int argc, char **argv) {
err = avcodec_send_frame(audio_track.codec_context, aframe);
if(err >= 0){
// TODO: Move to separate thread because this could write to network (for example when livestreaming)
receive_frames(audio_track.codec_context, audio_track.stream_index, audio_track.stream, aframe->pts, av_format_context, record_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
receive_frames(audio_track.codec_context, audio_track.stream_index, audio_track.stream, aframe->pts, av_format_context, replay_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
} else {
fprintf(stderr, "Failed to encode audio!\n");
}
@@ -4196,7 +4219,7 @@ int main(int argc, char **argv) {
if(ret == 0) {
// TODO: Move to separate thread because this could write to network (for example when livestreaming)
receive_frames(video_codec_context, VIDEO_STREAM_INDEX, video_stream, video_frame->pts, av_format_context,
record_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
replay_start_time, frame_data_queue, replay_buffer_size_secs, frames_erased, write_output_mutex, paused_time_offset);
} else {
fprintf(stderr, "Error: avcodec_send_frame failed, error: %s\n", av_error_to_string(ret));
}
@@ -4225,8 +4248,14 @@ int main(int argc, char **argv) {
fflush(stdout);
if(recording_saved_script)
run_recording_saved_script_async(recording_saved_script, save_replay_output_filepath.c_str(), "replay");
std::lock_guard<std::mutex> lock(write_output_mutex);
save_replay_packets.clear();
if(!overlap_replay) {
frame_data_queue.clear();
frames_erased = true;
replay_start_time = clock_get_monotonic_seconds() - paused_time_offset;
}
}
if(save_replay == 1 && !save_replay_thread.valid() && replay_buffer_size_secs != -1) {