{"id":36236736,"url":"https://github.com/xmoezzz/amv_decoder","last_synced_at":"2026-01-11T06:01:16.409Z","repository":{"id":328914451,"uuid":"1117319646","full_name":"xmoezzz/amv_decoder","owner":"xmoezzz","description":"Experimental AMV parser and decoder for KiriKiri2 / KiriKiriZ engine videos.","archived":false,"fork":false,"pushed_at":"2025-12-16T07:10:09.000Z","size":2591,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-19T18:26:14.622Z","etag":null,"topics":["kirikiri","krkrz","multimedia","reverse-engineering"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xmoezzz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-16T06:32:18.000Z","updated_at":"2025-12-17T17:35:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/xmoezzz/amv_decoder","commit_stats":null,"previous_names":["xmoezzz/amv_decoder"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/xmoezzz/amv_decoder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmoezzz%2Famv_decoder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmoezzz%2Famv_decoder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmoezzz%2Famv_decoder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmoezzz%2Famv_decoder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xmoezzz","download_url":"https://codeload.github.com/xmoezzz/amv_decoder/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmoezzz%2Famv_decoder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28293188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-11T04:44:51.577Z","status":"ssl_error","status_checked_at":"2026-01-11T04:44:44.232Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kirikiri","krkrz","multimedia","reverse-engineering"],"created_at":"2026-01-11T06:01:15.780Z","updated_at":"2026-01-11T06:01:16.403Z","avatar_url":"https://github.com/xmoezzz.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# amv_decoder\n\n`amv_decoder` is an experimental Rust project that parses and (partially) decodes the **AJPM / “Alpha Movie”** video\nformat used by some **KiriKiri2** and **KiriKiriZ (krkrz)** engine titles.\n\nThis repository is the product of reverse engineering work. It is not affiliated with, endorsed by, or supported by\nany engine or game vendor.\n\n## Status\n\n- The container parser and packet splitter are stable enough for iterative RE work.\n\n## Features\n\n- Reads the 40-byte file header (little-endian, magic `0x4D504A41` / `AJPM`).\n- Loads global quantization tables.\n- Iterates frame packets from `header_size`.\n- Dumps raw packet bytes and per-segment blobs for analysis.\n- Decodes frame packets into RGBA frames (experimental) and can emit PPM images for quick inspection.\n\n## Quick start\n\nPrerequisites\n\n- Rust stable toolchain.\n\nBuild\n\n```bash\ncargo build\n```\n\nDump packets (recommended first step for new samples)\n\n```bash\ncargo run -- dump testcase/1.amv --out out_dump\n```\n\nThis writes:\n\n- `out_dump/index.json`\n- `out_dump/frames/frame_000000.packet.bin`\n- For packet type A (see format notes), also:\n  - `out_dump/frames/frame_000000.seg0.bin`\n  - `out_dump/frames/frame_000000.seg1.bin`\n\nDecode frames (experimental)\n\n```bash\ncargo run -- decode testcase/1.amv --out out_decode --ppm true\n```\n\nThis writes per-frame outputs:\n\n- `out_decode/frame_000000.rgba` (raw RGBA bytes)\n- `out_decode/frame_000000.ppm` (RGB-only PPM, if `--ppm true`)\n\n## Tests\n\nSample-based decode tests are marked `#[ignore]` because `testcase/1.amv` is not committed.\nRun ignored tests locally:\n\n```bash\ncargo test -- --ignored --nocapture\n```\n\n## AMV container notes\n\nAll integers are little-endian.\n\n### File header (40 bytes)\n\nA minimal working layout based on observed loader behavior:\n\n- `u32 magic` = `0x4D504A41` (`AJPM`)\n- `u32 unknown_04`\n- `u32 revision` (expected `0`)\n- `u32 header_size` (observed `168` or `232`)\n- `u32 unknown_10`\n- `u32 frame_count`\n- `u32 fps_num`\n- `u32 fps_den`\n- `u16 width`\n- `u16 height`\n- `u8  attr`\n- `u8[3] reserved`\n\nImmediately after the 40-byte header, the file contains global quantization tables whose size is\n`header_size - 40`:\n\n- `128` bytes in packet type A mode\n- `192` bytes in packet type B mode\n\nThe engine-side flag that selects the seek path (`stream+29` in the IDA output) is derived from `attr`.\nIn practice, this correlates with whether alpha data is present.\n\n### Frame packet type A (seek path `sub_10016D20`)\n\nThis packet type begins with a 24-byte header and is split into two payload segments. Conceptually:\n\n- `u32 tag`\n- `u32 chunk_size` (bytes after the first 8 bytes)\n- `u32 frame_id`\n- `i16 p0`\n- `i16 p1`\n- `u16 w_aligned` (multiple of 16)\n- `u16 h_aligned` (multiple of 16)\n- `u32 seg0_len`\n- `u8  seg0[seg0_len]`\n- `u8  seg1[chunk_size - 16 - seg0_len]`\n\nObserved behavior suggests:\n\n- `seg0` is zlib-compressed and inflates to a `w_aligned * h_aligned` byte plane.\n- `seg1` is an entropy-coded DCT coefficient stream.\n- Per macroblock, 6 × 8×8 blocks are decoded (consistent with YCbCr 4:2:0 without alpha).\n\n### Frame packet type B (seek path `sub_10017570`)\n\nThis packet type begins with a 20-byte header and contains a single payload blob:\n\n- `u32 tag`\n- `u32 chunk_size` (bytes after the first 8 bytes)\n- `u32 frame_id`\n- `i16 p0`\n- `i16 p1`\n- `u16 w_aligned` (multiple of 16)\n- `u16 h_aligned` (multiple of 16)\n- `u8  payload[chunk_size - 12]`\n\nObserved behavior suggests:\n\n- Per macroblock, 10 × 8×8 blocks are decoded.\n- Blocks appear to be split across multiple Huffman/bitstream contexts.\n- The 10-block structure is consistent with Y (4 blocks) + Cb (1) + Cr (1) + Alpha (4), but this remains a\n  working hypothesis until composition code is fully matched.\n\n### Entropy coding model (high level)\n\nBoth packet types use a JPEG-like coding model for 8×8 blocks:\n\n- DC coefficient uses a predictor and Huffman-coded category, followed by extra bits.\n- AC coefficients use Huffman-coded (RUN, SIZE) symbols with zig-zag order and EOB/ZRL semantics.\n- Coefficients are dequantized using the global quantization tables and reconstructed via IDCT.\n- The output is then composed into a frame buffer.\n\n## License\n\nMPL-2.0 (see `Cargo.toml`).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmoezzz%2Famv_decoder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxmoezzz%2Famv_decoder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmoezzz%2Famv_decoder/lists"}