Package selection guidance compiled from public package information, community data, and project usage.
A Flutter package that enables efficient encoding of raw RGB frames into MP4 videos using hardware H.264 encoders on Android, iOS, and macOS. It supports PCM audio input for creating M4A audio tracks, making it ideal for real-time video recording and processing. The package leverages native platform capabilities to deliver high performance with minimal CPU usage. Designed for developers building multimedia applications requiring fast, low-latency video encoding.
Use cases
Real-time video recording
Live streaming capture
Video editing workflows
On-device video compression
Audio-video synchronization
Key features
Hardware-accelerated H.264 encoding
PCM audio support
Cross-platform compatibility
Low CPU overhead
Simple API for frame input
Suitable for
Mobile video apps
Camera-based applications
Media processing tools
Embedded video systems
High-performance recording
Considerations
Requires native platform permissions
Limited to RGB input format
No software fallback for encoding
Platform-specific configuration needed
Audio sync requires precise timing
Original README
Original README snapshot from the linked source repository. Visit the repository for the latest content.
Quickly encode raw RGB images & PCM audio to MP4 video using the system h264 encoder
No Dependencies
FlutterQuickVideoEncoder has zero dependencies besides Flutter, Android, iOS, and MacOS themselves. No FFMPEG.
We use AVFoundation on iOS and MediaCodec on Android. These are native system libraries.
For encoding raw RGB pixels
Unlike the video_compress package, this package takes raw rgb pixel buffers as input, not video files.
⭐ Stars ⭐
Please star this repo & on pub.dev. We all benefit from having a larger community.
Usage
awaitFlutterQuickVideoEncoder.setup(
width: 1920,
height: 1080,
fps: 60,
videoBitrate: 2500000,
audioChannels: 1,
audioBitrate: 64000,
sampleRate: 44100,
filepath: "/documents/video.mp4", // output file
);
for(int i = 0; i < frameCount; i++) {
Uint8List rgba = _renderVideoFrame(i); // your video functionUint8List pcm = _renderAudioFrame(i); // your audio functionawaitFlutterQuickVideoEncoder.appendVideoFrame(rgba);
awaitFlutterQuickVideoEncoder.appendAudioFrame(pcm);
}
awaitFlutterQuickVideoEncoder.finish();
Example App
Enable the platforms you need.
cd ./example
flutter config --enable-macos-desktop
flutter config --enable-android
flutter config --enable-ios
flutter create .
flutter run
Create video frames using ui.Image
The easiest way to render a video frame is to use Flutter!
For example, you can render an RGBA frame using ui.Image
Future<Uint8List> _generateVideoFrame(int frameIndex) async {
constint boxSize = 50; // Size of the moving box// Calculate the box positionint boxX = (frameIndex * 5) % width;
int boxY = (frameIndex * 5) % height;
// Paint the moving boxfinal recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
final paint = Paint();
// Draw a white background
paint.color = Colors.white;
canvas.drawRect(Rect.fromLTWH(0, 0, width.toDouble(), height.toDouble()), paint);
// Draw the blue box
paint.color = Colors.blue;
canvas.drawRect(Rect.fromLTWH(boxX.toDouble(), boxY.toDouble(), boxSize.toDouble(), boxSize.toDouble()), paint);
// Convert canvas to imagefinal picture = recorder.endRecording();
final img = await picture.toImage(width, height);
// Convert the image to a byte arrayfinal byteData = await img.toByteData(format: ui.ImageByteFormat.rawRgba);
return byteData!.buffer.asUint8List();
}
Create video frames from Widgets
You can also create video frames from widgets, using RenderRepaintBoundary
import'dart:ui'as ui;
import'package:flutter/material.dart';
import'dart:typed_data';
classMyWidgetextendsStatefulWidget{
@override_MyWidgetStatecreateState() => _MyWidgetState();
}
class_MyWidgetStateextendsState<MyWidget> {
GlobalKey repaintBoundaryKey = GlobalKey();
@overrideWidgetbuild(BuildContext context) {
returnRepaintBoundary(
key: repaintBoundaryKey,
child: YourWidget(), // Replace with your actual widget
);
}
// you would then call appendVideoFrame with this dataFuture<Uint8List?> captureWidgetAsRGBA() async {
try {
RenderRepaintBoundary boundary = repaintBoundaryKey.currentContext!.findRenderObject() asRenderRepaintBoundary;
ui.Image image = await boundary.toImage(pixelRatio: 1.0);
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
return byteData?.buffer.asUint8List();
} catch (e) {
print(e);
returnnull;
}
}
}