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!