Skip to content

Commit 76c3463

Browse files
fix(linux/wlgrab): add frame_timestamp using wayland's ready timestamp (#4787)
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
1 parent e776b65 commit 76c3463

3 files changed

Lines changed: 65 additions & 49 deletions

File tree

src/platform/linux/wayland.cpp

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,17 @@ namespace wl {
5454
}
5555

5656
if (!display_name) {
57-
BOOST_LOG(error) << "Environment variable WAYLAND_DISPLAY has not been defined"sv;
57+
BOOST_LOG(error) << "[wayland] Environment variable WAYLAND_DISPLAY has not been defined"sv;
5858
return -1;
5959
}
6060

6161
display_internal.reset(wl_display_connect(display_name));
6262
if (!display_internal) {
63-
BOOST_LOG(error) << "Couldn't connect to Wayland display: "sv << display_name;
63+
BOOST_LOG(error) << "[wayland] Couldn't connect to Wayland display: "sv << display_name;
6464
return -1;
6565
}
6666

67-
BOOST_LOG(info) << "Found display ["sv << display_name << ']';
67+
BOOST_LOG(info) << "[wayland] Found display ["sv << display_name << ']';
6868

6969
return 0;
7070
}
@@ -127,26 +127,26 @@ namespace wl {
127127
inline void monitor_t::xdg_name(zxdg_output_v1 *, const char *name) {
128128
this->name = name;
129129

130-
BOOST_LOG(info) << "Name: "sv << this->name;
130+
BOOST_LOG(info) << "[wayland] Name: "sv << this->name;
131131
}
132132

133133
void monitor_t::xdg_description(zxdg_output_v1 *, const char *description) {
134134
this->description = description;
135135

136-
BOOST_LOG(info) << "Found monitor: "sv << this->description;
136+
BOOST_LOG(info) << "[wayland] Found monitor: "sv << this->description;
137137
}
138138

139139
void monitor_t::xdg_position(zxdg_output_v1 *, std::int32_t x, std::int32_t y) {
140140
viewport.offset_x = x;
141141
viewport.offset_y = y;
142142

143-
BOOST_LOG(info) << "Offset: "sv << x << 'x' << y;
143+
BOOST_LOG(info) << "[wayland] Offset: "sv << x << 'x' << y;
144144
}
145145

146146
void monitor_t::xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height) {
147147
viewport.logical_width = width;
148148
viewport.logical_height = height;
149-
BOOST_LOG(info) << "Logical size: "sv << width << 'x' << height;
149+
BOOST_LOG(info) << "[wayland] Logical size: "sv << width << 'x' << height;
150150
}
151151

152152
void monitor_t::wl_mode(
@@ -159,7 +159,7 @@ namespace wl {
159159
viewport.width = width;
160160
viewport.height = height;
161161

162-
BOOST_LOG(info) << "Resolution: "sv << width << 'x' << height;
162+
BOOST_LOG(info) << "[wayland] Resolution: "sv << width << 'x' << height;
163163
}
164164

165165
void monitor_t::listen(zxdg_output_manager_v1 *output_manager) {
@@ -189,35 +189,35 @@ namespace wl {
189189
const char *interface,
190190
std::uint32_t version
191191
) {
192-
BOOST_LOG(debug) << "Available interface: "sv << interface << '(' << id << ") version "sv << version;
192+
BOOST_LOG(debug) << "[wayland] Available interface: "sv << interface << '(' << id << ") version "sv << version;
193193

194194
if (!std::strcmp(interface, wl_output_interface.name)) {
195-
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
195+
BOOST_LOG(info) << "[wayland] Found interface: "sv << interface << '(' << id << ") version "sv << version;
196196
monitors.emplace_back(
197197
std::make_unique<monitor_t>(
198198
(wl_output *) wl_registry_bind(registry, id, &wl_output_interface, 2)
199199
)
200200
);
201201
} else if (!std::strcmp(interface, zxdg_output_manager_v1_interface.name)) {
202-
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
202+
BOOST_LOG(info) << "[wayland] Found interface: "sv << interface << '(' << id << ") version "sv << version;
203203
output_manager = (zxdg_output_manager_v1 *) wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version);
204204

205205
this->interface[XDG_OUTPUT] = true;
206206
} else if (!std::strcmp(interface, zwlr_screencopy_manager_v1_interface.name)) {
207-
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
207+
BOOST_LOG(info) << "[wayland] Found interface: "sv << interface << '(' << id << ") version "sv << version;
208208
screencopy_manager = (zwlr_screencopy_manager_v1 *) wl_registry_bind(registry, id, &zwlr_screencopy_manager_v1_interface, version);
209209

210210
this->interface[WLR_EXPORT_DMABUF] = true;
211211
} else if (!std::strcmp(interface, zwp_linux_dmabuf_v1_interface.name)) {
212-
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
212+
BOOST_LOG(info) << "[wayland] Found interface: "sv << interface << '(' << id << ") version "sv << version;
213213
dmabuf_interface = (zwp_linux_dmabuf_v1 *) wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, version);
214214

215215
this->interface[LINUX_DMABUF] = true;
216216
}
217217
}
218218

219219
void interface_t::del_interface(wl_registry *registry, uint32_t id) {
220-
BOOST_LOG(info) << "Delete: "sv << id;
220+
BOOST_LOG(info) << "[wayland] Delete: "sv << id;
221221
}
222222

223223
// Initialize GBM
@@ -230,7 +230,7 @@ namespace wl {
230230
drmDevice *devices[16];
231231
int n = drmGetDevices2(0, devices, 16);
232232
if (n <= 0) {
233-
BOOST_LOG(error) << "No DRM devices found"sv;
233+
BOOST_LOG(error) << "[wayland] No DRM devices found"sv;
234234
return false;
235235
}
236236

@@ -246,14 +246,14 @@ namespace wl {
246246
drmFreeDevices(devices, n);
247247

248248
if (drm_fd < 0) {
249-
BOOST_LOG(error) << "Failed to open DRM render node"sv;
249+
BOOST_LOG(error) << "[wayland] Failed to open DRM render node"sv;
250250
return false;
251251
}
252252

253253
gbm_device = gbm_create_device(drm_fd);
254254
if (!gbm_device) {
255255
close(drm_fd);
256-
BOOST_LOG(error) << "Failed to create GBM device"sv;
256+
BOOST_LOG(error) << "[wayland] Failed to create GBM device"sv;
257257
return false;
258258
}
259259

@@ -343,8 +343,6 @@ namespace wl {
343343
shm_info.width = width;
344344
shm_info.height = height;
345345
shm_info.stride = stride;
346-
347-
BOOST_LOG(debug) << "Screencopy supports SHM format: "sv << format;
348346
}
349347

350348
// DMA-BUF format callback
@@ -358,14 +356,12 @@ namespace wl {
358356
dmabuf_info.format = format;
359357
dmabuf_info.width = width;
360358
dmabuf_info.height = height;
361-
362-
BOOST_LOG(debug) << "Screencopy supports DMA-BUF format: "sv << format;
363359
}
364360

365361
// Flags callback
366362
void dmabuf_t::flags(zwlr_screencopy_frame_v1 *frame, std::uint32_t flags) {
367363
y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
368-
BOOST_LOG(debug) << "Frame flags: "sv << flags << (y_invert ? " (y_invert)" : "");
364+
BOOST_LOG(verbose) << "Frame flags: "sv << flags << (y_invert ? " (y_invert)" : "");
369365
}
370366

371367
// DMA-BUF creation helper
@@ -433,11 +429,11 @@ namespace wl {
433429
create_and_copy_dmabuf(frame);
434430
} else if (shm_info.supported) {
435431
// SHM fallback would go here
436-
BOOST_LOG(warning) << "SHM capture not implemented"sv;
432+
BOOST_LOG(warning) << "[wayland] SHM capture not implemented"sv;
437433
zwlr_screencopy_frame_v1_destroy(frame);
438434
status = REINIT;
439435
} else {
440-
BOOST_LOG(error) << "No supported buffer types"sv;
436+
BOOST_LOG(error) << "[wayland] No supported buffer types"sv;
441437
zwlr_screencopy_frame_v1_destroy(frame);
442438
status = REINIT;
443439
}
@@ -468,7 +464,7 @@ namespace wl {
468464
auto frame = static_cast<zwlr_screencopy_frame_v1 *>(data);
469465
auto self = static_cast<dmabuf_t *>(zwlr_screencopy_frame_v1_get_user_data(frame));
470466

471-
BOOST_LOG(error) << "Failed to create buffer from params"sv;
467+
BOOST_LOG(error) << "[wayland] Failed to create buffer from params"sv;
472468
self->cleanup_gbm();
473469

474470
zwp_linux_buffer_params_v1_destroy(params);
@@ -483,12 +479,16 @@ namespace wl {
483479
std::uint32_t tv_sec_lo,
484480
std::uint32_t tv_nsec
485481
) {
486-
BOOST_LOG(debug) << "Frame ready"sv;
487-
488482
// Frame is ready for use, GBM buffer now contains screen content
489483
current_frame->destroy();
490484
current_frame = get_next_frame();
491485

486+
std::uint64_t sec = (std::uint64_t(tv_sec_hi) << 32) | tv_sec_lo;
487+
auto ready_ts = std::chrono::seconds(sec) + std::chrono::nanoseconds(tv_nsec);
488+
current_frame->frame_timestamp = std::chrono::steady_clock::time_point {
489+
std::chrono::duration_cast<std::chrono::steady_clock::duration>(ready_ts)
490+
};
491+
492492
// Keep the GBM buffer alive but destroy the Wayland objects
493493
if (current_wl_buffer) {
494494
wl_buffer_destroy(current_wl_buffer);
@@ -503,7 +503,7 @@ namespace wl {
503503

504504
// Failed callback
505505
void dmabuf_t::failed(zwlr_screencopy_frame_v1 *frame) {
506-
BOOST_LOG(error) << "Frame capture failed"sv;
506+
BOOST_LOG(error) << "[wayland] Frame capture failed"sv;
507507

508508
// Clean up resources
509509
cleanup_gbm();
@@ -514,6 +514,7 @@ namespace wl {
514514
status = REINIT;
515515
}
516516

517+
// Only called if using zwlr_screencopy_frame_v1_copy_with_damage()
517518
void dmabuf_t::damage(
518519
zwlr_screencopy_frame_v1 *frame,
519520
std::uint32_t x,
@@ -550,7 +551,7 @@ namespace wl {
550551
display.roundtrip();
551552

552553
if (!interface[interface_t::XDG_OUTPUT]) {
553-
BOOST_LOG(error) << "Missing Wayland wire XDG_OUTPUT"sv;
554+
BOOST_LOG(error) << "[wayland] Missing Wayland wire XDG_OUTPUT"sv;
554555
return {};
555556
}
556557

src/platform/linux/wayland.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace wl {
3131
void destroy();
3232

3333
egl::surface_descriptor_t sd;
34+
std::optional<std::chrono::steady_clock::time_point> frame_timestamp;
3435
};
3536

3637
class dmabuf_t {

src/platform/linux/wlgrab.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,18 @@ namespace wl {
2929
class wlr_t: public platf::display_t {
3030
public:
3131
int init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) {
32-
delay = std::chrono::nanoseconds {1s} / config.framerate;
32+
// calculate frame interval we should capture at
33+
if (config.framerateX100 > 0) {
34+
AVRational fps_strict = ::video::framerateX100_to_rational(config.framerateX100);
35+
delay = std::chrono::nanoseconds(
36+
(static_cast<int64_t>(fps_strict.den) * 1'000'000'000LL) / fps_strict.num
37+
);
38+
BOOST_LOG(info) << "[wlgrab] Requested frame rate [" << fps_strict.num << "/" << fps_strict.den << ", approx. " << av_q2d(fps_strict) << " fps]";
39+
} else {
40+
delay = std::chrono::nanoseconds {1s} / config.framerate;
41+
BOOST_LOG(info) << "[wlgrab] Requested frame rate [" << config.framerate << "fps]";
42+
}
43+
3344
mem_type = hwdevice_type;
3445

3546
if (display.init()) {
@@ -41,12 +52,12 @@ namespace wl {
4152
display.roundtrip();
4253

4354
if (!interface[wl::interface_t::XDG_OUTPUT]) {
44-
BOOST_LOG(error) << "Missing Wayland wire for xdg_output"sv;
55+
BOOST_LOG(error) << "[wlgrab] Missing Wayland wire for xdg_output"sv;
4556
return -1;
4657
}
4758

4859
if (!interface[wl::interface_t::WLR_EXPORT_DMABUF]) {
49-
BOOST_LOG(error) << "Missing Wayland wire for wlr-export-dmabuf"sv;
60+
BOOST_LOG(error) << "[wlgrab] Missing Wayland wire for wlr-export-dmabuf"sv;
5061
return -1;
5162
}
5263

@@ -88,12 +99,12 @@ namespace wl {
8899
this->env_logical_width = desktop_logical_width;
89100
this->env_logical_height = desktop_logical_height;
90101

91-
BOOST_LOG(info) << "Selected monitor ["sv << monitor->description << "] for streaming"sv;
92-
BOOST_LOG(debug) << "Offset: "sv << offset_x << 'x' << offset_y;
93-
BOOST_LOG(debug) << "Resolution: "sv << width << 'x' << height;
94-
BOOST_LOG(debug) << "Logical Resolution: "sv << logical_width << 'x' << logical_height;
95-
BOOST_LOG(debug) << "Desktop Resolution: "sv << env_width << 'x' << env_height;
96-
BOOST_LOG(debug) << "Logical Desktop Resolution: "sv << env_logical_width << 'x' << env_logical_height;
102+
BOOST_LOG(info) << "[wlgrab] Selected monitor ["sv << monitor->description << "] for streaming"sv;
103+
BOOST_LOG(debug) << "[wlgrab] Offset: "sv << offset_x << 'x' << offset_y;
104+
BOOST_LOG(debug) << "[wlgrab] Resolution: "sv << width << 'x' << height;
105+
BOOST_LOG(debug) << "[wlgrab] Logical Resolution: "sv << logical_width << 'x' << logical_height;
106+
BOOST_LOG(debug) << "[wlgrab] Desktop Resolution: "sv << env_width << 'x' << env_height;
107+
BOOST_LOG(debug) << "[wlgrab] Logical Desktop Resolution: "sv << env_logical_width << 'x' << env_logical_height;
97108

98109
return 0;
99110
}
@@ -177,7 +188,7 @@ namespace wl {
177188
}
178189
break;
179190
default:
180-
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
191+
BOOST_LOG(error) << "[wlgrab] Unrecognized capture status ["sv << std::to_underlying(status) << ']';
181192
return status;
182193
}
183194
}
@@ -210,11 +221,13 @@ namespace wl {
210221
int w;
211222
gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
212223
gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
213-
BOOST_LOG(debug) << "width and height: w "sv << w << " h "sv << h;
224+
BOOST_LOG(debug) << "[wlgrab] width and height: w "sv << w << " h "sv << h;
214225

215226
gl::ctx.GetTextureSubImage((*rgb_opt)->tex[0], 0, 0, 0, 0, width, height, 1, GL_BGRA, GL_UNSIGNED_BYTE, img_out->height * img_out->row_pitch, img_out->data);
216227
gl::ctx.BindTexture(GL_TEXTURE_2D, 0);
217228

229+
img_out->frame_timestamp = current_frame->frame_timestamp;
230+
218231
return platf::capture_e::ok;
219232
}
220233

@@ -308,7 +321,7 @@ namespace wl {
308321
}
309322
break;
310323
default:
311-
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
324+
BOOST_LOG(error) << "[wlgrab] Unrecognized capture status ["sv << std::to_underlying(status) << ']';
312325
return status;
313326
}
314327
}
@@ -334,6 +347,7 @@ namespace wl {
334347
img->sequence = sequence;
335348

336349
img->sd = current_frame->sd;
350+
img->frame_timestamp = current_frame->frame_timestamp;
337351

338352
// Prevent dmabuf from closing the file descriptors.
339353
std::fill_n(current_frame->sd.fds, 4, -1);
@@ -385,7 +399,7 @@ namespace wl {
385399
namespace platf {
386400
std::shared_ptr<display_t> wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) {
387401
if (hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
388-
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
402+
BOOST_LOG(error) << "[wlgrab] Could not initialize display with the given hw device type."sv;
389403
return nullptr;
390404
}
391405

@@ -420,12 +434,12 @@ namespace platf {
420434
display.roundtrip();
421435

422436
if (!interface[wl::interface_t::XDG_OUTPUT]) {
423-
BOOST_LOG(warning) << "Missing Wayland wire for xdg_output"sv;
437+
BOOST_LOG(warning) << "[wlgrab] Missing Wayland wire for xdg_output"sv;
424438
return {};
425439
}
426440

427441
if (!interface[wl::interface_t::WLR_EXPORT_DMABUF]) {
428-
BOOST_LOG(warning) << "Missing Wayland wire for wlr-export-dmabuf"sv;
442+
BOOST_LOG(warning) << "[wlgrab] Missing Wayland wire for wlr-export-dmabuf"sv;
429443
return {};
430444
}
431445

@@ -438,20 +452,20 @@ namespace platf {
438452

439453
display.roundtrip();
440454

441-
BOOST_LOG(info) << "-------- Start of Wayland monitor list --------"sv;
455+
BOOST_LOG(info) << "[wlgrab] -------- Start of Wayland monitor list --------"sv;
442456

443457
for (int x = 0; x < interface.monitors.size(); ++x) {
444458
auto monitor = interface.monitors[x].get();
445459

446-
wl::env_width = std::max(wl::env_width, (int) (monitor->viewport.offset_x + monitor->viewport.width));
447-
wl::env_height = std::max(wl::env_height, (int) (monitor->viewport.offset_y + monitor->viewport.height));
460+
wl::env_width = std::max(wl::env_width, monitor->viewport.offset_x + monitor->viewport.width);
461+
wl::env_height = std::max(wl::env_height, monitor->viewport.offset_y + monitor->viewport.height);
448462

449-
BOOST_LOG(info) << "Monitor " << x << " is "sv << monitor->name << ": "sv << monitor->description;
463+
BOOST_LOG(info) << "[wlgrab] Monitor " << x << " is "sv << monitor->name << ": "sv << monitor->description;
450464

451465
display_names.emplace_back(std::to_string(x));
452466
}
453467

454-
BOOST_LOG(info) << "--------- End of Wayland monitor list ---------"sv;
468+
BOOST_LOG(info) << "[wlgrab] --------- End of Wayland monitor list ---------"sv;
455469

456470
return display_names;
457471
}

0 commit comments

Comments
 (0)