2 个版本

0.1.1 2020 年 6 月 12 日
0.1.0 2020 年 6 月 8 日

#130渲染

MIT 和可能 LGPL-2.0

78KB
2K SLoC

Xfbs 播放器

想法是写一个工具,我可以用来创建关于编程的视频。它应该能够接受一个脚本(定义所有场景,包括动画、文本、代码输入、终端会话回放、背景音频、前景音频(旁白),每个场景或时间偏移等。

  • 文本
  • 动画
  • 代码输入
  • 终端会话回放
  • 背景音频
  • 前景音频(旁白),每个场景或时间偏移

这应该可以在 Gtk 播放器应用程序中回放以供审查,或者进一步处理成视频文件(任何所需格式)。还应支持 CLI,并加载预先解析的序列化数据结构。

基础应该围绕一个包含音频(带有时间索引)以及动画(带有类型、参数、Z 值和时间索引)的数据结构。然后播放器将遍历此数据结构,并生成它看到的东西。

数据结构必须能够支持分数时间,以便可以将帧率设置为所需的任何值(24、30、60、最大帧率)。

脚本语言(REPL)

声音?

  • 可能需要支持 AAC 和 Vorbis(用于 mp4 和 webm)
  • 需要一些库可以处理任意声音的解码、混合以及重新编码回某种格式。

视频生成?

  • 某种类型的 h.264 编码器以及 webm?

动画?

  • cairo 和 gtk,结合在一起

二进制格式?

  • 能够运行脚本,创建所有数据结构,然后使用 serde 将其序列化到某种可以共享的格式中。

语法高亮器?

  • ???

功能

  • 重点:ffmpeg 编码
  • 重点:ttyrec 播放
  • 重点:LaTeX 支持?
  • 重点:文本输入
  • 重点:淡入淡出
  • 将一切从 box 迁移到 rc(尽管它在序列化期间没有帮助)
  • 完成音频实现
  • 完成动画实现
  • 使用 HSLuv 或类似的东西进行背景颜色渐变?
  • 加载并显示图像
  • 实现包装类型
  • 实现斜体等
  • 实现自定义颜色方案
  • TEX 显示(通过 svg 渲染?)
  • 使用 mathjax 和 quick-js 的简单数学显示?
  • 音频编码
  • 屏幕上显示位置
  • 延迟 png 渲染
  • 渲染为JPEG
  • 渲染为APNG
  • 渲染为webm
  • 渲染为mp4
  • 实现其他缓动函数
  • 淡入
  • 可渲染项目组
  • CI测试
  • 为可绘制对象编写单元测试
  • 为动画对象编写单元测试
  • 自定义缓动函数
  • 实现场景
  • 使用resvg显示SVG
  • 渲染为GIF
  • 移动正弦波(?)
  • 移动三次方
  • 移动二次方
  • 实现音频架构
  • 使高亮延迟加载
  • 使高亮返回错误
  • 修复解析速度慢的问题
  • 使颜色方案延迟加载
  • 音频解码
    • mp3解码
    • wav解码
    • ogg解码
  • 使用rodio播放音频
  • 实时播放控制
  • 暂停、恢复
  • 动画
    • 线性移动
    • 平滑移动
  • 使彩色文本可缩放
  • 使用crate显示源代码(高亮)
  • 实现新架构
  • 脚本语言接口
  • 文本显示
  • 彩色文本显示
  • 渲染为PNG
  • 实时播放
  • 设置背景颜色
  • 为特质提出新架构

用法

您将“电影”作为rhai脚本编写。它看起来像这样

let movie = movie();

let bg = background(...);

movie

您可以使用编译子命令将此脚本编译成电影(使用自定义二进制格式)。

$ xfpl compile script.rhai -o movie.xfpl

这会生成一个.xfpl二进制文件,您可以使用播放子命令来播放它。

$ xfpl play movie.xfpl

为了方便,可以省略编译脚本,并使用--parse标志告诉播放器自行解析脚本。

$ xfpl play --parse script.rhai

最后,可以使用render子命令将电影导出为视频文件。

$ xfpl render script.rhai --format apkg --output out.png --resolution fullhd

请注意,这可能需要一些时间,通常使用播放器观看会更好。

我想实现自己的自定义绘图函数

您需要决定您是要绘制静态内容还是动画内容。如果您想绘制静态内容(即,不改变的内容),您需要实现Drawable特质。例如

struct MyDrawing;

impl MyDrawing {
    pub fn new() -> MyDrawing {
        MyDrawing
    }
}

#[typetag::serde]
impl Drawing for MyDrawing {
    pub fn draw(&self, context: cairo::Context) {
        // draw
        context.set_source.rgba(1.0, 0.0, 1.0, 0.5);
        context.move_to(0.1, 0.1);
        context.draw();
    }

    pub fn size(&self) -> Size {
        Size::new(0.1, 0.1)
    }
}

draw()函数中,您可以基本上调用任何Cairo绘图函数。如果您将要调用会改变上下文的内容,您应该在保存/恢复块中包装您的绘图代码,如下所示

context.save();
// your code here
context.restore();

否则可能会破坏某些东西。size()函数应返回您所绘制的任何内容的大小。

如果您注意到您实际上想要绘制的是动画内容,那么您需要实现的是Animated特质。这与Drawable特质类似,但在绘制时,它会获取当前的时间戳,具有持续时间,并且可以播放音频文件。

依赖项

~30–41MB
~722K SLoC