mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-03-31 09:07:13 +09:00
Fix incorrect bitrate calculation for constant bitrate
This commit is contained in:
6
TODO
6
TODO
@@ -178,6 +178,10 @@ Default to hevc if capture size is larger than 4096 in width or height.
|
|||||||
|
|
||||||
Set low latency mode on vulkan encoding.
|
Set low latency mode on vulkan encoding.
|
||||||
|
|
||||||
Support pipewire audio capture which also allows capturing audio from a single application.
|
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.
|
Support recording/replay/livestreaming at the same time by allowing commands to be run on an existing gpu screen recorder instance.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
window=$(xdotool selectwindow)
|
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 '/\\' '_')"
|
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")"
|
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")"
|
||||||
|
|||||||
@@ -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"
|
# 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=$(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 '/\\' '_')"
|
window_name="$(echo "$window_name" | tr '/\\' '_')"
|
||||||
|
|
||||||
video_dir="$HOME/Videos/Replays/$window_name"
|
video_dir="$HOME/Videos/Replays/$window_name"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
window=$(xdotool selectwindow)
|
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 '/\\' '_')"
|
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"
|
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) {
|
if(wayland) {
|
||||||
self->wayland.dpy = wl_display_connect(NULL);
|
self->wayland.dpy = wl_display_connect(NULL);
|
||||||
if(!self->wayland.dpy) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
34
src/main.cpp
34
src/main.cpp
@@ -585,7 +585,7 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt,
|
|||||||
codec_context->global_quality = 120 * quality_multiply;
|
codec_context->global_quality = 120 * quality_multiply;
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
case VideoQuality::VERY_HIGH:
|
||||||
codec_context->global_quality = 100 * quality_multiply;
|
codec_context->global_quality = 115 * quality_multiply;
|
||||||
break;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
codec_context->global_quality = 90 * quality_multiply;
|
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;
|
codec_context->global_quality = 30 * quality_multiply;
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
case VideoQuality::VERY_HIGH:
|
||||||
codec_context->global_quality = 20 * quality_multiply;
|
codec_context->global_quality = 25 * quality_multiply;
|
||||||
break;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
codec_context->global_quality = 10 * quality_multiply;
|
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;
|
codec_context->global_quality = 30 * quality_multiply;
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
case VideoQuality::VERY_HIGH:
|
||||||
codec_context->global_quality = 20 * quality_multiply;
|
codec_context->global_quality = 25 * quality_multiply;
|
||||||
break;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
codec_context->global_quality = 10 * quality_multiply;
|
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);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 20 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
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) {
|
} else if(codec_context->codec_id == AV_CODEC_ID_H264) {
|
||||||
switch(video_quality) {
|
switch(video_quality) {
|
||||||
case VideoQuality::MEDIUM:
|
case VideoQuality::MEDIUM:
|
||||||
av_dict_set_int(options, "qp", 34 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 35 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::HIGH:
|
case VideoQuality::HIGH:
|
||||||
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 20 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(codec_context->codec_id == AV_CODEC_ID_HEVC) {
|
} 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);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
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);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
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) {
|
} else if(codec_context->codec_id == AV_CODEC_ID_H264) {
|
||||||
switch(video_quality) {
|
switch(video_quality) {
|
||||||
case VideoQuality::MEDIUM:
|
case VideoQuality::MEDIUM:
|
||||||
av_dict_set_int(options, "qp", 34 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 35 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::HIGH:
|
case VideoQuality::HIGH:
|
||||||
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 20 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(codec_context->codec_id == AV_CODEC_ID_HEVC) {
|
} 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);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
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);
|
av_dict_set_int(options, "qp", 30 * qp_multiply, 0);
|
||||||
break;
|
break;
|
||||||
case VideoQuality::VERY_HIGH:
|
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;
|
break;
|
||||||
case VideoQuality::ULTRA:
|
case VideoQuality::ULTRA:
|
||||||
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
av_dict_set_int(options, "qp", 22 * qp_multiply, 0);
|
||||||
@@ -3108,7 +3108,7 @@ int main(int argc, char **argv) {
|
|||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
video_bitrate *= 1000LL;
|
video_bitrate *= 1024LL * 8LL;
|
||||||
} else {
|
} else {
|
||||||
if(!quality_str)
|
if(!quality_str)
|
||||||
quality_str = "very_high";
|
quality_str = "very_high";
|
||||||
|
|||||||
@@ -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) {
|
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 state = 0;
|
||||||
int pa_ready = 0;
|
int pa_ready = 0;
|
||||||
pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready);
|
|
||||||
|
|
||||||
pa_operation *pa_op = NULL;
|
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(;;) {
|
for(;;) {
|
||||||
// Not ready
|
// Not ready
|
||||||
if(pa_ready == 0) {
|
if(pa_ready == 0) {
|
||||||
@@ -366,23 +368,25 @@ static void get_pulseaudio_default_inputs(AudioDevices &audio_devices) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Couldn't get connection to the server
|
// 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_ready == 2 || (state == 1 && pa_op && pa_operation_get_state(pa_op) == PA_OPERATION_DONE))
|
||||||
if(pa_op)
|
break;
|
||||||
pa_operation_unref(pa_op);
|
|
||||||
pa_context_disconnect(ctx);
|
|
||||||
pa_context_unref(ctx);
|
|
||||||
pa_mainloop_free(main_loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_mainloop_iterate(main_loop, 1, NULL);
|
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);
|
pa_mainloop_free(main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevices get_pulseaudio_inputs() {
|
AudioDevices get_pulseaudio_inputs() {
|
||||||
AudioDevices audio_devices;
|
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
|
// TODO: Do this in the same connection below instead of two separate connections
|
||||||
get_pulseaudio_default_inputs(audio_devices);
|
get_pulseaudio_default_inputs(audio_devices);
|
||||||
@@ -390,12 +394,10 @@ AudioDevices get_pulseaudio_inputs() {
|
|||||||
pa_mainloop *main_loop = pa_mainloop_new();
|
pa_mainloop *main_loop = pa_mainloop_new();
|
||||||
|
|
||||||
pa_context *ctx = pa_context_new(pa_mainloop_get_api(main_loop), "gpu-screen-recorder");
|
pa_context *ctx = pa_context_new(pa_mainloop_get_api(main_loop), "gpu-screen-recorder");
|
||||||
pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL);
|
if(pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
|
||||||
int state = 0;
|
goto done;
|
||||||
int pa_ready = 0;
|
|
||||||
pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready);
|
|
||||||
|
|
||||||
pa_operation *pa_op = NULL;
|
pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready);
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// Not ready
|
// Not ready
|
||||||
@@ -413,17 +415,17 @@ AudioDevices get_pulseaudio_inputs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Couldn't get connection to the server
|
// 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_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);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
pa_mainloop_iterate(main_loop, 1, NULL);
|
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);
|
pa_mainloop_free(main_loop);
|
||||||
return audio_devices;
|
return audio_devices;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user