diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-15 16:00:06 -0500 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-15 16:00:06 -0500 |
| commit | 43bbf490dca972cb96fcf1d69dd0b6859377e452 (patch) | |
| tree | ac836f0dfcd50b3302d29a88402b1753127f7cf2 /tools/guest-diag/gzf2_video.py | |
| parent | f37f1f6a92939a8c147da1ed5a9032d9e8604ddc (diff) | |
| download | open-iov-43bbf490dca972cb96fcf1d69dd0b6859377e452.tar.gz open-iov-43bbf490dca972cb96fcf1d69dd0b6859377e452.zip | |
tools/guest-diag: tag BGRA capture records as GZF2 fmt 33
sdl_cap.c wrote the same 32 in the GZF2 record format field for every
capture path, so gzf2_video.py's auto mode decoded ARGB8888/X-surface
frames (BGRA byte order on little-endian) as RGBA and swapped red and
blue. Make the field the documented pixel-order tag: 32 = RGBA8 from
the GL swap path (glReadPixels GL_RGBA), 33 = BGRA8 from
SDL_RenderReadPixels(ARGB8888) and X window surfaces; xgrab.c tags its
ZPixmap BGRA records 33 as well.
gzf2_video.py continues to accept both tags (and old all-32 captures
via --pix-fmt bgra), checks ffmpeg/ffprobe before indexing, and keeps
the final resampled endpoint so a 90-frame 60 fps capture encodes as
90 frames instead of 88.
Diffstat (limited to 'tools/guest-diag/gzf2_video.py')
| -rw-r--r-- | tools/guest-diag/gzf2_video.py | 25 |
1 files changed, 20 insertions, 5 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 |
