闲聊时刻

前两天跟朋友聊天,说到视频转格式这事儿,大家第一反应都是"用FFmpeg呗"。确实,FFmpeg这玩意儿就像视频界的瑞士军刀,什么都能干,谁家电脑里没装过?

但你知道这玩意儿背后是用什么写的吗?C语言。而且年代相当久远,代码量巨大,那个架构复杂得跟老城区的电线似的,乱糟糟但能跑。

ffmpReg项目封面,展示Rust多媒体开发的未来愿景

最近有个叫Ajay Kumar的小伙子,才21岁,干了件挺疯狂的事——他决定用Rust从零重写FFmpeg。项目名叫ffmpReg,听着就像"FFmpeg注册表"什么的,挺好玩。

我第一反应是:这孩子是不是闲得慌?

为什么要重写一个轮子

说实话,看到这个项目的时候我脑子里也是一堆问号。FFmpeg不是好好的吗?修修补补不就行了?

但听人家说完理由,我好像有点理解了。

多媒体处理这事儿,本质上就是个"完美风暴":低延迟IO、位运算那堆脏活累活、解析器必须安全可靠、性能要求还贼高。这四样凑一块,简直就是程序员的噩梦。

但Rust恰恰就擅长这些:内存安全不用GC,并发编程不用怕,组件组合起来跟积木似的。你说这不是天作之合是什么?

Rust多媒体管道设计架构图

ffmpReg到底是个啥

先说清楚,ffmpReg不是那种薄薄一层包装FFmpeg的库。人家是从头开始,纯纯的Rust实现。

想象一下,整个处理流程就像一串乐高积木:解复用、解码、转换、编码、再复用,每一步都是独立的"积木块",想怎么拼就怎么拼。这比FFmpeg那种"上帝函数"式的架构清爽多了。

目前能干啥

这小伙才搞了五周,但已经有点样子了:

WAV格式转换已经能跑通端到端了,pcm_s16le、pcm_s24le、pcm_f32le这些格式随便互转。

MKV解析做了一半,容器信息、编码格式、时间基准元数据这些都能读出来了。

下一步就是把容器支持做完整,MKV、MP4、WAV、AIFF这些主流格式都拿下。

代码长啥样

给你看个小例子,WAV采样格式转换:

// s16转f32转换
ffmpreg convert input.wav --to pcm_f32le -o out.wav

底层实现是这样的:

use ffmpreg::audio::{Frame, SampleFormat, convert};

fn s16_to_f32(frame: Frame<i16>) -> Frame<f32> {
    convert::pcm_s16_to_f32(&frame)
}

看着还挺清爽的对吧?

再看个MKV文件信息查询:

ffmpreg inspect video.mkv

输出大概这样:

Container: Matroska (EBML v1)
Duration: 00:04:12.345
Streams:
[0] Video  av1  timebase=1/1000  size=1920x1080
[1] Audio  opus timebase=1/48000  ch=2  layout=stereo

ffmpReg命令行工具运行截图

设计理念挺有意思

这小伙的设计目标有几个挺亮眼的:

内存安全第一:解析器里不能有那些未定义行为的幺蛾子。Rust的借用检查器和模式匹配能直接干掉一整类bug。

零拷贝:该省的地方省,I/O切片用&[u8]和Bytes,数据包生命周期用arena管理。

性能确定性:热循环里不能有意外的内存分配,啥时候分配啥时候释放心里要有数。

可组合的图结构:每个处理阶段都是trait对象或者泛型,支持背压,类型明确。

按需启用:编码器和容器都可以feature-gated,要啥开啥,保持二进制文件精简。

时间戳处理的小细节

多媒体代码最容易出问题的就是时间戳。 ffmpReg直接把它搞成了头等类型:

#[derive(Copy, Clone)]
pub struct Timebase {
    pub num: u32,
    pub den: u32,
}

#[derive(Copy, Clone)]
pub struct Timestamp {
    pub pts: i64,
    pub tb: Timebase,
}

impl Timestamp {
    pub fn to(&self, dst: Timebase) -> Timestamp {
        // 精确的有理数转换,带溢出检查
        let num = (self.pts as i128) * (self.tb.num as i128) * (dst.den as i128);
        let den = (self.tb.den as i128) * (dst.num as i128);
        Timestamp { pts: (num / den) as i64, tb: dst }
    }
}

这就避免了那种"我想想…这是毫秒还是别的啥"的尴尬情况。

和FFmpeg比到底差在哪

说实话,FFmpeg那是老江湖了,经过无数次实战检验。ffmpReg想取代它,路还长着呢。

但ffmpReg追求的是一种不同的路子:Rust优先的人体工学设计,小巧可审计的组件,可预测的构建流程。这跟FFmpeg那种"C API + 全局状态 + unsafe边边角角"完全是两种哲学。

我的看法

重写一个FFmpeg这种级别的项目,听起来确实挺疯狂的。但有时候,正是因为有人敢于去做这些"不理智"的事情,技术世界才会有新的可能性。

对于Rust社区来说,ffmpReg不管最后能不能成,都是一次有价值的尝试。它证明了Rust在多媒体领域的可行性,也为后来者铺了一段路。

而且你看,人家才21岁,刚搞了五周就已经有东西能跑起来了。谁知道一年后会发生什么?

下一步计划

从项目的路线图来看,接下来要做的包括:

MKV的完整性:blocks、lacing、cues、seeking、元数据这些都要补齐。

音频必备功能:重采样、声道映射、抖动、PCM和float的完美转换。

容器支持:MP4/ISOBMFF的解复用和复用,WAV/AIFF的完善。

编解码器:FLAC解码、Vorbis解码、Opus、AV1编码这些。

CLI用户体验:convert、inspect、probe、transcode这些子命令,JSON输出,进度条。

测试套件:fuzz测试、golden vectors、和参考工具交叉验证。

写在最后

ffmpReg是不是"又一次重写轮子",现在下结论还太早。但有一点可以肯定:在多媒体这个领域,Rust正在悄悄证明自己的价值。

如果你对音视频处理感兴趣,或者单纯想看看一个21岁的小伙能搞出什么名堂,可以去关注一下这个项目。就算最后没成,这个过程本身也够精彩的。


觉得这篇文章对你有帮助吗? 点赞 + 在看,让更多朋友看到这篇内容。分享给正在学习 Rust 或音视频开发的小伙伴,关注公众号「梦兽编程」,获取更多技术干货。我们下期见!