{"id":50361250,"url":"https://github.com/rafaelcaricio/wav1c","last_synced_at":"2026-05-30T01:30:56.789Z","repository":{"id":338406695,"uuid":"1157466127","full_name":"rafaelcaricio/wav1c","owner":"rafaelcaricio","description":"Wondrous AV1 Coder. A spec-compliant AV1 video encoder written from scratch in safe Rust with zero dependencies. Usable as a Rust library, C shared library, WebAssembly module, or as an FFmpeg encoder plugin.","archived":false,"fork":false,"pushed_at":"2026-02-22T00:19:17.000Z","size":421,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-22T08:32:17.267Z","etag":null,"topics":["av1","av1-codec","av1-encoder"],"latest_commit_sha":null,"homepage":"https://rafaelcaricio.github.io/wav1c_demo/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rafaelcaricio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-13T21:14:40.000Z","updated_at":"2026-02-22T04:19:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rafaelcaricio/wav1c","commit_stats":null,"previous_names":["rafaelcaricio/wav1c"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/rafaelcaricio/wav1c","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafaelcaricio%2Fwav1c","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafaelcaricio%2Fwav1c/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafaelcaricio%2Fwav1c/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafaelcaricio%2Fwav1c/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rafaelcaricio","download_url":"https://codeload.github.com/rafaelcaricio/wav1c/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rafaelcaricio%2Fwav1c/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33677258,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["av1","av1-codec","av1-encoder"],"created_at":"2026-05-30T01:30:56.189Z","updated_at":"2026-05-30T01:30:56.784Z","avatar_url":"https://github.com/rafaelcaricio.png","language":"Rust","funding_links":[],"categories":["Encoding \u0026 Codecs"],"sub_categories":["Codecs"],"readme":"# wav1c - Wondrous AV1 Encoder\n\n[![crates.io](https://img.shields.io/crates/v/wav1c.svg)](https://crates.io/crates/wav1c)\n[![license](https://img.shields.io/crates/l/wav1c.svg)](LICENSE)\n[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)\n\nA spec-compliant AV1 encoder written from scratch in safe Rust with zero runtime dependencies.\n\n`wav1c` can be used as:\n- A Rust library (`wav1c` crate)\n- A CLI encoder (`wav1c-cli`)\n- A C ABI library (`wav1c-ffi`)\n- A WebAssembly module (`wav1c-wasm`)\n- An FFmpeg external encoder (`libwav1c`)\n\n## Feature Summary\n\n- AV1 4:2:0 encoding for SDR and HDR workflows\n- Bit depths: 8-bit and 10-bit\n- HDR signaling:\n  - Sequence-header color signaling (range + color description)\n  - HDR metadata OBUs:\n    - CLL (`max_cll`, `max_fall`)\n    - MDCV (mastering display metadata)\n  - AVIF compatibility signaling:\n    - AVIF item properties: `clli` (+ optional `mdcv`)\n    - Single-frame AVIF sequence headers set `still_picture=1`\n- Y4M parsing:\n  - `C420*` 8-bit and `C420p10`\n  - `XCOLORRANGE=FULL|LIMITED` in stream and `FRAME` headers\n  - Typed parse errors for malformed/truncated input\n- Intra + inter coding pipeline with RD decisions, transforms, and entropy coding\n- B-frame pipeline support\n- Large-dimension support in core encoder via AV1 multi-tile payload assembly (memory permitting)\n\nCurrent scope limits:\n- Chroma format: 4:2:0 only\n- Bit depth: 8/10-bit only (no 12-bit)\n- Container limits in CLI:\n  - IVF/MP4: `width \u003c= 65535`, `height \u003c= 65535`\n  - AVIF: large dimensions supported\n\n## Workspace Layout\n\n```text\nwav1c/          Core library (Rust API, bitstream generation)\nwav1c-cli/      Command-line encoder\nwav1c-ffi/      C FFI shared/static library\nwav1c-wasm/     WebAssembly bindings (wasm-bindgen)\ndocs/           Project documentation (including HDR + HEIC guide)\n```\n\n## Build\n\n```bash\ncargo build --workspace --release\n```\n\n## CLI Usage\n\nAll examples below use the workspace binary:\n\n```bash\ncargo run -q -p wav1c-cli -- \u003cargs...\u003e\n```\n\nBasic SDR encode from Y4M:\n\n```bash\ncargo run -q -p wav1c-cli -- input.y4m -o output.ivf\n```\n\nSolid-color frame encode (5 positional args: `W H Y U V`):\n\n```bash\ncargo run -q -p wav1c-cli -- 320 240 128 128 128 -o gray.ivf\n```\n\n10-bit HDR10 encode from Y4M:\n\n```bash\ncargo run -q -p wav1c-cli -- input_10bit.y4m -o output_hdr.ivf \\\n  --bit-depth 10 \\\n  --hdr10 \\\n  --color-range full \\\n  --max-cll 203 \\\n  --max-fall 64\n```\n\nCustom color description + MDCV:\n\n```bash\ncargo run -q -p wav1c-cli -- input_10bit.y4m -o output_hdr.ivf \\\n  --bit-depth 10 \\\n  --color-range limited \\\n  --color-primaries 9 \\\n  --transfer 16 \\\n  --matrix 9 \\\n  --mdcv 34000,16000,13250,34500,7500,3000,15635,16450,10000000,1\n```\n\nCLI HDR flags:\n- `--bit-depth \u003c8|10\u003e`\n- `--hdr10`\n- `--color-range \u003climited|full\u003e`\n- `--color-primaries \u003cu8\u003e`\n- `--transfer \u003cu8\u003e`\n- `--matrix \u003cu8\u003e`\n- `--max-cll \u003cu16\u003e` and `--max-fall \u003cu16\u003e` (must be provided together)\n- `--mdcv \u003crx,ry,gx,gy,bx,by,wx,wy,max_lum,min_lum\u003e`\n\nNotes:\n- When input is Y4M and `--bit-depth` or `--color-range` are omitted, values are inferred from Y4M headers.\n- `--hdr10` applies default color description (`primaries=9`, `transfer=16`, `matrix=9`).\n\n## Rust API\n\n### Simple 8-bit SDR frame (solid color)\n\n```rust\nuse wav1c::y4m::FramePixels;\nuse wav1c::{encode_packets, EncodeConfig};\n\nlet frame = FramePixels::solid(320, 240, 128, 128, 128);\nlet packets = encode_packets(\u0026[frame], \u0026EncodeConfig::default());\n\nassert!(!packets.is_empty());\nassert!(!packets[0].data.is_empty());\n```\n\n### Simple Y4M file encode (8-bit or 10-bit input)\n\n```rust\nuse std::path::Path;\nuse wav1c::y4m::FramePixels;\nuse wav1c::{encode_packets, EncodeConfig, Fps};\n\nlet frames = FramePixels::all_from_y4m_file(Path::new(\"input.y4m\"))?;\nlet config = EncodeConfig {\n    base_q_idx: 110,\n    keyint: 60,\n    fps: Fps::from_int(30).unwrap(),\n    b_frames: true,\n    gop_size: 4,\n    ..EncodeConfig::default()\n};\n\nlet packets = encode_packets(\u0026frames, \u0026config);\nassert!(!packets.is_empty());\n# Ok::\u003c(), Box\u003cdyn std::error::Error\u003e\u003e(())\n```\n\n### 10-bit HDR encode (signal + metadata)\n\n```rust\nuse wav1c::y4m::FramePixels;\nuse wav1c::{\n    encode_packets, BitDepth, ColorRange, ContentLightLevel, EncodeConfig, Fps,\n    MasteringDisplayMetadata, VideoSignal,\n};\n\nlet frame = FramePixels::solid_with_bit_depth(\n    1920,\n    1080,\n    512,\n    512,\n    512,\n    BitDepth::Ten,\n    ColorRange::Full,\n);\n\nlet config = EncodeConfig {\n    keyint: 60,\n    fps: Fps::from_int(30).unwrap(),\n    b_frames: true,\n    gop_size: 4,\n    video_signal: VideoSignal::hdr10(ColorRange::Full),\n    content_light: Some(ContentLightLevel {\n        max_content_light_level: 203,\n        max_frame_average_light_level: 64,\n    }),\n    mastering_display: Some(MasteringDisplayMetadata {\n        primaries: [[34000, 16000], [13250, 34500], [7500, 3000]],\n        white_point: [15635, 16450],\n        max_luminance: 10_000_000,\n        min_luminance: 1,\n    }),\n    ..EncodeConfig::default()\n};\n\nlet packets = encode_packets(\u0026[frame], \u0026config);\nassert!(!packets.is_empty());\n```\n\n### Key signal and metadata types\n\nExported from the crate root:\n- `BitDepth`\n- `ColorRange`\n- `ColorDescription`\n- `Fps`\n- `VideoSignal`\n- `ContentLightLevel`\n- `MasteringDisplayMetadata`\n\n## C FFI API (`wav1c-ffi`)\n\nHeader: `wav1c-ffi/include/wav1c.h`\n\nCanonical API:\n- `wav1c_default_config()`\n- `wav1c_encoder_new(...)`\n- `wav1c_encoder_send_frame(...)` (8-bit planes)\n- `wav1c_encoder_send_frame_u16(...)` (10-bit planes)\n- `wav1c_encoder_rate_control_stats(...)`\n- `wav1c_last_error_message()`\n\n`Wav1cConfig` fields:\n- `fps_num`, `fps_den`: frame rate rational (`num/den`)\n- `bit_depth`: `8` or `10`\n- `color_range`: `0` limited, `1` full\n- `color_primaries`, `transfer_characteristics`, `matrix_coefficients`: set to `-1` to omit color description\n- `has_cll`, `max_cll`, `max_fall`\n- `has_mdcv`, primaries/white-point/luminance fields\n\nSimple 8-bit SDR usage:\n\n```c\n#include \u003cstdio.h\u003e\n#include \"wav1c.h\"\n\nWav1cConfig cfg = wav1c_default_config();\ncfg.base_q_idx = 128;\ncfg.keyint = 60;\ncfg.fps_num = 30;\ncfg.fps_den = 1;\ncfg.b_frames = 1;\ncfg.gop_size = 4;\n\nWav1cEncoder *enc = wav1c_encoder_new(320, 240, \u0026cfg);\nif (!enc) {\n    fprintf(stderr, \"encoder_new failed: %s\\n\", wav1c_last_error_message());\n    return -1;\n}\n\n// y/u/v are 4:2:0 8-bit planes. Lengths are sample counts, not byte counts.\nif (wav1c_encoder_send_frame(enc, y, y_len, u, u_len, v, v_len, 0, 0) != WAV1C_STATUS_OK) {\n    fprintf(stderr, \"send_frame failed: %s\\n\", wav1c_last_error_message());\n    wav1c_encoder_free(enc);\n    return -1;\n}\n\nwav1c_encoder_flush(enc);\nfor (Wav1cPacket *pkt = NULL; (pkt = wav1c_encoder_receive_packet(enc)) != NULL; ) {\n    // pkt-\u003edata / pkt-\u003esize contains AV1 OBU payload\n    wav1c_packet_free(pkt);\n}\n\nwav1c_encoder_free(enc);\n```\n\nSimple rate-control stats query:\n\n```c\n#include \u003cstdio.h\u003e\n#include \"wav1c.h\"\n\nWav1cConfig cfg = wav1c_default_config();\ncfg.target_bitrate = 2 * 1000 * 1000; // 2 Mbps\n\nWav1cEncoder *enc = wav1c_encoder_new(1280, 720, \u0026cfg);\nif (!enc) return -1;\n\nWav1cRateControlStats stats;\nif (wav1c_encoder_rate_control_stats(enc, \u0026stats) == WAV1C_STATUS_OK) {\n    printf(\"target=%llu, avg_qp=%u, buffer=%u%%\\n\",\n           (unsigned long long)stats.target_bitrate,\n           stats.avg_qp,\n           stats.buffer_fullness_pct);\n}\n\nwav1c_encoder_free(enc);\n```\n\n10-bit HDR usage:\n\n```c\n#include \u003cstdio.h\u003e\n#include \"wav1c.h\"\n\nWav1cConfig cfg = wav1c_default_config();\ncfg.keyint = 60;\ncfg.fps_num = 30;\ncfg.fps_den = 1;\ncfg.b_frames = 1;\ncfg.gop_size = 4;\ncfg.bit_depth = 10;\ncfg.color_range = 1; // full\ncfg.color_primaries = 9;\ncfg.transfer_characteristics = 16;\ncfg.matrix_coefficients = 9;\ncfg.has_cll = 1;\ncfg.max_cll = 203;\ncfg.max_fall = 64;\n\nWav1cEncoder *enc = wav1c_encoder_new(1920, 1080, \u0026cfg);\nif (!enc) {\n    fprintf(stderr, \"encoder_new failed: %s\\n\", wav1c_last_error_message());\n    return -1;\n}\n\n// y_len/u_len/v_len are sample counts, not byte counts.\nif (wav1c_encoder_send_frame_u16(\n        enc, y, y_len, u, u_len, v, v_len, y_stride, uv_stride) != WAV1C_STATUS_OK) {\n    fprintf(stderr, \"send_frame_u16 failed: %s\\n\", wav1c_last_error_message());\n    wav1c_encoder_free(enc);\n    return -1;\n}\n\nwav1c_encoder_flush(enc);\nWav1cPacket *pkt = wav1c_encoder_receive_packet(enc);\n\nif (pkt) wav1c_packet_free(pkt);\nwav1c_encoder_free(enc);\n```\n\nBuild artifacts:\n- `libwav1c_ffi.dylib` / `libwav1c_ffi.so`\n- `libwav1c_ffi.a`\n\n## WebAssembly API (`wav1c-wasm`)\n\nMain entry point: `WasmEncoder`\n\nConstructor:\n- `new(width, height, base_q_idx, keyint, b_frames, gop_size, fps_num, fps_den, target_bitrate, bit_depth, color_range, cp, tc, mc, has_cll, max_cll, max_fall)`\n\n10-bit/HDR methods:\n- `encode_frame_10bit(y, u, v)`\n- `set_hdr10(color_range)`\n- `set_video_signal(bit_depth, color_range, cp, tc, mc)`\n- `set_content_light_level(max_cll, max_fall)`\n- `set_mastering_display_metadata(...)`\n- `rate_control_stats()`\n\nImportant: signal and metadata mutators must be called before the first submitted frame.\n\n## FFmpeg Integration (`libwav1c`)\n\nThis repository contains `ffmpeg-libwav1c.patch`, and we also maintain direct FFmpeg integration updates in `../FFmpeg` during active development.\n\nBuild `wav1c-ffi` first:\n\n```bash\ncargo build -p wav1c-ffi --release\n```\n\nConfigure FFmpeg with `libwav1c`:\n\n```bash\ncd ../FFmpeg\n./configure --enable-libwav1c \\\n  --extra-cflags=\"-I/absolute/path/to/wav1c/wav1c-ffi/include\" \\\n  --extra-ldflags=\"-L/absolute/path/to/wav1c/target/release\"\nmake -j$(sysctl -n hw.ncpu 2\u003e/dev/null || nproc)\n```\n\nRun with dynamic library path (macOS example):\n\n```bash\nDYLD_LIBRARY_PATH=/absolute/path/to/wav1c/target/release ./ffmpeg \\\n  -i input.y4m \\\n  -pix_fmt yuv420p10le \\\n  -c:v libwav1c \\\n  -wav1c-hdr10 1 \\\n  -wav1c-max-cll 203 \\\n  -wav1c-max-fall 64 \\\n  -f ivf output.ivf\n```\n\nSupported FFmpeg `libwav1c` pixel formats:\n- `yuv420p`\n- `yuv420p10le`\n\nSupported FFmpeg private options:\n- `-wav1c-q`\n- `-wav1c-b-frames`\n- `-wav1c-gop-size`\n- `-wav1c-hdr10`\n- `-wav1c-max-cll`\n- `-wav1c-max-fall`\n- `-wav1c-mdcv`\n\n## HEIC to HDR Workflow\n\nFor a full HEIC -\u003e HDR AV1 workflow (CLI and FFmpeg), including verification with `ffprobe` and `dav1d`, see:\n\n- `docs/HDR_HEIC_MANUAL.md`\n\nPractical note for HEIC inputs:\n- Some HEIC files decode as tile grids.\n- Do not force-map an individual dependent tile if you want the full composed image.\n- For very large outputs, prefer AVIF when IVF/MP4 16-bit container dimensions would be exceeded.\n\n## Testing\n\n```bash\ncargo test --workspace\n```\n\nIntegration tests decode encoded output with [dav1d](https://code.videolan.org/videolan/dav1d). If `dav1d` is unavailable, tests that require it are skipped.\n\n## License\n\nThis project is licensed under the Mozilla Public License 2.0. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafaelcaricio%2Fwav1c","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frafaelcaricio%2Fwav1c","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frafaelcaricio%2Fwav1c/lists"}