-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Control how many frames are captured per second
The goal is to control the rate of capture while in screencast, as it can represent a performance issue and can cause input lag and the feeling of having a laggy mouse. This commit addresses the issue reported in #66. The code measures the time elapsed to make a single screen capture, and calculates how much to wait for the next capture to achieve the targeted frame rate. To delay the capturing of the next frame, the code introduces timers into the event loop based on the event loop in https://github.com/emersion/mako Added a command-line argument and an entry in the config file as well for the max FPS. The default value is 0, meaning no rate control. Added code to measure the average FPS every 5 seconds and print it with DEBUG level.
- Loading branch information
1 parent
323d89e
commit c131ce5
Showing
15 changed files
with
317 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
image: freebsd/latest | ||
packages: | ||
- basu | ||
- libepoll-shim | ||
- meson | ||
- pipewire | ||
- pkgconf | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
[screencast] | ||
output= | ||
output_name= | ||
max_fps=30 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
|
||
struct config_screencast { | ||
char *output_name; | ||
double max_fps; | ||
}; | ||
|
||
struct xdpw_config { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#ifndef FPS_LIMIT_H | ||
#define FPS_LIMIT_H | ||
|
||
#include <stdint.h> | ||
#include <time.h> | ||
|
||
struct fps_limit_state { | ||
struct timespec frame_last_time; | ||
|
||
struct timespec fps_last_time; | ||
uint64_t fps_frame_count; | ||
}; | ||
|
||
void fps_limit_measure_start(struct fps_limit_state *state, double max_fps); | ||
|
||
uint64_t fps_limit_measure_end(struct fps_limit_state *state, double max_fps); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#ifndef TIMESPEC_UTIL_H | ||
#define TIMESPEC_UTIL_H | ||
|
||
#include <time.h> | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
#define TIMESPEC_NSEC_PER_SEC 1000000000L | ||
|
||
void timespec_add(struct timespec *t, int64_t delta_ns); | ||
|
||
bool timespec_less(struct timespec *t1, struct timespec *t2); | ||
|
||
bool timespec_is_zero(struct timespec *t); | ||
|
||
int64_t timespec_diff_ns(struct timespec *t1, struct timespec *t2); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#include <poll.h> | ||
#include <wayland-util.h> | ||
#include <sys/timerfd.h> | ||
|
||
#include "xdpw.h" | ||
#include "logger.h" | ||
#include "timespec_util.h" | ||
|
||
static void update_timer(struct xdpw_state *state) { | ||
int timer_fd = state->timer_poll_fd; | ||
if (timer_fd < 0) { | ||
return; | ||
} | ||
|
||
bool updated = false; | ||
struct xdpw_timer *timer; | ||
wl_list_for_each(timer, &state->timers, link) { | ||
if (state->next_timer == NULL || | ||
timespec_less(&timer->at, &state->next_timer->at)) { | ||
state->next_timer = timer; | ||
updated = true; | ||
} | ||
} | ||
|
||
if (updated) { | ||
struct itimerspec delay = { .it_value = state->next_timer->at }; | ||
errno = 0; | ||
int ret = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &delay, NULL); | ||
if (ret < 0) { | ||
fprintf(stderr, "failed to timerfd_settime(): %s\n", | ||
strerror(errno)); | ||
} | ||
} | ||
} | ||
|
||
struct xdpw_timer *xdpw_add_timer(struct xdpw_state *state, | ||
uint64_t delay_ns, xdpw_event_loop_timer_func_t func, void *data) { | ||
struct xdpw_timer *timer = calloc(1, sizeof(struct xdpw_timer)); | ||
if (timer == NULL) { | ||
logprint(ERROR, "Timer allocation failed"); | ||
return NULL; | ||
} | ||
timer->state = state; | ||
timer->func = func; | ||
timer->user_data = data; | ||
wl_list_insert(&state->timers, &timer->link); | ||
|
||
clock_gettime(CLOCK_MONOTONIC, &timer->at); | ||
timespec_add(&timer->at, delay_ns); | ||
|
||
update_timer(state); | ||
return timer; | ||
} | ||
|
||
void xdpw_destroy_timer(struct xdpw_timer *timer) { | ||
if (timer == NULL) { | ||
return; | ||
} | ||
struct xdpw_state *state = timer->state; | ||
|
||
if (state->next_timer == timer) { | ||
state->next_timer = NULL; | ||
} | ||
|
||
wl_list_remove(&timer->link); | ||
free(timer); | ||
|
||
update_timer(state); | ||
} |
Oops, something went wrong.