Add -ffmpeg-opts argument to pass additional options to ffmpeg

This commit is contained in:
dec05eba
2025-12-30 02:33:12 +01:00
parent 5857cfa1b4
commit cb9cb6c567
4 changed files with 25 additions and 13 deletions

View File

@@ -301,6 +301,11 @@ Script to run after saving video. Receives filepath and type ("regular", "replay
.BI \-portal\-session\-token\-filepath " path"
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",
.br
for example: -ffmpeg-opts "hls_list_size=3;hls_time=1;hls_flags=delete_segments".
.TP
.BI \-gl\-debug " yes|no"
OpenGL debug output (default: no).
.TP

View File

@@ -8,7 +8,7 @@
typedef struct gsr_egl gsr_egl;
#define NUM_ARGS 32
#define NUM_ARGS 33
typedef enum {
GSR_CAPTURE_SOURCE_TYPE_WINDOW,
@@ -85,6 +85,7 @@ typedef struct {
const char *replay_recording_directory;
const char *portal_session_token_filepath;
const char *recording_saved_script;
const char *ffmpeg_opts;
bool verbose;
bool gl_debug;
bool fallback_cpu_encoding;

View File

@@ -196,8 +196,8 @@ static void usage_header(void) {
"[-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] [-tune performance|quality] [-df yes|no] [-sc <script_path>] [-p <plugin_path>] "
"[-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] "
"[-fallback-cpu-encoding yes|no] [-o <output_file>] [-ro <output_directory>] [--list-capture-options [card_path]] [--list-audio-devices] "
"[--list-application-audio] [--list-v4l2-devices] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
"[-fallback-cpu-encoding yes|no] [-o <output_file>] [-ro <output_directory>] [-ffmpeg-opts <options>] [--list-capture-options [card_path]] "
"[--list-audio-devices] [--list-application-audio] [--list-v4l2-devices] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
fflush(stdout);
}
@@ -440,6 +440,8 @@ static bool args_parser_set_values(args_parser *self) {
self->recording_saved_script = NULL;
}
self->ffmpeg_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-opts");
return true;
}
@@ -529,6 +531,7 @@ bool args_parser_parse(args_parser *self, int argc, char **argv, const args_hand
self->args[arg_index++] = (Arg){ .key = "-fallback-cpu-encoding", .optional = true, .list = false, .type = ARG_TYPE_BOOLEAN };
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 };
assert(arg_index == NUM_ARGS);
for(int i = 1; i < argc; i += 2) {

View File

@@ -1193,9 +1193,9 @@ struct VideoSource {
CaptureSource *capture_source;
};
static RecordingStartResult start_recording_create_streams(const char *filename, const char *container_format, AVCodecContext *video_codec_context, const std::vector<AudioTrack> &audio_tracks, bool hdr, std::vector<VideoSource> &video_sources) {
static RecordingStartResult start_recording_create_streams(const char *filename, const args_parser &args_parser, AVCodecContext *video_codec_context, const std::vector<AudioTrack> &audio_tracks, bool hdr, std::vector<VideoSource> &video_sources) {
AVFormatContext *av_format_context;
avformat_alloc_output_context2(&av_format_context, nullptr, container_format, filename);
avformat_alloc_output_context2(&av_format_context, nullptr, args_parser.container_format, filename);
AVStream *video_stream = create_stream(av_format_context, video_codec_context);
avcodec_parameters_from_context(video_stream->codecpar, video_codec_context);
@@ -1219,6 +1219,8 @@ 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);
const int header_write_ret = avformat_write_header(av_format_context, &options);
av_dict_free(&options);
@@ -1282,7 +1284,7 @@ struct AudioPtsOffset {
int stream_index = 0;
};
static void save_replay_async(AVCodecContext *video_codec_context, int video_stream_index, const std::vector<AudioTrack> &audio_tracks, gsr_replay_buffer *replay_buffer, std::string output_dir, const char *container_format, const std::string &file_extension, bool date_folders, bool hdr, std::vector<VideoSource> &video_sources, int current_save_replay_seconds) {
static void save_replay_async(AVCodecContext *video_codec_context, int video_stream_index, const std::vector<AudioTrack> &audio_tracks, gsr_replay_buffer *replay_buffer, const args_parser &arg_parser, const std::string &file_extension, bool date_folders, bool hdr, std::vector<VideoSource> &video_sources, int current_save_replay_seconds) {
if(save_replay_thread.valid())
return;
@@ -1310,8 +1312,8 @@ static void save_replay_async(AVCodecContext *video_codec_context, int video_str
return;
}
std::string output_filepath = create_new_recording_filepath_from_timestamp(output_dir, "Replay", file_extension, date_folders);
RecordingStartResult recording_start_result = start_recording_create_streams(output_filepath.c_str(), container_format, video_codec_context, audio_tracks, hdr, video_sources);
std::string output_filepath = create_new_recording_filepath_from_timestamp(arg_parser.filename, "Replay", file_extension, date_folders);
RecordingStartResult recording_start_result = start_recording_create_streams(output_filepath.c_str(), arg_parser, video_codec_context, audio_tracks, hdr, video_sources);
if(!recording_start_result.av_format_context)
return;
@@ -3430,7 +3432,7 @@ static bool get_image_format_from_filename(const char *filename, gsr_image_forma
}
// TODO: replace this with start_recording_create_steams
static bool av_open_file_write_header(AVFormatContext *av_format_context, const char *filename) {
static bool av_open_file_write_header(AVFormatContext *av_format_context, const char *filename, const char *ffmpeg_opts) {
int ret = avio_open(&av_format_context->pb, filename, AVIO_FLAG_WRITE);
if(ret < 0) {
fprintf(stderr, "gsr error: Could not open '%s': %s\n", filename, av_error_to_string(ret));
@@ -3439,7 +3441,8 @@ static bool av_open_file_write_header(AVFormatContext *av_format_context, const
AVDictionary *options = nullptr;
av_dict_set(&options, "strict", "experimental", 0);
//av_dict_set_int(&av_format_context->metadata, "video_full_range_flag", 1, 0);
if(ffmpeg_opts)
av_dict_parse_string(&options, ffmpeg_opts, "=", ";", 0);
ret = avformat_write_header(av_format_context, &options);
if(ret < 0)
@@ -3989,7 +3992,7 @@ int main(int argc, char **argv) {
//av_dump_format(av_format_context, 0, filename, 1);
if(!is_replaying) {
if(!av_open_file_write_header(av_format_context, arg_parser.filename))
if(!av_open_file_write_header(av_format_context, arg_parser.filename, arg_parser.ffmpeg_opts))
_exit(1);
}
@@ -4448,7 +4451,7 @@ int main(int argc, char **argv) {
std::lock_guard<std::mutex> lock(audio_filter_mutex);
replay_recording_items.clear();
replay_recording_filepath = create_new_recording_filepath_from_timestamp(arg_parser.replay_recording_directory, "Video", file_extension, arg_parser.date_folders);
replay_recording_start_result = start_recording_create_streams(replay_recording_filepath.c_str(), arg_parser.container_format, video_codec_context, audio_tracks, hdr, video_sources);
replay_recording_start_result = start_recording_create_streams(replay_recording_filepath.c_str(), arg_parser, video_codec_context, audio_tracks, hdr, video_sources);
if(replay_recording_start_result.av_format_context) {
const size_t video_recording_destination_id = gsr_encoder_add_recording_destination(&encoder, video_codec_context, replay_recording_start_result.av_format_context, replay_recording_start_result.video_stream, video_frame->pts);
if(video_recording_destination_id != (size_t)-1)
@@ -4510,7 +4513,7 @@ int main(int argc, char **argv) {
save_replay_seconds = 0;
save_replay_output_filepath.clear();
save_replay_async(video_codec_context, VIDEO_STREAM_INDEX, audio_tracks, encoder.replay_buffer, arg_parser.filename, arg_parser.container_format, file_extension, arg_parser.date_folders, hdr, video_sources, current_save_replay_seconds);
save_replay_async(video_codec_context, VIDEO_STREAM_INDEX, audio_tracks, encoder.replay_buffer, arg_parser, file_extension, arg_parser.date_folders, hdr, video_sources, current_save_replay_seconds);
if(arg_parser.restart_replay_on_save && current_save_replay_seconds == save_replay_seconds_full)
gsr_replay_buffer_clear(encoder.replay_buffer);