# Faceswap Writer Plugins for Video Output: ffmpeg, gif, and patch Explained

> Explore Faceswap writer plugins: ffmpeg for fast video, gif for animations, and patch for face extraction. Understand their roles in video output.

- Repository: [deepfakes/faceswap](https://github.com/deepfakes/faceswap)
- Tags: deep-dive
- Published: 2026-03-06

---

**Faceswap delegates all video and image output to modular writer plugins—ffmpeg for high-performance video encoding, gif for animated loops, and patch for face-patch extraction—each implementing the abstract `Output` class from [`plugins/convert/writer/_base.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/_base.py).**

The deepfakes/faceswap conversion pipeline relies on a plugin-based architecture to generate final output. When you run the `convert` command with the `-w/--writer` flag, the system loads a specific writer plugin via `PluginLoader.get_converter("writer", name)` to handle frame serialization. These plugins handle everything from high-efficiency video compression to per-face image extraction with transformation metadata.

## Writer Plugin Architecture

All output handlers inherit from the abstract `Output` class defined in [`plugins/convert/writer/_base.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/_base.py). This base implements core methods including `write()`, `close()`, and frame-ordering logic to ensure sequential output regardless of processing order.

The `PluginLoader` class in [`plugins/plugin_loader.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/plugin_loader.py) registers each writer under the *convert → writer* category. When you specify a writer name via CLI, the loader returns the concrete implementation class that matches the requested output format.

## Video Output Writer Plugins

Faceswap provides three primary writer plugins for video and sequence output: **ffmpeg** for standard video containers, **gif** for animated images, and **patch** for extracted face data.

### ffmpeg Writer

The **ffmpeg** writer in [`plugins/convert/writer/ffmpeg.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/ffmpeg.py) generates high-performance video output using *imageio-ffmpeg*. It supports container formats such as MP4, MKV, and WebM with configurable codec selection, CRF values, presets, and tuning options.

Key implementation details include:

- **FPS detection**: The `_video_fps()` method extracts the source video frame rate to maintain temporal accuracy.
- **Audio handling**: `_test_for_audio_stream()` checks for audio streams and handles muxing or skipping based on configuration.
- **Parameter building**: `_output_params()` constructs the ffmpeg command-line arguments dynamically.
- **Frame writing**: Uses `imageio_ffmpeg.write_frames` as a generator to stream frames efficiently.

Configuration options reside in [`plugins/convert/writer/ffmpeg_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/ffmpeg_defaults.py), exposing helpers like `codec()`, `crf()`, and `preset()` that read from [`config/convert.ini`](https://github.com/deepfakes/faceswap/blob/main/config/convert.ini).

### gif Writer

The **gif** writer in [`plugins/convert/writer/gif.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/gif.py) produces animated GIFs using the *imageio* library. It supports configurable FPS, palette sizes, loop counts, and sub-rectangle optimization for reduced file sizes.

After receiving the first frame, the writer lazily initializes the `imageio` GIF writer and fixes output dimensions via `_set_dimensions()`. The implementation maintains a frame cache to handle out-of-order processing, appending each frame via `self._writer.append_data()`.

Default values and helper functions are defined in [`plugins/convert/writer/gif_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/gif_defaults.py).

### patch Writer

The **patch** writer in [`plugins/convert/writer/patch.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/patch.py) exports each swapped face as an individual image file (PNG or TIFF) alongside a JSON sidecar containing the transformation matrix. This plugin is essential for downstream pipelines that require re-insertion of processed faces into original frames.

Key features include:

- **Individual file output**: Saves each face patch separately with configurable naming conventions.
- **Metadata preservation**: Stores the affine transformation matrix in a companion JSON file when `--patch.json-output` is enabled.
- **Bit-depth control**: Supports 8-bit or 16-bit output depths via [`patch_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/patch_defaults.py).

This writer does not produce video files but generates image sequences with spatial metadata, making it distinct from the ffmpeg and gif video encoders.

## Static Image Writers

In addition to video-specific plugins, Faceswap includes **pillow** and **opencv** writers for simple static image output.

The **pillow** writer ([`plugins/convert/writer/pillow.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/pillow.py)) delegates to Pillow's `Image.save()` method, supporting any format Pillow handles natively. The **opencv** writer ([`plugins/convert/writer/opencv.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/opencv.py)) uses `cv2.imwrite()` and provides access to OpenCV-specific encoding flags such as PNG compression levels.

Both inherit the same caching and ordering logic from the base class but lack video-specific options.

## Configuration and Defaults

Each writer plugin maintains a corresponding defaults module that interfaces with the global Faceswap configuration:

- [`ffmpeg_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/ffmpeg_defaults.py): Exposes `codec()`, `crf()`, `preset()`, and audio muxing options.
- [`gif_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/gif_defaults.py): Controls `fps()`, `loop()`, and `palettesize()` settings.
- [`patch_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/patch_defaults.py): Manages `format()`, `bit-depth()`, and JSON output toggles.

These modules read from [`config/convert.ini`](https://github.com/deepfakes/faceswap/blob/main/config/convert.ini) and provide type-safe access to user preferences.

## Command Line Usage Examples

Select your output format using the `-w` or `--writer` flag followed by plugin-specific arguments.

### Encoding to MP4 with ffmpeg

```bash
faceswap convert -i input_folder -o output_folder -w ffmpeg \
    --ffmpeg.codec libx264 --ffmpeg.crf 23 --ffmpeg.preset medium

```

This creates `*_converted.mp4` with H.264 encoding at CRF 23. Audio automatically muxes from the source unless you specify `--ffmpeg.skip-mux`.

### Creating Animated GIFs

```bash
faceswap convert -i frames/ -o gif_output/ -w gif \
    --gif.fps 15 --gif.loop 0 --gif.palettesize 256

```

The output `frames_converted.gif` loops infinitely at 15 FPS using a 256-color palette.

### Extracting Face Patches

```bash
faceswap convert -i video.mp4 -o patches/ -w patch \
    --patch.format png --patch.bit-depth 16 --patch.json-output true

```

Each swapped face saves as a 16-bit PNG with a corresponding JSON file containing the transform matrix.

### Static Image Output

For simple frame-by-frame output using Pillow:

```bash
faceswap convert -i frames/ -o images/ -w pillow

```

Or using OpenCV with compression flags:

```bash
faceswap convert -i frames/ -o images_opencv/ -w opencv \
    --opencv.png-compress-level 3

```

## Summary

- **Plugin Architecture**: All writers inherit from the abstract `Output` class in [`plugins/convert/writer/_base.py`](https://github.com/deepfakes/faceswap/blob/main/plugins/convert/writer/_base.py) and register via `PluginLoader`.
- **ffmpeg**: High-performance video encoding with audio muxing, codec selection, and quality controls via [`ffmpeg_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/ffmpeg_defaults.py).
- **gif**: Animated GIF generation with configurable looping and palette optimization using `imageio`.
- **patch**: Face-patch extraction with transformation matrix metadata for downstream processing pipelines.
- **Configuration**: Each plugin has a dedicated defaults file (e.g., [`ffmpeg_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/ffmpeg_defaults.py)) that reads from [`config/convert.ini`](https://github.com/deepfakes/faceswap/blob/main/config/convert.ini).
- **CLI Selection**: Use `-w plugin_name` to activate a specific writer with `--plugin.option` syntax for parameters.

## Frequently Asked Questions

### What is the difference between the ffmpeg and gif writers in Faceswap?

The **ffmpeg** writer generates standard video container files (MP4, MKV, WebM) using *imageio-ffmpeg* with full audio support and codec customization, while the **gif** writer produces animated GIF images optimized for web use with limited color palettes and no audio track. Use ffmpeg for high-fidelity video preservation and gif for lightweight, looping previews.

### When should I use the patch writer instead of video output?

Use the **patch** writer when you need to extract individual face images with their transformation matrices for external editing or re-insertion into different backgrounds. Unlike ffmpeg or gif, the patch writer outputs separate PNG/TIFF files and JSON sidecars rather than a single video file, making it ideal for compositing workflows.

### How do I configure video codec and quality settings?

Codec selection, CRF values, and encoding presets are configured through the [`ffmpeg_defaults.py`](https://github.com/deepfakes/faceswap/blob/main/ffmpeg_defaults.py) module or via CLI arguments. Pass `--ffmpeg.codec` (e.g., `libx264`, `libx265`), `--ffmpeg.crf` (0-51, lower is higher quality), and `--ffmpeg.preset` (e.g., `slow`, `medium`, `fast`) to balance quality versus encoding speed.

### Can I use the pillow or opencv writers for video sequences?

While **pillow** and **opencv** writers can process video frames, they output individual static images rather than encoded video files. These writers are suitable when you need frame-by-frame access or specific image formats, but they lack the compression efficiency and audio capabilities of the ffmpeg writer.