所有格式页面 ↓
图形与媒体

Smacker / ZRB——过场视频

来自 coreprime/kbot @ 0ab97bf · 在 GitHub 上编辑

横扫千军的开场动画、任务简报和结尾过场都是 RAD Game Tools 的 Smacker 视频。它们以两种不同的扩展名存储:

扩展名 使用者 说明
.smk 通用的 Smacker 工具 标准的 RAD 格式。
.zrb TA 的 data/*.zrb 载荷 Cavedog 把 Smacker 文件改名为 .zrb,以免被随手提取。二进制内容逐字节相同。

FFmpeg 原生支持解码 Smacker,kbot 用它作为 Smacker → MP4 的转换引擎。反方向则没有任何工具能转换: 原版 FFmpeg 没有 Smacker 编码器或封装器(muxer),kbot 也没有 Smacker 写入器。给 TA 用的 SMK2 影片要用 RAD Game Tools 的 Smacker 工具制作。

Tip

自己试试。

kbot zrb info     data/1.zrb               # header summary
kbot zrb to-mp4   data/1.zrb intro.mp4     # decode to a 640x480 MP4 (requires ffmpeg)
kbot zrb from-mp4 intro.mp4 out.zrb        # reports that no Smacker encoder exists

在 Go 中调用。 使用 formats/smacker:

import "github.com/coreprime/kbot/formats/smacker"

r, _ := smacker.OpenReader("data/1.zrb")
defer r.Close()
fmt.Println(r.Width(), r.Height(), r.FrameCount(), r.FrameRate())
_ = smacker.ConvertToMP4("data/1.zrb", "intro.mp4")

TA 安装目录中有什么

$ ls $(kbot ctx path)/data/*.zrb
1.zrb  2.zrb  3.zrb  4.zrb  5.zrb

每个带编号的文件都是一段过场动画——最初的“Arm 对 Core”开场序列、任务简报等。帧以 640 × 240 存储并设置了隔行标志,因此游戏以 640 × 480 显示它们,每隔一行为黑色,帧率为 30 fps。kbot zrb to-mp4、MCP 的 zrb_to_mp4 工具和 studio 的视频播放器(及其缩略图)都以同样的方式显示它们。


文件头(至少 104 字节)

Smacker 文件头包含签名、几何尺寸、帧数、音频配置和指针表大小。读取它很简单,但主体的解码涉及位级的哈夫曼树,所以 kbot 不自己处理主体,而是交给 FFmpeg。

typedef struct {
    uint32 Signature;        // 'SMK2' = 0x324B4D53 or 'SMK4' = 0x344B4D53
    uint32 Width;
    uint32 Height;
    uint32 Frames;
    int32  FrameRate;        // See below — sign-encoded
    uint32 Flags;
    uint32 AudioSize[7];
    uint32 TreesSize;        // Huffman tree section length
    uint32 MMapSize;
    uint32 MClrSize;
    uint32 FullSize;
    uint32 TypeSize;
    uint32 AudioRate[7];     // packed: rate in bits 0-23, flags in bits 24-31
    uint32 dummy;            // 4-byte reserved; the header ends here (104 bytes)
    // …followed by one entry per frame, plus one for the ring frame
    // when Flags bit 0 is set:
    uint32 FrameSizes[Frames (+1)];
    uint8  FrameTypes[Frames (+1)];
    uint8  HuffmanTrees[TreesSize];
} SmackerHeader;

Flags 各位:0x01 环形帧(在最后一帧之后多出一帧,用于循环),0x02 隔行(以两倍高度显示,每隔一行为黑色),0x04 倍高(以两倍高度显示,每一行重复一次)。0x02 和 0x04 同时设置时,影片以其存储的高度显示。

解码帧率

FrameRate 的符号决定使用两种编码中的哪一种:

值 含义
> 0 每帧的毫秒数:fps = 1000 / FrameRate。
< 0 每帧的十万分之一秒数:fps = 100_000 / abs(FrameRate)。
0 没有定义时序——kbot 使用 15 fps。

30 fps 时通常会看到 -3333(≈ -100000/30)。

签名变体

  • SMK2——最初的 Smacker 格式。Cavedog 的过场动画几乎全都使用它。
  • SMK4——较新的 RAD 工具所用的扩展格式,压缩效果更好。TA 3.1c 只能播放 SMK2。

kbot 两种都能读取(遇到 SMK4 文件时会注明);FFmpeg 两种都能解码。

音轨

最多 7 条音轨。每个 AudioRate[i] 字打包了采样率(第 0–23 位)和该音轨的标志(第 24–31 位):0x80 已压缩,0x40 存在,0x20 16 位(否则为 8 位),0x10 立体声(否则为单声道)。只有当音轨的“存在”位被置位时,游戏才会使用它,不论其采样率是多少。没有单独的标志表:文件头之后的七个字是帧大小表。

Note

Cavedog 的 ZRB 文件只在第 0 槽有一条音轨:字值为 0xD0005622——存在、22,050 Hz、立体声、8 位、已压缩。其余六个槽都是零。kbot zrb info 和 MCP 的 zrb_info 工具只列出存在的音轨。


“数据是加密的”这一误解

模组作者中常见一种看法,认为 .zrb 文件是 Smacker 的一种加密变体。并不是。 把 1.zrb 改名为 1.smk,任何支持 Smacker 的工具(RAD 的 Bink/Smacker 工具、FFmpeg、VLC)都能播放它。Cavedog 唯一的混淆手段就是扩展名本身。

# Equivalent — try both
ffplay data/1.zrb
cp data/1.zrb /tmp/intro.smk && ffplay /tmp/intro.smk

转换管线

kbot zrb to-mp4 先读取文件头,再让 FFmpeg 把影片按游戏显示的样子解码为 H.264(CRF 18)和 AAC:使用显示高度(隔行的 640×240 影片变为 640×480,每隔一行为黑色),使用方形像素,并在文件头给出的帧数处停止(环形帧不显示)。

参数 作用
--line-double 用重复每条存储行的方式,而不是用黑色,填充隔行影片多出的那些行。
--stored-height 保持存储的帧高度(640×240)。

studio 的视频播放器使用同样的转换,其缩略图也保持 4:3 的显示比例(128×96,行加倍)。

Important

不存在 MP4 → Smacker 的路径。 原版 FFmpeg 没有 Smacker 编码器(smackvid / smackaud)或封装器,kbot 也没有 Smacker 写入器。kbot zrb from-mp4 和 MCP 的 zrb_from_mp4 工具会如实报告这一点(只有当 FFmpeg 同时列出 smackvid 编码器和 smk 封装器时,才会尝试使用它)。给 TA 用的 SMK2 影片请用 RAD Game Tools 的 Smacker 工具制作。


典型大小

资源 分辨率 帧数 时长 文件大小
开场动画(data/1.zrb) 640 × 240(显示为 640 × 480) 599 约 20 秒 约 7 MB
其他过场动画(data/2.zrb–5.zrb) 640 × 240(显示为 640 × 480) — — 10–41 MB

坑点

Warning

AudioRate 是一个打包的字,而不是采样率本身。 若当作普通数字读取,零售版中的字 0xD0005622 就是 3,489,682,978 “Hz”。取低 24 位得到采样率,检测 0x40000000 位判断是否存在。在文件头之后再读七个“标志”字的工具,读到的其实是帧大小表。

  • Smacker 不是 Bink。 RAD 先发布了 Smacker,后来又推出 Bink 作为其后继者。TA 只使用 Smacker;横扫千军:王国改用了 Bink。不要用 kbot zrb 加载 .bik 文件——请改用 kbot bik。
  • SMK4 的哈夫曼树与 SMK2 解码器不向后兼容。 FFmpeg 两者都能处理,但较老的第三方库可能不行。
  • 发行的过场动画存的是 -3333(100,000 / 3,333 ≈ 30.003 fps)。
  • 存储的高度不等于显示的高度。 检查隔行和倍高标志;以 640×240 播放零售版影片,会把它们压扁成一半高度。
  • 在 .zrb ↔ .smk 之间改名无害,但游戏期望 data/ 目录中的是 .zrb。不要把以 .smk 命名的文件交给引擎。

另见

  • Bink——横扫千军:王国用来取代 Smacker 的后继编解码器。
  • HPI——发布 ZRB 文件的外层压缩包。
  • 术语表——帧率(frame rate)、签名(signature)。