summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/guest-diag/gzf2_video.py25
-rw-r--r--tools/guest-diag/sdl_cap.c21
-rw-r--r--tools/guest-diag/xgrab.c5
3 files changed, 36 insertions, 15 deletions
diff --git a/tools/guest-diag/gzf2_video.py b/tools/guest-diag/gzf2_video.py
index aa88aa0..8635ca0 100644
--- a/tools/guest-diag/gzf2_video.py
+++ b/tools/guest-diag/gzf2_video.py
@@ -9,9 +9,11 @@
#
# Format: [0..8) = "GZCAPV01", zero pad to 4096; then records:
# 4B "GZF2" | u32 w | u32 h | u32 stride | u32 fmt | u64 ts_ns | u64 seq |
-# stride*h bytes, top-down. fmt 32 = RGBA8 (GL swap path), 33 = BGRA8
-# (SDL_RenderReadPixels ARGB8888 / X surface). A trailing
-# "GZF2" + u64 0xffffffffffffffff marks a clean stop.
+# stride*h bytes, top-down. fmt is a pixel-order tag: 32 = RGBA8 (GL swap
+# path, glReadPixels GL_RGBA), 33 = BGRA8 (SDL_RenderReadPixels ARGB8888 /
+# X surface). A trailing "GZF2" + u64 0xffffffffffffffff marks a clean stop.
+# Captures written before the 33 tag existed recorded BGRA paths as 32;
+# decode those with --pix-fmt bgra.
#
# Usage:
# gzf2_video.py CAPTURE OUT.mp4 [--fps 60] [--skip 5] [--duration 20]
@@ -22,6 +24,7 @@ import bisect
import hashlib
import json
import os
+import shutil
import struct
import subprocess
import sys
@@ -89,7 +92,13 @@ def pick_frames(recs, fps, skip_s, duration_s):
cand = [r for r in recs if r["ts"] >= t0] or recs
ts = [r["ts"] for r in cand]
span = (ts[-1] - ts[0]) / 1e9
- n = int(duration_s * fps) if duration_s else max(1, int(span * fps))
+ if duration_s:
+ n = max(1, int(round(duration_s * fps)))
+ else:
+ # Nearest-frame sampling must include both endpoints: a capture that
+ # spans k frame periods yields k+1 output frames (int() alone drops
+ # the last frame and can lose one more to float formatting).
+ n = max(1, int(round(span * fps)) + 1)
picks, held = [], 0
for i in range(n):
want = ts[0] + int(i * 1e9 / fps)
@@ -179,10 +188,16 @@ def main():
default="libx264")
ap.add_argument("--crf", type=int, default=18)
ap.add_argument("--pix-fmt", choices=["auto", "rgba", "bgra"],
- default="auto", help="auto uses record fmt (33=BGRA)")
+ default="auto",
+ help="auto uses the record tag (32=RGBA, 33=BGRA); "
+ "old BGRA captures tagged 32 need bgra")
ap.add_argument("--info-only", action="store_true")
args = ap.parse_args()
+ for tool in ("ffmpeg", "ffprobe"):
+ if not shutil.which(tool):
+ die(f"{tool} not found in PATH")
+
recs, clean, corrupt = index_capture(args.capture)
uniq = len({r["md5"] for r in recs})
span = (recs[-1]["ts"] - recs[0]["ts"]) / 1e9
diff --git a/tools/guest-diag/sdl_cap.c b/tools/guest-diag/sdl_cap.c
index 5b9c096..f875ed0 100644
--- a/tools/guest-diag/sdl_cap.c
+++ b/tools/guest-diag/sdl_cap.c
@@ -11,9 +11,12 @@
// File layout (little endian):
// [0] 8B magic "GZCAPV01" (+ 4088 B reserved zero)
// [4096] frame records:
-// 4B "GZF2" | u32 w | u32 h | u32 stride | u32 bpp
+// 4B "GZF2" | u32 w | u32 h | u32 stride | u32 fmt
// u64 ts_ns (CLOCK_MONOTONIC) | u64 seq | stride*h bytes (top-down)
-// A trailing record with seq = 0xFFFFFFFFFFFFFFFF marks clean stop.
+// fmt is a pixel-order tag (not bits per pixel): 32 = RGBA8 from the GL
+// swap path (glReadPixels GL_RGBA), 33 = BGRA8 from SDL_RenderReadPixels
+// ARGB8888 or an X window surface. A trailing record with
+// seq = 0xFFFFFFFFFFFFFFFF marks clean stop.
//
// Env: GZCAP (path, default /dev/shm/gzframes.bin), GZCAP_MAXF (0=unlimited)
#define _GNU_SOURCE
@@ -26,6 +29,8 @@
#include <unistd.h>
#define ARGB8888 0x16362004u
+#define GZF2_FMT_RGBA 32
+#define GZF2_FMT_BGRA 33
typedef struct SDL_Renderer SDL_Renderer;
typedef struct SDL_Window SDL_Window;
@@ -87,7 +92,7 @@ __attribute__((constructor)) static void cap_init(void)
if (h)
real_glReadPixels = dlsym(h, "glReadPixels");
}
- fprintf(stderr, "[gzcap] init pid=%d path=%s present=%p updwin=%p swap=%p read=%p gros=%p\n",
+ fprintf(stderr, "[gzcap] init pid=%d path=%s present=%p updwin=%p swap=%p read=%p gros=%p readpix=%p\n",
(int)getpid(), p, (void *)real_RenderPresent, (void *)real_UpdateWindowSurface,
(void *)real_GL_SwapWindow, (void *)real_RenderReadPixels,
(void *)real_GetRendererOutputSize, (void *)real_glReadPixels);
@@ -102,7 +107,7 @@ __attribute__((constructor)) static void cap_init(void)
fflush(cap_fp);
}
-static void cap_record(const void *px, int w, int h, int stride, int bpp)
+static void cap_record(const void *px, int w, int h, int stride, int fmt)
{
struct timespec ts;
uint64_t tns, seq;
@@ -126,7 +131,7 @@ static void cap_record(const void *px, int w, int h, int stride, int bpp)
rh[0] = (uint32_t)w;
rh[1] = (uint32_t)h;
rh[2] = (uint32_t)stride;
- rh[3] = (uint32_t)bpp;
+ rh[3] = (uint32_t)fmt;
fwrite(m, 1, 4, cap_fp);
fwrite(rh, 4, 4, cap_fp);
fwrite(&tns, 8, 1, cap_fp);
@@ -161,7 +166,7 @@ int SDL_RenderPresent(SDL_Renderer *r)
}
if (buf && real_RenderReadPixels(r, NULL, ARGB8888, buf,
w * 4) == 0)
- cap_record(buf, w, h, w * 4, 32);
+ cap_record(buf, w, h, w * 4, GZF2_FMT_BGRA);
}
}
if (real_RenderPresent)
@@ -180,7 +185,7 @@ int SDL_UpdateWindowSurface(SDL_Window *win)
if (s && s->pixels && s->w > 0 && s->h > 0 && s->pitch > 0 &&
s->w <= 4096 && s->h <= 4096)
- cap_record(s->pixels, s->w, s->h, s->pitch, 32);
+ cap_record(s->pixels, s->w, s->h, s->pitch, GZF2_FMT_BGRA);
}
if (real_UpdateWindowSurface)
return real_UpdateWindowSurface(win);
@@ -221,7 +226,7 @@ void SDL_GL_SwapWindow(SDL_Window *win)
memcpy(tmp + (size_t)y * w * 4,
gbuf + (size_t)(h - 1 - y) * w * 4,
(size_t)w * 4);
- cap_record(tmp, w, h, w * 4, 32);
+ cap_record(tmp, w, h, w * 4, GZF2_FMT_RGBA);
free(tmp);
}
}
diff --git a/tools/guest-diag/xgrab.c b/tools/guest-diag/xgrab.c
index eb605d6..bca23c0 100644
--- a/tools/guest-diag/xgrab.c
+++ b/tools/guest-diag/xgrab.c
@@ -3,8 +3,9 @@
// 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 |
+// [4096..] records: 4B "GZF2" | u32 w | u32 h | u32 stride | u32 fmt |
// u64 ts_ns | u64 seq | stride*h bytes (top-down BGRA)
+// fmt is a pixel-order tag: 33 = BGRA8 (ZPixmap on little-endian X).
// Trailing record seq=0xFFFFFFFFFFFFFFFF on clean stop.
// Usage: xgrab <display> <out> <maxframes|0> <pace_us|0>
#include <X11/Xlib.h>
@@ -83,7 +84,7 @@ int main(int argc, char **argv)
rh[0] = (uint32_t)r_w;
rh[1] = (uint32_t)r_h;
rh[2] = (uint32_t)r_w * 4;
- rh[3] = 32;
+ rh[3] = 33; /* GZF2 pixel-order tag: BGRA8 */
fwrite(m, 1, 4, f);
fwrite(rh, 4, 4, f);
fwrite(&tns, 8, 1, f);