mirror of
https://github.com/Pixelplanet/Pixel-VR-Player.git
synced 2026-10-25 21:01:32 +01:00
145 lines
5.6 KiB
Markdown
145 lines
5.6 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
./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:
|
|
|
|
```bash
|
|
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):
|
|
|
|
```bash
|
|
./tools/build.sh # configures + builds build/ for host arch
|
|
```
|
|
|
|
aarch64 cross (for the Steam Frame):
|
|
|
|
```bash
|
|
./tools/build.sh --aarch64 # configures + builds build-aarch64/
|
|
```
|
|
|
|
## Deploy to Steam Frame
|
|
|
|
See the full walkthrough in
|
|
[docs/deploy-to-steam-frame.md](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:
|
|
|
|
```bash
|
|
./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:
|
|
|
|
```bash
|
|
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.
|