aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2026-01-05 20:24:41 +0100
committerdec05eba <dec05eba@protonmail.com>2026-01-05 20:24:41 +0100
commitf1acb95cf39c45182371af01272f8793ae5c28f7 (patch)
treee3a72a2f19b1f5070363f02c0c3b2912ffb0d33a
parentcb9cb6c567181de2150c445a238f66ea2741f6fd (diff)
Add -ffmpeg-video-opts and -ffmpeg-audio-opts
-rw-r--r--TODO4
-rw-r--r--gpu-screen-recorder.118
-rw-r--r--include/args_parser.h4
-rw-r--r--src/args_parser.c4
-rw-r--r--src/main.cpp16
5 files changed, 42 insertions, 4 deletions
diff --git a/TODO b/TODO
index f6bda68..76db810 100644
--- a/TODO
+++ b/TODO
@@ -387,3 +387,7 @@ Support camera controls, such as white balance. Otherwise tell user to use camer
Camera capture doesn't work perfectly. The image gets glitched, need to properly wait for image to be done.
Use one pipewire connection (pipewire video) instead of multiple ones when recording with portal multiple times (multiple sources).
+
+Close pipewire links or maybe there are file descriptor leaks?
+
+Make multiple capture sources work properly in regards to size. The size of the video should be the region size of each capture source. \ No newline at end of file
diff --git a/gpu-screen-recorder.1 b/gpu-screen-recorder.1
index bab12b2..ab946a2 100644
--- a/gpu-screen-recorder.1
+++ b/gpu-screen-recorder.1
@@ -302,9 +302,25 @@ Script to run after saving video. Receives filepath and type ("regular", "replay
Portal session token file (default: ~/.config/gpu-screen-recorder/restore_token).
.TP
.BI \-ffmpeg-opts " options"
-Additional arguments to pass to FFmpeg in a list of key-values pairs in the format "key=value;key=value",
+Additional arguments to pass to FFmpeg for the file in a list of key-values pairs in the format "key=value;key=value",
.br
for example: -ffmpeg-opts "hls_list_size=3;hls_time=1;hls_flags=delete_segments".
+.br
+Note: this overwrites options set by GPU Screen Recorder with the same name.
+.TP
+.BI \-ffmpeg-video-opts " options"
+Additional arguments to pass to FFmpeg for the video in a list of key-values pairs in the format "key=value;key=value",
+.br
+for example: -ffmpeg-video-opts "codec=cabac;rc_mode=CQP;qp=16".
+.br
+Note: this overwrites options set by GPU Screen Recorder with the same name.
+.TP
+.BI \-ffmpeg-audio-opts " options"
+Additional arguments to pass to FFmpeg for the audio in a list of key-values pairs in the format "key=value;key=value",
+.br
+for example: -ffmpeg-audio-opts "aac_coder=fast;aac_pce=true".
+.br
+Note: this overwrites options set by GPU Screen Recorder with the same name.
.TP
.BI \-gl\-debug " yes|no"
OpenGL debug output (default: no).
diff --git a/include/args_parser.h b/include/args_parser.h
index 0a03024..8e60b8b 100644
--- a/include/args_parser.h
+++ b/include/args_parser.h
@@ -8,7 +8,7 @@
typedef struct gsr_egl gsr_egl;
-#define NUM_ARGS 33
+#define NUM_ARGS 35
typedef enum {
GSR_CAPTURE_SOURCE_TYPE_WINDOW,
@@ -86,6 +86,8 @@ typedef struct {
const char *portal_session_token_filepath;
const char *recording_saved_script;
const char *ffmpeg_opts;
+ const char *ffmpeg_video_opts;
+ const char *ffmpeg_audio_opts;
bool verbose;
bool gl_debug;
bool fallback_cpu_encoding;
diff --git a/src/args_parser.c b/src/args_parser.c
index c95c43a..5584e5c 100644
--- a/src/args_parser.c
+++ b/src/args_parser.c
@@ -441,6 +441,8 @@ static bool args_parser_set_values(args_parser *self) {
}
self->ffmpeg_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-opts");
+ self->ffmpeg_video_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-video-opts");
+ self->ffmpeg_audio_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-audio-opts");
return true;
}
@@ -532,6 +534,8 @@ bool args_parser_parse(args_parser *self, int argc, char **argv, const args_hand
self->args[arg_index++] = (Arg){ .key = "-replay-storage", .optional = true, .list = false, .type = ARG_TYPE_ENUM, .enum_values = replay_storage_enums, .num_enum_values = sizeof(replay_storage_enums)/sizeof(ArgEnum) };
self->args[arg_index++] = (Arg){ .key = "-p", .optional = true, .list = true, .type = ARG_TYPE_STRING };
self->args[arg_index++] = (Arg){ .key = "-ffmpeg-opts", .optional = true, .list = false, .type = ARG_TYPE_STRING };
+ self->args[arg_index++] = (Arg){ .key = "-ffmpeg-video-opts", .optional = true, .list = false, .type = ARG_TYPE_STRING };
+ self->args[arg_index++] = (Arg){ .key = "-ffmpeg-audio-opts", .optional = true, .list = false, .type = ARG_TYPE_STRING };
assert(arg_index == NUM_ARGS);
for(int i = 1; i < argc; i += 2) {
diff --git a/src/main.cpp b/src/main.cpp
index bcfce99..d2c999a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -528,10 +528,13 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt, const A
return codec_context;
}
-static void open_audio(AVCodecContext *audio_codec_context) {
+static void open_audio(AVCodecContext *audio_codec_context, const char *ffmpeg_audio_opts) {
AVDictionary *options = nullptr;
av_dict_set(&options, "strict", "experimental", 0);
+ if(ffmpeg_audio_opts)
+ av_dict_parse_string(&options, ffmpeg_audio_opts, "=", ";", 0);
+
int ret;
ret = avcodec_open2(audio_codec_context, audio_codec_context->codec, &options);
if(ret < 0) {
@@ -678,6 +681,9 @@ static void open_video_software(AVCodecContext *codec_context, const args_parser
av_dict_set(&options, "strict", "experimental", 0);
+ if(arg_parser.ffmpeg_video_opts)
+ av_dict_parse_string(&options, arg_parser.ffmpeg_video_opts, "=", ";", 0);
+
int ret = avcodec_open2(codec_context, codec_context->codec, &options);
if (ret < 0) {
fprintf(stderr, "gsr error: Could not open video codec: %s\n", av_error_to_string(ret));
@@ -926,6 +932,9 @@ static void open_video_hardware(AVCodecContext *codec_context, bool low_power, c
av_dict_set(&options, "strict", "experimental", 0);
+ if(arg_parser.ffmpeg_video_opts)
+ av_dict_parse_string(&options, arg_parser.ffmpeg_video_opts, "=", ";", 0);
+
int ret = avcodec_open2(codec_context, codec_context->codec, &options);
if (ret < 0) {
fprintf(stderr, "gsr error: Could not open video codec: %s\n", av_error_to_string(ret));
@@ -1219,6 +1228,7 @@ static RecordingStartResult start_recording_create_streams(const char *filename,
AVDictionary *options = nullptr;
av_dict_set(&options, "strict", "experimental", 0);
+
if(args_parser.ffmpeg_opts)
av_dict_parse_string(&options, args_parser.ffmpeg_opts, "=", ";", 0);
@@ -2388,6 +2398,7 @@ static std::vector<VideoSource> create_video_sources(const args_parser &arg_pars
}
}
+ // TODO: Video size should be end pos - start pos, where start pos = pos and end pos = pos + size
video_size = {0, 0};
for(const VideoSource &video_source : video_sources) {
video_size.x = std::max(video_size.x, video_source.metadata.video_size.x);
@@ -3441,6 +3452,7 @@ static bool av_open_file_write_header(AVFormatContext *av_format_context, const
AVDictionary *options = nullptr;
av_dict_set(&options, "strict", "experimental", 0);
+
if(ffmpeg_opts)
av_dict_parse_string(&options, ffmpeg_opts, "=", ";", 0);
@@ -3934,7 +3946,7 @@ int main(int argc, char **argv) {
if(audio_stream && !merged_audio_inputs.track_name.empty())
av_dict_set(&audio_stream->metadata, "title", merged_audio_inputs.track_name.c_str(), 0);
- open_audio(audio_codec_context);
+ open_audio(audio_codec_context, arg_parser.ffmpeg_audio_opts);
if(audio_stream)
avcodec_parameters_from_context(audio_stream->codecpar, audio_codec_context);