Pixel VR Player

A native VR video player for the Valve Steam Frame, playing flat 2D, 180°, and 360° video (mono and stereoscopic 3D) from local storage and the local network.

  • Platform: SteamOS (Arch Linux, ARM64) on Snapdragon 8 Gen 3
  • Stack: C++20 · OpenXR (SteamVR runtime) · Vulkan · FFmpeg (V4L2 M2M HW decode)
  • Targets: native Linux x86_64 (for SteamVR-streamed desktop dev) and aarch64 (on-device, run directly on the SteamOS host)

Status: Playable core. OpenXR + Vulkan per-eye rendering; hardware video decode (h264_v4l2m2m / hevc_v4l2m2m → NV12) with GPU YUV→RGB conversion; flat / 180° / 360° projection and mono / SBS / TB stereo, auto-detected from the filename; PulseAudio/PipeWire audio on desktop. Transport UI and controller input are next.

Repository layout

src/
  util/      logging, math, small helpers
  xr/        OpenXR instance/system/session, swapchains, frame loop, input
  gfx/       Vulkan device (from OpenXR), render pass, pipelines, per-eye render
  scene/     projection meshes (flat / 180 hemisphere / 360 sphere), stereo material
  media/     demux + decode, frame queue, A/V clock, audio out   (Phase 2+)
  ui/        in-VR panel: file/library browser, transport, settings  (Phase 2+)
  sources/   local FS + SMB/DLNA/HTTP media sources                 (Phase 4)
  app/       app lifecycle, config, wiring
shaders/     GLSL sources compiled to SPIR-V at build time
cmake/       toolchain + shader-compile helpers
tools/       build & deploy scripts

Prerequisites (Linux build environment)

On Windows, use WSL2 (Ubuntu 22.04+) or a Linux container. Install:

sudo apt update
sudo apt install -y build-essential cmake ninja-build git pkg-config \
    libvulkan-dev vulkan-tools glslang-tools spirv-tools \
    libx11-dev libxrandr-dev libxxf86vm-dev mesa-common-dev libgl1-mesa-dev \
    libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev

The OpenXR loader is fetched and built from source via CMake FetchContent, so no system OpenXR package is required. It is built statically into the executable (no libopenxr_loader.so to ship) and configured for the xlib presentation backend only (XCB/Wayland disabled), so the libx11/mesa headers above are the only windowing dependencies needed to build it.

On WSL, VS Code cannot answer sudo's password prompt; run apt as root instead: wsl -u root -- apt-get install -y ....

aarch64 cross-compilation

Two options, in order of runtime reliability:

  1. Device sysroot (recommended). Capture the headset's own libraries so the binary links against the exact FFmpeg / Vulkan / X11 SONAMEs it will load:

    ./tools/fetch-sysroot.sh steamos@frame        # rsyncs into ./sysroot
    PIXELVR_SYSROOT="$PWD/sysroot" ./tools/build.sh --aarch64
    
  2. Debian/Ubuntu arm64 multiarch (quick validation). Enable the arm64 ports archive and install the :arm64 -dev packages, then build without a sysroot:

    sudo dpkg --add-architecture arm64
    # add http://ports.ubuntu.com/ubuntu-ports/ as an arm64 source, then:
    sudo apt-get update
    sudo apt-get install -y g++-aarch64-linux-gnu \
        libavcodec-dev:arm64 libavformat-dev:arm64 libavutil-dev:arm64 \
        libswscale-dev:arm64 libswresample-dev:arm64 \
        libvulkan-dev:arm64 libx11-dev:arm64 libxrandr-dev:arm64 libxxf86vm-dev:arm64
    ./tools/build.sh --aarch64
    

    Ubuntu's arm64 FFmpeg may differ in SONAME from the headset's; if the app fails to load a library on-device, use the sysroot path above. Audio (libpulse-dev) is omitted here because its glib dev chain is not co-installable across architectures — the sysroot build restores it.

Build

Native (desktop, for SteamVR-streamed iteration):

./tools/build.sh            # configures + builds build/ for host arch

aarch64 cross (for the Steam Frame):

./tools/build.sh --aarch64  # configures + builds build-aarch64/

Deploy to Steam Frame

See the full walkthrough in docs/deploy-to-steam-frame.md (options, runtime choice, and troubleshooting). In short, after a one-time Developer-Mode pairing:

  • GUI (easiest to start): ./tools/stage.sh to assemble dist/PixelVRPlayer/, then upload it in the SteamOS Devkit Client (Runtime: Steam Linux Runtime 3.0 ARM64 (Sniper), Start Command: pixelvr).

  • CLI (easiest to iterate): one command copies the binary + shaders and launches it in the headset:

    ./tools/deploy.sh --launch -- /home/steamos/Videos/clip_360_tb.mp4
    # override the target with --host steamos@<ip> or FRAME_HOST
    

Either way the app appears in Steam ▸ Library ▸ Non-Steam as Devkit Game: PixelVRPlayer. To run it manually over SSH for debugging:

ssh steamos@frame '~/devkit-game/PixelVRPlayer/launch.sh /path/to/video.mp4'

Test on device

Projection and stereo layout are inferred from the filename, so name test clips accordingly (or pass a plain 2D clip for flat playback):

Filename contains Projection Stereo
...360..., _sbs/_lr 360° side-by-side
...180.../vr180, _tb/_ou 180° top-bottom
(none) flat 2D mono

Requirements and tips:

  • 8-bit H.264 or HEVC with even width/height (4:2:0). 10-bit / Main10 is not supported by the V4L2 M2M decoder path.
  • PIXELVR_FORCE_SW=1 forces software decode (useful for debugging).
  • PIXELVR_LOG=debug raises log verbosity.

License

TBD.

S
Description
GitHub pull mirror of Pixelplanet/Pixel-VR-Player. GitHub repository ID: 1404618068.
https://github.com/Pixelplanet/Pixel-VR-Player Readme
39 MiB
0 Stars 1 Watchers 0 Forks
v1.5.0
Latest
2026-10-19 01:01:30 +02:00
Languages
C++ 87.3%
Shell 4.8%
GLSL 3.5%
Python 2.3%
CMake 1.6%
Other 0.5%