Metadata-Version: 2.1
Name: vsfgs
Version: 0.6.0
Summary: A VapourSynth plugin for applying Film Grain Synthesis (FGS) using the dav1d engine.
Keywords: vapoursynth,film-grain,fgs,dav1d,video-processing,afgs1,av1,simd
Author: PingWer74
License: MIT
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Multimedia :: Video :: Non-Linear Editor
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: C++
Classifier: Programming Language :: Assembly
Classifier: Operating System :: OS Independent
Classifier: Environment :: Plugins
Project-URL: Repository, https://github.com/PingWer/vs-fgs
Project-URL: Issues, https://github.com/PingWer/vs-fgs/issues
Requires-Python: >=3.13
Requires-Dist: vapoursynth>=74
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Description-Content-Type: text/markdown

# vs-fgs

A VapourSynth plugin for applying Film Grain Synthesis' table (FGS) using the [dav1d](https://code.videolan.org/videolan/dav1d) decoder.

Since `dav1d` is widely regarded as the best and fastest AV1 decoder available, its FGS engine is fully spec-compliant with **AFGS1** (AOMedia Film Grain Synthesis 1), guaranteeing highly accurate, performant, and standardized grain generation.

`vsfgs` parses standard FGS text files and applies film grain to the input clip natively in **8-bit, 10-bit, or 12-bit YUV**. It also handles automatic dithering if the input bit depth is higher.

## Installation
```bash
pip install vsfgs
```

## Usage

```python
import vapoursynth as vs
import vsfgs

core = vs.core

# 1. Load your video
clip = your_video_loader("source.mkv")

# 2. Apply Film Grain
# - ignore_chroma: If True, grain is only applied to Luma (Chroma is copied).
# - static: If True, uses the seed from the FGS table for all frames (if dynamic FGS, per event). If False, rotates the seed for each frame. Note: for `.bin` files, dynamic_seed is disabled automatically.
# - simd: Hardware SIMD architecture ('auto', 'avx512', 'avx2', 'sse41', 'sse3', 'sse2', or 'none'/'c' for plain C). Defaults to 'auto'.
# - temporal_average: Apply temporal smoothing to the generated grain. Provide a float (weight) or a tuple (weight, radius).
clip = vsfgs.apply_fgs(clip, "grain_table.bin", ignore_chroma=False, static=False, simd="auto", temporal_average=0.5)

clip.set_output()
```

### Frame Properties

For each processed frame, `vsfgs` outputs the exact seed integer used during synthesis into the VapourSynth frame properties map: **`FGS_Seed`**


## Input Format & Advanced Customization

`vsfgs` supports input grain files in both standard **`.txt` (AFGS1 textual format)** and directly compiled **`.bin` (Binary format)**. It allows for extreme and advanced customization of the film grain synthesis pattern.

For complete details on the required text syntax, binary packing parameters, and an advanced visual editor to create and fine-tune these tables, please refer to the **FGSEditor** wiki:
[https://github.com/PingWer/FGSEditor](https://github.com/PingWer/FGSEditor/wiki)

## Performance & Compatibility

`vsfgs` uses `dav1d`'s hand-written Assembly instructions (AVX-512, AVX2, SSE3 ...), resulting in extremely high throughput with almost zero overhead.

**Platform Support:**

| OS | Architecture | Supported | Tested |
| :--- | :--- | :---: | :---: |
| **Windows** | x86_64, ARM64 | ✅ | ✅ |
| **Linux** | x86_64, aarch64 | ✅ | ❌ |
| **macOS** | x86_64, Apple Silicon | ✅ | ❌ |

**Benchmark Comparison** *(2,000 frames of real 1080p source via `BestSource`)*:
Tests compared `vsfgs` against `Grainer.GAUSS` (from `vsjetpack`). It also demonstrates the speedup of `dav1d`'s hardware SIMD Assembly optimizations over unvectorized reference C code (`simd='none'`).

| Format | Baseline (BestSource + 16bit conversion) | `vsfgs` (SIMD: Auto / AVX-512) | `vsfgs` (SIMD: None / Plain C) | `Grainer.GAUSS` (`vsjetpack`) |
| --- | --- | --- | --- | --- |
| **YUV420P16** | ~1128 FPS | **~557 FPS** | ~514 FPS | ~347 FPS |
| **YUV422P16** | ~866 FPS | **~434 FPS** | ~425 FPS | ~322 FPS |
| **YUV444P16** | ~649 FPS | **~305 FPS** | ~299 FPS | ~279 FPS |

## Building from Source

To compile the plugin manually, you must have a working C++ toolchain and Meson setup. The plugin depends on `dav1d`, which will be built automatically as a Meson subproject.

### Prerequisites

- **Python 3.13+** (or newer)
- **C++ Compiler**: GCC/Clang (Linux/macOS) or MSVC (Windows)
- **Meson & Ninja**: Build system (`pip install meson ninja`)
- **nasm**: Highly recommended for x86/x64 systems to enable `dav1d` assembly optimizations (drastically improves grain synthesis performance).
  - *Windows*: `choco install nasm`
  - *Linux*: `sudo apt-get install nasm` or `sudo dnf install nasm`
  - *macOS*: `brew install nasm`

### Build Steps

1. Clone the repository recursively to fetch the `dav1d` submodule:
   ```bash
   git clone --recursive https://github.com/PingWer/vs-fgs.git
   cd vs-fgs
   ```

2. Build and install the plugin directly into your active Python environment:
   ```bash
   pip install .
   ```

### Standalone Build (Without Python Installation)

If you only want to compile the VapourSynth plugin binary (DLL/SO/DYLIB) without installing it via pip, you can use Meson directly:

```bash
meson setup build --buildtype=release --vsenv
meson compile -C build
```
## TODO

- [x] **Binary FGS Support**: Support loading film grain synthesis tables directly from binary format.
- [ ] **Direct Video Extraction**: Support direct extraction of FGS tables from encoded video files (will require `grav1synth`).

## Community & Support

For questions, feedback, or troubleshooting, feel free to join and reach out on the **AV1 Weeb edition** [Discord server](https://discord.gg/NbwnwhcgUq)

## License

This project is licensed under the **MIT License**.
