video_forge 1.0.0
video_forge: ^1.0.0 copied to clipboard
High-performance Rust video processing engine for Flutter. Hardware-accelerated video transcoding, frame-accurate previews, audio mixing, and fast thumbnail generation powered by FFmpeg. Low-level eng [...]
video_forge #
Open-source project maintained by the community. Found a bug or want to contribute? PRs and issues are welcome.
High-performance Rust video processing engine for Flutter — hardware-accelerated transcoding, frame-accurate previews, audio mixing, and fast thumbnail generation. Powered by native FFmpeg with platform codecs (MediaCodec, VideoToolbox).
Note
This is a low-level engine — raw FFI bindings to Rust + FFmpeg. Provides hardware-accelerated transcoding, frame-accurate previews, audio mixing, and thumbnail generation.
Platform Support #
| Platform | Status |
|---|---|
| Android | Tested (SDK 24+, MediaCodec) |
| iOS | Tested (13.0+, VideoToolbox) |
| macOS | Tested (10.15+, VideoToolbox) |
| Windows | In progress |
| Linux | In progress |
| Web | Not supported |
Quick Start #
import 'package:video_forge/video_forge.dart';
// Call once at app startup
await initialize();
// Probe video metadata
final info = await getMediaInfo(path: '/path/to/video.mp4');
print('${info.width}x${info.height} ${info.durationMs}ms');
// Compress with progress stream
final progress = startCompress(options: CompressOptions(
inputPath: '/path/to/video.mp4',
outputPath: '/path/to/output.mp4',
));
await for (final event in progress) {
print('${event.phase}: ${event.fps} fps');
}
// Extract a thumbnail
final thumbPath = await thumbnail(options: ThumbnailOptions(
inputPath: '/path/to/video.mp4',
positionMs: 1500,
outputPath: '/path/to/thumb.jpg',
));
What You Can Do #
- Video transcoding — Async compression with hardware acceleration (MediaCodec, VideoToolbox). Phase-based progress reporting with FPS and ETA.
- Metadata probing — Fast MP4 inspection (mp4parse) with FFmpeg fallback. Dimensions, duration, framerate, codecs, rotation, Dolby Vision markers.
- Thumbnails & filmstrips — Frame-accurate single/batch extraction with optimized GOP seek. Output to files or in-memory byte arrays.
- Frame-accurate previews — Decode frames to raw RGBA or Apple zero-copy
CVPixelBuffer. No temp files. - Audio mixing — Mix external audio tracks with source video. Per-track offsets, durations, and volume.
- Overlay burn-in — Composite PNG overlays (watermarks, stickers) onto video frames with fade transitions.
- Playback sessions — Decoder-driven playback with seek, play/pause, and custom frame-rate ticks.
- Buffer pool — Recycled byte vectors to eliminate allocations during scrub sessions.
For the full API, see the Dart API reference.
Pros & Cons #
| Pros | Cons |
|---|---|
| Hardware-accelerated video processing | No web support |
| Async jobs with progress updates | FFmpeg libraries add significant app size |
| Android, iOS, macOS (Windows & Linux in progress) | FFmpeg setup can be involved (especially macOS VT) |
| Frame-accurate previews without temp files | FFmpeg is LGPL — requires license notice in your app |
| Built-in audio mixing for timeline editors | Needs native build toolchain, not pure Dart |
| Fast thumbnail and filmstrip generation | Large binary from bundled video codecs |
App Size #
The package includes native Rust code plus external FFmpeg libraries:
| Component | Est. Size |
|---|---|
| Rust engine (transcoding, preview, thumbnails, audio mix) | ~5–8 MB |
| FFmpeg libraries (libavcodec, libavformat, libavfilter, libswscale) | ~15–30 MB |
| Total | ~20–38 MB |
FFmpeg is the dominant cost. The Rust engine itself is modest — most of the weight comes from video/audio codec libraries. Android uses App Bundles, so users only download their device's ABI.
Installation #
flutter pub add video_forge
Prerequisites:
- Rust toolchain on your development machine
- FFmpeg libraries (
libavcodec,libavformat,libavfilter,libswscale) on your linker path - macOS with VideoToolbox: Build FFmpeg with VT support
- Android: NDK configured in
local.properties; install Android Rust targets:rustup target add aarch64-linux-android armv7-linux-androideabi \ x86_64-linux-android i686-linux-android
More Examples #
Batch thumbnails (filmstrip) #
final result = await batchThumbnails(options: BatchThumbnailOptions(
inputPath: '/path/to/video.mp4',
positionsMs: [0, 5000, 10000, 15000],
outputDir: '/tmp/thumbs',
));
// Or in-memory for UI display
final frames = await batchThumbnailBytes(options: BatchThumbnailBytesOptions(
inputPath: '/path/to/video.mp4',
positionsMs: [0, 5000, 10000, 15000],
));
Frame-accurate preview decode #
final frame = await decodePreviewFrameRgba(
inputPath: '/path/to/video.mp4',
positionMs: BigInt.from(4200),
maxEdge: 720,
);
// frame.width, frame.height, frame.data (RGBA bytes)
Cancel a running job #
final jobId = /* from startCompress */;
await cancelJob(jobId: jobId);
print('Active jobs: ${await activeJobCount()}');
Contributing #
This package is part of the MediaForge monorepo. Issues and pull requests are welcome on GitHub.