mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-04-06 03:26:38 +09:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57caf13d65 | ||
|
|
bdf1950ca2 | ||
|
|
144b481526 | ||
|
|
f4ee71a094 | ||
|
|
2dce92d82f | ||
|
|
933911bdde | ||
|
|
01d0df500c | ||
|
|
95415f7ac7 | ||
|
|
a39dad1c02 |
6
TODO
6
TODO
@@ -312,8 +312,6 @@ Check if region capture works properly with fractional scaling on wayland.
|
||||
Add option to specify medium/high/very high/ultra for -bm cbr as well, which should automatically pick bitrate based on resolution and framerate.
|
||||
This should also be reflected in gsr ui.
|
||||
|
||||
Create a manpage and move --help text there and mention the manpage command to view it (and make it work in flatpak, maybe with man <link-to-manpage-file>).
|
||||
|
||||
Implement webcam support by using mjpeg with v4l2 and use ffmpeg mjpeg decoder.
|
||||
|
||||
After adding rpc, making recording while in replay/streaming work differently. Start recording should take audio as an argument, to optionally specify different audio for recording than replay/stream.
|
||||
@@ -398,4 +396,6 @@ Return the max resolution of each codec in --info to display an error in the UI
|
||||
|
||||
Should -low-power option also use vaapi/vulkan low power, if available?
|
||||
|
||||
Should capture option x=bla;y=bla be scaled by -s (output resolution scale)? width and height is.
|
||||
Should capture option x=bla;y=bla be scaled by -s (output resolution scale)? width and height is.
|
||||
|
||||
Certain webcam resolutions yuyv resolutions dont work (on amd at least), such as 800x600. Maybe it's because of alignment issue, 600 isn't divisible by 16.
|
||||
|
||||
@@ -105,18 +105,18 @@ These are the available options for all capture sources (optional):
|
||||
.RS
|
||||
.IP \(bu 3
|
||||
.B x
|
||||
- The X position in pixels. If the number ends with % and is a number between 0 and 100 then it's a position relative to the video size
|
||||
- The X position in pixels. If the number ends with % then this sets the X position relative to the video width (integer percentage where 100 = 100%)
|
||||
.IP \(bu 3
|
||||
.B y
|
||||
- The Y position in pixels. If the number ends with % and is a number between 0 and 100 then it's a position relative to the video size
|
||||
- The Y position in pixels. If the number ends with % then this sets the Y position relative to the video height (integer percentage where 100 = 100%)
|
||||
.IP \(bu 3
|
||||
.B width
|
||||
- The width in pixels. If the number ends with % and is a number between 0 and 100 then it's a size relative to the video size.
|
||||
- The width in pixels. If the number ends with % then this sets the width relative to the video width (integer percentage where 100 = 100%).
|
||||
|
||||
A value of 0 means to not scale the capture source and instead use the original width.
|
||||
.IP \(bu 3
|
||||
.B height
|
||||
- The height in pixels. If the number ends with % and is a number between 0 and 100 then it's a size relative to the video size
|
||||
- The height in pixels. If the number ends with % then this sets the height relative to the video height (integer percentage where 100 = 100%).
|
||||
|
||||
A value of 0 means to not scale the capture source and instead use the original height.
|
||||
.IP \(bu 3
|
||||
@@ -372,6 +372,14 @@ It's recommended to also use the option
|
||||
when this is set to
|
||||
.B yes
|
||||
to only encode frames when the screen content updates to lower GPU and video encoding usage when the system is idle.
|
||||
.TP
|
||||
.BI \-write\-first\-frame\-ts " yes|no"
|
||||
When enabled, writes a timestamp file with extra extension \fI.ts\fR next to the output video containing:
|
||||
.nf
|
||||
monotonic_microsec realtime_microsec
|
||||
<monotonic_microsec> <realtime_microsec>
|
||||
.fi
|
||||
(default: no). Ignored for livestreaming and when output is piped.
|
||||
.SS Output Options
|
||||
.TP
|
||||
.BI \-o " output"
|
||||
@@ -467,7 +475,7 @@ Instant replay (last 60 seconds):
|
||||
.PP
|
||||
.nf
|
||||
.RS
|
||||
gpu-screen-recorder -w screen -f 60 -c mkv -r 60 -o ~/Videos
|
||||
gpu-screen-recorder -w screen -c mkv -r 60 -o ~/Videos
|
||||
.RE
|
||||
.fi
|
||||
.PP
|
||||
@@ -491,15 +499,15 @@ Instant replay and launch a script when saving replay:
|
||||
.PP
|
||||
.nf
|
||||
.RS
|
||||
gpu-screen-recorder -w screen -f 60 -c mkv -r 60 -sc ./script.sh -o ~/Videos
|
||||
gpu-screen-recorder -w screen -c mkv -r 60 -sc ./script.sh -o ~/Videos
|
||||
.RE
|
||||
.fi
|
||||
.PP
|
||||
Stream to Twitch:
|
||||
Stream to Twitch with constant bitrate mode:
|
||||
.PP
|
||||
.nf
|
||||
.RS
|
||||
gpu-screen-recorder -w screen -f 60 -a default_output -o "rtmp://live.twitch.tv/app/stream_key"
|
||||
gpu-screen-recorder -w screen -c flv -a default_output -bm cbr -q 8000 -o "rtmp://live.twitch.tv/app/stream_key"
|
||||
.RE
|
||||
.fi
|
||||
.PP
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
typedef struct gsr_egl gsr_egl;
|
||||
|
||||
#define NUM_ARGS 36
|
||||
#define NUM_ARGS 37
|
||||
|
||||
typedef enum {
|
||||
GSR_CAPTURE_SOURCE_TYPE_WINDOW,
|
||||
@@ -97,6 +97,7 @@ typedef struct {
|
||||
bool restore_portal_session;
|
||||
bool restart_replay_on_save;
|
||||
bool overclock;
|
||||
bool write_first_frame_ts;
|
||||
bool is_livestream;
|
||||
bool is_output_piped;
|
||||
bool low_latency_recording;
|
||||
|
||||
@@ -20,6 +20,8 @@ typedef struct {
|
||||
AVStream *stream;
|
||||
int64_t start_pts;
|
||||
bool has_received_keyframe;
|
||||
char *first_frame_ts_filepath;
|
||||
bool first_frame_ts_written;
|
||||
} gsr_encoder_recording_destination;
|
||||
|
||||
typedef struct {
|
||||
@@ -43,5 +45,6 @@ void gsr_encoder_receive_packets(gsr_encoder *self, AVCodecContext *codec_contex
|
||||
/* Returns the id to the recording destination, or -1 on error */
|
||||
size_t gsr_encoder_add_recording_destination(gsr_encoder *self, AVCodecContext *codec_context, AVFormatContext *format_context, AVStream *stream, int64_t start_pts);
|
||||
bool gsr_encoder_remove_recording_destination(gsr_encoder *self, size_t id);
|
||||
bool gsr_encoder_set_recording_destination_first_frame_ts_filepath(gsr_encoder *self, size_t id, const char *filepath);
|
||||
|
||||
#endif /* GSR_ENCODER_H */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.12.2', default_options : ['warning_level=2'])
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.12.3', default_options : ['warning_level=2'])
|
||||
|
||||
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
|
||||
if get_option('buildtype') == 'debug'
|
||||
@@ -117,6 +117,7 @@ executable('gpu-screen-recorder', src, dependencies : dep, install : true)
|
||||
|
||||
install_headers('plugin/plugin.h', install_dir : 'include/gsr')
|
||||
install_man('gpu-screen-recorder.1', 'gsr-kms-server.1')
|
||||
install_subdir('scripts', install_dir: 'share/gpu-screen-recorder')
|
||||
|
||||
if get_option('systemd') == true
|
||||
install_data(files('extra/gpu-screen-recorder.service'), install_dir : 'lib/systemd/user')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "gpu-screen-recorder"
|
||||
type = "executable"
|
||||
version = "5.12.2"
|
||||
version = "5.12.3"
|
||||
platforms = ["posix"]
|
||||
|
||||
[config]
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
[ "$#" -ne 4 ] && echo "usage: twitch-stream-local-copy.sh <window_id> <fps> <livestream_key> <local_file>" && exit 1
|
||||
active_sink=default_output
|
||||
gpu-screen-recorder -w "$1" -c flv -f "$2" -q high -a "$active_sink" | tee -- "$4" | ffmpeg -i pipe:0 -c copy -f flv -- "rtmp://live.twitch.tv/app/$3"
|
||||
gpu-screen-recorder -w "$1" -c flv -f "$2" -bm cbr -q 8000 -a "$active_sink" | tee -- "$4" | ffmpeg -i pipe:0 -c copy -f flv -- "rtmp://live.twitch.tv/app/$3"
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
[ "$#" -ne 3 ] && echo "usage: twitch-stream.sh <window_id> <fps> <livestream_key>" && exit 1
|
||||
active_sink=default_output
|
||||
gpu-screen-recorder -w "$1" -c flv -f "$2" -q high -a "$active_sink" -o "rtmp://live.twitch.tv/app/$3"
|
||||
gpu-screen-recorder -w "$1" -c flv -f "$2" -bm cbr -q 8000 -a "$active_sink" -o "rtmp://live.twitch.tv/app/$3"
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
[ "$#" -ne 3 ] && echo "usage: youtube-hls-stream.sh <window_id> <fps> <livestream_key>" && exit 1
|
||||
active_sink=default_output
|
||||
gpu-screen-recorder -w "$1" -c hls -f "$2" -q high -a "$active_sink" -ac aac -o "https://a.upload.youtube.com/http_upload_hls?cid=$3©=0&file=stream.m3u8"
|
||||
gpu-screen-recorder -w "$1" -c hls -f "$2" -bm cbr -q 8000 -a "$active_sink" -ac aac -o "https://a.upload.youtube.com/http_upload_hls?cid=$3©=0&file=stream.m3u8"
|
||||
@@ -196,7 +196,7 @@ static void usage_header(void) {
|
||||
"[-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>] [-ffmpeg-opts <options>] [--list-capture-options [card_path]] "
|
||||
"[--list-audio-devices] [--list-application-audio] [--list-v4l2-devices] [-low-power yes|no] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
|
||||
"[--list-audio-devices] [--list-application-audio] [--list-v4l2-devices] [-write-first-frame-ts yes|no] [-low-power yes|no] [-v yes|no] [-gl-debug yes|no] [--version] [-h|--help]\n", program_name);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
@@ -255,6 +255,7 @@ static bool args_parser_set_values(args_parser *self) {
|
||||
self->restart_replay_on_save = args_get_boolean_by_key(self->args, NUM_ARGS, "-restart-replay-on-save", false);
|
||||
self->overclock = args_get_boolean_by_key(self->args, NUM_ARGS, "-oc", false);
|
||||
self->fallback_cpu_encoding = args_get_boolean_by_key(self->args, NUM_ARGS, "-fallback-cpu-encoding", false);
|
||||
self->write_first_frame_ts = args_get_boolean_by_key(self->args, NUM_ARGS, "-write-first-frame-ts", false);
|
||||
self->low_power = args_get_boolean_by_key(self->args, NUM_ARGS, "-low-power", false);
|
||||
|
||||
self->audio_bitrate = args_get_i64_by_key(self->args, NUM_ARGS, "-ab", 0);
|
||||
@@ -432,6 +433,10 @@ static bool args_parser_set_values(args_parser *self) {
|
||||
|
||||
self->is_output_piped = strcmp(self->filename, "/dev/stdout") == 0;
|
||||
self->low_latency_recording = self->is_livestream || self->is_output_piped;
|
||||
if(self->write_first_frame_ts && (self->is_livestream || self->is_output_piped)) {
|
||||
fprintf(stderr, "gsr warning: -write-first-frame-ts is ignored for livestreaming or when output is piped\n");
|
||||
self->write_first_frame_ts = false;
|
||||
}
|
||||
|
||||
self->replay_recording_directory = args_get_value_by_key(self->args, NUM_ARGS, "-ro");
|
||||
|
||||
@@ -536,6 +541,7 @@ bool args_parser_parse(args_parser *self, int argc, char **argv, const args_hand
|
||||
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 };
|
||||
self->args[arg_index++] = (Arg){ .key = "-write-first-frame-ts", .optional = true, .list = false, .type = ARG_TYPE_BOOLEAN };
|
||||
self->args[arg_index++] = (Arg){ .key = "-low-power", .optional = true, .list = false, .type = ARG_TYPE_BOOLEAN };
|
||||
assert(arg_index == NUM_ARGS);
|
||||
|
||||
|
||||
16
src/dbus.c
16
src/dbus.c
@@ -78,14 +78,6 @@ bool gsr_dbus_init(gsr_dbus *self, const char *screencast_restore_token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: Check the name */
|
||||
const int ret = dbus_bus_request_name(self->con, "com.dec05eba.gpu_screen_recorder", DBUS_NAME_FLAG_REPLACE_EXISTING, &self->err);
|
||||
if(dbus_error_is_set(&self->err)) {
|
||||
fprintf(stderr, "gsr error: gsr_dbus_init: dbus_bus_request_name failed with error: %s\n", self->err.message);
|
||||
gsr_dbus_deinit(self);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(screencast_restore_token) {
|
||||
self->screencast_restore_token = strdup(screencast_restore_token);
|
||||
if(!self->screencast_restore_token) {
|
||||
@@ -95,12 +87,6 @@ bool gsr_dbus_init(gsr_dbus *self, const char *screencast_restore_token) {
|
||||
}
|
||||
}
|
||||
|
||||
(void)ret;
|
||||
// if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
|
||||
// fprintf(stderr, "gsr error: gsr_capture_portal_setup_dbus: dbus_bus_request_name failed to get primary owner\n");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -119,8 +105,6 @@ void gsr_dbus_deinit(gsr_dbus *self) {
|
||||
if(self->con) {
|
||||
dbus_error_free(&self->err);
|
||||
|
||||
dbus_bus_release_name(self->con, "com.dec05eba.gpu_screen_recorder", NULL);
|
||||
|
||||
// Apparently shouldn't be used when a connection is setup by using dbus_bus_get
|
||||
//dbus_connection_close(self->con);
|
||||
dbus_connection_unref(self->con);
|
||||
|
||||
@@ -3,10 +3,37 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
static uint64_t clock_gettime_microseconds(clockid_t clock_id) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
clock_gettime(clock_id, &ts);
|
||||
return (uint64_t)ts.tv_sec * 1000000ULL + (uint64_t)ts.tv_nsec / 1000ULL;
|
||||
}
|
||||
|
||||
static void gsr_write_first_frame_timestamp_file(const char *filepath) {
|
||||
const uint64_t evdev_compatible_ts = clock_gettime_microseconds(CLOCK_MONOTONIC);
|
||||
const uint64_t unix_time_microsec = clock_gettime_microseconds(CLOCK_REALTIME);
|
||||
|
||||
FILE *file = fopen(filepath, "w");
|
||||
if(!file) {
|
||||
fprintf(stderr, "gsr warning: failed to open timestamp file '%s': %s\n", filepath, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
fputs("monotonic_microsec\trealtime_microsec\n", file);
|
||||
fprintf(file, "%" PRIu64 "\t%" PRIu64 "\n", evdev_compatible_ts, unix_time_microsec);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
bool gsr_encoder_init(gsr_encoder *self, gsr_replay_storage replay_storage, size_t replay_buffer_num_packets, double replay_buffer_time, const char *replay_directory) {
|
||||
memset(self, 0, sizeof(*self));
|
||||
self->num_recording_destinations = 0;
|
||||
@@ -39,6 +66,16 @@ bool gsr_encoder_init(gsr_encoder *self, gsr_replay_storage replay_storage, size
|
||||
}
|
||||
|
||||
void gsr_encoder_deinit(gsr_encoder *self) {
|
||||
if(self->file_write_mutex_created)
|
||||
pthread_mutex_lock(&self->file_write_mutex);
|
||||
for(size_t i = 0; i < self->num_recording_destinations; ++i) {
|
||||
free(self->recording_destinations[i].first_frame_ts_filepath);
|
||||
self->recording_destinations[i].first_frame_ts_filepath = NULL;
|
||||
self->recording_destinations[i].first_frame_ts_written = false;
|
||||
}
|
||||
if(self->file_write_mutex_created)
|
||||
pthread_mutex_unlock(&self->file_write_mutex);
|
||||
|
||||
if(self->replay_buffer) {
|
||||
pthread_mutex_lock(&self->replay_mutex);
|
||||
gsr_replay_buffer_destroy(self->replay_buffer);
|
||||
@@ -94,6 +131,11 @@ void gsr_encoder_receive_packets(gsr_encoder *self, AVCodecContext *codec_contex
|
||||
else if(!recording_destination->has_received_keyframe)
|
||||
continue;
|
||||
|
||||
if(recording_destination->first_frame_ts_filepath && !recording_destination->first_frame_ts_written) {
|
||||
gsr_write_first_frame_timestamp_file(recording_destination->first_frame_ts_filepath);
|
||||
recording_destination->first_frame_ts_written = true;
|
||||
}
|
||||
|
||||
av_packet->pts = pts - recording_destination->start_pts;
|
||||
av_packet->dts = pts - recording_destination->start_pts;
|
||||
|
||||
@@ -148,6 +190,8 @@ size_t gsr_encoder_add_recording_destination(gsr_encoder *self, AVCodecContext *
|
||||
recording_destination->stream = stream;
|
||||
recording_destination->start_pts = start_pts;
|
||||
recording_destination->has_received_keyframe = false;
|
||||
recording_destination->first_frame_ts_filepath = NULL;
|
||||
recording_destination->first_frame_ts_written = false;
|
||||
|
||||
++self->recording_destination_id_counter;
|
||||
++self->num_recording_destinations;
|
||||
@@ -161,6 +205,9 @@ bool gsr_encoder_remove_recording_destination(gsr_encoder *self, size_t id) {
|
||||
pthread_mutex_lock(&self->file_write_mutex);
|
||||
for(size_t i = 0; i < self->num_recording_destinations; ++i) {
|
||||
if(self->recording_destinations[i].id == id) {
|
||||
free(self->recording_destinations[i].first_frame_ts_filepath);
|
||||
self->recording_destinations[i].first_frame_ts_filepath = NULL;
|
||||
self->recording_destinations[i].first_frame_ts_written = false;
|
||||
self->recording_destinations[i] = self->recording_destinations[self->num_recording_destinations - 1];
|
||||
--self->num_recording_destinations;
|
||||
found = true;
|
||||
@@ -170,3 +217,26 @@ bool gsr_encoder_remove_recording_destination(gsr_encoder *self, size_t id) {
|
||||
pthread_mutex_unlock(&self->file_write_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool gsr_encoder_set_recording_destination_first_frame_ts_filepath(gsr_encoder *self, size_t id, const char *filepath) {
|
||||
if(!filepath)
|
||||
return false;
|
||||
|
||||
bool found = false;
|
||||
pthread_mutex_lock(&self->file_write_mutex);
|
||||
for(size_t i = 0; i < self->num_recording_destinations; ++i) {
|
||||
if(self->recording_destinations[i].id == id) {
|
||||
char *filepath_copy = strdup(filepath);
|
||||
if(!filepath_copy)
|
||||
break;
|
||||
|
||||
free(self->recording_destinations[i].first_frame_ts_filepath);
|
||||
self->recording_destinations[i].first_frame_ts_filepath = filepath_copy;
|
||||
self->recording_destinations[i].first_frame_ts_written = false;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&self->file_write_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
32
src/main.cpp
32
src/main.cpp
@@ -2269,6 +2269,7 @@ static std::string region_get_data(gsr_egl *egl, vec2i *region_size, vec2i *regi
|
||||
} else {
|
||||
region_position->x -= monitor_pos.x;
|
||||
region_position->y -= monitor_pos.y;
|
||||
// Match drm plane coordinate space (1x scaling) to wayland coordinate space (which may have scaling set by user)
|
||||
region_position->x *= monitor_scale_inverted;
|
||||
region_position->y *= monitor_scale_inverted;
|
||||
|
||||
@@ -2799,15 +2800,6 @@ static bool string_to_bool(const char *str, size_t len, bool *value) {
|
||||
}
|
||||
}
|
||||
|
||||
static int clamp_scalar(int value) {
|
||||
if(value < -100)
|
||||
return -100;
|
||||
else if(value > 100)
|
||||
return 100;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
static void parse_capture_source_options(const std::string &capture_source_str, CaptureSource &capture_source) {
|
||||
bool is_first_column = true;
|
||||
|
||||
@@ -2829,9 +2821,6 @@ static void parse_capture_source_options(const std::string &capture_source_str,
|
||||
fprintf(stderr, "gsr error: invalid capture target value for option x: \"%.*s\", expected a number\n", (int)size, sub);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if(capture_source.pos.x_type == VVEC2I_TYPE_SCALAR)
|
||||
capture_source.pos.x = clamp_scalar(capture_source.pos.x);
|
||||
} else if(string_starts_with(sub, size, "y=")) {
|
||||
capture_source.pos.y_type = sub[size - 1] == '%' ? VVEC2I_TYPE_SCALAR : VVEC2I_TYPE_PIXELS;
|
||||
sub += 2;
|
||||
@@ -2841,8 +2830,6 @@ static void parse_capture_source_options(const std::string &capture_source_str,
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if(capture_source.pos.y_type == VVEC2I_TYPE_SCALAR)
|
||||
capture_source.pos.y = clamp_scalar(capture_source.pos.y);
|
||||
} else if(string_starts_with(sub, size, "width=")) {
|
||||
capture_source.size.x_type = sub[size - 1] == '%' ? VVEC2I_TYPE_SCALAR : VVEC2I_TYPE_PIXELS;
|
||||
sub += 6;
|
||||
@@ -2851,9 +2838,6 @@ static void parse_capture_source_options(const std::string &capture_source_str,
|
||||
fprintf(stderr, "gsr error: invalid capture target value for option width: \"%.*s\", expected a number\n", (int)size, sub);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if(capture_source.size.x_type == VVEC2I_TYPE_SCALAR)
|
||||
capture_source.size.x = clamp_scalar(capture_source.size.x);
|
||||
} else if(string_starts_with(sub, size, "height=")) {
|
||||
capture_source.size.y_type = sub[size - 1] == '%' ? VVEC2I_TYPE_SCALAR : VVEC2I_TYPE_PIXELS;
|
||||
sub += 7;
|
||||
@@ -2862,9 +2846,6 @@ static void parse_capture_source_options(const std::string &capture_source_str,
|
||||
fprintf(stderr, "gsr error: invalid capture target value for option height: \"%.*s\", expected a number\n", (int)size, sub);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if(capture_source.size.y_type == VVEC2I_TYPE_SCALAR)
|
||||
capture_source.size.y = clamp_scalar(capture_source.size.y);
|
||||
} else if(string_starts_with(sub, size, "halign=")) {
|
||||
sub += 7;
|
||||
size -= 7;
|
||||
@@ -4007,7 +3988,11 @@ int main(int argc, char **argv) {
|
||||
|
||||
if(video_stream) {
|
||||
avcodec_parameters_from_context(video_stream->codecpar, video_codec_context);
|
||||
gsr_encoder_add_recording_destination(&encoder, video_codec_context, av_format_context, video_stream, 0);
|
||||
const size_t video_destination_id = gsr_encoder_add_recording_destination(&encoder, video_codec_context, av_format_context, video_stream, 0);
|
||||
if(arg_parser.write_first_frame_ts && video_destination_id != (size_t)-1) {
|
||||
std::string ts_filepath = std::string(arg_parser.filename) + ".ts";
|
||||
gsr_encoder_set_recording_destination_first_frame_ts_filepath(&encoder, video_destination_id, ts_filepath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int audio_max_frame_size = 1024;
|
||||
@@ -4546,6 +4531,11 @@ int main(int argc, char **argv) {
|
||||
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(arg_parser.write_first_frame_ts && video_recording_destination_id != (size_t)-1) {
|
||||
std::string ts_filepath = replay_recording_filepath + ".ts";
|
||||
gsr_encoder_set_recording_destination_first_frame_ts_filepath(&encoder, video_recording_destination_id, ts_filepath.c_str());
|
||||
}
|
||||
|
||||
if(video_recording_destination_id != (size_t)-1)
|
||||
replay_recording_items.push_back(video_recording_destination_id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user