Skip to content

Port optional libmpv video playback to USCE - #173

Draft
dgruss wants to merge 17 commits into
mainfrom
feature/libmpv-port
Draft

dgruss wants to merge 17 commits into
mainfrom
feature/libmpv-port

Conversation

@dgruss

@dgruss dgruss commented Oct 26, 2026 •

Copy link
Copy Markdown

Problem and resulting behavior

Port the optional libmpv video backend from Tycorc/USDX to USCE for assessment in #164. FFmpeg remains the default. Builds configured with --with-mpv can select MPV in Tools > Options > Graphics, with automatic or software decoding. Missing libmpv and render/open failures retain FFmpeg fallback. Song audio remains on USCE's existing audio clock.

The port includes shared video presentation, renderer-owned offscreen targets, synchronization, startup/seek/EOF fixes, decoder probing and player reuse. USCE-specific sound helpers and current renderer behavior are preserved. No score/config schema migration or release packaging change is introduced.

Validation

Local Ubuntu 26.04.1 x86-64 laptop: Intel Core i7-8550U, Intel UHD Graphics 620/i915, Mesa 26.0.8, FFmpeg 8.0, libmpv 0.41.0.

  • Native debug builds with and without MPV passed.
  • VideoSyncTest passed.
  • Real-renderer integration checks passed on desktop GL, GL2, GLES2 and GLES3: orientation/color, state restoration, pause, seek, looping, EOF, lifetime, configured provider selection, repeated startup and FFmpeg fallback after a forced MPV render-context failure.
  • The native H.264 hardware test selected vaapi-copy.
  • Song loading and real-library song video/audio playback were checked. Graphics selectors were visually checked and their saved values verified using an isolated config.

CPU time during approximately 60 seconds of playback, with the game window at 1920x1080 and a 60 fps cap:

Input Main / FFmpeg MPV software MPV auto Actual auto decoder
H.264/x264 High, 1080p30 51.39 s 32.39 s 31.30 s vaapi-copy
AV1 Main, 1080p (~24 fps) 58.98 s 45.44 s 45.56 s software; AV1 hardware unsupported
HEVC/x265 Main, 720p25 19.77 s 13.90 s 10.55 s vaapi-copy

Mean resident memory:

Input Main / FFmpeg MPV software MPV auto
H.264/x264 307.7 MiB 452.4 MiB 463.8 MiB
AV1 299.6 MiB 464.7 MiB 487.9 MiB
HEVC/x265 276.0 MiB 464.3 MiB 469.5 MiB

These are exploratory single samples, in sequential order, with post-startup windows that are not aligned to precisely identical media timestamps. The inputs differ across codecs/resolutions, so compare modes within each row. CPU includes the whole game. All 60 focus samples were valid in each run; MPV did not fall back to the FFmpeg video provider. The fps cap is a setting, not a measurement of achieved fps. Frame times, dropped frames, long-term sync, microphone input and singing accuracy were not measured. Windows, macOS and Raspberry Pi were not tested.

Review notes

  • Twelve imported commits retain Tycho Schottdorf's original author name, email and author dates. Commit hashes change during porting; each message links the source commit. USCE adaptations are separate commits. Full provenance is in doc/mpv-port-provenance.md.
  • Implementation adaptations and local validation were assisted by OpenAI Codex. This is a draft for human review, not an approval or merge request.
  • MPV stays optional and dynamically loaded. Platform packaging/runtime integration and broader native compatibility still need review. No original song files, normal configuration or score databases were modified; test configurations and scores were isolated.

Latest upstream follow-up: adopted @Tycorc's a090432 with its original authorship. A stream that reaches EOF without rendering a frame now fails promptly. The updated MPV-enabled Windows build and actual hidden-GL video smoke run pass: provider selection, FFmpeg/MPV playback, startup/reuse, missing/corrupt fallback and the no-frame clip. No-frame fallback took 109 ms, below the 3-second test limit and the former 5-second timeout. The smoke runner now keeps its Windows child console hidden while preserving redirected output.

Tycorc and others added 15 commits October 27, 2026 00:27
Keep explicit positioning and loop behavior while suppressing periodic drift seeks past EOF. Cover long final frames and seeking back into range. Remove unused mpv property-query bindings and the dependency script's redundant newline delta against upstream.

Ported-from: Tycorc@a2f9b4b
The sing screen positions the video at the song start and then requests
the bare video gap until its transition finishes. The controller seeked
back to the gap and jumped forward again when the clock arrived, and each
seek blanked the video. Now a video ahead of the clock waits for it, as
the FFmpeg backend does, and an explicit jump seeks only when the player
does not already show that position.

Playback positions arrive once per decoded frame, so a low frame rate
produces a sawtooth that reached the seek threshold every frame. Lag now
has to persist for half a second before a corrective seek.

Observe eof-reached so the final frame is held when the video track ends
before the file's duration or the duration is unknown. Keep drawing the
previous frame while a seek completes, and avoid Max() with an integer
literal, which rounded positions to single precision.

Ported-from: Tycorc@b6b0d16
load-scripts and osc only exist when libmpv was built with Lua or
JavaScript support. Setting them on other builds failed player creation
and silently fell back to FFmpeg for every video.

Ported-from: Tycorc@d154390
libmpv probes every hardware decoder on every open, and each probe creates
a device: nvdec 3.3 s, d3d11va-copy 2.2 s, dxva2-copy 1.6 s, nvdec-copy
4.9 s on an RTX 2080 SUPER. A codec the GPU cannot decode (AV1 on Turing)
reached software decoding after 10 to 12 s, past the 5 s open timeout, so
the song dropped to the FFmpeg backend. A decodable H.264 file still spent
3.4 to 4 s in CUDA device creation on every open because each open created
a new player; the same player opened the next H.264 file in 0.85 s.

Every file now opens with software decoding and switches to the configured
hardware decoding after its first frame, so the open never waits for a
probe. The switch ends with mpv's refresh seek; its PLAYBACK_RESTART reads
hwdec-current and stores it per video codec for the session, so later
files of that codec request that decoder directly, or stay in software when
the GPU cannot decode the codec. One idle player survives Close: it is
stopped, reset to paused software decoding, drained of its END_FILE, and
reused by the next Open together with its render context and decoder
devices. mpv sends no change event for an observed value equal to the
previous file's, so the dimensions, duration and decoder are read directly
once playback has started.

The smoke test opens the fixture five times with automatic decoding; the
runner requires one probe per session, a remembered decoder and a reused
player. Passed locally on gl and gl2 under Xvfb.

Ported-from: Tycorc@3f0c706
The startup test switched software runs to automatic decoding to exercise
the decoder memory. The native software comparison then saw nvdec and
failed its no-hardware contract on gamertyc. The test now keeps the
requested mode: software runs must reuse the player without probing, and
automatic runs must probe once and reuse the remembered decoder. CI adds
an automatic-decoding run so the decoder memory stays covered.

Ported-from: Tycorc@dfb8082
Preserve USCE sound helpers and program naming; expose backend and hardware decoding choices with English help. Carry the video test workflow with the pinned checkout action. Record upstream provenance.

AI-assisted-by: OpenAI Codex (implementation adaptation and local validation)

dgruss commented Oct 26, 2026

Copy link
Copy Markdown
Author

@Tycorc, thanks for the work. Codex-assisted local testing of the USCE port on my Ubuntu laptop looks good so far for playback and layout. The 12 imported commits still have your original author name and dates, and GitHub maps them to your account. USCE adaptations are separate commits.

Whole-game CPU time over approximately 60 seconds of playback:

Input Main / FFmpeg MPV software MPV auto
x264, 1080p30 51.39 s 32.39 s 31.30 s
AV1, 1080p (~24 fps) 58.98 s 45.44 s 45.56 s
x265/HEVC, 720p25 19.77 s 13.90 s 10.55 s

Intel i7-8550U / UHD Graphics 620, Ubuntu 26.04.1, Mesa 26.0.8, 1920x1080 game window, 60 fps cap. H.264 and HEVC auto selected vaapi-copy; AV1 auto stayed in software. MPV used more memory; the full memory table and test limits are in the PR description. These are single samples, not an achieved-fps or frame-time benchmark, and different inputs/resolutions prevent a codec-to-codec comparison.

Paired native framebuffer captures using the same generated 1080p H.264 pattern and pinned Modern theme:

Screen Main / FFmpeg MPV
Video preview Main video preview MPV video preview
Singing Main singing MPV singing

Orientation, cropping and UI placement match in these captures. The color bars do expose a color-conversion difference between providers, so I would not call them pixel-identical. Matrix/range handling still needs review. The images are unretouched captures from a dedicated display/screen-API test harness; no original library artwork or music was uploaded. See capture provenance and limits. Microphone input and singing accuracy were not tested.

dgruss commented Oct 26, 2026

Copy link
Copy Markdown
Author

@codex review

Please check the optional/default provider selection and FFmpeg fallback, graphics-state restoration, color-matrix/range differences visible in the paired captures above, audio-clock synchronization through startup/pause/seek/EOF, resource ownership and multiple graphics contexts, and cross-platform build compatibility.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T21:16:15.588728Z 1803fba Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: d759794b8b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dgruss

dgruss commented Oct 27, 2026

Copy link
Copy Markdown
Author

Green looks marginally different.

dgruss commented Oct 28, 2026

Copy link
Copy Markdown
Author

One newer delta from @Tycorc is still missing here: a0904322.

With keep-open, a file that reaches clean EOF without rendering a frame can stay in the startup loop until the 5-second deadline. The fix exits when fFileLoaded, fPlaybackStarted and fEndReached are all true, so FFmpeg fallback can start sooner. It also adds a smoke test using an H.264 clip without its IDR slice.

The condition and test are absent at d759794. This is a remaining port delta from #235; it has not been applied or tested in USCE yet.

Tycorc and others added 2 commits October 29, 2026 21:46
With keep-open, libmpv holds a cleanly ended file instead of sending
END_FILE. A video stream that loads and starts but never yields a
decodable frame therefore waited the full 5 s open timeout before the
FFmpeg fallback took over. Fail as soon as eof-reached is set after the
playback restart and no frame has rendered.

The video smoke test generates an H.264 clip without its IDR slice and
checks that libmpv gives up on it in under 3 s.

(cherry picked from commit a090432)

dgruss commented Oct 29, 2026

Copy link
Copy Markdown
Author

@codex review

Please review current head 1803fba3 after adopting Tycorc's no-frame EOF fix and correcting Windows smoke-output capture. MPV-enabled Windows build and the full hidden native video smoke test pass, including a 109 ms no-frame fallback.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 1803fba378

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dgruss dgruss added the needs testing Needs targeted gameplay, visual or platform testing before merging. label Oct 29, 2026 — with ChatGPT Codex Connector

dgruss commented Oct 29, 2026

Copy link
Copy Markdown
Author

#264's newer Tycorc snapshot adds 56ea7d9b: the Windows benchmark retains the process handle before playback and disposes it only after post-exit CPU accounting. Otherwise TotalProcessorTime can disappear after exit. Include this when adopting or running that benchmark; do not interpret failed CPU accounting as a performance result. The other newer commits merge upstream PrintScreen/completion changes already covered in USCE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs testing Needs targeted gameplay, visual or platform testing before merging.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants