SidCK09/TahoeWallpaperSwap
GitHub: SidCK09/TahoeWallpaperSwap
通过逆向工程 macOS Tahoe 航拍壁纸引擎,让用户无需第三方后台应用即可将自定义视频设为系统动态壁纸。
Stars: 0 | Forks: 0
# TahoeWallpaperSwap
**将你自己的视频放入 macOS Tahoe 内置的航拍壁纸播放器中。** 无需在后台运行第三方应用,无需 sudo,无需修改 SIP —— 播放 Apple 无人机航拍素材的同一引擎将播放你的视频片段,包括慢动作定格效果。
为 AI 优先而构建:克隆该项目,在该文件夹中打开 [Claude Code](https://claude.com/claude-code),然后说 *“把这个视频做成我的壁纸。”* 内置的 skill 会教导 agent 整个 pipeline —— 包括脚本无法预料的各种奇怪边缘情况。更喜欢纯终端?`./swap.sh` 可以执行标准路径流程。
## 背景故事
我想要一段动漫片段作为我的桌面壁纸。macOS 拥有一个华丽的动态壁纸引擎 —— 它可以在桌面和屏幕保护程序中播放航拍视频,并在你坐下来工作时减速定格。它只是不允许你输入自己的视频。
那个老把戏 —— 将 `~/Library` 中缓存的 `.mov` 文件替换为你同名文件 —— 已经在互联网上随处可见。但这在 macOS 26 上已经**彻底失效了**。尝试这么做,你会遇到 Tahoe 典型的故障:你的视频在屏幕保护程序中播放*完美*,但当你回到桌面时,壁纸却变成了**永久黑屏**。设置预览:消失。重新选择:无效。只有杀掉壁纸进程才能让它恢复过来 —— 直到下一次运行屏幕保护程序。
我们做了每个人起初都会做的事:认为文件的格式不够像 Apple 官方的。我们匹配了分辨率。匹配了 243 秒的持续时间。匹配了 240 fps 的帧率、精确的 5 秒关键帧间隔、容器 atom 的顺序,甚至匹配了 Apple 下载器写入的扩展属性。**每一次尝试都以同样的方式失败。** 与此同时,真正的 Apple 文件每次都能正常工作。这看起来完全就像 DRM。
但事实并非如此。整个 pipeline 中没有任何验证 —— 没有哈希校验,没有签名,没有任何回传检查。我们通过在系统崩溃的那一刻阅读系统日志发现了这一点:
```
Pause Called → Pause Action: Switch to .beginRampingDown
E Error handling sample: Error Domain=WallpaperExtensionKit.VideoSampleReadingErrors Code=4.
FigVideoQueue: 0 frames enqueued ... Timebase time 296.810, rate 1.00 ← file is 243 s long
```
“黑屏”是一个**失控的播放器**:减速坡度向文件请求某些内容,读取失败并返回 `Code=4`,而 Apple 的状态机没有错误处理路径 —— 播放时钟会永远针对空的帧队列运行。
那么减速坡度到底在请求什么?对真正的 Apple 航拍视频与我们的视频进行的比特流分析:
| | Apple 的航拍视频 | 任何普通编码视频 |
|---|---|---|
| HEVC temporal sub-layers | **5** (15/30/60/120/240 fps 子集) | 1 |
| `tscl`/`tsas` 每采样分组元数据 | 存在 | 缺失 |
**Apple 的航拍视频采用 temporally scalable HEVC。** 引擎通过*逐层遍历 temporal layers* 来减速 —— 日志字面意思是这么写的:`RAMP-DOWN switch from level 1 to level 2` —— 而世上没有任何一款消费级编码器能生成这种结构。每一次 ffmpeg/x265/VideoToolbox 编码都会在同样的采样读取中失败。这就是为什么全互联网的方法同时失效的原因。
修复方法并不需要 scalable 编码器。如果每一帧都被标记为 *base layer*,那么每一个 sub-layer 子集都会解析为所有帧 —— 这完全合法。将约 208 字节的分组元数据从任何真正的航拍视频复制到你的文件中,修改 codec header 中的一个字节,减速功能就能正常工作了。
……只完成了一半。壁纸随后*有时*会变黑 —— 大约有一半的时间,看似是随机的。日志显示,减速结束时的定格画面是通过在 deadline 内,从前一个关键帧解码到确切的停止帧来生成的。在 5 秒 GOP 的第 4.42 秒处停止:勉强赶上了。在 4.6 秒处停止:黑屏。这是一场与硬件解码器的赛跑,硬币落下的位置完全取决于减速坡度碰巧停在哪里。(Apple 从未输掉这场比赛 —— 利用真正的 temporal layers,他们最坏的情况只有约 75 帧。而我们有大约 1100 帧。)将关键帧设为每秒一次、使用 closed GOP,我们就能以 20 倍的余量赢得这场比赛 —— 这在我们能测试的所有定格位置上都得到了验证。
总体的修改代价:一处重新编码设置,一次 AVFoundation remux,208 个嫁接的字节,一个修改的字节。系统的其他部分就只是……默默接受了它。包含日志和十六进制的完整取证分析见:[TECHNICAL.md](TECHNICAL.md)。
## 快速开始
### AI 方式(推荐)
```
brew install ffmpeg # plus Xcode Command Line Tools if you don't have them
git clone https://github.com/SidCK09/TahoeWallpaperSwap
cd TahoeWallpaperSwap
claude # open Claude Code here
```
然后只需告诉它你的需求:
内置的 skill(`.claude/skills/wallpaper-swap/`)会引导 agent 完成探测你的视频、仅修复需要修复的部分、嫁接元数据、验证所有要求、备份原始文件以及执行替换的全部过程 —— 包括各种奇怪的情况:HDR 素材、竖屏视频、需要循环的 10 秒短片,以及不应盲目放大的源文件。当需要做出真正的选择时,它会询问*你*。
### 脚本方式
```
./swap.sh --list # see your cached aerials, with names
./swap.sh myvideo.mp4 # convert only → myvideo-aerial.mov
./swap.sh myvideo.mp4 --install # convert + back up original + swap in
./swap.sh --restore # put Apple's original back
./swap.sh --verify some.mov # check a file against every requirement
```
安装完成后:**系统设置 → 壁纸 → 点击任意其他壁纸 → 重新选择你替换过的那个。**
## 本仓库包含什么
| 文件 | 它是什么 |
|---|---|
| `README.md` | 你正在阅读的这个文件 |
| `TECHNICAL.md` | 完整的逆向工程说明文档 —— 日志证据、比特流差异、GOP 赛跑 |
| `CLAUDE.md` | 当 AI agent 打开此文件夹时自动加载的说明 |
| `.claude/skills/wallpaper-swap/SKILL.md` | AI skill:完整的自适应 pipeline,包含边缘情况处理 |
| `swap.sh` | 脚本化的标准流程(转换 / 列出 / 安装 / 恢复 / 验证) |
| `tools/applemux.swift` | 微型的 AVFoundation remuxer —— 像苹果自带工具那样重新封装你的视频 |
| `tools/tscl_patch.py` | 嫁接工具:将 temporal-scalability 元数据从真正的航拍视频复制到你的视频中 |
## 系统要求
- macOS 26 "Tahoe"(在 26.5.2,Apple Silicon 上构建和测试)
- `ffmpeg`/`ffprobe`(通过 Homebrew 安装)以及 Xcode Command Line Tools(`swiftc` 会在首次运行时编译 remuxer)
- 至少下载了一个航拍视频(系统设置 → 壁纸 → 点击一个航拍视频)—— 它会提供所需的元数据
## 安全性
- 所有内容都位于**你的用户 Library 中** —— 无需 sudo,无需 SIP,不会触及任何系统级文件。
- 原始文件在进行任何替换之前都会备份到 `./backups/`,并且一旦保存就永远不会被覆盖。`--restore` 可执行还原。
- macOS 更新可能会在你的文件上重新下载原始文件。只需再次运行安装即可;你转换后的文件会被保留。
- 如果壁纸出现任何异常行为:`killall WallpaperAerialsExtension WallpaperAgent` —— 进程会自动重启。这能修复*任何*问题。
标签:Cutter, 逆向工具