Desktop app - Settings -> Picture: GPU passes between the stream and the screen. Upscaling (Bilinear, Lanczos, AMD FSR 1, FSRCNNX AI), CAS sharpening, denoise, debanding, dithering and colour; profiles plus a frame-time guard. My presets: save, apply, update, revert, delete, remembered. - Side-by-side compare (C) with zoom and pan, tweak panel (X). - One viewer: connecting takes the stream; "Watching elsewhere" when another viewer takes it. - Lower sound delay (about 190 -> 100 ms). - Gallery follows the folder, PNG sizes, Fit/100% switch, drag to pan. - Fixed crashes on fast zooming and on opening the gallery. Payload - 20 Mbit/s encoder bitrate; set once at start (live changes lock the encoder, documented in docs/API.md). - One viewer at a time (409 for a pushed-out viewer), viewers and bitrate in status.json. - Process name Glint.elf, previous log kept, quits at once when refused. Browser dashboard - Fixed the freeze after ~8 s, lower latency, sound on by default, one viewer with Watch here. Version 1.5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Glint desktop app
Windows app that connects to the Glint payload on a PS5, decodes the live H.264 stream (D3D11VA or FFmpeg), renders it with Vulkan + Dear ImGui 1.91.9b, plays the sound and drives the payload API.
What works
- GLFW + Vulkan swapchain + ImGui UI.
- Payload client (libcurl):
config.json,status.json,/frames,/audiotransport, keyframe/record/profile/stop commands. - H.264 decode with FFmpeg; SPS/PPS injected from
config.jsonon every IDR. - UI: the console picture fills the window (Fit/Fill/No upscaling). A glass status pill (console, picture, a frame strip of the last second with late frames in amber, hold and bitrate), round gallery / full screen / settings buttons and a command bar (sound + volume, screenshot, record, latency Lowest/Balanced/Smooth, hide) float over it and fade after 3 s without input. Recording and live stay shown at the top centre. Settings is a sheet that slides in from the right (Console, Video, Audio, Capture, Streaming, Help); the gallery is a full-window grid with thumbnails. Without a picture the window shows a connect screen with recent consoles.
- Dark (default) and light theme, cross-fading when you switch (Video page or T).
Geist and Geist Mono are embedded in the exe (
vendor/fonts, SIL OFL; regeneratesrc/fonts.incwithnode tools/embed_fonts.js). Icons come from Segoe Fluent Icons (Windows 11); without that font the UI falls back to text. Shortcuts: M sound, S screenshot, R record, G gallery, P picture size, L latency, H hide controls, T theme, F11 full screen, Ctrl+, settings, Esc close. - Console recording start/stop, keyframe, stop stream. Capture is 1080p60.
- Local PC recording to MKV (H.264 stream-copy + AAC), PNG screenshots, and a
gallery (play, export MP4/MKV, delete). Recordings and screenshots open in
a built-in viewer (sound, seek, volume; zoom and pan for pictures; Space,
arrows, Page Up/Down, Esc). Default folder
%USERPROFILE%\Videos\Glint. - Live streaming is switched off in this build (
SL_LIVE_STREAMINGinsrc/main.cpp; build with-DSL_LIVE_STREAMING=1to bring it back). When on (Settings > Streaming, Go live in the command bar): up to 5 RTMP/RTMPS destinations at once (Twitch, YouTube, TikTok, custom), re-encoded with the GPU when possible (AMD AMF, Media Foundation, else x264), keyframe every 2 s. RTMPS goes through Windows TLS with certificate checks. Keys and tokens live in Windows Credential Manager. Optional Twitch/YouTube sign-in with your own registered app fetches the key for you. - SDL2 audio playback of the payload
/audiostream: Sound on/off, volume 0-4x, delay Auto (default, sized from measured network jitter) or manual 0-400 ms. - A/V sync: video is held by the audio playout latency plus an A/V offset.
- Video page: GPU (D3D11VA) or CPU decoding, GPU (Vulkan compute) or CPU colour conversion, Latency Lowest/Balanced/Smooth, graphics card and driver info.
- Settings survive restarts in
%LOCALAPPDATA%\Glint:console.conf,audio.conf,video.conf,capture.conf(folder),window.conf(incl. theme),destinations.conf,oauth-apps.conf. Rollingglint.logand a diagnostics zip (Help page) without secrets. - Headless modes for testing;
tests/mock_payload.jsserves the payload API from a recording when no console is available.
What is not implemented yet
- Re-encoding PC recorder, console recording library, image quality panel.
- Plugin manager and store.
Out of scope: Sony Remote Play and cloud sessions.
Build (MSYS2 / MinGW-w64)
Dependencies installed with pacman:
base-devel # make, tar, diffutils for build_deps.sh
mingw-w64-x86_64-gcc
mingw-w64-x86_64-pkgconf
mingw-w64-x86_64-cmake # builds curl, with ninja
mingw-w64-x86_64-ninja
mingw-w64-x86_64-nasm # FFmpeg's x86 assembly
mingw-w64-x86_64-amf-headers # AMD hardware encoder
mingw-w64-x86_64-x264
mingw-w64-x86_64-zlib
mingw-w64-x86_64-glfw
mingw-w64-x86_64-vulkan-loader
mingw-w64-x86_64-SDL2 # audio output
mingw-w64-x86_64-shaderc # optional: glslc, rebuilds the compute shader
From an MSYS2 MinGW 64-bit shell:
cd app
./build_deps.sh # once: static FFmpeg and curl -> app/deps/prefix
./build.sh # -> app/build/Glint.exe, app/build/probe.exe
build_deps.sh downloads pinned FFmpeg and curl sources (checked by SHA-256)
and builds them with only what Glint uses. build.sh links them and
everything else statically, so Glint.exe is a single file: it needs no
MSYS2 DLLs, only Windows and the graphics driver's Vulkan loader.
Run
Double-click build/Glint.exe (no console window opens; started from a
terminal, --version and the test modes print there), or pass your console's address to
run.cmd (or set GLINT_URL), or run it manually. The examples below use
<ps5-ip> as a placeholder; replace it with your console's address.
build/Glint.exe --url http://<ps5-ip>:7231
build/Glint.exe --url http://<ps5-ip>:7231 --fullscreen
build/Glint.exe --url http://<ps5-ip>:7231 --headless 60
build/Glint.exe --version
build/Glint.exe --url http://<ps5-ip>:7231 --audio-soak 600 # headless audio soak
build/Glint.exe --url http://<ps5-ip>:7231 --audio-soak 60 --audio-exercise
build/Glint.exe --url http://<ps5-ip>:7231 --audio-cycles 5 # start/stop thread check
build/Glint.exe --url http://<ps5-ip>:7231 --record-test 60 --record-dir C:\tmp\rec
build/Glint.exe --gallery-test C:\tmp\rec # list / export / delete
build/Glint.exe --url http://<ps5-ip>:7231 --page 4 # open Settings on a tab (1-5)
build/Glint.exe --url http://<ps5-ip>:7231 --gallery # open the gallery
build/Glint.exe --url http://<ps5-ip>:7231 --theme light # dark (default) or light
build/Glint.exe --view C:\tmp\rec\clip.mkv # open a recording or screenshot in the viewer
build/Glint.exe --url http://<ps5-ip>:7231 --broadcast-test 20 --broadcast-url rtmp://127.0.0.1:1935/live/key # streaming builds only
build/Glint.exe --tls-probe live.twitch.tv:443 # TLS handshake only (streaming builds)
build/Glint.exe --decode-file rec.mkv gpu # decoder check on a file
Tests that touch settings or the vault honour GLINT_SETTINGS_DIR and
GLINT_VAULT_PREFIX, so they never see your real destinations (--store-test
and --oauth-test exist in streaming builds only):
GLINT_SETTINGS_DIR=/tmp/sl GLINT_VAULT_PREFIX=Glint-selftest build/Glint.exe --store-test
GLINT_OAUTH_TEST_BASE=http://127.0.0.1:18080 build/Glint.exe --oauth-test twitch # local mock
The payload must be running on the console first. --headless N decodes N
frames and exits with status 0/1; it is the quickest regression check.
Layout
src/main.cpp Vulkan + ImGui bootstrap, video texture, YUV converter, UI, headless modes
src/core/app.cpp payload session, decode thread, status thread
src/core/payload_client.cpp libcurl HTTP client (include/glint/payload_client.h)
src/core/settings.cpp saved settings, migration from the old name
src/core/log.cpp log file, diagnostics zip
src/media/decoder.cpp H.264 decode (D3D11VA / FFmpeg)
src/media/audio.cpp SDL2 audio: /audio thread -> ring -> callback
src/media/recorder.cpp local MKV recorder (H.264 copy + AAC, writer thread)
src/media/media.cpp screenshots, gallery, export
src/media/player.cpp built-in viewer's player (demux, decode, SDL sound clock)
src/stream/broadcast.cpp live encoder + per-destination RTMP writers
src/stream/tls_relay.cpp RTMPS through Windows TLS (Schannel)
src/stream/destinations.cpp stream-destinations.conf, Credential Manager vault
src/stream/oauth.cpp Twitch device flow, YouTube loopback + PKCE
src/shaders/ YUV -> RGBA compute shader (+ generated SPIR-V)
tools/probe.cpp headless transport probe / recorder
vendor/imgui/ Dear ImGui 1.91.9b
Live test checklist (streaming builds only)
- Use a throwaway or unlisted channel.
- Settings > Live streaming > Add a destination > Twitch / YouTube / Custom, paste the stream key, Save. (Or sign in: Twitch needs a Client ID from dev.twitch.tv/console; YouTube a Google "Desktop app" OAuth client ID and secret with the YouTube Data API v3 enabled.)
- Pick quality (1080p60 6000 kbps is a good start), click Go live twice.
- Watch the destination rows: Connecting -> Live, kbps, any error text.
- End broadcast; the platform should show the stream ending normally.