mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-04-19 08:25:48 +09:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
640e377c90 | ||
|
|
2545db7e50 | ||
|
|
997d4ae922 | ||
|
|
57e9b994a7 | ||
|
|
3117f30143 | ||
|
|
f1acb95cf3 | ||
|
|
cb9cb6c567 | ||
|
|
5857cfa1b4 |
6
TODO
6
TODO
@@ -387,3 +387,9 @@ 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.
|
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).
|
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.
|
||||||
|
|
||||||
|
--
|
||||||
|
|||||||
@@ -301,6 +301,27 @@ Script to run after saving video. Receives filepath and type ("regular", "replay
|
|||||||
.BI \-portal\-session\-token\-filepath " path"
|
.BI \-portal\-session\-token\-filepath " path"
|
||||||
Portal session token file (default: ~/.config/gpu-screen-recorder/restore_token).
|
Portal session token file (default: ~/.config/gpu-screen-recorder/restore_token).
|
||||||
.TP
|
.TP
|
||||||
|
.BI \-ffmpeg-opts " options"
|
||||||
|
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"
|
.BI \-gl\-debug " yes|no"
|
||||||
OpenGL debug output (default: no).
|
OpenGL debug output (default: no).
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
typedef struct gsr_egl gsr_egl;
|
typedef struct gsr_egl gsr_egl;
|
||||||
|
|
||||||
#define NUM_ARGS 32
|
#define NUM_ARGS 35
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GSR_CAPTURE_SOURCE_TYPE_WINDOW,
|
GSR_CAPTURE_SOURCE_TYPE_WINDOW,
|
||||||
@@ -85,6 +85,9 @@ typedef struct {
|
|||||||
const char *replay_recording_directory;
|
const char *replay_recording_directory;
|
||||||
const char *portal_session_token_filepath;
|
const char *portal_session_token_filepath;
|
||||||
const char *recording_saved_script;
|
const char *recording_saved_script;
|
||||||
|
const char *ffmpeg_opts;
|
||||||
|
const char *ffmpeg_video_opts;
|
||||||
|
const char *ffmpeg_audio_opts;
|
||||||
bool verbose;
|
bool verbose;
|
||||||
bool gl_debug;
|
bool gl_debug;
|
||||||
bool fallback_cpu_encoding;
|
bool fallback_cpu_encoding;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.11.2', default_options : ['warning_level=2'])
|
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.11.4', default_options : ['warning_level=2'])
|
||||||
|
|
||||||
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
|
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
|
||||||
if get_option('buildtype') == 'debug'
|
if get_option('buildtype') == 'debug'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gpu-screen-recorder"
|
name = "gpu-screen-recorder"
|
||||||
type = "executable"
|
type = "executable"
|
||||||
version = "5.11.2"
|
version = "5.11.4"
|
||||||
platforms = ["posix"]
|
platforms = ["posix"]
|
||||||
|
|
||||||
[config]
|
[config]
|
||||||
|
|||||||
@@ -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] "
|
"[-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>] "
|
"[-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] "
|
"[-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] "
|
"[-fallback-cpu-encoding yes|no] [-o <output_file>] [-ro <output_directory>] [-ffmpeg-opts <options>] [--list-capture-options [card_path]] "
|
||||||
"[--list-application-audio] [--list-v4l2-devices] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
|
"[--list-audio-devices] [--list-application-audio] [--list-v4l2-devices] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,6 +440,10 @@ static bool args_parser_set_values(args_parser *self) {
|
|||||||
self->recording_saved_script = NULL;
|
self->recording_saved_script = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,6 +533,9 @@ 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 = "-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 = "-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 = "-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);
|
assert(arg_index == NUM_ARGS);
|
||||||
|
|
||||||
for(int i = 1; i < argc; i += 2) {
|
for(int i = 1; i < argc; i += 2) {
|
||||||
|
|||||||
@@ -553,6 +553,9 @@ static int gsr_capture_v4l2_capture(gsr_capture *cap, gsr_capture_metadata *capt
|
|||||||
const vec2i target_pos = gsr_capture_get_target_position(output_size, capture_metadata);
|
const vec2i target_pos = gsr_capture_get_target_position(output_size, capture_metadata);
|
||||||
|
|
||||||
self->params.egl->glFlush();
|
self->params.egl->glFlush();
|
||||||
|
// TODO: Use the minimal barrier required
|
||||||
|
self->params.egl->glMemoryBarrier(GL_ALL_BARRIER_BITS);
|
||||||
|
// TODO: Remove this?
|
||||||
if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA)
|
if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA)
|
||||||
self->params.egl->glFinish();
|
self->params.egl->glFinish();
|
||||||
|
|
||||||
@@ -671,8 +674,11 @@ void gsr_capture_v4l2_list_devices(v4l2_devices_query_callback callback, void *u
|
|||||||
if(xioctl(fd, VIDIOC_G_FMT, &fmt) == -1)
|
if(xioctl(fd, VIDIOC_G_FMT, &fmt) == -1)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
const gsr_capture_v4l2_supported_pixfmts supported_pixfmts = gsr_capture_v4l2_get_supported_pixfmts(fd);
|
gsr_capture_v4l2_supported_pixfmts supported_pixfmts = gsr_capture_v4l2_get_supported_pixfmts(fd);
|
||||||
if(supported_pixfmts.yuyv || (supported_pixfmts.mjpeg && has_libturbojpeg_lib))
|
if(!has_libturbojpeg_lib)
|
||||||
|
supported_pixfmts.mjpeg = false;
|
||||||
|
|
||||||
|
if(supported_pixfmts.yuyv || supported_pixfmts.mjpeg)
|
||||||
callback(v4l2_device_path, supported_pixfmts, (vec2i){ fmt.fmt.pix.width, fmt.fmt.pix.height }, userdata);
|
callback(v4l2_device_path, supported_pixfmts, (vec2i){ fmt.fmt.pix.width, fmt.fmt.pix.height }, userdata);
|
||||||
|
|
||||||
next:
|
next:
|
||||||
|
|||||||
@@ -781,7 +781,6 @@ static void gsr_color_conversion_draw_graphics(gsr_color_conversion *self, unsig
|
|||||||
self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer_object_id);
|
self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer_object_id);
|
||||||
self->params.egl->glBufferSubData(GL_ARRAY_BUFFER, 0, 24 * sizeof(float), vertices);
|
self->params.egl->glBufferSubData(GL_ARRAY_BUFFER, 0, 24 * sizeof(float), vertices);
|
||||||
|
|
||||||
// TODO:
|
|
||||||
switch(source_color) {
|
switch(source_color) {
|
||||||
case GSR_SOURCE_COLOR_RGB:
|
case GSR_SOURCE_COLOR_RGB:
|
||||||
case GSR_SOURCE_COLOR_BGR: {
|
case GSR_SOURCE_COLOR_BGR: {
|
||||||
|
|||||||
@@ -523,4 +523,7 @@ void gsr_egl_swap_buffers(gsr_egl *self) {
|
|||||||
self->glFlush();
|
self->glFlush();
|
||||||
// TODO: Use the minimal barrier required
|
// TODO: Use the minimal barrier required
|
||||||
self->glMemoryBarrier(GL_ALL_BARRIER_BITS); // GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
|
self->glMemoryBarrier(GL_ALL_BARRIER_BITS); // GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
|
||||||
|
// TODO: This is needed on nvidia because the cursor can flicker otherwise. Find a better solution
|
||||||
|
if(self->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA)
|
||||||
|
self->glFinish();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,8 +245,8 @@ static bool gsr_video_encoder_vaapi_start(gsr_video_encoder *encoder, AVCodecCon
|
|||||||
video_codec_context->width = FFALIGN(video_codec_context->width, 2);
|
video_codec_context->width = FFALIGN(video_codec_context->width, 2);
|
||||||
video_codec_context->height = FFALIGN(video_codec_context->height, 2);
|
video_codec_context->height = FFALIGN(video_codec_context->height, 2);
|
||||||
} else {
|
} else {
|
||||||
video_codec_context->width = FFALIGN(video_codec_context->width, 256);
|
video_codec_context->width = FFALIGN(video_codec_context->width, 64);
|
||||||
video_codec_context->height = FFALIGN(video_codec_context->height, 256);
|
video_codec_context->height = FFALIGN(video_codec_context->height, 16);
|
||||||
}
|
}
|
||||||
} else if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD && video_codec_context->codec_id == AV_CODEC_ID_AV1) {
|
} else if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD && video_codec_context->codec_id == AV_CODEC_ID_AV1) {
|
||||||
// TODO: Dont do this for VCN 5 and forward which should fix this hardware bug
|
// TODO: Dont do this for VCN 5 and forward which should fix this hardware bug
|
||||||
|
|||||||
39
src/main.cpp
39
src/main.cpp
@@ -528,10 +528,13 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt, const A
|
|||||||
return codec_context;
|
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;
|
AVDictionary *options = nullptr;
|
||||||
av_dict_set(&options, "strict", "experimental", 0);
|
av_dict_set(&options, "strict", "experimental", 0);
|
||||||
|
|
||||||
|
if(ffmpeg_audio_opts)
|
||||||
|
av_dict_parse_string(&options, ffmpeg_audio_opts, "=", ";", 0);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
ret = avcodec_open2(audio_codec_context, audio_codec_context->codec, &options);
|
ret = avcodec_open2(audio_codec_context, audio_codec_context->codec, &options);
|
||||||
if(ret < 0) {
|
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);
|
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);
|
int ret = avcodec_open2(codec_context, codec_context->codec, &options);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "gsr error: Could not open video codec: %s\n", av_error_to_string(ret));
|
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);
|
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);
|
int ret = avcodec_open2(codec_context, codec_context->codec, &options);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "gsr error: Could not open video codec: %s\n", av_error_to_string(ret));
|
fprintf(stderr, "gsr error: Could not open video codec: %s\n", av_error_to_string(ret));
|
||||||
@@ -1193,9 +1202,9 @@ struct VideoSource {
|
|||||||
CaptureSource *capture_source;
|
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;
|
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);
|
AVStream *video_stream = create_stream(av_format_context, video_codec_context);
|
||||||
avcodec_parameters_from_context(video_stream->codecpar, video_codec_context);
|
avcodec_parameters_from_context(video_stream->codecpar, video_codec_context);
|
||||||
@@ -1220,6 +1229,9 @@ static RecordingStartResult start_recording_create_streams(const char *filename,
|
|||||||
AVDictionary *options = nullptr;
|
AVDictionary *options = nullptr;
|
||||||
av_dict_set(&options, "strict", "experimental", 0);
|
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);
|
const int header_write_ret = avformat_write_header(av_format_context, &options);
|
||||||
av_dict_free(&options);
|
av_dict_free(&options);
|
||||||
if(header_write_ret < 0) {
|
if(header_write_ret < 0) {
|
||||||
@@ -1282,7 +1294,7 @@ struct AudioPtsOffset {
|
|||||||
int stream_index = 0;
|
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())
|
if(save_replay_thread.valid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1310,8 +1322,8 @@ static void save_replay_async(AVCodecContext *video_codec_context, int video_str
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string output_filepath = create_new_recording_filepath_from_timestamp(output_dir, "Replay", file_extension, date_folders);
|
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(), container_format, video_codec_context, audio_tracks, hdr, video_sources);
|
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)
|
if(!recording_start_result.av_format_context)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -2386,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};
|
video_size = {0, 0};
|
||||||
for(const VideoSource &video_source : video_sources) {
|
for(const VideoSource &video_source : video_sources) {
|
||||||
video_size.x = std::max(video_size.x, video_source.metadata.video_size.x);
|
video_size.x = std::max(video_size.x, video_source.metadata.video_size.x);
|
||||||
@@ -3430,7 +3443,7 @@ static bool get_image_format_from_filename(const char *filename, gsr_image_forma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace this with start_recording_create_steams
|
// 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);
|
int ret = avio_open(&av_format_context->pb, filename, AVIO_FLAG_WRITE);
|
||||||
if(ret < 0) {
|
if(ret < 0) {
|
||||||
fprintf(stderr, "gsr error: Could not open '%s': %s\n", filename, av_error_to_string(ret));
|
fprintf(stderr, "gsr error: Could not open '%s': %s\n", filename, av_error_to_string(ret));
|
||||||
@@ -3439,7 +3452,9 @@ static bool av_open_file_write_header(AVFormatContext *av_format_context, const
|
|||||||
|
|
||||||
AVDictionary *options = nullptr;
|
AVDictionary *options = nullptr;
|
||||||
av_dict_set(&options, "strict", "experimental", 0);
|
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);
|
ret = avformat_write_header(av_format_context, &options);
|
||||||
if(ret < 0)
|
if(ret < 0)
|
||||||
@@ -3931,7 +3946,7 @@ int main(int argc, char **argv) {
|
|||||||
if(audio_stream && !merged_audio_inputs.track_name.empty())
|
if(audio_stream && !merged_audio_inputs.track_name.empty())
|
||||||
av_dict_set(&audio_stream->metadata, "title", merged_audio_inputs.track_name.c_str(), 0);
|
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)
|
if(audio_stream)
|
||||||
avcodec_parameters_from_context(audio_stream->codecpar, audio_codec_context);
|
avcodec_parameters_from_context(audio_stream->codecpar, audio_codec_context);
|
||||||
|
|
||||||
@@ -3989,7 +4004,7 @@ int main(int argc, char **argv) {
|
|||||||
//av_dump_format(av_format_context, 0, filename, 1);
|
//av_dump_format(av_format_context, 0, filename, 1);
|
||||||
|
|
||||||
if(!is_replaying) {
|
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);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4448,7 +4463,7 @@ int main(int argc, char **argv) {
|
|||||||
std::lock_guard<std::mutex> lock(audio_filter_mutex);
|
std::lock_guard<std::mutex> lock(audio_filter_mutex);
|
||||||
replay_recording_items.clear();
|
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_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) {
|
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);
|
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)
|
if(video_recording_destination_id != (size_t)-1)
|
||||||
@@ -4510,7 +4525,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
save_replay_seconds = 0;
|
save_replay_seconds = 0;
|
||||||
save_replay_output_filepath.clear();
|
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)
|
if(arg_parser.restart_replay_on_save && current_save_replay_seconds == save_replay_seconds_full)
|
||||||
gsr_replay_buffer_clear(encoder.replay_buffer);
|
gsr_replay_buffer_clear(encoder.replay_buffer);
|
||||||
|
|||||||
Reference in New Issue
Block a user