Smacker / ZRB — カットシーンの動画
Total Annihilationのイントロ、ミッションのブリーフィング、エンディングのムービーは、RAD Game ToolsのSmackerの動画です。2種類の拡張子で格納されています。
拡張子 使われる場所 備考 .smk一般的なSmackerのツール RADの標準形式。 .zrbTAの data/*.zrbのペイロードCavedogは、気軽に取り出されないようにSmackerのファイルを .zrbに改名しました。バイナリの中身はバイト単位で同一です。FFmpegはSmackerをネイティブにデコードでき、kbotはSmacker → MP4の変換エンジンとしてこれを使っています。逆方向に変換するものは何もありません。標準のFFmpegにはSmackerのエンコーダーもマルチプレクサーもなく、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で格納され、インターレースのフラグが立っているので、ゲームはこれを1行おきに黒い行を挟んだ640 × 480、30 fpsで表示します。kbot zrb to-mp4、MCPのzrb_to_mp4ツール、スタジオの動画プレーヤー(とそのサムネイル)も、同じように表示します。
ヘッダー(最低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はインターレース(高さを2倍にし、1行おきに黒い行を挟んで表示)、0x04は倍化(高さを2倍にし、各行を繰り返して表示)です。0x02と0x04の両方が立っている場合、ムービーは格納された高さのまま表示されます。
フレームレートのデコード
FrameRateの符号によって、2つのエンコード方式のどちらかが選ばれます。
| 値 | 意味 |
|---|---|
> 0 |
1フレームあたりのミリ秒:fps = 1000 / FrameRate。 |
< 0 |
1フレームあたりの10万分の1秒: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がステレオ(なければモノラル)です。ゲームがトラックを使うのは、存在のビットが立っている場合だけです。レートの値は関係ありません。独立したフラグのテーブルはありません。ヘッダーの後に続く7つのワードは、フレームサイズのテーブルです。
Note
CavedogのZRBファイルは、スロット0にトラックが1つだけあります。ワードは0xD0005622で、存在、22,050 Hz、ステレオ、8ビット、圧縮を意味します。ほかの6つのスロットは0で埋められています。kbot zrb infoとMCPのzrb_infoツールは、存在するトラックだけを一覧表示します。
「データが暗号化されている」という誤解
MOD制作者の間では、.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のムービーは、1行おきに黒い行が入った640×480になります)、正方形のピクセルで、ヘッダーのフレーム数のところで止めます(リングフレームは表示されません)。
| フラグ | 効果 |
|---|---|
--line-double |
インターレースのムービーで増える行を、黒ではなく格納された各行を繰り返して埋めます。 |
--stored-height |
格納されたフレームの高さ(640×240)のままにします。 |
スタジオの動画プレーヤーも同じ変換を使い、そのサムネイルは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で調べてください。ヘッダーの後にさらに7つの「flags」ワードを読むツールは、実際にはフレームサイズのテーブルを読んでいます。
- SmackerはBinkではありません。RADは先にSmackerを出し、その後継としてBinkを出しました。TAが使うのはSmackerだけで、TA: KingdomsはBinkに切り替えました。
.bikファイルをkbot zrbで読み込まないでください。代わりにkbot bikを使います。 SMK4のハフマン木は、SMK2のデコーダーとの後方互換性がありません。FFmpegはどちらも扱えますが、古いサードパーティーのライブラリは扱えないことがあります。- 同梱のムービーには
-3333が格納されています(100,000 / 3,333 ≈ 30.003 fps)。 - 格納された高さは、表示される高さではありません。インターレースと倍化のフラグを確認してください。製品版のムービーを640×240で再生すると、高さが半分に押しつぶされます。
.zrb↔.smkの改名は無害ですが、ゲームはdata/ディレクトリに.zrbがあることを前提にしています。.smkという名前のファイルをエンジン向けに配布しないでください。