cmux-next: video backgrounds fade in and free their decoder when out of sight

Merged
TE
18d ago
+186-16

Phase 2 of the backgrounds plan (briefs/next-backgrounds-plan.md): video background playback.

What changes

  • Fade in. A video's first frame fades in over its poster (Motion fade token fadeIn) instead of cutting from the still. Frames that stop, such as a released decoder, still hide at once, which leaves the poster underneath.
  • Free the decoder when nobody can see the video. BackdropVideoPlayers now tracks which windows could be seen at all (BackdropVideoView.canBeSeen): on screen, not minimized or app-hidden, not covered by other windows, screens awake, session active.
    • When no window showing a video could be seen for releaseAfter (60 s), the shared player:
      • saves its time
      • disables looping
      • drops its items, which frees the hardware decoder and its frame buffers
    • When a window can be seen again, it rebuilds the looper on the same AVQueuePlayer and seeks to the saved frame, so the windows' layers keep their player.
    • The deadline starts when the last viewer goes out of sight. Updates while hidden don't push it back.
  • Videos paused but still on screen keep their decoder. That covers Low Power Mode, a hot Mac, and Reduce Motion or animations off. Their frame never drops to the poster in front of someone.
  • Not needed: poster caching. BackdropImageStore already snapshots a video's first frame on first decode, so launches reuse it. I've dropped that item from the plan.

Tests

In CmuxNextAppTests/VideoWallpaperTests:

  • aVideoNoOneCanSeeGivesBackItsDecoderAndPicksUpWhereItWas: a video held for Low Power keeps its items. A hidden one releases them, comes back on the same player when seen, and plays.
  • theDecoderGoesOnlyAfterTheDeadline: the release waits for releaseAfter, and updates while hidden don't reset it.

Verification

  • Not built locally: this lane has no Mac. Swift compile and tests are left to this PR's CI.
  • lint-ios-package-conventions.sh: clean.
  • CmuxNextApp source lines are unchanged (84323).
  • Not dogfooded. To try it with a dev-build: pick a video background, hide cmux for over a minute, then show it again. The video should come back at the same frame and fade in.

WINDOW

None.

Changelog

Changed: Video backgrounds fade in, and stop using video memory while no one can see them.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Video backgrounds in cmux-next now fade in over their poster and free their hardware decoder when no one can see them.

  • The first frame fades in over the poster instead of cutting; a frame that stops (a released decoder) goes away at once, leaving the poster below.
  • When no window showing a video can be seen (hidden, minimized, covered, screens asleep, or the session inactive) for releaseAfter (60 s), the shared player saves its position, drops its items, and frees the decoder and its frame buffers.
  • When a window is seen again, the player rebuilds the looper on the same AVQueuePlayer and, once the new item is ready, seeks to the saved frame with zero tolerance, so layers keep their player and the video resumes at the exact frame it held.
  • The release deadline starts when the last viewer goes out of sight; updates while hidden don't push it back, and it is timed by an injectable clock.
  • Videos paused on screen (Low Power Mode, a hot Mac, Reduce Motion) keep their decoder so their frame never drops to the poster.