1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
// SPDX-License-Identifier: BSD-3-Clause
// xgrab.c - capture the X screen (root window) into an append-only frame file.
// Pure client-side XGetImage on a software X server (Xvfb): no GL, no driver,
// no present-path hooks. Same record format as sdl_cap.c:
// [0] 8B "GZCAPV01" + zero pad to 4096
// [4096..] records: 4B "GZF2" | u32 w | u32 h | u32 stride | u32 bpp |
// u64 ts_ns | u64 seq | stride*h bytes (top-down BGRA)
// Trailing record seq=0xFFFFFFFFFFFFFFFF on clean stop.
// Usage: xgrab <display> <out> <maxframes|0> <pace_us|0>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char **argv)
{
const char *dpy = argc > 1 ? argv[1] : ":1";
const char *out = argc > 2 ? argv[2] : "/dev/shm/gzframes.bin";
long maxf = argc > 3 ? atol(argv[3]) : 0;
long pace = argc > 4 ? atol(argv[4]) : 0;
int r_x = argc > 5 ? atoi(argv[5]) : -1;
int r_y = argc > 6 ? atoi(argv[6]) : 0;
int r_w = argc > 7 ? atoi(argv[7]) : 0;
int r_h = argc > 8 ? atoi(argv[8]) : 0;
Display *d;
Window root;
XWindowAttributes wa;
FILE *f;
char hdr[4096];
uint64_t seq = 0;
d = XOpenDisplay(dpy);
if (!d) {
fprintf(stderr, "xgrab: cannot open display %s\n", dpy);
return 1;
}
root = DefaultRootWindow(d);
if (!XGetWindowAttributes(d, root, &wa)) {
fprintf(stderr, "xgrab: no root attrs\n");
return 1;
}
if (r_x < 0 || r_w <= 0 || r_h <= 0 || r_x + r_w > wa.width ||
r_y + r_h > wa.height) {
r_x = 0; r_y = 0; r_w = wa.width; r_h = wa.height;
}
fprintf(stderr, "xgrab: root %dx%d depth=%d region %d,%d %dx%d\n",
wa.width, wa.height, wa.depth, r_x, r_y, r_w, r_h);
f = fopen(out, "wb");
if (!f) {
perror("xgrab: open out");
return 1;
}
memset(hdr, 0, sizeof(hdr));
memcpy(hdr, "GZCAPV01", 8);
fwrite(hdr, 1, sizeof(hdr), f);
fflush(f);
while (!maxf || (long)seq < maxf) {
XImage *im = XGetImage(d, root, r_x, r_y, r_w, r_h, AllPlanes,
ZPixmap);
struct timespec ts;
uint64_t tns;
uint32_t rh[4];
char m[4] = { 'G', 'Z', 'F', '2' };
int y;
if (!im) {
usleep(10000);
continue;
}
if (im->bits_per_pixel != 32) {
fprintf(stderr, "xgrab: unexpected bpp %d\n",
im->bits_per_pixel);
XDestroyImage(im);
break;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
tns = (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec;
rh[0] = (uint32_t)r_w;
rh[1] = (uint32_t)r_h;
rh[2] = (uint32_t)r_w * 4;
rh[3] = 32;
fwrite(m, 1, 4, f);
fwrite(rh, 4, 4, f);
fwrite(&tns, 8, 1, f);
fwrite(&seq, 8, 1, f);
for (y = 0; y < r_h; y++)
fwrite(im->data + (size_t)y * im->bytes_per_line, 1,
(size_t)r_w * 4, f);
fflush(f);
seq++;
XDestroyImage(im);
if (pace)
usleep(pace);
if ((seq & 63) == 0)
fprintf(stderr, "xgrab: frames=%llu\n",
(unsigned long long)seq);
}
{
char m[4] = { 'G', 'Z', 'F', '2' };
uint64_t end = 0xFFFFFFFFFFFFFFFFull;
fwrite(m, 1, 4, f);
fwrite(&end, 8, 1, f);
fflush(f);
}
fclose(f);
XCloseDisplay(d);
fprintf(stderr, "xgrab: done frames=%llu\n", (unsigned long long)seq);
return 0;
}
|