docs: add validation guide, hardware and Windows scripts, CI
Documents what the rig proved and what it found, adds the hardware sign-off script for the Hyprland machine and an (untested) Windows validation script, and updates CI to build the cached OBS runtime, run tests and lint the Windows code paths.
This commit is contained in:
@@ -5,20 +5,58 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
checks:
|
linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: https://github.com/actions/checkout@v4
|
- uses: https://github.com/actions/checkout@v4
|
||||||
- uses: https://github.com/dtolnay/rust-toolchain@1.98.0
|
- uses: https://github.com/dtolnay/rust-toolchain@1.98.0
|
||||||
with:
|
with:
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
- name: Install native UI build dependencies
|
- name: Install native build dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential pkg-config libfontconfig1-dev libfreetype6-dev libwayland-dev libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev libssl-dev
|
# GPUI, plus clang for the libobs bindings.
|
||||||
|
sudo apt-get install -y build-essential pkg-config clang libfontconfig1-dev libfreetype6-dev \
|
||||||
|
libwayland-dev libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev libssl-dev
|
||||||
|
# OBS 32.0.4 libobs and the bundled plugins (scripts/obs/build-linux.sh).
|
||||||
|
sudo apt-get install -y cmake ninja-build extra-cmake-modules libavcodec-dev libavdevice-dev \
|
||||||
|
libavfilter-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev \
|
||||||
|
libcurl4-openssl-dev libmbedtls-dev libgl1-mesa-dev libglvnd-dev libgles2-mesa-dev libjansson-dev \
|
||||||
|
libx11-dev libx11-xcb-dev libxcb-randr0-dev libxcb-shm0-dev libxcb-xinerama0-dev \
|
||||||
|
libxcb-composite0-dev libxcb-xfixes0-dev libxcb-xinput-dev libxcomposite-dev libxinerama-dev \
|
||||||
|
libxss-dev libpci-dev libpipewire-0.3-dev libpulse-dev libudev-dev libva-dev libdrm-dev \
|
||||||
|
librist-dev libsrt-openssl-dev uthash-dev libsimde-dev nlohmann-json3-dev libffmpeg-nvenc-dev \
|
||||||
|
uuid-dev libglib2.0-dev
|
||||||
|
- name: Cache the OBS runtime
|
||||||
|
uses: https://github.com/actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: target/obs-runtime/linux-x86_64
|
||||||
|
key: obs-runtime-linux-${{ hashFiles('scripts/obs/versions.env', 'scripts/obs/build-linux.sh') }}
|
||||||
|
- name: Build the OBS runtime
|
||||||
|
run: |
|
||||||
|
if [ ! -f target/obs-runtime/linux-x86_64/VERSION ]; then
|
||||||
|
scripts/obs/build-linux.sh
|
||||||
|
fi
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
- name: Check Rust
|
- name: Lint
|
||||||
run: cargo clippy --locked --workspace --all-targets -- -D warnings
|
run: cargo clippy --locked --workspace --all-targets -- -D warnings
|
||||||
|
- name: Test
|
||||||
|
run: cargo test --locked --workspace
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --locked --workspace
|
run: cargo build --locked --workspace
|
||||||
|
|
||||||
|
windows-cross-check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://github.com/actions/checkout@v4
|
||||||
|
- uses: https://github.com/dtolnay/rust-toolchain@1.98.0
|
||||||
|
with:
|
||||||
|
components: clippy
|
||||||
|
targets: x86_64-pc-windows-msvc
|
||||||
|
# Type-checks the Windows code paths; nothing is linked or run. The GPUI
|
||||||
|
# crate needs the MSVC C toolchain and is checked on Windows instead.
|
||||||
|
- name: Lint Windows code paths
|
||||||
|
run: >
|
||||||
|
cargo clippy --locked --target x86_64-pc-windows-msvc
|
||||||
|
-p clipbin-core -p clipbin-obs -p clipbin-probe --all-targets -- -D warnings
|
||||||
|
|||||||
@@ -1,26 +1,34 @@
|
|||||||
# Clipbin Desktop
|
# Clipbin Desktop
|
||||||
|
|
||||||
An open-source game recorder for Windows and Linux, inspired by Plays.tv. Rust and GPUI provide the desktop interface; the recording engine will use libobs and official OBS capture components.
|
An open-source game recorder for Windows and Linux, inspired by Plays.tv. Rust and GPUI provide the desktop interface; the recording engine uses libobs and official OBS capture components.
|
||||||
|
|
||||||
[SPEC.md](SPEC.md) defines the agreed v1 product requirements.
|
[SPEC.md](SPEC.md) defines the agreed v1 product requirements.
|
||||||
|
|
||||||
## Current state
|
## Current state
|
||||||
|
|
||||||
This is the initial project scaffold. It opens a native GPUI window, displays the agreed recording defaults, and always reports **Not recording**.
|
The recording foundation is being validated (see [docs/validation.md](docs/validation.md)). `clipbin-obs` records official OBS capture sources through one hardware encoder into keyframe-aligned segments and reports honest status; `clipbin-probe` exercises it. It passes the Linux headless rig; hardware sign-off on Hyprland and all Windows validation are still to do.
|
||||||
|
|
||||||
Capture, Steam detection, recording, playback, clipping, bookmarks, persistence, global hotkeys, autostart, and background recording are not implemented yet. Closing the window exits this initial shell. The full application will keep its recorder running independently of window closure, as specified in SPEC.md.
|
The desktop app is still the initial shell: it opens a GPUI window, displays the agreed recording defaults, and always reports **Not recording**. Steam detection, the recorder in the app, playback, clipping, bookmarks, persistence, global hotkeys, autostart, and background recording are not implemented yet.
|
||||||
|
|
||||||
|
Windows is a first-class target. Every change must keep the Windows code paths building (`cargo clippy --target x86_64-pc-windows-msvc`) and list what still needs validating on Windows.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
```text
|
```text
|
||||||
crates/
|
crates/
|
||||||
clipbin-core/ Settings and recorder state; independent of GPUI and native OBS.
|
clipbin-core/ Settings and recorder state; independent of GPUI and native OBS.
|
||||||
|
clipbin-obs/ Recording engine over the pinned libobs runtime; all unsafe code is in src/ffi.rs.
|
||||||
|
clipbin-probe/ Validation probe for capture, encoders, segments and status.
|
||||||
clipbin-desktop/ GPUI application and initial session-library view.
|
clipbin-desktop/ GPUI application and initial session-library view.
|
||||||
.gitea/workflows/ Rust formatting and compilation checks.
|
scripts/obs/ Assemble the pinned OBS runtime for Linux (built from source) and Windows (official release).
|
||||||
|
scripts/rig/ Headless Wayland/X11 desktop for capture tests on machines without a display.
|
||||||
|
scripts/validate/ Validation suites: Linux rig, Linux hardware, Windows.
|
||||||
|
docs/validation.md Validation status and findings.
|
||||||
|
.gitea/workflows/ Formatting, lint, test and Windows cross-checks.
|
||||||
SPEC.md Product requirements and acceptance checks.
|
SPEC.md Product requirements and acceptance checks.
|
||||||
```
|
```
|
||||||
|
|
||||||
The core currently has no external dependencies. Keep capture and session operations out of the UI thread when the recording engine is added.
|
The core has no external dependencies. Keep capture and session operations out of the UI thread.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -31,9 +39,23 @@ Keep the lockfile checked in and use `--locked`. It currently pins `libc` to 0.2
|
|||||||
On Arch/CachyOS, install the native build dependencies:
|
On Arch/CachyOS, install the native build dependencies:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -S --needed base-devel pkgconf fontconfig freetype2 wayland libxcb libxkbcommon libxkbcommon-x11 openssl
|
sudo pacman -S --needed base-devel pkgconf fontconfig freetype2 wayland libxcb libxkbcommon libxkbcommon-x11 openssl clang
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### OBS runtime
|
||||||
|
|
||||||
|
Clipbin bundles a pinned OBS **32.0.4** runtime (`scripts/obs/versions.env`) with only the official plugins it uses. The `libobs` crate's headers match that version; the engine refuses to start against any other.
|
||||||
|
|
||||||
|
- Linux: `scripts/obs/build-linux.sh` builds libobs and the plugins from source into `target/obs-runtime/linux-x86_64`. Arch/CachyOS build dependencies:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo pacman -S --needed cmake ninja extra-cmake-modules ffmpeg x264 pipewire libpulse libdrm libva jansson curl libxcomposite libxinerama libxrandr wayland-protocols simde uthash nlohmann-json mbedtls3 pciutils srt librist ffnvcodec-headers amf-headers
|
||||||
|
```
|
||||||
|
|
||||||
|
- Windows: `scripts/obs/assemble-windows.sh` (Git Bash) verifies and unpacks the official release zip into `target/obs-runtime/windows-x86_64`, copying files byte-for-byte so the Game Capture hook keeps its signature.
|
||||||
|
|
||||||
|
Development builds find the runtime through `.cargo/config.toml`; `clipbin-probe`'s build script places `obs-ffmpeg-mux` (and on Windows the OBS DLLs) next to the executable, where OBS looks for them.
|
||||||
|
|
||||||
On Debian/Ubuntu:
|
On Debian/Ubuntu:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -41,7 +63,7 @@ sudo apt-get update
|
|||||||
sudo apt-get install build-essential pkg-config libfontconfig1-dev libfreetype6-dev libwayland-dev libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev libssl-dev
|
sudo apt-get install build-essential pkg-config libfontconfig1-dev libfreetype6-dev libwayland-dev libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev libssl-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
For Windows, use the MSVC Rust toolchain and Visual Studio Build Tools with the Desktop development with C++ workload. Windows support needs validation on a Windows machine.
|
For Windows, use the MSVC Rust toolchain and Visual Studio Build Tools with the Desktop development with C++ workload. Windows support needs validation on a Windows machine; see [docs/validation.md](docs/validation.md#windows).
|
||||||
|
|
||||||
Run the desktop shell from an active graphical session:
|
Run the desktop shell from an active graphical session:
|
||||||
|
|
||||||
@@ -58,9 +80,13 @@ Checks:
|
|||||||
```sh
|
```sh
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
cargo clippy --locked --workspace --all-targets -- -D warnings
|
cargo clippy --locked --workspace --all-targets -- -D warnings
|
||||||
cargo build --locked --workspace
|
cargo test --locked --workspace
|
||||||
|
# Windows code paths, from any platform (rustup target add x86_64-pc-windows-msvc):
|
||||||
|
cargo clippy --locked --target x86_64-pc-windows-msvc -p clipbin-core -p clipbin-obs -p clipbin-probe --all-targets -- -D warnings
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Recording validation on Linux, headless: `scripts/validate/linux-rig.sh`.
|
||||||
|
|
||||||
The core can also be checked without native UI dependencies:
|
The core can also be checked without native UI dependencies:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -69,14 +95,12 @@ cargo check --locked -p clipbin-core
|
|||||||
|
|
||||||
## First recording milestone
|
## First recording milestone
|
||||||
|
|
||||||
1. Validate official OBS capture and recording-health signals on CachyOS, Hyprland and the RX 9070 XT at 1440p60.
|
1. Validate official OBS capture and recording-health signals on CachyOS, Hyprland and the RX 9070 XT at 1440p60. *Rig validated; hardware sign-off pending.*
|
||||||
2. Select and pin a tested OBS runtime, Rust bindings, and official plugin set together. Preserve the original signed Windows capture-hook binaries.
|
2. Select and pin a tested OBS runtime, Rust bindings, and official plugin set together. Preserve the original signed Windows capture-hook binaries. *Pinned to OBS 32.0.4 and libobs crate 5.0.1; Windows runtime unvalidated.*
|
||||||
3. Prove one continuous hardware encoder can produce short keyframe-aligned segments and remux clips across their boundaries while recording continues.
|
3. Prove one continuous hardware encoder can produce short keyframe-aligned segments and remux clips across their boundaries while recording continues. *Proven in the rig with VA-API H.264 and HEVC.*
|
||||||
4. Integrate the recorder without blocking GPUI, then add native playback and seeking.
|
4. Integrate the recorder without blocking GPUI, then add native playback and seeking.
|
||||||
|
|
||||||
OBS is not linked or bundled in this scaffold. Adding an unused native dependency would not validate the required runtime/plugin compatibility. The runtime bundle and adapter belong to the first recording milestone.
|
The capture integration uses official OBS components only: Windows Game Capture/Window Capture, X11 Xcomposite, and Wayland PipeWire/desktop-portal capture. Third-party game hooks are excluded.
|
||||||
|
|
||||||
The capture integration must use official OBS components: Windows Game Capture/Window Capture, X11 Xcomposite, and Wayland PipeWire/desktop-portal capture. Third-party game hooks are excluded.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
# Recording foundation validation
|
||||||
|
|
||||||
|
The first recording milestone proves the OBS capture, encoder and segment
|
||||||
|
pipeline before the UI is built (SPEC.md, "Implementation validation before
|
||||||
|
building out the UI"). `clipbin-probe` drives the real `clipbin-obs` engine and
|
||||||
|
prints `key=value` lines; the scripts in `scripts/validate/` turn them into
|
||||||
|
pass/fail results.
|
||||||
|
|
||||||
|
| Where | Script | Status |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Linux, headless rig (Wayland portal + Xwayland) | `scripts/validate/linux-rig.sh` | All 9 scenarios pass on devbox (Intel UHD 770, VA-API) |
|
||||||
|
| Linux, real session (CachyOS, Hyprland, RX 9070 XT, 1440p60) | `scripts/validate/linux-hardware.sh` | Not run yet |
|
||||||
|
| Windows (Game Capture, NVENC/AMF/QSV) | `scripts/validate/windows.ps1` | Not run yet; script untested |
|
||||||
|
|
||||||
|
## Probe commands
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo run -p clipbin-probe -- encoders --verify # hardware encoders per codec, proven by encoding
|
||||||
|
cargo run -p clipbin-probe -- record --target monitor # records; prints status, health and segments
|
||||||
|
cargo run -p clipbin-probe -- check # keyframes, codec, durations, cross-boundary remux
|
||||||
|
```
|
||||||
|
|
||||||
|
`record` targets `monitor`, `window` or `game` (Game Capture on Windows; the
|
||||||
|
same as `window` elsewhere). On Windows and X11, `--window` takes OBS's window
|
||||||
|
identifier; on Wayland the portal picker chooses and `--restore-token` reuses
|
||||||
|
an earlier choice. See the top of `crates/clipbin-probe/src/main.rs` for all
|
||||||
|
options. `check` needs FFmpeg's `ffprobe` and `ffmpeg` on `PATH`.
|
||||||
|
|
||||||
|
## Linux headless rig
|
||||||
|
|
||||||
|
`scripts/rig/headless.sh [--x11] <command>` runs a command inside a private
|
||||||
|
D-Bus session with PipeWire, a virtual audio sink, headless Sway on the GPU,
|
||||||
|
xdg-desktop-portal-wlr (auto-selecting the only output) and a 60 FPS test
|
||||||
|
pattern with a tone. `--x11` runs the game and command on Sway's Xwayland.
|
||||||
|
|
||||||
|
Arch packages: `sway xdg-desktop-portal xdg-desktop-portal-wlr xorg-xwayland
|
||||||
|
xorg-xwininfo pipewire pipewire-pulse wireplumber libpulse ffmpeg` plus a VA-API
|
||||||
|
driver (`intel-media-driver` or `libva-mesa-driver`).
|
||||||
|
|
||||||
|
The suite covers:
|
||||||
|
|
||||||
|
1. Encoder verification: H.264 must be usable; HEVC and AV1 are reported.
|
||||||
|
2. Wayland monitor capture in H.264 and HEVC: segments start on keyframes,
|
||||||
|
last 2 s, remux to MP4 across boundaries, decode cleanly, carry the tone.
|
||||||
|
3. X11 window capture (Xcomposite).
|
||||||
|
4. Failures that must end in `status=failed`: PipeWire stream lost, captured
|
||||||
|
X11 window closed, segment directory unwritable, free space below the margin.
|
||||||
|
5. A portal that grants no usable source never reports `Recording`.
|
||||||
|
|
||||||
|
## Linux hardware sign-off
|
||||||
|
|
||||||
|
Run `scripts/validate/linux-hardware.sh` from the Hyprland session. It verifies
|
||||||
|
encoders at 1440p60, records the monitor with each usable codec (the first run
|
||||||
|
shows the portal picker; later runs pass the restore token and ask whether the
|
||||||
|
picker stayed away), records a window, and asks you to close a window
|
||||||
|
mid-recording. Send back `report.txt` from the output directory.
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
Run `scripts/validate/windows.ps1 -GameWindow "<title>:<class>:<exe>"` with a
|
||||||
|
game running. It assembles the official OBS 32.0.4 runtime, checks the Game
|
||||||
|
Capture hook signatures, builds the probe, verifies NVENC/AMF/QSV encoders and
|
||||||
|
records Monitor, Game and Window Capture.
|
||||||
|
|
||||||
|
Windows status:
|
||||||
|
|
||||||
|
- `clipbin-core`, `clipbin-obs` and `clipbin-probe` pass `cargo clippy` for
|
||||||
|
`x86_64-pc-windows-msvc` (cross-checked from Linux). Nothing has been linked
|
||||||
|
or run on Windows.
|
||||||
|
- The GPUI desktop crate has not been checked for Windows; its `ring`
|
||||||
|
dependency needs the MSVC C toolchain.
|
||||||
|
- The assembled runtime keeps the six Game Capture hook binaries byte-identical
|
||||||
|
to the release, with their Authenticode signatures present; signature
|
||||||
|
validity has not been checked on Windows.
|
||||||
|
- Unvalidated: encoder ids and settings for NVENC, AMF and QSV; Game Capture
|
||||||
|
hooking and its loss detection (the engine expects the source size to drop
|
||||||
|
to 0); WASAPI audio; `obs-ffmpeg-mux.exe` beside the executable; linking
|
||||||
|
`dstr_vprintf` through the libobs crate's `obs.lib`.
|
||||||
|
|
||||||
|
## Findings for the next milestones
|
||||||
|
|
||||||
|
- **Plugin loading.** libobs always adds default plugin paths: the build-time
|
||||||
|
install prefix on Linux and `../../obs-plugins/64bit` relative to the
|
||||||
|
working directory on Windows. Searching would load other OBS installations'
|
||||||
|
plugins or load ours twice, so the engine opens exactly the bundled
|
||||||
|
allowlist (`runtime::PLUGINS`) by path.
|
||||||
|
- **Segment timestamps.** The FFmpeg muxer restarts each segment's video and
|
||||||
|
audio timestamps at zero independently. Concatenating segments naively leaves
|
||||||
|
22–43 ms video gaps at boundaries. Video is constant frame rate and AAC
|
||||||
|
packets are continuous, so a segment's exact session offset is the count of
|
||||||
|
earlier frames and audio packets; the A/V offset stays within one AAC packet
|
||||||
|
(≤21 ms) and does not drift. The timeline and export work must place
|
||||||
|
segments this way.
|
||||||
|
- **Availability.** With 1 s keyframes and 2 s segments, splits happen on
|
||||||
|
schedule every 2.0 s, so the newest complete footage is about 2 s behind
|
||||||
|
plus finalisation: inside the spec's 2–5 s window.
|
||||||
|
- **Honest status needs more than OBS's counters.** OBS kept counting bytes
|
||||||
|
into a dead muxer process, and once reported a clean stop after the disk
|
||||||
|
filled. Status therefore requires footage to grow on disk, and recording
|
||||||
|
stops while 1 GB remains so the last segment can be finalised.
|
||||||
|
- **PipeWire source loss.** OBS's PipeWire capture keeps its size and renders
|
||||||
|
its last frame after the stream stops, and only logs the stream state. The
|
||||||
|
engine reads that log line (stable for the pinned OBS version). A more robust
|
||||||
|
follow-up is watching the PipeWire node state directly.
|
||||||
|
- **Audio capture failures are not detected yet.** When the PulseAudio server
|
||||||
|
was unreachable, recording continued with a silent track.
|
||||||
|
- **Linux runtime dependencies.** The Linux OBS build links the system's
|
||||||
|
FFmpeg, PipeWire and other libraries, so it is tied to the distribution it
|
||||||
|
was built on. Packaging (for example Flatpak, or bundling FFmpeg) is an open
|
||||||
|
decision; OBS 32.0 needs mbedtls 3 (`mbedtls3` on Arch).
|
||||||
|
- **OBS objects.** Scenes and sources are created private (OBS 31+ otherwise
|
||||||
|
registers scenes with the main canvas, which keeps them alive), unknown
|
||||||
|
source types fail instead of becoming placeholders, and shutdown drains
|
||||||
|
libobs's destroy queue first.
|
||||||
|
- **Plugin configuration.** libobs is started without a module config path;
|
||||||
|
set one under the app's config directory before plugins that save settings
|
||||||
|
are added.
|
||||||
Executable
+84
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Hardware sign-off for Linux: run from a real desktop session (Hyprland,
|
||||||
|
# another Wayland compositor, or X11) on the machine being validated.
|
||||||
|
#
|
||||||
|
# scripts/validate/linux-hardware.sh [output-dir]
|
||||||
|
#
|
||||||
|
# Records at 1440p60 with every usable hardware codec, checks the segments,
|
||||||
|
# confirms the portal restores its selection without asking again, and
|
||||||
|
# records a window. Writes report.txt in the output directory.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
out="${1:-${TMPDIR:-/tmp}/clipbin-hardware}"
|
||||||
|
probe="${repo}/target/debug/clipbin-probe"
|
||||||
|
report="${out}/report.txt"
|
||||||
|
rm -rf "${out}" && mkdir -p "${out}"
|
||||||
|
format=(--width 2560 --height 1440 --fps 60 --bitrate 40000)
|
||||||
|
|
||||||
|
cargo build --locked -p clipbin-probe --manifest-path "${repo}/Cargo.toml" || exit 1
|
||||||
|
|
||||||
|
log() { echo "$*" | tee -a "${report}"; }
|
||||||
|
ask() {
|
||||||
|
local answer
|
||||||
|
read -r -p "$1 [y/n] " answer
|
||||||
|
log "answer: $1 -> ${answer}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log "Clipbin hardware validation $(date -Is)"
|
||||||
|
log "host: $(uname -r) session=${XDG_SESSION_TYPE:-?} desktop=${XDG_CURRENT_DESKTOP:-?}"
|
||||||
|
log "gpu: $(lspci 2>/dev/null | grep -iE 'vga|display' | cut -d: -f3- | xargs)"
|
||||||
|
|
||||||
|
"${probe}" encoders --verify "${format[@]}" --out "${out}/encoders" > "${out}/encoders.log" 2> "${out}/encoders.obs.log"
|
||||||
|
log "$(grep -E '^(obs_version|usable\.|verify\.)' "${out}/encoders.log")"
|
||||||
|
|
||||||
|
token=""
|
||||||
|
for codec in h264 hevc av1; do
|
||||||
|
if grep -q "^usable\.${codec}=none" "${out}/encoders.log"; then
|
||||||
|
log "SKIP ${codec}: no usable hardware encoder"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ -z "${token}" ]]; then
|
||||||
|
echo
|
||||||
|
echo "Recording a monitor for 20 seconds with ${codec}. The portal will ask"
|
||||||
|
echo "you to pick a monitor: pick one and keep some motion on screen."
|
||||||
|
fi
|
||||||
|
dir="${out}/monitor-${codec}"
|
||||||
|
restore=()
|
||||||
|
[[ -n "${token}" ]] && restore=(--restore-token "${token}")
|
||||||
|
"${probe}" record --target monitor --codec "${codec}" "${restore[@]}" --seconds 20 "${format[@]}" \
|
||||||
|
--out "${dir}" > "${dir}.log" 2> "${dir}.obs.log"
|
||||||
|
record_exit=$?
|
||||||
|
"${probe}" check --codec "${codec}" --out "${dir}" >> "${dir}.log" 2>&1
|
||||||
|
check_exit=$?
|
||||||
|
log "monitor-${codec}: record_exit=${record_exit} check_exit=${check_exit} $(grep -E '^(encoder|recorded|check)=' "${dir}.log" | tr '\n' ' ')"
|
||||||
|
log "$(grep -E 'status=' "${dir}.log" | tr '\n' ' ')"
|
||||||
|
if [[ -z "${token}" ]]; then
|
||||||
|
token="$(sed -n 's/^restore_token=//p' "${dir}.log")"
|
||||||
|
log "restore token received: $([[ -n "${token}" ]] && echo yes || echo no)"
|
||||||
|
else
|
||||||
|
ask "Did ${codec} start WITHOUT showing the portal picker again?"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Now recording a window for 20 seconds. Start a game (or any moving"
|
||||||
|
echo "window) first, then pick it in the portal."
|
||||||
|
read -r -p "Press Enter when ready. " _
|
||||||
|
dir="${out}/window-h264"
|
||||||
|
"${probe}" record --target window --seconds 20 "${format[@]}" --out "${dir}" > "${dir}.log" 2> "${dir}.obs.log"
|
||||||
|
record_exit=$?
|
||||||
|
"${probe}" check --out "${dir}" >> "${dir}.log" 2>&1
|
||||||
|
log "window-h264: record_exit=${record_exit} check_exit=$? $(grep -E '^(recorded|check)=' "${dir}.log" | tr '\n' ' ')"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Last: source loss. Record a window again, then close that window"
|
||||||
|
echo "about 5 seconds in. The probe should report a failure."
|
||||||
|
read -r -p "Press Enter when ready. " _
|
||||||
|
dir="${out}/window-closed"
|
||||||
|
"${probe}" record --target window --seconds 20 "${format[@]}" --out "${dir}" > "${dir}.log" 2> "${dir}.obs.log"
|
||||||
|
log "window-closed: exit=$? $(grep -E 'status=failed' "${dir}.log" | head -1)"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Report: ${report}"
|
||||||
|
echo "Recordings and logs: ${out}"
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# Hardware validation for Windows. Not yet run on Windows: it is the first
|
||||||
|
# job for the Windows implementor, who should fix what it finds.
|
||||||
|
#
|
||||||
|
# powershell -ExecutionPolicy Bypass -File scripts\validate\windows.ps1 [-Out <dir>] [-GameWindow "<title>:<class>:<exe>"]
|
||||||
|
#
|
||||||
|
# Needs: Rust (rustup, MSVC toolchain), Visual Studio Build Tools (C++),
|
||||||
|
# Git for Windows (its bash runs scripts/obs/assemble-windows.sh) and FFmpeg
|
||||||
|
# on PATH for the segment checks (winget install Gyan.FFmpeg).
|
||||||
|
#
|
||||||
|
# -GameWindow is OBS's window identifier for a running game, as shown in OBS
|
||||||
|
# Studio's Game Capture "Window" list: "<title>:<window class>:<executable>".
|
||||||
|
param(
|
||||||
|
[string]$Out = "$env:TEMP\clipbin-windows",
|
||||||
|
[string]$GameWindow = ""
|
||||||
|
)
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$repo = Resolve-Path "$PSScriptRoot\..\.."
|
||||||
|
$report = Join-Path $Out "report.txt"
|
||||||
|
Remove-Item -Recurse -Force $Out -ErrorAction SilentlyContinue
|
||||||
|
New-Item -ItemType Directory -Force $Out | Out-Null
|
||||||
|
function Log($text) { $text | Tee-Object -FilePath $report -Append }
|
||||||
|
|
||||||
|
Log "Clipbin Windows validation $(Get-Date -Format o)"
|
||||||
|
Log "os: $((Get-CimInstance Win32_OperatingSystem).Caption) $([Environment]::OSVersion.Version)"
|
||||||
|
Log "gpu: $((Get-CimInstance Win32_VideoController).Name -join ', ')"
|
||||||
|
|
||||||
|
# 1. The pinned official OBS runtime, with the Game Capture hook still signed.
|
||||||
|
& bash "$repo/scripts/obs/assemble-windows.sh"
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "assembling the OBS runtime failed" }
|
||||||
|
$runtime = Join-Path $repo "target\obs-runtime\windows-x86_64"
|
||||||
|
Get-ChildItem "$runtime\data\obs-plugins\win-capture\*" -Include *.exe, *.dll | ForEach-Object {
|
||||||
|
$signature = Get-AuthenticodeSignature $_.FullName
|
||||||
|
Log ("signature {0}: {1} ({2})" -f $_.Name, $signature.Status, $signature.SignerCertificate.Subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. Build the probe (also checks the Windows code paths compile and link).
|
||||||
|
Push-Location $repo
|
||||||
|
cargo build --locked -p clipbin-probe
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "building clipbin-probe failed" }
|
||||||
|
Pop-Location
|
||||||
|
$probe = Join-Path $repo "target\debug\clipbin-probe.exe"
|
||||||
|
$format = @("--width", "2560", "--height", "1440", "--fps", "60", "--bitrate", "40000")
|
||||||
|
|
||||||
|
function Record($name, $codec, [string[]]$arguments) {
|
||||||
|
$dir = Join-Path $Out $name
|
||||||
|
& $probe record @arguments --codec $codec @format --seconds 20 --out $dir > "$dir.log" 2> "$dir.obs.log"
|
||||||
|
$recordExit = $LASTEXITCODE
|
||||||
|
& $probe check --codec $codec --out $dir >> "$dir.log" 2>&1
|
||||||
|
$checkExit = $LASTEXITCODE
|
||||||
|
Log "${name}: record_exit=$recordExit check_exit=$checkExit $((Select-String -Path "$dir.log" -Pattern '^(encoder|recorded|check)=').Line -join ' ')"
|
||||||
|
Log ((Select-String -Path "$dir.log" -Pattern 'status=').Line -join ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
# 3. Hardware encoders: NVENC, AMF or QSV for H.264, HEVC and AV1.
|
||||||
|
& $probe encoders --verify @format --out (Join-Path $Out "encoders") > "$Out\encoders.log" 2> "$Out\encoders.obs.log"
|
||||||
|
Log ((Select-String -Path "$Out\encoders.log" -Pattern '^(obs_version|usable\.|verify\.)').Line -join "`n")
|
||||||
|
|
||||||
|
# 4. Monitor capture with each usable codec.
|
||||||
|
foreach ($codec in "h264", "hevc", "av1") {
|
||||||
|
if (Select-String -Path "$Out\encoders.log" -Pattern "^usable\.$codec=none" -Quiet) {
|
||||||
|
Log "SKIP ${codec}: no usable hardware encoder"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
Record "monitor-$codec" $codec @("--target", "monitor")
|
||||||
|
}
|
||||||
|
|
||||||
|
# 5. Game Capture (signed hook) and Window Capture of a running game.
|
||||||
|
if ($GameWindow) {
|
||||||
|
Record "game-capture" "h264" @("--target", "game", "--window", $GameWindow)
|
||||||
|
Record "window-capture" "h264" @("--target", "window", "--window", $GameWindow)
|
||||||
|
Write-Host "Last: start a recording, then quit the game about 5 seconds in."
|
||||||
|
Read-Host "Press Enter when ready"
|
||||||
|
$dir = Join-Path $Out "game-closed"
|
||||||
|
& $probe record --target game --window $GameWindow @format --seconds 20 --out $dir > "$dir.log" 2> "$dir.obs.log"
|
||||||
|
Log "game-closed: exit=$LASTEXITCODE $((Select-String -Path "$dir.log" -Pattern 'status=failed').Line | Select-Object -First 1)"
|
||||||
|
} else {
|
||||||
|
Log "SKIP game capture: pass -GameWindow with a running game's window identifier"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Report: $report"
|
||||||
Reference in New Issue
Block a user