The ProVideoEditor is a Flutter widget designed for video editing within your application. It provides a flexible and convenient way to integrate video editing capabilities into your Flutter project.
Table of contents
- ๐ท Preview
- โจ Features
- ๐ง Setup
- โ Usage
- ๐ Sponsors
- ๐ฆ Included Packages
- ๐ค Contributors
- ๐ License
- ๐ Notices
Preview
| Basic-Editor | Grounded-Design | Paint-Editor |
|---|---|---|
|
|
|
| Crop-Rotate-Editor | Tune-Editor | Filter-Editor |
|---|---|---|
|
|
|
| Paint-Editor-Grounded | Emoji-Editor | |
|---|---|---|
|
|
Features
๐ฅ Video Editing Capabilities
- ๐ Metadata: Extract detailed metadata from the video file.
- ๐ผ๏ธ Thumbnails: Generate one or multiple thumbnails from the video.
- ๐๏ธ Keyframes: Retrieve keyframe information from the video.
- โ๏ธ Trim: Cut the video to a specified start and end time.
- ๐ Merge Videos: Concatenate multiple video clips into a single output.
- โฉ Playback Speed: Adjust the playback speed of the video.
- ๐ Mute Audio: Remove or mute the audio track from the video.
๐ง Transformations
- โ๏ธ Crop by
x,y,width, andheight - ๐ Flip horizontally and/or vertically
- ๐ Rotate by 90deg turns
- ๐ Scale to a custom size
๐จ Visual Effects
- ๐ผ๏ธ Layers: Overlay a image like a text or drawings on the video.
- ๐งฎ Color Matrix: Apply one or multiple 4x5 color matrices (e.g., for filters).
- ๐ง Blur: Add a blur effect to the video.
- ๐ก Bitrate: Set a custom video bitrate. If constant bitrate (CBR) isn't supported, it will gracefully fall back to the next available mode.
๐ฑ Runtime Features
- ๐ Progress: Track the progress of one or multiple running tasks.
- ๐งต Multi-Tasking: Execute multiple video processing tasks concurrently.
Platform Support
| Method | Android | iOS | macOS | Windows | Linux | Web |
|---|---|---|---|---|---|---|
Metadata |
โ | โ | โ | โ | โ ๏ธ | โ |
Thumbnails |
โ | โ | โ | โ | โ | โ |
KeyFrames |
โ | โ | โ | โ | โ | โ |
Rotate |
โ | โ | โ | โ | โ | ๐ซ |
Flip |
โ | โ | โ | โ | โ | ๐ซ |
Crop |
โ | โ | โ | โ | โ | ๐ซ |
Scale |
โ | โ | โ | โ | โ | ๐ซ |
Trim |
โ | โ | โ | โ | โ | ๐ซ |
Playback-Speed |
โ | โ | โ | โ | โ | ๐ซ |
Remove-Audio |
โ | โ | โ | โ | โ | ๐ซ |
Overlay Layers |
โ | โ | โ | โ | โ | ๐ซ |
Multiple ColorMatrix 4x5 |
โ | โ | โ | โ | โ | ๐ซ |
Cancel export task |
โ | โ | โ | โ | โ | ๐ซ |
Blur background |
๐งช | ๐งช | ๐งช | โ | โ | ๐ซ |
Custom Audio Tracks |
๐งช | โ | โ | โ | โ | ๐ซ |
Merge Videos |
โ | โ | โ | โ | โ | ๐ซ |
Censor-Layers "Pixelate" |
โ | โ | โ | โ | โ | ๐ซ |
Legend
- โ Supported with Native-Code
- โ ๏ธ Supported with Native-Code but not tested
- ๐งช Supported but visual output can differs from Flutter
- โ Not supported but planned
- ๐ซ Not supported and not planned
Setup
Android, iOS, macOS, Linux, Windows, Web
No additional setup required.
Usage
Basic Example
var data = RenderVideoModel(
video: EditorVideo.asset('assets/my-video.mp4'),
// video: EditorVideo.file(File('/path/to/video.mp4')),
// video: EditorVideo.network('https://example.com/video.mp4'),
// video: EditorVideo.memory(videoBytes),
enableAudio: false,
startTime: const Duration(seconds: 5),
endTime: const Duration(seconds: 20),
);
Uint8List result = await ProVideoEditor.instance.renderVideo(data);
/// If you're rendering larger videos, it's better to write them directly to a file
/// instead of returning them as a Uint8List, as this can overload your RAM.
///
/// final directory = await getTemporaryDirectory();
/// String outputPath = '${directory.path}/my_video.mp4';
///
/// await ProVideoEditor.instance.renderVideoToFile('${directory.path}/my_video.mp4', data);
/// Listen progress
StreamBuilder<ProgressModel>(
stream: ProVideoEditor.instance.progressStream,
builder: (context, snapshot) {
var progress = snapshot.data?.progress ?? 0;
return CircularProgressIndicator(value: animatedValue);
}
)
Quality Preset Example
/// Use quality presets for simplified video export configuration
/// Available presets: ultra4K, k4, p1080High, p1080, p720High, p720, p480, low, custom
var data = RenderVideoModel.withQualityPreset(
video: EditorVideo.asset('assets/my-video.mp4'),
qualityPreset: VideoQualityPreset.p1080, // 1080p at 8 Mbps
startTime: const Duration(seconds: 5),
endTime: const Duration(seconds: 20),
);
Uint8List result = await ProVideoEditor.instance.renderVideo(data);
/// Override the preset's bitrate if needed
var customData = RenderVideoModel.withQualityPreset(
video: EditorVideo.asset('assets/my-video.mp4'),
qualityPreset: VideoQualityPreset.p720,
bitrateOverride: 5000000, // 5 Mbps instead of default 3 Mbps
);
Merge Videos Example
/// Concatenate multiple video clips into a single output video
/// Each clip can have its own trim settings (startTime/endTime)
var data = RenderVideoModel(
videoClips: [
VideoSegment(
video: EditorVideo.file(File('/path/to/video1.mp4')),
startTime: Duration(seconds: 0),
endTime: Duration(seconds: 5),
),
VideoSegment(
video: EditorVideo.file(File('/path/to/video2.mp4')),
startTime: Duration(seconds: 2),
endTime: Duration(seconds: 8),
),
VideoSegment(
video: EditorVideo.asset('assets/video3.mp4'),
// No trim - uses full video duration
),
],
outputFormat: VideoOutputFormat.mp4,
);
Uint8List result = await ProVideoEditor.instance.renderVideo(data);
/// Note: You must use either 'video' (single video) OR 'videoClips' (multiple videos),
/// but not both. The clips will be joined in the order they appear in the list.
Cancel an active render
The cancel API is currently implemented only on Android, iOS, and macOS.
On Windows, Linux, and Web, cancel is not wired up yet, so callers should either:
- gate by platform before calling
cancel, or - be prepared to handle a
PlatformException/UnimplementedError.
When you cancel a render started with renderVideoToFile, the returned Future completes with a RenderCanceledException. If your UI is awaiting that future directly (instead of using unawaited), make sure to catch this exception so you can reset any loading state cleanly rather than treating it as an error.
final renderModel = RenderVideoModel(
video: EditorVideo.asset('assets/sample.mp4'),
);
final outputPath = '${(await getTemporaryDirectory()).path}/video.mp4';
// Start the render. Keep the model.id so you can cancel it later.
final renderFuture = ProVideoEditor.instance.renderVideoToFile(
outputPath,
renderModel,
);
// Option 1: fire-and-forget (example app pattern).
unawaited(renderFuture);
// Option 2: if you await directly, handle cancellation:
try {
await renderFuture;
} on RenderCanceledException {
// User canceled: reset UI state, do not treat as an error.
}
// ...from a UI callback (Android/iOS/macOS only)
if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {
await ProVideoEditor.instance.cancel(renderModel.id);
}
Advanced Example
/// Every option except videoBytes is optional.
var task = RenderVideoModel(
id: 'my-special-task'
video: EditorVideo.asset('assets/my-video.mp4'),
imageBytes: imageBytes, /// A image "Layer" which will overlay the video.
outputFormat: VideoOutputFormat.mp4,
playbackSpeed: 2,
startTime: const Duration(seconds: 5),
endTime: const Duration(seconds: 20),
blur: 10,
bitrate: 5000000,
customAudioPath: customAudioPath,
enableAudio: false,
originalAudioVolume: 0.7, // Original audio at 70%
customAudioVolume: 0.3, // Background music at 30%
transform: const ExportTransform(
flipX: true,
flipY: true,
x: 10,
y: 20,
width: 300,
height: 400,
rotateTurns: 3,
scaleX: .5,
scaleY: .5,
),
colorMatrixList: [
[ 1.0, 0.0, 0.0, 0.0, 50.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 ],
[ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 ],
],
);
Uint8List result = await ProVideoEditor.instance.renderVideo(task);
/// Note: Blur is an experimental feature (๐งช in platform matrix)
/// The blur effect may render differently than in Flutter's preview.
/// Listen progress
StreamBuilder<ProgressModel>(
stream: ProVideoEditor.instance.progressStreamById(task.id),
builder: (context, snapshot) {
var progress = snapshot.data?.progress ?? 0;
return TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0, end: progress),
duration: const Duration(milliseconds: 300),
builder: (context, animatedValue, _) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
spacing: 10,
children: [
CircularProgressIndicator(value: animatedValue),
Text(
'${(animatedValue * 100).toStringAsFixed(1)} / 100',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
)
],
);
});
}
)
Editor Example
The video editor requires the use of the pro_image_editor. You can find the basic video editor example here and the "grounded" design example here.
You can also use other prebuilt designs from pro_image_editor, such as the WhatsApp or Frosted Glass design. Just check the examples in pro_image_editor to see how it's done.
API Reference
VideoSegment
Represents a video clip segment for merging multiple videos.
VideoSegment({
required EditorVideo video, // Video source (file, asset, network, memory)
Duration? startTime, // Optional: Start time for trimming
Duration? endTime, // Optional: End time for trimming
})
Parameters:
video(required): The video source usingEditorVideo.file(),EditorVideo.asset(),EditorVideo.network(), orEditorVideo.memory().startTime(optional): The starting point for this clip. If omitted, starts from the beginning (0:00).endTime(optional): The ending point for this clip. If omitted, uses the full video duration.
Usage Example:
// Full video
VideoSegment(video: EditorVideo.asset('video.mp4'))
// Trimmed video (5s to 10s)
VideoSegment(
video: EditorVideo.file(File('video.mp4')),
startTime: Duration(seconds: 5),
endTime: Duration(seconds: 10),
)
Metadata Example
VideoMetadata result = await ProVideoEditor.instance.getMetadata(
video: EditorVideo.asset('assets/my-video.mp4'),
);
Thumbnails Example
List<Uint8List> result = await ProVideoEditor.instance.getThumbnails(
ThumbnailConfigs(
video: EditorVideo.asset('assets/my-video.mp4'),
outputFormat: ThumbnailFormat.jpeg,
timestamps: const [
Duration(seconds: 10),
Duration(seconds: 15),
Duration(seconds: 22),
],
outputSize: const Size(200, 200),
boxFit: ThumbnailBoxFit.cover,
),
);
Keyframes Example
List<Uint8List> result = await ProVideoEditor.instance.getKeyFrames(
KeyFramesConfigs(
video: EditorVideo.asset('assets/my-video.mp4'),
outputFormat: ThumbnailFormat.jpeg,
maxOutputFrames: 20,
outputSize: const Size(200, 200),
boxFit: ThumbnailBoxFit.cover,
),
);
Sponsors
Included Packages
A big thanks to the authors of these amazing packages.
- Packages created by the Dart team:
Contributors
Made with contrib.rocks.
Libraries
- core/models/exceptions/render_exceptions
- core/models/thumbnail/key_frames_configs_model
- core/models/thumbnail/thumbnail_base_abstract
- core/models/thumbnail/thumbnail_box_fit_model
- core/models/thumbnail/thumbnail_configs_model
- core/models/thumbnail/thumbnail_format_model
- core/models/video/editor_video_model
- core/models/video/export_transform_model
- core/models/video/progress_model
- core/models/video/render_video_model
- core/models/video/video_metadata_model
- core/models/video/video_quality_config
- core/models/video/video_quality_preset
- core/models/video/video_segment_model
- core/platform/io/io_helper
- core/platform/io/io_web
- core/platform/native_method_channel
- core/platform/platform_interface
- core/platform/web_method_channel
- core/services/web/web_manager
- core/services/web/web_meta_data_reader
- core/services/web/web_thumbnail_generator
- core/utils/web_blob_utils
- core/utils/web_canvas_utils
- pro_video_editor
- shared/utils/converters
- shared/utils/file_constructor_utils
- shared/utils/parser/double_parser
- shared/utils/parser/int_parser
- shared/utils/parser/size_parser