mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-22 22:35:59 +01:00
screencast: introduce xdpw_frame_state and xdpw_wlr_stream_finish
The enum xdpw_frame_state is used to track the state of the xdpw_frame through the screencopy callbacks. xdpw_wlr_stream_finish is used as the new endpoint of the screencopy callbacks. Here we clean up the screencopy_frame, enqueue the pipewire buffer and restart the screencopy loop if needed.
This commit is contained in:
parent
b986020050
commit
66db43ea0e
4 changed files with 63 additions and 26 deletions
|
@ -29,6 +29,13 @@ enum xdpw_chooser_types {
|
||||||
XDPW_CHOOSER_DMENU,
|
XDPW_CHOOSER_DMENU,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum xdpw_frame_state {
|
||||||
|
XDPW_FRAME_STATE_NONE,
|
||||||
|
XDPW_FRAME_STATE_RENEG,
|
||||||
|
XDPW_FRAME_STATE_FAILED,
|
||||||
|
XDPW_FRAME_STATE_SUCCESS,
|
||||||
|
};
|
||||||
|
|
||||||
struct xdpw_output_chooser {
|
struct xdpw_output_chooser {
|
||||||
enum xdpw_chooser_types type;
|
enum xdpw_chooser_types type;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
@ -89,6 +96,7 @@ struct xdpw_screencast_instance {
|
||||||
struct xdpw_screencast_context *ctx;
|
struct xdpw_screencast_context *ctx;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
struct xdpw_frame current_frame;
|
struct xdpw_frame current_frame;
|
||||||
|
enum xdpw_frame_state frame_state;
|
||||||
|
|
||||||
// pipewire
|
// pipewire
|
||||||
struct pw_stream *stream;
|
struct pw_stream *stream;
|
||||||
|
@ -108,7 +116,6 @@ struct xdpw_screencast_instance {
|
||||||
bool with_cursor;
|
bool with_cursor;
|
||||||
int err;
|
int err;
|
||||||
bool quit;
|
bool quit;
|
||||||
bool copied;
|
|
||||||
|
|
||||||
// fps limit
|
// fps limit
|
||||||
struct fps_limit_state fps_limit;
|
struct fps_limit_state fps_limit;
|
||||||
|
|
|
@ -24,7 +24,8 @@ struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context *ctx
|
||||||
struct wl_output *out, uint32_t id);
|
struct wl_output *out, uint32_t id);
|
||||||
struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct xdpw_screencast_context *ctx);
|
struct xdpw_wlr_output *xdpw_wlr_output_chooser(struct xdpw_screencast_context *ctx);
|
||||||
|
|
||||||
void xdpw_wlr_frame_free(struct xdpw_screencast_instance *cast);
|
void xdpw_wlr_frame_finish(struct xdpw_screencast_instance *cast);
|
||||||
|
void xdpw_wlr_frame_start(struct xdpw_screencast_instance *cast);
|
||||||
void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast);
|
void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -57,7 +57,7 @@ static void pwr_handle_stream_state_changed(void *data,
|
||||||
case PW_STREAM_STATE_STREAMING:
|
case PW_STREAM_STATE_STREAMING:
|
||||||
cast->pwr_stream_state = true;
|
cast->pwr_stream_state = true;
|
||||||
if (!cast->wlr_frame) {
|
if (!cast->wlr_frame) {
|
||||||
xdpw_wlr_register_cb(cast);
|
xdpw_wlr_frame_start(cast);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -20,10 +20,29 @@
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "fps_limit.h"
|
#include "fps_limit.h"
|
||||||
|
|
||||||
void xdpw_wlr_frame_free(struct xdpw_screencast_instance *cast) {
|
void wlr_frame_free(struct xdpw_screencast_instance *cast) {
|
||||||
zwlr_screencopy_frame_v1_destroy(cast->wlr_frame);
|
zwlr_screencopy_frame_v1_destroy(cast->wlr_frame);
|
||||||
cast->wlr_frame = NULL;
|
cast->wlr_frame = NULL;
|
||||||
logprint(TRACE, "wlroots: frame destroyed");
|
logprint(TRACE, "wlroots: frame destroyed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void xdpw_wlr_frame_finish(struct xdpw_screencast_instance *cast) {
|
||||||
|
logprint(TRACE, "wlroots: finish screencopy");
|
||||||
|
|
||||||
|
wlr_frame_free(cast);
|
||||||
|
|
||||||
|
if (!cast->pwr_stream_state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have a buffer
|
||||||
|
if (cast->current_frame.current_pw_buffer) {
|
||||||
|
xdpw_pwr_enqueue_buffer(cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cast->frame_state == XDPW_FRAME_STATE_RENEG) {
|
||||||
|
pwr_update_stream_param(cast);
|
||||||
|
}
|
||||||
|
|
||||||
if (cast->quit || cast->err) {
|
if (cast->quit || cast->err) {
|
||||||
// TODO: revisit the exit condition (remove quit?)
|
// TODO: revisit the exit condition (remove quit?)
|
||||||
|
@ -34,19 +53,33 @@ void xdpw_wlr_frame_free(struct xdpw_screencast_instance *cast) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cast->pwr_stream_state) {
|
if (cast->pwr_stream_state) {
|
||||||
if (cast->copied) {
|
if (cast->frame_state == XDPW_FRAME_STATE_SUCCESS) {
|
||||||
uint64_t delay_ns = fps_limit_measure_end(&cast->fps_limit, cast->framerate);
|
uint64_t delay_ns = fps_limit_measure_end(&cast->fps_limit, cast->framerate);
|
||||||
cast->copied = false;
|
|
||||||
if (delay_ns > 0) {
|
if (delay_ns > 0) {
|
||||||
xdpw_add_timer(cast->ctx->state, delay_ns,
|
xdpw_add_timer(cast->ctx->state, delay_ns,
|
||||||
(xdpw_event_loop_timer_func_t) xdpw_wlr_register_cb, cast);
|
(xdpw_event_loop_timer_func_t) xdpw_wlr_frame_start, cast);
|
||||||
} else {
|
} else {
|
||||||
xdpw_wlr_register_cb(cast);
|
xdpw_wlr_frame_start(cast);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
xdpw_wlr_frame_start(cast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void xdpw_wlr_frame_start(struct xdpw_screencast_instance *cast) {
|
||||||
|
logprint(TRACE, "wlroots: start screencopy");
|
||||||
|
if (cast->pwr_stream_state) {
|
||||||
|
xdpw_pwr_dequeue_buffer(cast);
|
||||||
|
|
||||||
|
if (!cast->current_frame.current_pw_buffer) {
|
||||||
|
logprint(WARN, "wlroots: failed to dequeue buffer");
|
||||||
|
// TODO: wait for next frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cast->frame_state = XDPW_FRAME_STATE_NONE;
|
||||||
xdpw_wlr_register_cb(cast);
|
xdpw_wlr_register_cb(cast);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_buffer_done(void *data,
|
static void wlr_frame_buffer_done(void *data,
|
||||||
|
@ -81,13 +114,14 @@ static void wlr_frame_buffer_done(void *data,
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
|
|
||||||
logprint(TRACE, "wlroots: buffer_done event handler");
|
logprint(TRACE, "wlroots: buffer_done event handler");
|
||||||
if (cast->pwr_stream_state) {
|
if (!cast->pwr_stream_state) {
|
||||||
xdpw_pwr_dequeue_buffer(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cast->current_frame.current_pw_buffer) {
|
if (!cast->current_frame.current_pw_buffer) {
|
||||||
logprint(WARN, "wlroots: failed to dequeue buffer");
|
logprint(WARN, "wlroots: no current buffer");
|
||||||
xdpw_wlr_frame_free(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,12 +131,8 @@ static void wlr_frame_buffer_done(void *data,
|
||||||
cast->pwr_format.size.width != cast->screencopy_frame.width ||
|
cast->pwr_format.size.width != cast->screencopy_frame.width ||
|
||||||
cast->pwr_format.size.height != cast->screencopy_frame.height) {
|
cast->pwr_format.size.height != cast->screencopy_frame.height) {
|
||||||
logprint(DEBUG, "wlroots: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
logprint(DEBUG, "wlroots: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
||||||
|
cast->frame_state = XDPW_FRAME_STATE_RENEG;
|
||||||
xdpw_pwr_enqueue_buffer(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
if (cast->pwr_stream_state) {
|
|
||||||
pwr_update_stream_param(cast);
|
|
||||||
}
|
|
||||||
xdpw_wlr_frame_free(cast);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +140,8 @@ static void wlr_frame_buffer_done(void *data,
|
||||||
if (cast->current_frame.size != cast->screencopy_frame.size ||
|
if (cast->current_frame.size != cast->screencopy_frame.size ||
|
||||||
cast->current_frame.stride != cast->screencopy_frame.stride) {
|
cast->current_frame.stride != cast->screencopy_frame.stride) {
|
||||||
logprint(DEBUG, "wlroots: pipewire buffer has wrong dimensions");
|
logprint(DEBUG, "wlroots: pipewire buffer has wrong dimensions");
|
||||||
xdpw_pwr_enqueue_buffer(cast);
|
cast->frame_state = XDPW_FRAME_STATE_FAILED;
|
||||||
xdpw_wlr_frame_free(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,11 +184,10 @@ static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
|
|
||||||
cast->current_frame.tv_sec = ((((uint64_t)tv_sec_hi) << 32) | tv_sec_lo);
|
cast->current_frame.tv_sec = ((((uint64_t)tv_sec_hi) << 32) | tv_sec_lo);
|
||||||
cast->current_frame.tv_nsec = tv_nsec;
|
cast->current_frame.tv_nsec = tv_nsec;
|
||||||
cast->copied = true;
|
|
||||||
|
|
||||||
xdpw_pwr_enqueue_buffer(cast);
|
cast->frame_state = XDPW_FRAME_STATE_SUCCESS;
|
||||||
|
|
||||||
xdpw_wlr_frame_free(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_failed(void *data,
|
static void wlr_frame_failed(void *data,
|
||||||
|
@ -168,9 +197,9 @@ static void wlr_frame_failed(void *data,
|
||||||
logprint(TRACE, "wlroots: failed event handler");
|
logprint(TRACE, "wlroots: failed event handler");
|
||||||
cast->err = true;
|
cast->err = true;
|
||||||
|
|
||||||
xdpw_pwr_enqueue_buffer(cast);
|
cast->frame_state = XDPW_FRAME_STATE_FAILED;
|
||||||
|
|
||||||
xdpw_wlr_frame_free(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = {
|
static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = {
|
||||||
|
|
Loading…
Reference in a new issue