2swap/swaptube
GitHub: 2swap/swaptube
基于 FFMPEG 和 GPU 加速的视频渲染项目,旨在提供可脚本化的时间控制与自定义渲染能力。
Stars: 1501 | Forks: 69
# SwapTube
这是我用来渲染[我的YouTube视频](https://www.youtube.com/@twoswap)的仓库。
SwapTube 基于 FFMPEG 构建,但视频和音频编码层之上的大多数功能都是自定义实现的。该项目不使用任何复杂的图形库,仅对特定功能有一些例外。
# 教程视频
[](https://www.youtube.com/watch?v=paqBduieRks "SwapTube 教程视频")
# 学习 SwapTube 的 Discord 服务器
https://discord.gg/a786NZXYQ3
# 兼容性
SwapTube 已在多个 Linux 发行版上开发并测试可以编译和运行。MacOS 和 Windows 未经测试。
有一个实验性的 Windows/MSVC 构建版本存在于一个 fork 中:[meghanto/swaptube](https://github.com/meghanto/swaptube)。它在此处不受官方支持,可能落后于 `master`,并且不保证持续维护。
SwapTube 最初设计为仅与 CUDA 配合使用,需要 NVIDIA GPU。现在应该可以使用 HIP 在 AMD 上运行。此功能是新的,可能存在错误。如果使用 HIP 替代 CUDA,需要安装 AMD ROCm。请按照[此指南](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/install/quick-start.html)安装 ROCm 和 HIP。
请注意,HIP 文件夹是在支持 HIP 的机器上通过将 CUDA 文件夹翻译(hipify)生成的。不要修改 HIP/ 文件夹中的任何内容,而是将 CUDA 文件夹视为真实源文件并修改它。它将在 CMake 中重新翻译。
如果你没有支持 CUDA 或 HIP 的 NVIDIA 或 AMD GPU(即集成显卡或 Intel Arc),你将无法运行使用 CUDA 的项目。CUDAFreePendulumDemo 可能无需硬件支持即可运行。
如果 CUDA 或 HIP 未正确安装(例如,Cuda 版本与现有硬件不兼容),在没有支持硬件的机器上运行 MandelbrotDemo 等项目可能会完全显示黑色或灰色。
## 安装设置
### 外部依赖
以下外部依赖项用于项目中的特定功能。如果你想使用相关功能,必须安装这些依赖项。
| 项目 | 用于什么功能? | 使用位置? | 使用方式? | 示例 Ubuntu 安装命令 |
|------------|---------|---------|----------------|--------------|
| CMake 和 Ninja | 所有功能 | go.sh 脚本 | 编译项目 | `sudo apt install cmake` |
| FFMPEG 5.0 或更高版本及相关开发库 | 所有功能 | audio_video 文件夹 | 编码和处理音视频流 | `sudo apt install ffmpeg libswscale-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libavfilter-dev` 注意:从源码编译 ffmpeg 时,可能会根据系统检测到的功能进行编译,而这些功能并未包含在我的 CMake 配置中。建议安装预编译的二进制包。 |
| CUDA 或 HIP/ROCm | 计算密集型图形 | 视频渲染循环 | 各种 | 硬件相关 |
| gnuplot | 调试图表生成 | DebugPlot.h | 将输出/ 下的数据渲染为 PNG | `sudo apt install gnuplot` |
| MicroTeX | 视频中的 LaTeX、LatexScene | visual_media.cpp | 将 LaTeX 公式转换为 SVG 文件以进行渲染 | 参见:https://github.com/NanoMichael/MicroTeX/ 你应该在 MicroTeX-master 目录下安装 MicroTeX,与 swaptube 检出目录并列。会打印安装说明(如果未找到)。 |
| RSVG 和 GLib | 视频中的 LaTeX | visual_media.cpp | 加载并渲染 SVG 文件为像素数据 | `sudo apt install librsvg2-dev libglib2.0-dev` |
| Cairo | 视频中的 LaTeX | visual_media.cpp | 将 SVG 文件渲染到 Cairo 表面并转换为像素数据 | `sudo apt install libcairo2-dev` |
| LibPNG | PNG 场景 | visual_media.cpp | 读取 PNG 文件并转换为像素数据 | `sudo apt install libpng-dev` |
| nlohmann/json | 在 I/O 中读写 JSON 文件 | Connect 4 数据结构、GraphScene | GraphScene 可以将图表写入磁盘为 JSON,Connect 4 稳定状态和计算缓存从 JSON 读取 | `sudo apt install nlohmann-json3-dev` |
## Docker 设置
如需包含所有依赖项的容器化部署,请参阅 [docker/README.md](docker/README.md)。这是可选的,由社区为 Docker 用户创建。我(2swap)个人不使用或维护它。
# 如何运行
当你创建了项目文件 `Projects/yourprojectname.cpp` 后,可以通过执行以下命令编译并运行整个项目:
```
./go.sh yourprojectname 640 360 30
```
一些示例代码和演示可以在 `src/Projects/Demos/` 中找到。如何运行一个演示(在项目根目录运行代码):
```
./go.sh LoopingLambdaDemo 640 360 30
```
这表示分辨率为 640x360、帧率为 30FPS。Swaptube 默认音频采样率为 48000 Hz——如果需要更改,请在 `go.sh` 和 `record_audios.py` 中指定。
# 测试
你可以通过运行 `./test.sh` 来验证本地安装,该脚本会编译并对每个“Demo”项目(位于 `src/Projects/Demos/`)进行冒烟测试而不进行渲染。
# 仓库结构
### 顶级文件和文件夹
- **src/**:源代码文件夹结构在其中的 readme 中有详细说明。
- **out/**:包含 Swaptube 生成的输出文件(视频、对应的字幕文件、数据表格和 gnuplot)。
- 每个子文件夹对应一个项目,项目下每个渲染结果存储在一个以时间戳命名的独立文件夹中。
- **media/**:存储项目使用的输入媒体文件。这包括脚本录音、生成的 LaTeX、源 MP4 和源 PNG。
- 你不应该需要手动修改此处的任何内容,除了放置源 PNG 和 MP4 文件。音频应使用 `record_audios.py` 在渲染项目后录制。
- `Some_Project/`:将你的项目媒体文件放在这里。
- `record_list.tsv`:程序渲染项目后会生成此文件,并被 `record_audios.py` 脚本读取,以便你可以批量录制音频脚本。
- **build/**:包含编译后的二进制文件,最重要的是编译结果。缓存和其他中间产物也可能存储在此,例如发现的 Connect 4 稳定状态和图表,以及 CMake 缓存等。你不需要进入此文件夹,应使用 `go.sh` 脚本启动构建。
- **record_audios.py**:读取 `record_list.tsv` 文件并允许你快速录制所有视频脚本的音频文件。
- **go.sh**:程序入口点!它编译、冒烟测试并运行你的项目文件,可指定分辨率和帧率。
- **play.sh**:播放最近一次渲染的视频(需提供项目名称)。
- **test.sh**:编译并对所有的演示项目进行冒烟测试。
# 设计理念
### 时间控制
Swaptube 使用两层时间组织系统。在最高级别,视频被划分为 Macroblocks(宏块),可以将其视为音频的原子单位。实际上,一个 Macroblock 通常对应脚本中的一个句子。Macroblock 被细分为 Microblocks(微块),它们代表控制视觉变换的原子时间单位。通常一个 Macroblock 只包含一个 Microblock,但更复杂的 Macroblock 可能包含多个 Microblock,以允许在 Macroblock 持续时间内进行视觉过渡或动画。
这种划分允许用户使用内联脚本定义视频,使得 SwapTube 能够管理所有时间控制,而用户无需手动为每个视频片段计时。
此外,这还支持原生过渡:因为过渡发生在 Macroblock 或 Microblock 期间,Swaptube 知道过渡持续的时间,并能通过 State 自动管理过渡过程。
##### Macroblocks(宏块)
存在几种类型的 Macroblock:FileBlocks、SilenceBlocks、GeneratedBlocks 等。FileBlocks 由 media 文件夹中音频文件的路径定义。
SilenceBlocks 由持续时间(秒)定义,GeneratedBlocks 由项目文件中生成的缓冲音频样本数组定义。
可以使用以下方式创建一个 Macroblock:`yourscene.stage_macroblock(FileBlock("youraudio_no_file_extension"), 2);`,这会将 Macroblock 设置为包含 2 个 Microblock。
##### Microblocks(微块)
在 Macroblock 调用 `stage` 方法并设置 `n` 个 Microblock 后,项目文件将通过对 `yourscene.render_microblock();` 的 `n` 次调用来渲染每个 Microblock。请务必调用该函数 `n` 次,否则 SwapTube 会失败退出。
### 冒烟测试
为了确保时间控制定义正确(渲染了适当数量的 Microblock)并且项目文件定义不会在运行时崩溃(不触发可能耗时数小时的完整渲染),Swaptube 提供了“冒烟测试”功能。默认情况下,每次运行 Swaptube 都会执行冒烟测试。
冒烟测试期间会发生以下操作:
- 为每个 Microblock 阶段渲染一帧
- 正常修改 DataObjects
- 正常执行 State 过渡以测试状态方程定义的有效性
- 重新生成 record_list.tsv 文件,以便你可以在冒烟测试后录制音频脚本,而无需完整渲染
- 使用单帧时间生成字幕(时间戳不正确,反映每个 Microblock 一帧的时序)
以下操作**不会**在冒烟测试期间发生:
- 不进行视频或音频编码或渲染
- 由于没有实际渲染,不会绘制偶尔的帧到标准输出
- 忽略视频宽度、高度和帧率,除非它们影响状态方程和 DataObject 修改
你可以通过运行 `./go.sh MyProjectName 640 360 -s`,使用 `-s` 标志表示“仅冒烟测试”。使用此标志将跳过冒烟测试后的完整渲染。
此外,还有一个可切换的布尔变量 `FOR_REAL`,可以在项目文件中将其设为 true 或 false,从而在真实渲染和冒烟测试模式之间切换。这允许你在开发视频最后一部分时,无需每次都重新渲染开头部分。
### 场景、状态与数据
单个帧的数据结构由三部分组成,从本质上区分其性质:
- **Scene(场景)**:Scene 是用户在项目文件中构建的对象。它从根本上定义了**要渲染什么**。例如,MandelbrotScene 负责渲染曼德布罗特集合。
- **State(状态)**:State 可视为 Scene 用于渲染特定帧的所有数值信息。这控制诸如对象的透明度,或以 Mandelbrot 为例的缩放级别等属性。所有 Scene 都包含一个 StateManager,用户修改 Scene 状态时,可以通过调用 StateManager 上的函数来实现。通常是 `set` 和 `transition` 调用。因为 State 仅包含数值信息,Swaptube 会处理所有状态的平滑过渡。
- **Data(数据)**:Data 是 Scene 需要记住的非数值状态信息。一个典型例子是 LambdaScene,它绘制 Tromp Lambda 图表,并将特定的 lambda 表达式存储为数据。类似地,GraphScene 需要状态化地跟踪一个包含节点和边的 Graph。这类信息是非数值的,不能简单地进行插值过渡,因此必须通过 Scene 与 DataObject 之间定义的接口,将其保存在 DataObject 中。
标签:AMD GPU, Bash脚本, CUDA, DNS解析, FFmpeg, HIP, NVIDIA GPU, Shader, Vectored Exception Handling, YouTube视频渲染, 图形渲染, 媒体工具, 开源项目, 自定义渲染, 视频合成, 视频处理, 视频播放器, 视频渲染, 音视频编码, 高性能计算