Controlled Flutter plugin for reading local video metadata and extracting a cover frame through LGPL FFmpeg dynamic libraries.
This package intentionally exposes a small API surface. It does not provide arbitrary FFmpeg command execution, transcoding, compression, HLS processing, network input, or GPL/nonfree codec builds.
| Platform | Status | Notes |
|---|---|---|
| Android | Supported | arm64-v8a only, minSdk 24 |
| iOS | Supported | arm64 device and arm64 simulator, iOS 13+ |
| macOS, Windows, Linux, Web | Not supported | No platform implementation is bundled |
Android apps should keep arm64-v8a in their ABI filters unless they rebuild
and add FFmpeg dynamic libraries for additional ABIs.
flutter pub add lgpl_ffmpeg_flutterimport 'package:lgpl_ffmpeg_flutter/lgpl_ffmpeg_flutter.dart';
final info = await LgplFfmpegFlutter.readInfo(videoPath: video.path);
final backend = await LgplFfmpegFlutter.backendInfo();
final cover = await LgplFfmpegFlutter.generateCoverImage(
videoPath: video.path,
preferredTimes: const [Duration(seconds: 1), Duration(seconds: 3)],
maxLongEdge: 1280,
quality: 90,
);
final frame = await LgplFfmpegFlutter.extractFrame(
videoPath: video.path,
time: const Duration(seconds: 5),
maxLongEdge: 720,
);
final deletedCount = await LgplFfmpegFlutter.deleteGeneratedFiles();
print(info.duration);
print(info.videoCodec);
print(backend.license);
print(cover?.path);
print(frame?.actualTime);
print(deletedCount);readInfo returns a VideoInfo value with the following fields:
duration: video duration.widthandheight: encoded video dimensions when available.rotation: display rotation in degrees, defaulting to0.bitrate: stream bitrate when available.mimeType: container or video MIME type when available.formatName: FFmpeg container format name when available.videoCodec: FFmpeg video codec name when available.audioCodec: FFmpeg audio codec name when available.fileSizeBytes: local file size when available.
final info = await LgplFfmpegFlutter.readInfo(videoPath: video.path);
debugPrint('duration=${info.duration}');
debugPrint('size=${info.width}x${info.height}');
debugPrint('codec=${info.videoCodec}/${info.audioCodec}');backendInfo returns runtime diagnostics from the bundled FFmpeg libraries:
ffmpegVersion: FFmpeg version string compiled into libavutil.avformatVersion,avcodecVersion, andavutilVersion: linked library versions.configuration: FFmpeg configure arguments compiled into the libraries.license: FFmpeg license string reported by libavformat.supportedInputFormats: container formats enabled by the bundled build.supportedVideoDecoders: video decoders enabled by the bundled build.supportedAudioDecoders: audio decoders enabled by the bundled build.outputImageFormat: generated image format, currentlypng.
final backend = await LgplFfmpegFlutter.backendInfo();
debugPrint(backend.ffmpegVersion);
debugPrint(backend.supportedInputFormats.join(', '));
debugPrint(backend.configuration);generateCoverImage writes a .png image file in the platform cache directory
and returns a CoverImage value with the generated path, output dimensions,
requested timestamp, and best-effort decoded frame timestamp.
extractFrame extracts a frame near the requested time and returns the same
CoverImage metadata. Seeking is best-effort and does not guarantee exact
frame-accurate output.
generateCover remains available for backwards compatibility and returns only
the generated PNG path.
final cover = await LgplFfmpegFlutter.generateCoverImage(
videoPath: video.path,
preferredTimes: const [Duration(milliseconds: 300), Duration(seconds: 1)],
maxLongEdge: 1280,
);
final frame = await LgplFfmpegFlutter.extractFrame(
videoPath: video.path,
time: const Duration(seconds: 5),
maxLongEdge: 720,
);
debugPrint(cover?.path);
debugPrint('${frame?.width} x ${frame?.height}');generateCoverImage accepts these options:
preferredTimes: candidate timestamps to try in order. When omitted, the native implementation chooses fallback timestamps.maxLongEdge: maximum output width or height after scaling. The value must be greater than0; the default is1920.quality: reserved output quality value from1to100; the default is95.
deleteGeneratedFiles removes only plugin-generated lgpl_ffmpeg_*.png files
from the platform cache and returns the number of deleted files.
final deletedCount = await LgplFfmpegFlutter.deleteGeneratedFiles();
debugPrint('Deleted $deletedCount generated image(s).');Errors from the platform layer are surfaced as VideoProcessException.
Known error codes include:
invalidPath: the input path is empty or otherwise invalid. The Dart API also uses this code formaxLongEdge <= 0orqualityoutside1..100before invoking the platform layer.invalidArgument: native arguments are malformed, including platform-layer validation failures formaxLongEdgeorquality.openFailed: FFmpeg could not open the local video file.noVideoStream: the input file does not contain a video stream.readInfoFailed: metadata probing failed.decodeFailed: a frame could not be decoded.outputFailed: cover file creation, scaling, or rotation failed.ffmpegUnavailable: bundled native FFmpeg libraries could not be loaded.unknown: fallback for an unrecognized platform error code.
try {
final cover = await LgplFfmpegFlutter.generateCoverImage(
videoPath: video.path,
);
if (cover != null) {
// The path points to a generated .png file in the platform cache directory.
}
} on VideoProcessException catch (error) {
// Handle error.code and error.message in the host app.
}The example app lets you pick a local video, read its metadata, generate a
cover frame, extract a frame near a chosen timestamp, inspect backend
capabilities, and clean generated cache files.
cd example
flutter runOn Android, run the example on an arm64-v8a device or emulator unless you
have rebuilt and bundled FFmpeg libraries for another ABI.
This package bundles prebuilt FFmpeg 8.0.1 dynamic libraries for Android and iOS. The bundled libraries are built with an LGPL-oriented configuration:
--disable-gpl
--disable-nonfree
--enable-shared
--disable-static
--disable-programs
--disable-doc
--disable-network
--disable-autodetect
Forbidden options for this package include --enable-gpl,
--enable-nonfree, --enable-libx264, --enable-libx265,
--enable-libxvid, and --enable-libvidstab.
The build script and recorded configuration are included in the package:
scripts/build_ffmpeg_lgpl.shthird_party/ffmpeg/VERSIONthird_party/ffmpeg/source-url.txtthird_party/ffmpeg/configure_args.txt
The lgpl_ffmpeg_flutter plugin code is released under the MIT License.
The bundled FFmpeg dynamic libraries are distributed under the GNU Lesser
General Public License version 2.1 or later (LGPL v2.1+). FFmpeg license texts
and third-party notices are included in NOTICE.md and
third_party/ffmpeg/LICENSES/.