smart_video_thumbnail 0.6.0
smart_video_thumbnail: ^0.6.0 copied to clipboard
High-performance Flutter plugin for extracting video thumbnails using native FFmpeg engine. Supports all video formats (MP4, AVI, MKV, FLV, etc.) with CPU-only decoding.
smart_video_thumbnail #
A powerful Flutter plugin for generating video thumbnails using native FFmpeg engine. Fast, reliable, and supports all major video formats.
πΈ Screenshot #
![]()
Example app showing video thumbnails in a grid layout
β¨ Features #
- π¬ Native FFmpeg - Uses CPU-only decoding for maximum compatibility
- π¦ All Formats - Supports MP4, AVI, MKV, FLV, WMV and other FFmpeg formats
- π Fast - Optimized frame extraction with minimal overhead
- πΎ Caching - Automatic thumbnail caching for better performance (v0.2.0)
- π Progress - Real-time progress callbacks during generation (v0.2.0)
- π― Flexible - Multiple seek strategies (normal, keyframe, firstFrame)
- π§ Independent - No dependency on MediaMetadataRetriever or system APIs
- πͺ Reliable - Works with corrupted or unusual video files
- π± Optimized - ARM-only builds for smaller APK size (v0.2.0)
π¦ Installation #
Add this to your package's pubspec.yaml file:
dependencies:
smart_video_thumbnail: ^0.2.0
Then run:
flutter pub get
Android Setup #
No additional setup required! The plugin automatically downloads the native FFmpeg library from JitPack.
Note: The first build may take a bit longer as Gradle downloads the native library (~8MB).
iOS Setup #
No additional setup required! The plugin uses native AVFoundation framework for video processing.
Note: Make sure your app has the necessary permissions in Info.plist:
<key>NSPhotoLibraryUsageDescription</key> <string>This app needs access to your photo library to select videos.</string>Implementation Note: iOS version uses AVFoundation instead of FFmpeg for better system integration and smaller binary size.
macOS Setup #
No additional setup required! The plugin uses native AVFoundation framework for video processing.
Note: Make sure your app has the necessary entitlements for file access:
com.apple.security.files.user-selected.read-onlycom.apple.security.files.user-selected.read-writeThese are required for accessing video files selected by the user.
Implementation Note: macOS version uses AVFoundation instead of FFmpeg for better system integration and smaller binary size.
π Usage #
Basic Example #
import 'package:smart_video_thumbnail/smart_video_thumbnail.dart';
// Extract thumbnail at 1 second
final thumbnail = await SmartVideoThumbnail.getThumbnail(
videoPath: '/path/to/video.mp4',
timeMs: 1000,
width: 320,
height: 180,
);
if (thumbnail != null) {
// thumbnail is Uint8List with RGBA8888 data
// Size: width * height * 4 bytes
print('Thumbnail extracted: ${thumbnail.length} bytes');
}
Display with Image Widget #
import 'dart:ui' as ui;
import 'dart:async';
import 'package:flutter/material.dart';
Future<ui.Image?> createImageFromRGBA(
Uint8List rgba,
int width,
int height,
) async {
final completer = Completer<ui.Image>();
ui.decodeImageFromPixels(
rgba,
width,
height,
ui.PixelFormat.rgba8888,
(ui.Image image) {
completer.complete(image);
},
);
return completer.future;
}
// In your widget
final thumbnail = await SmartVideoThumbnail.getThumbnail(
videoPath: videoPath,
width: 320,
height: 180,
);
if (thumbnail != null) {
final image = await createImageFromRGBA(thumbnail, 320, 180);
return RawImage(image: image);
}
Extraction Strategies #
// Normal seek (default)
final thumbnail1 = await SmartVideoThumbnail.getThumbnail(
videoPath: videoPath,
strategy: ThumbnailStrategy.normal,
);
// Keyframe-focused seek (for AVI/FLV)
final thumbnail2 = await SmartVideoThumbnail.getThumbnail(
videoPath: videoPath,
strategy: ThumbnailStrategy.keyframe,
);
// First available frame (fastest)
final thumbnail3 = await SmartVideoThumbnail.getThumbnail(
videoPath: videoPath,
strategy: ThumbnailStrategy.firstFrame,
);
π API Reference #
getThumbnail #
Extracts a thumbnail from a video file.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
videoPath |
String |
β Yes | - | Path to the video file |
timeMs |
int |
β No | 1000 |
Target position in milliseconds |
width |
int |
β No | size |
Thumbnail width in pixels |
height |
int |
β No | size * 9/16 |
Thumbnail height in pixels |
size |
int |
β No | 720 |
Alternative way to set dimensions |
strategy |
ThumbnailStrategy |
β No | normal |
Frame extraction strategy |
Returns: Future<Uint8List?> - RGBA8888 pixel data or null on error
Data Format #
The plugin returns Uint8List with RGBA8888 format:
- 4 bytes per pixel (Red, Green, Blue, Alpha)
- Data size:
width * height * 4bytes - Pixel order: left to right, top to bottom
π± Platform Support #
| Platform | Status | Architectures | Backend |
|---|---|---|---|
| Android | β Supported | arm64-v8a, armeabi-v7a | FFmpeg 4.4.2 |
| iOS | β Supported | arm64, armv7 | AVFoundation |
| macOS | β Supported | x86_64, arm64 | AVFoundation |
| Windows | β Supported | x64 | Media Foundation |
| Web | β Supported | All browsers | HTML5 Video |
Supported Video Formats by Platform #
π€ Android (FFmpeg)
Supports all FFmpeg-compatible formats:
- β Container formats: MP4, AVI, MKV, FLV, WMV, MOV, 3GP, WebM, OGG, and more
- β Video codecs: H.264, H.265/HEVC, MPEG-4, VP8, VP9, Theora, WMV, DivX, Xvid, and more
- β Audio codecs: AAC, MP3, Vorbis, Opus, WMA, FLAC, and more
Note: FFmpeg provides the most comprehensive format support across all platforms.
π iOS (AVFoundation)
Supports system-native formats:
- β Container formats: MP4, MOV, M4V, 3GP
- β Video codecs: H.264, H.265/HEVC, MPEG-4
- β Audio codecs: AAC, MP3, Apple Lossless
Limitations:
- β AVI, MKV, FLV, WMV - not supported (requires FFmpeg)
- β οΈ Smaller binary size (~2MB vs ~8MB on Android)
- β οΈ Better battery efficiency due to hardware acceleration
π₯οΈ macOS (AVFoundation)
Supports system-native formats:
- β Container formats: MP4, MOV, M4V, 3GP
- β Video codecs: H.264, H.265/HEVC, MPEG-4, ProRes
- β Audio codecs: AAC, MP3, Apple Lossless, FLAC
Limitations:
- β AVI, MKV, FLV, WMV - not supported (requires FFmpeg)
- β οΈ Smaller binary size compared to FFmpeg
- β οΈ Better performance due to hardware acceleration
πͺ Windows (Media Foundation)
Supports Windows-native formats:
- β Container formats: MP4, AVI, WMV, ASF
- β Video codecs: H.264, H.265/HEVC, MPEG-4, WMV
- β Audio codecs: AAC, MP3, WMA
Limitations:
- β MKV, FLV - limited support
- β οΈ Format support depends on installed codecs
π Web (HTML5 Video)
Supports browser-native formats only:
- β MP4 (H.264/AAC) - Best compatibility, supported by all modern browsers
- β WebM (VP8/VP9/Vorbis/Opus) - Good support in Chrome, Firefox, Edge
- β Ogg (Theora/Vorbis) - Supported in Firefox, Chrome
Limitations:
- β AVI, WMV, FLV, MKV - NOT supported (no browser codecs)
- β οΈ Format support varies by browser
- β οΈ Requires video file to be loaded into memory
- π‘ Recommendation: Use MP4 (H.264) for maximum compatibility
Browser Compatibility:
| Format | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| MP4 | β | β | β | β |
| WebM | β | β | β | β |
| Ogg | β | β | β | β |
| AVI | β | β | β | β |
| WMV | β | β | β | β |
Format Recommendations #
For maximum cross-platform compatibility:
- π― Primary: MP4 (H.264 video + AAC audio)
- π― Alternative: WebM (VP9 video + Opus audio) for web
For Android-only apps:
- π― Use any format - FFmpeg supports everything
For iOS/macOS apps:
- π― Stick to MP4, MOV, M4V formats
- π― Use H.264 or H.265 codecs
For web apps:
- π― Must use: MP4 (H.264) - only reliable option
- β οΈ Convert AVI/WMV/FLV to MP4 before using
π§ Working with Unsupported Formats #
If you need to work with formats not natively supported on your platform (e.g., AVI on iOS, WMV on Web), you have several options:
Option 1: Convert to MP4 (Recommended) #
Using FFmpeg CLI:
ffmpeg -i input.avi -c:v libx264 -c:a aac output.mp4
Using ffmpeg_kit_flutter in your app:
import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
Future<String?> convertToMp4(String inputPath) async {
final outputPath = inputPath.replaceAll(RegExp(r'\.\w+$'), '.mp4');
await FFmpegKit.execute('-i "$inputPath" -c:v libx264 -c:a aac "$outputPath"');
return outputPath;
}
// Then use the converted file
final mp4Path = await convertToMp4('/path/to/video.avi');
if (mp4Path != null) {
final thumbnail = await SmartVideoThumbnail.getThumbnail(
videoPath: mp4Path,
);
}
Option 2: Future FFmpeg Extension (Coming Soon) #
We're planning an optional smart_video_thumbnail_ffmpeg package that will add support for all formats on iOS/macOS:
dependencies:
smart_video_thumbnail: ^0.4.0
smart_video_thumbnail_ffmpeg: ^1.0.0 # Optional, adds +20MB
Note: This will increase app size by ~20-30 MB but provide full format support.
Option 3: Server-Side Conversion (For Web) #
For web applications, consider converting videos on your server before sending to clients.
π For detailed solutions and recommendations, see UNSUPPORTED_FORMATS_SOLUTION.md
π Requirements #
Android #
- minSdk: 26 (Android 8.0+)
- targetSdk: 34
- NDK: r21 or higher
- CMake: 3.18.1 or higher
- FFmpeg: Included in plugin (v4.4.2)
iOS #
- Deployment Target: iOS 12.0 or higher
- Xcode: 12.0 or higher
- Video Processing: Native AVFoundation framework
macOS #
- Deployment Target: 10.14 or higher
- Xcode: 12.0 or higher
- Video Processing: Native AVFoundation framework
ποΈ Architecture #
The plugin consists of three layers:
βββββββββββββββββββββββββββββββββββ
β Flutter App (Dart) β
ββββββββββββββ¬βββββββββββββββββββββ
β MethodChannel
ββββββββββββββΌβββββββββββββββββββββ
β SmartVideoThumbnailPlugin (Kt) β
ββββββββββββββ¬βββββββββββββββββββββ
β JNI
ββββββββββββββΌβββββββββββββββββββββ
β SmartFfmpegBridge (C/C++) β
ββββββββββββββ¬βββββββββββββββββββββ
β
ββββββββββββββΌβββββββββββββββββββββ
β FFmpeg Libraries (v4.4.2) β
β β’ libavformat β’ libavcodec β
β β’ libswscale β’ libavutil β
βββββββββββββββββββββββββββββββββββ
Layers:
- Dart API - Flutter interface (
smart_video_thumbnail.dart) - Kotlin Bridge - JNI bridge (
SmartVideoThumbnailPlugin.kt) - Native Library - FFmpeg decoding (smart-ffmpeg-android)
β‘ Performance #
Typical frame extraction times:
| Format | Codec | Time |
|---|---|---|
| MP4 | H.264 | 50-150ms |
| AVI | MPEG-4 | 100-200ms |
| MKV | H.265 | 150-300ms |
| FLV | - | 100-250ms |
Performance factors:
- Video format and codec
- Output image size
- Frame position in video
- Device performance
π Debugging #
Enable Android logging:
adb logcat | grep -E "SmartVideoThumbnail|SmartFfmpegBridge"
Example logs:
I/SmartVideoThumbnail: π¬ getThumbnail: path=/path/to/video.mp4, targetMs=1000, size=320x180
I/SmartFfmpegBridge: Extracting thumbnail from: /path/to/video.mp4 at 1000 ms
I/SmartFfmpegBridge: Successfully extracted thumbnail: 230400 bytes
I/SmartVideoThumbnail: β
getThumbnail: Thumbnail extracted successfully (230400 bytes)
π€ Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
π License #
This project is licensed under the MIT License - see the LICENSE file for details.
π Links #
- Native Library: smart-ffmpeg-android
- FFmpeg: ffmpeg.org
- Issues: GitHub Issues
π¨βπ» Author #
PathCreator Team
If you find this plugin helpful, please give it a β on GitHub!