Flutter视频制作插件my_maker_video的使用
Flutter视频制作插件my_maker_video的使用
轻松地从一系列图像创建视频,添加精确位置的水印到视频中,降低视频质量以优化文件大小,并将视频转换为高质量的GIF。MyMakerVideo插件为您的Flutter项目提供了强大的、快速且可定制的功能。
安装
在pubspec.yaml
文件中添加以下依赖:
dependencies:
my_maker_video: ^latest_version
然后运行以下命令:
flutter pub get
Android 配置
在android/app/build.gradle
文件中添加以下配置:
defaultConfig {
applicationId = "com.example.my_maker_video_example"
// 更新这些值以满足您的应用需求。
minSdk = 24
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
在AndroidManifest.xml
文件中添加以下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
iOS 配置
在Info.plist
文件中添加以下键:
<key>NSPhotoLibraryUsageDescription</key>
<string>我们需要访问您的照片库来选择文件。</string>
<key>NSDocumentDirectoryUsageDescription</key>
<string>我们需要访问您的文档来选择文件。</string>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
确保在ios/Podfile
文件中设置平台版本为:
platform :ios, '13.0'
使用
导入插件包:
import 'package:my_maker_video/my_maker_video.dart';
权限
确保您的应用具有所需的写入权限。
功能
1. 从一系列图像创建视频
确保path/to/images
目录包含按自然数命名的.png
格式的图像,如示例所示:
final result = MyMakerVideo.ffmpegKit.convertImageDirectoryToVideo(
imagesPath: "path/to/images",
outputVideoPath: "path/to/videoOutput.mp4",
// fps: 2
);
注意: 如果视频较大,请允许一些时间进行处理。
2. 向视频添加水印
final result = MyMakerVideo.ffmpegKit.addWatermarkToVideo(
watermarkPath: watermarkPath!, // 水印图像或视频的路径
videoPath: videoPath!, // 要添加水印的视频路径
outputPath: pathVideo, // 输出视频保存路径
x: 20, // X坐标(左上角原点)
y: 30, // Y坐标
width: 200, // 水印宽度
height: 200 // 水印高度
);
3. 降低视频质量
final result = MyMakerVideo.ffmpegKit.reduceVideoQualityByPercentage(
inputPath: videoPath!, // 输入视频路径
outputPath: pathVideo, // 输出视频保存路径
qualityPercentage: 30 // 降低的质量百分比
);
4. 从视频创建GIF
final result = MyMakerVideo.ffmpegKit.createGifFromVideo(
inputPath: videoPath!, // 输入视频路径
outputPath: pathGif, // 输出GIF保存路径
quality: 100, // GIF质量
scale: 3200, // GIF缩放比例
fps: 2, // 每秒帧数
);
完整示例代码
import 'dart:io';
import 'dart:math';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:my_maker_video/my_maker_video.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('插件my_maker_video示例应用'),
),
body: Center(
child: SingleChildScrollView(
child: Column(
children: [
ImagesToVideo(),
Watermark(),
ReduceVideoQuality(),
VideoToGif(),
],
),
),
),
),
);
}
}
class ImagesToVideo extends StatefulWidget {
const ImagesToVideo({super.key});
[@override](/user/override)
State<ImagesToVideo> createState() => _ImagesToVideoState();
}
class _ImagesToVideoState extends State<ImagesToVideo> {
String? inputPath;
String? outputPath;
String? pathVideo;
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
children: [
Text(
"PART I | 图像转视频",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text("STEP 1 | 创建输入图像文件夹"),
TextButton(
onPressed: () async {
final downloadPath = !kIsWeb && Platform.isAndroid
? await createDirectory("/storage/emulated/0/Download/my_maker_video")
: await getApplicationDocumentsDirectory();
inputPath = "${downloadPath.path}/input-image";
await createDirectory(inputPath!);
setState(() {});
},
child: Text("创建")),
Text("STEP 2 | 将您的图像放入 $inputPath 文件夹中,文件名应为数字,例如 image.png"),
SizedBox(height: 400, child: Image.asset("assets/image.jpeg")),
Text("STEP 3 | 创建输出视频文件夹 $outputPath"),
TextButton(
onPressed: () async {
final downloadPath = !kIsWeb && Platform.isAndroid
? await createDirectory("/storage/emulated/0/Download/my_maker_video")
: await getApplicationDocumentsDirectory();
outputPath = "${downloadPath.path}/video";
await createDirectory(outputPath!);
setState(() {});
},
child: Text("创建")),
Text("STEP 4 | 允许保存视频的权限"),
TextButton(
onPressed: () async {
await Permission.storage.request().isGranted;
await Permission.photos.request().isGranted;
},
child: Text("允许")),
Text("STEP 5 | 从图像列表创建视频 $pathVideo"),
Text("注意:输出文件名必须唯一"),
TextButton(
onPressed: () async {
if (outputPath != null && inputPath != null) {
final pathVideo =
"$outputPath/image-to-video-${Random().nextInt(20)}.mp4";
final result = MyMakerVideo.ffmpegKit.convertImageDirectoryToVideo(
imagesPath: inputPath!,
outputVideoPath: pathVideo,
// fps: 2
);
setState(() {
this.pathVideo = pathVideo;
});
print("Path | $pathVideo");
}
},
child: Text("从图像创建视频")),
Text("STEP 6 | 等待"),
],
);
}
}
Future<Directory> createDirectory(String path) async {
print("Path | $path");
return await Directory(path).create(recursive: true);
}
class Watermark extends StatefulWidget {
const Watermark({super.key});
[@override](/user/override)
State<Watermark> createState() => _WatermarkState();
}
class _WatermarkState extends State<Watermark> {
String? watermarkPath;
String? videoPath;
String? outputPath;
String? pathVideo;
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
children: [
Text(
"PART II | 向视频添加水印",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text("STEP 1 | 选择视频 $videoPath"),
TextButton(
onPressed: () async {
videoPath = await pickOneVideo();
setState(() {});
},
child: Text("选择视频")),
Text("STEP 2 | 选择水印(视频或图像) $watermarkPath"),
TextButton(
onPressed: () async {
watermarkPath = await pickOneFile(allowedExtensions: ["mp4", "png"]);
setState(() {});
},
child: Text("选择水印")),
Text("STEP 3 | 创建输出视频文件夹 $outputPath"),
TextButton(
onPressed: () async {
final downloadPath = !kIsWeb && Platform.isAndroid
? await createDirectory("/storage/emulated/0/Download/my_maker_video")
: await getApplicationDocumentsDirectory();
outputPath = "${downloadPath.path}/video";
await createDirectory(outputPath!);
setState(() {});
},
child: Text("创建")),
Text("STEP 4 | 允许保存视频的权限"),
TextButton(
onPressed: () async {
await Permission.storage.request().isGranted;
await Permission.photos.request().isGranted;
},
child: Text("允许")),
Text("STEP 5 | 创建带有水印的视频 $pathVideo"),
TextButton(
onPressed: () async {
if (outputPath != null &&
watermarkPath != null &&
videoPath != null) {
final pathVideo =
"$outputPath/watermark-${Random().nextInt(20)}.mp4";
final result = MyMakerVideo.ffmpegKit.addWatermarkToVideo(
watermarkPath: watermarkPath!,
videoPath: videoPath!,
outputPath: pathVideo,
x: 20,
y: 30,
width: 200,
height: 200
// fps: 2
);
setState(() {
this.pathVideo = pathVideo;
});
print("Path | $pathVideo");
}
},
child: Text("创建带水印的视频")),
Text("STEP 6 | 等待"),
],
);
}
}
Future<String?> pickOneFile({List<String>? allowedExtensions}) async {
final FilePickerResult? result = await FilePicker.platform.pickFiles(
type: allowedExtensions == null ? FileType.any : FileType.custom,
allowedExtensions: allowedExtensions,
);
return result?.files.single.path!;
}
Future<String?> pickOneVideo() async {
final FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.video,
);
return result?.files.single.path!;
}
class ReduceVideoQuality extends StatefulWidget {
const ReduceVideoQuality({super.key});
[@override](/user/override)
State<ReduceVideoQuality> createState() => _ReduceVideoQualityState();
}
class _ReduceVideoQualityState extends State<ReduceVideoQuality> {
String? videoPath;
String? outputPath;
String? pathVideo;
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
children: [
Text(
"PART III | 降低视频质量",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text("STEP 1 | 选择视频 $videoPath"),
TextButton(
onPressed: () async {
videoPath = await pickOneVideo();
setState(() {});
},
child: Text("选择视频")),
Text("STEP 2 | 创建输出视频文件夹 $outputPath"),
TextButton(
onPressed: () async {
final downloadPath = !kIsWeb && Platform.isAndroid
? await createDirectory("/storage/emulated/0/Download/my_maker_video")
: await getApplicationDocumentsDirectory();
outputPath = "${downloadPath.path}/video";
await createDirectory(outputPath!);
setState(() {});
},
child: Text("创建")),
Text("STEP 3 | 允许保存视频的权限"),
TextButton(
onPressed: () async {
await Permission.storage.request().isGranted;
await Permission.photos.request().isGranted;
},
child: Text("允许")),
Text("STEP 4 | 降低视频质量 $pathVideo"),
TextButton(
onPressed: () async {
if (outputPath != null && videoPath != null) {
final pathVideo =
"$outputPath/reduce-quality-${Random().nextInt(20)}.mp4";
final result = MyMakerVideo.ffmpegKit.reduceVideoQualityByPercentage(
inputPath: videoPath!,
outputPath: pathVideo,
qualityPercentage: 30);
setState(() {
this.pathVideo = pathVideo;
});
print("Path | $pathVideo");
}
},
child: Text("降低视频质量")),
Text("STEP 5 | 等待"),
],
);
}
}
class VideoToGif extends StatefulWidget {
const VideoToGif({super.key});
[@override](/user/override)
State<VideoToGif> createState() => _VideoToGifState();
}
class _VideoToGifState extends State<VideoToGif> {
String? videoPath;
String? outputPath;
String? pathVideo;
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
children: [
Text(
"PART IV | 视频转GIF",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text("STEP 1 | 选择视频 $videoPath"),
TextButton(
onPressed: () async {
videoPath = await pickOneVideo();
setState(() {});
},
child: Text("选择视频")),
Text("STEP 2 | 创建输出视频文件夹 $outputPath"),
TextButton(
onPressed: () async {
final downloadPath = !kIsWeb && Platform.isAndroid
? await createDirectory("/storage/emulated/0/Download/my_maker_video")
: await getApplicationDocumentsDirectory();
outputPath = "${downloadPath.path}/video";
await createDirectory(outputPath!);
setState(() {});
},
child: Text("创建")),
Text("STEP 3 | 允许保存视频的权限"),
TextButton(
onPressed: () async {
await Permission.storage.request().isGranted;
await Permission.photos.request().isGranted;
},
child: Text("允许")),
Text("STEP 4 | 从视频创建GIF $pathVideo"),
TextButton(
onPressed: () async {
if (outputPath != null && videoPath != null) {
final pathGif = "$outputPath/gif-${Random().nextInt(20)}.gif";
final result = MyMakerVideo.ffmpegKit.createGifFromVideo(
inputPath: videoPath!,
outputPath: pathGif,
quality: 100,
scale: 3200,
fps: 2,
);
setState(() {
pathVideo = pathGif;
});
print("Path | $pathGif");
}
},
child: Text("创建GIF")),
Text("STEP 5 | 等待"),
],
);
}
}
更多关于Flutter视频制作插件my_maker_video的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频制作插件my_maker_video的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
my_maker_video
是一个用于 Flutter 的视频制作插件,它允许开发者在应用中创建和编辑视频。以下是如何使用 my_maker_video
插件的基本步骤。
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 my_maker_video
插件的依赖:
dependencies:
flutter:
sdk: flutter
my_maker_video: ^1.0.0 # 请使用最新的版本号
然后运行 flutter pub get
来安装依赖。
2. 导入插件
在需要使用 my_maker_video
的 Dart 文件中导入插件:
import 'package:my_maker_video/my_maker_video.dart';
3. 初始化插件
在使用插件之前,通常需要对其进行初始化:
void initVideoMaker() async {
await MyMakerVideo.initialize();
}
4. 创建视频
my_maker_video
提供了多种方法来创建和编辑视频。以下是一个简单的示例,展示如何将多张图片合并成一个视频:
void createVideo() async {
List<String> imagePaths = [
'assets/image1.jpg',
'assets/image2.jpg',
'assets/image3.jpg',
];
String outputPath = '/storage/emulated/0/Download/output.mp4';
await MyMakerVideo.createVideoFromImages(
imagePaths: imagePaths,
outputPath: outputPath,
durationPerImage: 3, // 每张图片显示3秒
onProgress: (double progress) {
print('视频制作进度: $progress');
},
onCompleted: (String filePath) {
print('视频制作完成,保存路径: $filePath');
},
onError: (String error) {
print('视频制作出错: $error');
},
);
}
5. 添加音频
你还可以为视频添加背景音乐:
void addAudioToVideo() async {
String videoPath = '/storage/emulated/0/Download/output.mp4';
String audioPath = 'assets/background_music.mp3';
String outputPath = '/storage/emulated/0/Download/output_with_audio.mp4';
await MyMakerVideo.addAudioToVideo(
videoPath: videoPath,
audioPath: audioPath,
outputPath: outputPath,
onCompleted: (String filePath) {
print('音频添加完成,保存路径: $filePath');
},
onError: (String error) {
print('音频添加出错: $error');
},
);
}