Flutter视频缩略图生成插件fc_native_video_thumbnail的使用
Flutter视频缩略图生成插件fc_native_video_thumbnail的使用
插件简介
fc_native_video_thumbnail
是一个用于通过原生API创建视频缩略图的Flutter插件。该插件支持iOS、Android、macOS和Windows平台,可以方便地从视频文件中提取缩略图,并保存为指定路径下的图片文件。
支持的平台与特性
平台 | Path | Uri |
---|---|---|
iOS | ✅ | ✅ |
Android | ✅ | ✅ |
macOS | ✅ | ✅ |
Windows | ✅ | - |
使用方法
以下是fc_native_video_thumbnail
的基本用法示例:
final plugin = FcNativeVideoThumbnail();
try {
/// 从[srcFile]获取缩略图,并根据给定选项保存到[destFile]。
///
/// [srcFile]:源视频路径或Uri(参见[srcFileUri])。
/// [srcFileUri]:如果为true,则[srcFile]是一个Uri(仅限Android/iOS/macOS)。
/// [destFile]:目标缩略图路径。
/// [width]/[height]:目标缩略图的最大尺寸。
/// Windows不支持非正方形缩略图图像,仅使用[width],结果为[width]x[width]的最大缩略图。
/// [format]:仅支持"jpeg"格式,默认为"jpeg"。
/// [quality]:缩略图图像的质量(0-100),可能被平台忽略。
///
/// 如果成功创建缩略图返回true;如果无法获取缩略图返回false。
/// 如果在生成缩略图时发生错误则抛出异常。
final thumbnailGenerated = await plugin.getVideoThumbnail(
srcFile: 'path/to/video.mp4',
destFile: 'path/to/thumbnail.jpg',
width: 300,
height: 300,
format: 'jpeg',
quality: 90);
} catch (err) {
// 处理平台错误。
}
完整示例代码
下面是一个完整的示例应用程序,演示了如何使用fc_native_video_thumbnail
插件来选择视频并生成缩略图:
import 'dart:io';
import 'package:fc_native_video_thumbnail/fc_native_video_thumbnail.dart';
import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:async';
import 'package:tmp_path/tmp_path.dart';
import 'package:path/path.dart' as p;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHome(),
);
}
}
class Task {
final String name;
final String srcFile;
final int width;
final int height;
final bool? isSrcUri;
String? destFile;
String? destImgSize;
String? error;
Task({
required this.name,
required this.srcFile,
required this.width,
required this.height,
this.isSrcUri,
});
Future<void> run() async {
try {
var plugin = FcNativeVideoThumbnail();
final destFile = tmpPath() + p.extension(srcFile);
await plugin.getVideoThumbnail(
srcFile: srcFile,
destFile: destFile,
width: width,
height: height,
srcFileUri: isSrcUri,
format: 'jpeg');
if (await File(destFile).exists()) {
var imageFile = File(destFile);
var decodedImage =
await decodeImageFromList(imageFile.readAsBytesSync());
destImgSize =
'Decoded size: ${decodedImage.width}x${decodedImage.height}';
this.destFile = destFile;
} else {
error = 'No thumbnail extracted';
}
} catch (err) {
error = err.toString();
}
}
}
class MyHome extends StatefulWidget {
const MyHome({super.key});
@override
State<MyHome> createState() => _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
final _tasks = <Task>[];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (Platform.isAndroid || Platform.isIOS) ...[
ElevatedButton(
onPressed: () => _selectVideo(true),
child: const Text('Select video from gallery'),
),
const SizedBox(height: 8.0),
],
ElevatedButton(
onPressed: () => _selectVideo(false),
child: const Text('Select video from file'),
),
const SizedBox(height: 8.0),
..._tasks.map((task) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8.0),
Text('>>> ${task.name}',
style: const TextStyle(
fontSize: 16.0, fontWeight: FontWeight.bold)),
if (task.error != null) ...[
const SizedBox(height: 8.0),
Text(task.error!,
style: const TextStyle(color: Colors.red)),
],
if (task.destFile != null) ...[
const SizedBox(height: 8.0),
Text('Dest image: ${task.destFile}'),
const SizedBox(height: 8.0),
Text(task.destImgSize ?? ''),
const SizedBox(height: 8.0),
Image(image: FileImage(File(task.destFile!))),
],
],
);
}),
],
),
),
),
);
}
Future<void> _selectVideo(bool gallery) async {
try {
String? srcPath;
bool srcUri = false;
if (!gallery) {
var src = await openFile();
if (src == null) {
return;
}
srcPath = src.path;
} else {
final picker = ImagePicker();
final xfile = await picker.pickVideo(source: ImageSource.gallery);
if (xfile == null) {
return;
}
srcPath = xfile.path;
}
setState(() {
_tasks.clear();
});
final smallVidBytes = await rootBundle.load('res/a.mp4');
final smallVidPath = '${tmpPath()}_small.mp4';
await File(smallVidPath).writeAsBytes(smallVidBytes.buffer.asUint8List());
_tasks.add(Task(
name: 'Resize to 300x300',
srcFile: srcPath,
isSrcUri: srcUri,
width: 300,
height: 300));
// Upscaling task.
_tasks.add(Task(
name: 'No upscaling to 1000x1000',
srcFile: smallVidPath,
width: 1000,
height: 1000));
await Future.forEach(_tasks, (Task task) async {
await task.run();
setState(() {});
});
} catch (err) {
if (!mounted) {
return;
}
await _showErrorAlert(context, err.toString());
}
}
Future<void> _showErrorAlert(BuildContext context, String msg) async {
return showDialog<void>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const SelectableText('Error'),
content: SelectableText(msg),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
}
}
此示例展示了如何使用fc_native_video_thumbnail
插件从用户选择的视频文件中生成缩略图,并在界面上显示生成的缩略图。同时,它还处理了不同平台上的特定情况,如iOS和Android上从相册选择视频,以及Windows平台上不支持Uri的情况。
希望这个详细的说明和示例能够帮助你更好地理解和使用fc_native_video_thumbnail
插件。如果你有任何问题或需要进一步的帮助,请随时提问!
更多关于Flutter视频缩略图生成插件fc_native_video_thumbnail的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频缩略图生成插件fc_native_video_thumbnail的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用fc_native_video_thumbnail
插件来生成视频缩略图的示例代码。这个插件允许你从本地视频文件中生成高质量的缩略图。
首先,你需要在你的Flutter项目中添加这个插件。在你的pubspec.yaml
文件中添加以下依赖项:
dependencies:
flutter:
sdk: flutter
fc_native_video_thumbnail: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装这个插件。
接下来,在你的Flutter项目中的Dart文件(例如main.dart
)中,你可以按照以下步骤使用fc_native_video_thumbnail
插件:
import 'package:flutter/material.dart';
import 'package:fc_native_video_thumbnail/fc_native_video_thumbnail.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Video Thumbnail Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? thumbnailPath;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Video Thumbnail Generator'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
thumbnailPath == null
? Text('Generating Thumbnail...')
: Image.file(File(thumbnailPath!)),
SizedBox(height: 20),
ElevatedButton(
onPressed: _generateThumbnail,
child: Text('Generate Thumbnail'),
),
],
),
),
);
}
Future<void> _generateThumbnail() async {
// 获取临时目录路径
final Directory tempDir = await getTemporaryDirectory();
final String videoPath = 'path/to/your/video.mp4'; // 替换为你的视频文件路径
final String thumbnailFilePath = '${tempDir.path}/thumbnail.jpg';
try {
// 生成缩略图
await FcNativeVideoThumbnail.getThumbnail(
videoPath: videoPath,
imagePath: thumbnailFilePath,
atSecond: 1.0, // 你可以指定从视频的哪一秒生成缩略图,这里设置为1秒
quality: 100, // 质量,范围从0到100
);
// 更新状态以显示缩略图
setState(() {
thumbnailPath = thumbnailFilePath;
});
} catch (e) {
print('Error generating thumbnail: $e');
}
}
}
说明:
- 添加依赖:首先,你需要在
pubspec.yaml
文件中添加fc_native_video_thumbnail
依赖。 - 获取临时目录:使用
path_provider
插件来获取设备的临时目录路径,以便保存生成的缩略图。 - 生成缩略图:调用
FcNativeVideoThumbnail.getThumbnail
方法,传入视频路径、缩略图保存路径、生成缩略图的时间点(秒)以及质量(0-100)。 - 显示缩略图:如果缩略图生成成功,使用
Image.file
来显示生成的缩略图。
请确保替换示例中的videoPath
为你的实际视频文件路径。这个示例代码展示了如何从视频文件中生成缩略图并在Flutter应用中显示它。