flutter開發(fā)實戰(zhàn)-實現(xiàn)獲取視頻的縮略圖封面video_thumbnail文章來源:http://www.zghlxwxcb.cn/news/detail-797496.html
在很多時候,我們查看視頻的時候,視頻沒有播放時候,會顯示一張封面,可能封面沒有配置圖片,這時候就需要通過獲取視頻的縮略圖來顯示封面了。這里使用了video_thumbnail來實現(xiàn)獲取視頻的縮略圖。
一、引入video_thumbnail
在工程的pubspec.yaml中引入插件
# 視頻縮略圖
video_thumbnail: ^0.5.3
VideoThumbnail的屬性如下
static Future<String?> thumbnailFile(
{required String video,
Map<String, String>? headers,
String? thumbnailPath,
ImageFormat imageFormat = ImageFormat.PNG,
int maxHeight = 0,
int maxWidth = 0,
int timeMs = 0,
int quality = 10})
- thumbnailPath為本地存儲的文件目錄
- imageFormat格式 jpg,png等
- video視頻地址
- timeMs
二、獲取視頻的縮略圖
使用video_thumbnail來獲取視頻縮略圖
定義視頻縮略圖信息
class VideoThumbInfo {
String url; // 原視頻地址
File? thumbFile; // 縮略圖本地file
int? width; // 縮略圖的width
int? height; // 縮略圖的height
VideoThumbInfo({
required this.url,
});
}
獲取視頻縮略圖本地File
String path = (await getTemporaryDirectory()).path;
String thumbnailPath = path + "/${DateTime.now().millisecond}.jpg";
final fileName = await VideoThumbnail.thumbnailFile(
video:
"https://vd2.bdstatic.com/mda-maif0tt1rirqp27q/540p/h264_cae/1611052585/mda-maif0tt1rirqp27q.mp4",
thumbnailPath: thumbnailPath,
imageFormat: imageFormat,
quality: quality,
maxWidth: maxWidth,
maxHeight: maxHeight,
timeMs: timeMs,
);
File file = File(thumbnailPath);
獲取縮略圖的寬高
Image image = Image.file(thumbFile!);
image.image.resolve(const ImageConfiguration()).addListener(
ImageStreamListener(
(ImageInfo imageInfo, bool synchronousCall) {
int imageWidth = imageInfo.image.width;
int imageHeight = imageInfo.image.height;
VideoThumbInfo videoThumbInfo = VideoThumbInfo(url: url);
videoThumbInfo.thumbFile = thumbFile;
videoThumbInfo.width = imageWidth;
videoThumbInfo.height = imageHeight;
VideoThumb.setThumbInfo(url, videoThumbInfo);
onVideoThumbInfoListener(videoThumbInfo);
},
onError: (exception, stackTrace) {
print(
"getVideoThumbInfoByFile imageStreamListener onError exception:${exception.toString()},stackTrace:${stackTrace}");
onVideoThumbInfoListener(null);
},
),
);
完整代碼如下
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:video_thumbnail/video_thumbnail.dart';
// ignore: non_constant_identifier_names
VideoThumbManager get VideoThumb => VideoThumbManager.instance;
class VideoThumbManager {
static VideoThumbManager get instance {
return _singleton;
}
//保存單例
static VideoThumbManager _singleton = VideoThumbManager._internal();
//工廠構造函數(shù)
factory VideoThumbManager() => _singleton;
//私有構造函數(shù)
VideoThumbManager._internal();
// 保存url對應的本地縮略圖file
final _thumbMap = Map<String, File>();
// url對應本地縮略圖的信息
final _thumbInfoMap = Map<String, VideoThumbInfo>();
Future<void> setThumb(String url, File file) async {
if (url.isEmpty) {
return;
}
bool exist = await file.exists();
if (exist == false) {
return;
}
_thumbMap[url] = file;
}
Future<File?> getThumb(
String url, {
ImageFormat imageFormat = ImageFormat.JPEG,
int maxHeight = 0,
int maxWidth = 0,
int timeMs = 0,
int quality = 100,
}) async {
File? thumbFile = _thumbMap[url];
if (thumbFile != null) {
return thumbFile;
}
String path = (await getTemporaryDirectory()).path;
String thumbnailPath = path + "/${DateTime.now().millisecond}.jpg";
final fileName = await VideoThumbnail.thumbnailFile(
video:
"https://vd2.bdstatic.com/mda-maif0tt1rirqp27q/540p/h264_cae/1611052585/mda-maif0tt1rirqp27q.mp4",
thumbnailPath: thumbnailPath,
imageFormat: imageFormat,
quality: quality,
maxWidth: maxWidth,
maxHeight: maxHeight,
timeMs: timeMs,
);
File file = File(thumbnailPath);
setThumb(url, file);
return file;
}
// 獲取縮略圖的大小
void getVideoThumbInfo(
String url, {
ImageFormat imageFormat = ImageFormat.JPEG,
int maxHeight = 0,
int maxWidth = 0,
int timeMs = 0,
int quality = 100,
required Function(VideoThumbInfo?) onVideoThumbInfoListener,
}) async {
try {
VideoThumbInfo? thumbInfo = VideoThumb.getThumbInfo(url);
if (thumbInfo != null) {
onVideoThumbInfoListener(thumbInfo);
return;
}
await VideoThumb.getThumb(
url,
imageFormat: imageFormat,
maxWidth: maxWidth,
maxHeight: maxHeight,
timeMs: timeMs,
quality: quality,
).then((value) {
File? thumbFile = value;
if (thumbFile != null) {
VideoThumb.getVideoThumbInfoByFile(
url: url,
thumbFile: thumbFile,
onVideoThumbInfoListener: onVideoThumbInfoListener,
);
} else {
onVideoThumbInfoListener(null);
}
}).onError((error, stackTrace) {
print("getVideoThumbInfo error:${error.toString()}");
onVideoThumbInfoListener(null);
}).whenComplete(() {
print("getVideoThumbInfo whenComplete");
});
} catch (e) {
print("getVideoThumbInfo catch error:${e.toString()}");
onVideoThumbInfoListener(null);
}
}
/// 根據(jù)file獲取縮略圖信息
void getVideoThumbInfoByFile({
required String url,
required File thumbFile,
required Function(VideoThumbInfo?) onVideoThumbInfoListener,
}) async {
try {
VideoThumbInfo? thumbInfo = VideoThumb.getThumbInfo(url);
if (thumbInfo != null) {
onVideoThumbInfoListener(thumbInfo);
return;
}
Image image = Image.file(thumbFile!);
image.image.resolve(const ImageConfiguration()).addListener(
ImageStreamListener(
(ImageInfo imageInfo, bool synchronousCall) {
int imageWidth = imageInfo.image.width;
int imageHeight = imageInfo.image.height;
VideoThumbInfo videoThumbInfo = VideoThumbInfo(url: url);
videoThumbInfo.thumbFile = thumbFile;
videoThumbInfo.width = imageWidth;
videoThumbInfo.height = imageHeight;
VideoThumb.setThumbInfo(url, videoThumbInfo);
onVideoThumbInfoListener(videoThumbInfo);
},
onError: (exception, stackTrace) {
print(
"getVideoThumbInfoByFile imageStreamListener onError exception:${exception.toString()},stackTrace:${stackTrace}");
onVideoThumbInfoListener(null);
},
),
);
} catch (e) {
print("getVideoThumbInfoByFile catch error:${e.toString()}");
onVideoThumbInfoListener(null);
}
}
void removeThumb(String url) {
if (url.isEmpty) {
return;
}
_thumbMap.remove(url);
}
/// 獲取存儲縮略圖信息
VideoThumbInfo? getThumbInfo(String url) {
if (url.isEmpty) {
return null;
}
VideoThumbInfo? thumbInfo = _thumbInfoMap[url];
return thumbInfo;
}
/// 存儲縮略圖信息
void setThumbInfo(String url, VideoThumbInfo videoThumbInfo) async {
if (url.isEmpty) {
return;
}
_thumbInfoMap[url] = videoThumbInfo;
}
void removeThumbInfo(String url) {
if (url.isEmpty) {
return;
}
_thumbInfoMap.remove(url);
}
void clear() {
_thumbMap.clear();
_thumbInfoMap.clear();
}
}
class VideoThumbInfo {
String url; // 原視頻地址
File? thumbFile; // 縮略圖本地file
int? width; // 縮略圖的width
int? height; // 縮略圖的height
VideoThumbInfo({
required this.url,
});
}
三、顯示視頻縮略圖的Widget
用于顯示視頻縮略圖的Widget
/// 用于顯示視頻縮略圖的Widget
class VideoThumbImage extends StatefulWidget {
const VideoThumbImage(
{super.key, required this.url, this.maxWidth, this.maxHeight});
final String url;
final double? maxWidth;
final double? maxHeight;
@override
State<VideoThumbImage> createState() => _VideoThumbImageState();
}
class _VideoThumbImageState extends State<VideoThumbImage> {
VideoThumbInfo? _videoThumbInfo;
@override
void initState() {
// TODO: implement initState
super.initState();
VideoThumb.getVideoThumbInfo(widget.url,
onVideoThumbInfoListener: (VideoThumbInfo? thumbInfo) {
if (mounted) {
setState(() {
_videoThumbInfo = thumbInfo;
});
}
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
// 根據(jù)VideoThumb來顯示圖片
Widget buildVideoThumb(BuildContext context) {
if (_videoThumbInfo != null && _videoThumbInfo!.thumbFile != null) {
double? imageWidth;
double? imageHeight;
if (_videoThumbInfo!.width != null && _videoThumbInfo!.height != null) {
imageWidth = _videoThumbInfo!.width!.toDouble();
imageWidth = _videoThumbInfo!.height!.toDouble();
}
return Container(
width: imageWidth,
height: imageHeight,
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(
color: Colors.transparent,
),
child: Image.file(
_videoThumbInfo!.thumbFile!,
width: imageWidth,
height: imageHeight,
),
);
}
return Container();
}
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: widget.maxWidth ?? double.infinity,
maxHeight: widget.maxHeight ?? double.infinity,
),
child: buildVideoThumb(context),
);
}
}
效果圖如下:
四、小結
flutter開發(fā)實戰(zhàn)-實現(xiàn)獲取視頻的縮略圖封面video_thumbnail
學習記錄,每天不停進步。文章來源地址http://www.zghlxwxcb.cn/news/detail-797496.html
到了這里,關于flutter開發(fā)實戰(zhàn)-實現(xiàn)獲取視頻的縮略圖封面video_thumbnail的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!