diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | TODO | 10 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | project.conf | 2 | ||||
-rwxr-xr-x | scripts/record-application-name.sh | 2 | ||||
-rwxr-xr-x | scripts/record-save-application-name.sh | 2 | ||||
-rwxr-xr-x | scripts/replay-application-name.sh | 2 | ||||
-rw-r--r-- | src/egl.c | 2 | ||||
-rw-r--r-- | src/main.cpp | 36 | ||||
-rw-r--r-- | src/sound.cpp | 52 |
10 files changed, 61 insertions, 51 deletions
@@ -149,7 +149,7 @@ You have to reboot your computer after installing GPU Screen Recorder for the fi Look at the [scripts](https://git.dec05eba.com/gpu-screen-recorder/tree/scripts) directory for script examples. For example if you want to automatically save a recording/replay into a folder with the same name as the game you are recording. # Reporting bugs -Issues are reported on this Github page: [https://github.com/dec05eba/gpu-screen-recorder-issues/issues](https://github.com/dec05eba/gpu-screen-recorder-issues/issues). +Issues are reported on this Github page: [https://github.com/dec05eba/gpu-screen-recorder-issues](https://github.com/dec05eba/gpu-screen-recorder-issues). # Contributing patches See [https://git.dec05eba.com/?p=about](https://git.dec05eba.com/?p=about) for contribution steps. # Donations @@ -176,4 +176,12 @@ 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.
\ No newline at end of file +Set low latency mode on vulkan encoding. + +Support pipewire audio capture which also allows capturing audio from a single application. This can also be done with pulseaudio by creating a virtual sink: + pactl load-module module-combine-sink sink_name=gsr2 slaves=$(pactl get-default-sink) sink_properties=device.description="gsr" + pactl move-sink-input 2944 gsr2 # 2944 comes from 'pactl list sink-inputs' + and then record gsr2.monitor. + Or use pa_stream_set_monitor_stream, which also takes the sink-input as input. However need to track when the sink disconnects to mute and then reconnect again. + +Support recording/replay/livestreaming at the same time by allowing commands to be run on an existing gpu screen recorder instance. diff --git a/meson.build b/meson.build index 00bac22..9e4bb68 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('gpu-screen-recorder', ['c', 'cpp'], version : '4.2.4', default_options : ['warning_level=2']) +project('gpu-screen-recorder', ['c', 'cpp'], version : '4.2.5', default_options : ['warning_level=2']) add_project_arguments('-Wshadow', language : ['c', 'cpp']) if get_option('buildtype') == 'debug' diff --git a/project.conf b/project.conf index 6baf6f2..93d01af 100644 --- a/project.conf +++ b/project.conf @@ -1,7 +1,7 @@ [package] name = "gpu-screen-recorder" type = "executable" -version = "4.2.4" +version = "4.2.5" platforms = ["posix"] [config] diff --git a/scripts/record-application-name.sh b/scripts/record-application-name.sh index 4139c9c..f8c9b0d 100755 --- a/scripts/record-application-name.sh +++ b/scripts/record-application-name.sh @@ -1,6 +1,6 @@ #!/bin/sh window=$(xdotool selectwindow) -window_name=$(xdotool getwindowclassname "$window" || xdotool getwindowname "$window" || echo "Game") +window_name=$(xdotool getwindowname "$window" || xdotool getwindowclassname "$window" || echo "Game") window_name="$(echo "$window_name" | tr '/\\' '_')" gpu-screen-recorder -w "$window" -f 60 -a default_output -o "$HOME/Videos/recording/$window_name/$(date +"Video_%Y-%m-%d_%H-%M-%S.mp4")" diff --git a/scripts/record-save-application-name.sh b/scripts/record-save-application-name.sh index b814809..c95f398 100755 --- a/scripts/record-save-application-name.sh +++ b/scripts/record-save-application-name.sh @@ -4,7 +4,7 @@ # gpu-screen-recorder -w screen -f 60 -a default_output -r 60 -sc scripts/record-save-application-name.sh -c mp4 -o "$HOME/Videos" window=$(xdotool getwindowfocus) -window_name=$(xdotool getwindowclassname "$window" || xdotool getwindowname "$window" || echo "Game") +window_name=$(xdotool getwindowname "$window" || xdotool getwindowclassname "$window" || echo "Game") window_name="$(echo "$window_name" | tr '/\\' '_')" video_dir="$HOME/Videos/Replays/$window_name" diff --git a/scripts/replay-application-name.sh b/scripts/replay-application-name.sh index 9f363f7..2a651bb 100755 --- a/scripts/replay-application-name.sh +++ b/scripts/replay-application-name.sh @@ -1,6 +1,6 @@ #!/bin/sh window=$(xdotool selectwindow) -window_name=$(xdotool getwindowclassname "$window" || xdotool getwindowname "$window" || echo "Game") +window_name=$(xdotool getwindowname "$window" || xdotool getwindowclassname "$window" || echo "Game") window_name="$(echo "$window_name" | tr '/\\' '_')" gpu-screen-recorder -w "$window" -f 60 -c mkv -a default_output -r 60 -o "$HOME/Videos/Replays/$window_name" @@ -223,7 +223,7 @@ static bool gsr_egl_create_window(gsr_egl *self, bool wayland) { if(wayland) { self->wayland.dpy = wl_display_connect(NULL); if(!self->wayland.dpy) { - fprintf(stderr, "gsr error: gsr_egl_create_window failed: wl_display_connect failed\n"); + fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to connect to the Wayland server\n"); goto fail; } diff --git a/src/main.cpp b/src/main.cpp index a628599..4a390e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -585,7 +585,7 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt, codec_context->global_quality = 120 * quality_multiply; break; case VideoQuality::VERY_HIGH: - codec_context->global_quality = 100 * quality_multiply; + codec_context->global_quality = 115 * quality_multiply; break; case VideoQuality::ULTRA: codec_context->global_quality = 90 * quality_multiply; @@ -600,7 +600,7 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt, codec_context->global_quality = 30 * quality_multiply; break; case VideoQuality::VERY_HIGH: - codec_context->global_quality = 20 * quality_multiply; + codec_context->global_quality = 25 * quality_multiply; break; case VideoQuality::ULTRA: codec_context->global_quality = 10 * quality_multiply; @@ -615,7 +615,7 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt, codec_context->global_quality = 30 * quality_multiply; break; case VideoQuality::VERY_HIGH: - codec_context->global_quality = 20 * quality_multiply; + codec_context->global_quality = 25 * quality_multiply; break; case VideoQuality::ULTRA: codec_context->global_quality = 10 * quality_multiply; @@ -779,10 +779,10 @@ static void video_software_set_qp(AVCodecContext *codec_context, VideoQuality vi av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 23 * qp_multiply, 0); + av_dict_set_int(options, "qp", 25 * qp_multiply, 0); break; case VideoQuality::ULTRA: - av_dict_set_int(options, "qp", 20 * qp_multiply, 0); + av_dict_set_int(options, "qp", 22 * qp_multiply, 0); break; } } else { @@ -873,7 +873,7 @@ static void video_hardware_set_qp(AVCodecContext *codec_context, VideoQuality vi av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 25 * qp_multiply, 0); + av_dict_set_int(options, "qp", 27 * qp_multiply, 0); break; case VideoQuality::ULTRA: av_dict_set_int(options, "qp", 22 * qp_multiply, 0); @@ -882,16 +882,16 @@ static void video_hardware_set_qp(AVCodecContext *codec_context, VideoQuality vi } else if(codec_context->codec_id == AV_CODEC_ID_H264) { switch(video_quality) { case VideoQuality::MEDIUM: - av_dict_set_int(options, "qp", 34 * qp_multiply, 0); + av_dict_set_int(options, "qp", 35 * qp_multiply, 0); break; case VideoQuality::HIGH: av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 23 * qp_multiply, 0); + av_dict_set_int(options, "qp", 27 * qp_multiply, 0); break; case VideoQuality::ULTRA: - av_dict_set_int(options, "qp", 20 * qp_multiply, 0); + av_dict_set_int(options, "qp", 22 * qp_multiply, 0); break; } } else if(codec_context->codec_id == AV_CODEC_ID_HEVC) { @@ -903,7 +903,7 @@ static void video_hardware_set_qp(AVCodecContext *codec_context, VideoQuality vi av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 25 * qp_multiply, 0); + av_dict_set_int(options, "qp", 27 * qp_multiply, 0); break; case VideoQuality::ULTRA: av_dict_set_int(options, "qp", 22 * qp_multiply, 0); @@ -918,7 +918,7 @@ static void video_hardware_set_qp(AVCodecContext *codec_context, VideoQuality vi av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 25 * qp_multiply, 0); + av_dict_set_int(options, "qp", 27 * qp_multiply, 0); break; case VideoQuality::ULTRA: av_dict_set_int(options, "qp", 22 * qp_multiply, 0); @@ -931,16 +931,16 @@ static void video_hardware_set_qp(AVCodecContext *codec_context, VideoQuality vi } else if(codec_context->codec_id == AV_CODEC_ID_H264) { switch(video_quality) { case VideoQuality::MEDIUM: - av_dict_set_int(options, "qp", 34 * qp_multiply, 0); + av_dict_set_int(options, "qp", 35 * qp_multiply, 0); break; case VideoQuality::HIGH: av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 23 * qp_multiply, 0); + av_dict_set_int(options, "qp", 27 * qp_multiply, 0); break; case VideoQuality::ULTRA: - av_dict_set_int(options, "qp", 20 * qp_multiply, 0); + av_dict_set_int(options, "qp", 22 * qp_multiply, 0); break; } } else if(codec_context->codec_id == AV_CODEC_ID_HEVC) { @@ -952,7 +952,7 @@ static void video_hardware_set_qp(AVCodecContext *codec_context, VideoQuality vi av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 25 * qp_multiply, 0); + av_dict_set_int(options, "qp", 27 * qp_multiply, 0); break; case VideoQuality::ULTRA: av_dict_set_int(options, "qp", 22 * qp_multiply, 0); @@ -967,7 +967,7 @@ static void video_hardware_set_qp(AVCodecContext *codec_context, VideoQuality vi av_dict_set_int(options, "qp", 30 * qp_multiply, 0); break; case VideoQuality::VERY_HIGH: - av_dict_set_int(options, "qp", 25 * qp_multiply, 0); + av_dict_set_int(options, "qp", 27 * qp_multiply, 0); break; case VideoQuality::ULTRA: av_dict_set_int(options, "qp", 22 * qp_multiply, 0); @@ -3108,7 +3108,7 @@ int main(int argc, char **argv) { usage(); } - video_bitrate *= 1000LL; + video_bitrate *= 1000LL * 8LL; } else { if(!quality_str) quality_str = "very_high"; @@ -3823,7 +3823,7 @@ int main(int argc, char **argv) { 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) + 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) diff --git a/src/sound.cpp b/src/sound.cpp index d0f2a80..aea5b91 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -340,16 +340,18 @@ static void pa_server_info_cb(pa_context*, const pa_server_info *server_info, vo } static void get_pulseaudio_default_inputs(AudioDevices &audio_devices) { - pa_mainloop *main_loop = pa_mainloop_new(); - - pa_context *ctx = pa_context_new(pa_mainloop_get_api(main_loop), "gpu-screen-recorder-gtk"); - pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); int state = 0; int pa_ready = 0; - pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready); - pa_operation *pa_op = NULL; + pa_mainloop *main_loop = pa_mainloop_new(); + + pa_context *ctx = pa_context_new(pa_mainloop_get_api(main_loop), "gpu-screen-recorder"); + if(pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) + goto done; + + pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready); + for(;;) { // Not ready if(pa_ready == 0) { @@ -366,23 +368,25 @@ static void get_pulseaudio_default_inputs(AudioDevices &audio_devices) { } // Couldn't get connection to the server - if(pa_ready == 2 || (state == 1 && pa_op && pa_operation_get_state(pa_op) == PA_OPERATION_DONE)) { - if(pa_op) - pa_operation_unref(pa_op); - pa_context_disconnect(ctx); - pa_context_unref(ctx); - pa_mainloop_free(main_loop); - return; - } + if(pa_ready == 2 || (state == 1 && pa_op && pa_operation_get_state(pa_op) == PA_OPERATION_DONE)) + break; pa_mainloop_iterate(main_loop, 1, NULL); } + done: + if(pa_op) + pa_operation_unref(pa_op); + pa_context_disconnect(ctx); + pa_context_unref(ctx); pa_mainloop_free(main_loop); } AudioDevices get_pulseaudio_inputs() { AudioDevices audio_devices; + int state = 0; + int pa_ready = 0; + pa_operation *pa_op = NULL; // TODO: Do this in the same connection below instead of two separate connections get_pulseaudio_default_inputs(audio_devices); @@ -390,12 +394,10 @@ AudioDevices get_pulseaudio_inputs() { pa_mainloop *main_loop = pa_mainloop_new(); pa_context *ctx = pa_context_new(pa_mainloop_get_api(main_loop), "gpu-screen-recorder"); - pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); - int state = 0; - int pa_ready = 0; - pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready); + if(pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) + goto done; - pa_operation *pa_op = NULL; + pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready); for(;;) { // Not ready @@ -413,17 +415,17 @@ AudioDevices get_pulseaudio_inputs() { } // Couldn't get connection to the server - if(pa_ready == 2 || (state == 1 && pa_op && pa_operation_get_state(pa_op) == PA_OPERATION_DONE)) { - if(pa_op) - pa_operation_unref(pa_op); - pa_context_disconnect(ctx); - pa_context_unref(ctx); + if(pa_ready == 2 || (state == 1 && pa_op && pa_operation_get_state(pa_op) == PA_OPERATION_DONE)) break; - } pa_mainloop_iterate(main_loop, 1, NULL); } + done: + if(pa_op) + pa_operation_unref(pa_op); + pa_context_disconnect(ctx); + pa_context_unref(ctx); pa_mainloop_free(main_loop); return audio_devices; } |