xmoezzz/amv_decoder
GitHub: xmoezzz/amv_decoder
一个实验性的 AMV 格式解析与解码项目,填补了 KiriKiri2/KiriKiriZ 相关视频格式的逆向工程工具空白。
Stars: 7 | Forks: 0
# amv_decoder
`amv_decoder` 是一个实验性的 Rust 项目,用于解析(部分解码)**AJPM / “Alpha Movie”** 视频格式,
该格式被部分 **KiriKiri2** 和 **KiriKiriZ (krkrz)** 引擎使用的作品采用。
本仓库是逆向工程工作的产物。它与任何引擎或游戏厂商无关,未获其认可或支持。
## 状态
- 容器解析器和数据包拆分器已足够稳定,可用于迭代式逆向工程(RE)工作。
## 功能
- 读取 40 字节文件头(小端序,魔术数 `0x4D504A41` / `AJPM`)。
- 加载全局量化表。
- 从 `header_size` 开始迭代帧数据包。
- 转储原始数据包字节和每个分段的数据块以便分析。
- 将帧数据包解码为 RGBA 帧(实验性),并可输出 PPM 图像用于快速检查。
## 快速开始
前置条件
- Rust 稳定工具链。
构建
```
cargo build
```
转储数据包(对新样本推荐的第一步)
```
cargo run -- dump testcase/1.amv --out out_dump
```
这将生成:
- `out_dump/index.json`
- `out_dump/frames/frame_000000.packet.bin`
- 对于数据包类型 A(参见格式说明),还包括:
- `out_dump/frames/frame_000000.seg0.bin`
- `out_dump/frames/frame_000000.seg1.bin`
解码帧(实验性)
```
cargo run -- decode testcase/1.amv --out out_decode --ppm true
```
这会为每个帧生成输出:
- `out_decode/frame_000000.rgba`(原始 RGBA 字节)
- `out_decode/frame_000000.ppm`(仅 RGB 的 PPM,若指定 `--ppm true`)
## 测试
基于样本的解码测试被标记为 `#[ignore]`,因为 `testcase/1.amv` 未被提交。
本地运行被忽略的测试:
```
cargo test -- --ignored --nocapture
```
## AMV 容器说明
所有整数均为小端序。
### 文件头(40 字节)
基于观察到的加载器行为的最小可用布局:
- `u32 magic` = `0x4D504A41` (`AJPM`)
- `u32 unknown_04`
- `u32 revision`(预期为 `0`)
- `u32 header_size`(观察到 `168` 或 `232`)
- `u32 unknown_10`
- `u32 frame_count`
- `u32 fps_num`
- `u32 fps_den`
- `u16 width`
- `u16 height`
- `u8 attr`
- `u8[3] reserved`
紧接在 40 字节头部之后,文件包含全局量化表,其大小为
`header_size - 40`:
- 类型 A 模式下为 `128` 字节
- 类型 B 模式下为 `192` 字节
引擎侧用于选择寻址路径的标志(IDA 输出中的 `stream+29`)由 `attr` 派生。
在实践中,这与是否存在 Alpha 数据相关。
### 帧数据包类型 A(寻址路径 `sub_10016D20`)
该数据包类型以 24 字节头部开始,并被拆分为两个有效载荷分段。概念上:
- `u32 tag`
- `u32 chunk_size`(首个 8 字节之后的数据字节数)
- `u32 frame_id`
- `i16 p0`
- `i16 p1`
- `u16 w_aligned`(16 的倍数)
- `u16 h_aligned`(16 的倍数)
- `u32 seg0_len`
- `u8 seg0[seg0_len]`
- `u8 seg1[chunk_size - 16 - seg0_len]`
观察行为表明:
- `seg0` 经过 zlib 压缩,解压后得到 `w_aligned * h_aligned` 字节的平面。
- `seg1` 是熵编码的 DCT 系数流。
- 每个宏块解码 6 × 8×8 块(与无 Alpha 的 YCbCr 4:2:0 一致)。
### 帧数据包类型 B(寻址路径 `sub_10017570`)
该数据包类型以 20 字节头部开始,并包含单个有效载荷数据块:
- `u32 tag`
- `u32 chunk_size`(首个 8 字节之后的数据字节数)
- `u32 frame_id`
- `i16 p0`
- `i16 p1`
- `u16 w_aligned`(16 的倍数)
- `u16 h_aligned`(16 的倍数)
- `u8 payload[chunk_size - 12]`
观察行为表明:
- 每个宏块解码 10 × 8×8 块。
- 块似乎被拆分到多个 Huffman/比特流上下文中。
- 10 个块的结构与 Y(4 块)+ Cb(1 块)+ Cr(1 块)+ Alpha(4 块)一致,但这仍是一个
工作假设,直到完全匹配组合代码。
### 熵编码模型(高层概览)
两种数据包类型均使用类似 JPEG 的 8×8 块编码模型:
- DC 系数使用预测器并通过 Huffman 编码分类,后跟额外比特。
- AC 系数使用 Huffman 编码的(RUN,SIZE)符号,采用 Zig-Zag 顺序以及 EOB/ZRL 语义。
- 系数经过全局量化表反量化并通过 IDCT 重建。
- 最终输出被合成到帧缓冲区中。
## 许可证
MPL-2.0(详见 `Cargo.toml`)。
标签:Alpha Movie, AMV, FFmpeg, KiriKiri2, KiriKiriZ, krkrz, PPM, RGBA, Rust, SEO: AMV 解码, SEO: KiriKiri 视频解析, SEO: 逆向分析, 云资产清单, 可视化界面, 图像处理, 多媒体解析, 实验性解析器, 容器格式, 小端解析, 帧分割, 帧解码, 文件格式, 游戏视频, 网络流量审计, 视频解析, 视频解码, 逆向工程, 通知系统, 量化表