Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
ethan
/
appframe
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit fac3e49d
authored
2025-11-27 17:16:08 +0800
by
tanghuan
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
优化
1 parent
0925b7fc
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
151 additions
and
114 deletions
lib/bloc/web_cubit.dart
lib/data/repositories/message/compress_handler.dart
lib/data/repositories/message/video_info_handler.dart
lib/utils/thumbnail_util.dart
lib/utils/video_util.dart
pubspec.yaml
lib/bloc/web_cubit.dart
View file @
fac3e49
...
@@ -194,14 +194,14 @@ class WebCubit extends Cubit<WebState> {
...
@@ -194,14 +194,14 @@ class WebCubit extends Cubit<WebState> {
var
versionConfig
=
await
_getVersionConfig
();
var
versionConfig
=
await
_getVersionConfig
();
var
correctVersion
=
versionConfig
[
'version'
]
as
String
;
var
correctVersion
=
versionConfig
[
'version'
]
as
String
;
var
downloadUrl
=
versionConfig
[
'zip'
]
as
String
;
var
downloadUrl
=
versionConfig
[
'zip'
]
as
String
;
var
urgency
=
versionConfig
[
'urgency'
]
as
int
?
??
0
;
var
force
=
versionConfig
[
'force'
]
as
String
;
// 当前使用的H5版本
// 当前使用的H5版本
var
curVersion
=
getIt
.
get
<
SharedPreferences
>().
getString
(
'h5_version'
)
??
Constant
.
h5Version
;
var
curVersion
=
getIt
.
get
<
SharedPreferences
>().
getString
(
'h5_version'
)
??
Constant
.
h5Version
;
// 版本不一致则需要升级
// 版本不一致则需要升级
if
(
curVersion
!=
correctVersion
)
{
if
(
curVersion
!=
correctVersion
)
{
if
(
urgency
==
1
)
{
if
(
force
==
"1"
)
{
// 一直等待升级完成
// 一直等待升级完成
// 遮罩界面
// 遮罩界面
emit
(
state
.
copyWith
(
isUpgrading:
true
));
emit
(
state
.
copyWith
(
isUpgrading:
true
));
...
@@ -256,11 +256,13 @@ class WebCubit extends Cubit<WebState> {
...
@@ -256,11 +256,13 @@ class WebCubit extends Cubit<WebState> {
}
}
String
version
=
response
.
data
[
'version'
]
as
String
;
String
version
=
response
.
data
[
'version'
]
as
String
;
String
force
=
response
.
data
[
'force'
]
as
String
;
String
zip
=
response
.
data
[
'zip'
]
as
String
;
String
zip
=
response
.
data
[
'zip'
]
as
String
;
return
{
return
{
'version'
:
version
,
'version'
:
version
,
'zip'
:
'http://192.168.2.177/1.0.0.zip'
,
'force'
:
force
,
// 'zip': zip,
// 'zip': 'http://192.168.2.177/1.0.0.zip',
'zip'
:
'
$zip$version
.zip'
,
};
};
}
finally
{
}
finally
{
dio
.
close
(
force:
true
);
dio
.
close
(
force:
true
);
...
@@ -481,11 +483,8 @@ class WebCubit extends Cubit<WebState> {
...
@@ -481,11 +483,8 @@ class WebCubit extends Cubit<WebState> {
_controller
.
reload
();
_controller
.
reload
();
}
}
///
/// 1 清理非 h5_version 的缓存
/// 2 清理文件目录和缓存目录(不包括解压的H5资源目录)
///
Future
<
void
>
clearStorage
()
async
{
Future
<
void
>
clearStorage
()
async
{
// 1 清理非 h5_version 的缓存
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
sharedPreferences
.
getKeys
().
forEach
((
key
)
{
sharedPreferences
.
getKeys
().
forEach
((
key
)
{
if
(!
key
.
startsWith
(
'h5_version'
))
{
if
(!
key
.
startsWith
(
'h5_version'
))
{
...
@@ -493,26 +492,34 @@ class WebCubit extends Cubit<WebState> {
...
@@ -493,26 +492,34 @@ class WebCubit extends Cubit<WebState> {
}
}
});
});
var
version
=
sharedPreferences
.
getString
(
'h5_version'
)
??
Constant
.
h5Version
;
// 2 清理 http_dist_assets 下的非当前版本号的文件和目录
var
dir
=
await
getApplicationSupportDirectory
();
var
dir
=
await
getApplicationSupportDirectory
();
String
httpDirPath
=
'
${dir.path}
/
${Constant.h5DistDir}
'
;
var
httpDir
=
Directory
(
'
${dir.path}
/
${Constant.h5DistDir}
'
);
if
(
httpDir
.
existsSync
())
{
var
httpDir
=
Directory
(
httpDirPath
);
var
version
=
sharedPreferences
.
getString
(
'h5_version'
)
??
Constant
.
h5Version
;
if
(!
httpDir
.
existsSync
())
{
return
;
await
for
(
final
FileSystemEntity
entity
in
httpDir
.
list
())
{
if
(
entity
is
Directory
)
{
// 删除目录
if
(!
entity
.
path
.
endsWith
(
version
))
{
await
entity
.
delete
(
recursive:
true
);
}
}
else
if
(
entity
is
File
)
{
// 删除文件
if
(!
entity
.
path
.
endsWith
(
'
$version
.zip'
))
{
await
entity
.
delete
();
}
}
}
}
}
// 查询目录下的所有文件和目录
// 3 清理临时目录下的所有文件和目录
List
<
FileSystemEntity
>
entities
=
await
Directory
(
httpDirPath
).
list
().
toList
();
var
tempDir
=
await
getTemporaryDirectory
();
for
(
var
entity
in
entities
)
{
if
(
tempDir
.
existsSync
())
{
if
(
entity
is
Directory
)
{
await
for
(
final
FileSystemEntity
entity
in
tempDir
.
list
())
{
// 删除目录
if
(
entity
is
Directory
)
{
if
(!
entity
.
path
.
endsWith
(
version
))
{
await
entity
.
delete
(
recursive:
true
);
await
entity
.
delete
(
recursive:
true
);
}
}
else
{
}
else
if
(
entity
is
File
)
{
// 删除文件
if
(!
entity
.
path
.
endsWith
(
'
$version
.zip'
))
{
await
entity
.
delete
();
await
entity
.
delete
();
}
}
}
}
...
...
lib/data/repositories/message/compress_handler.dart
View file @
fac3e49
import
'dart:io'
;
import
'dart:io'
;
import
'package:appframe/services/dispatcher.dart'
;
import
'package:appframe/services/dispatcher.dart'
;
import
'package:appframe/utils/file_type_util.dart'
;
import
'package:appframe/utils/video_util.dart'
;
import
'package:appframe/utils/video_util.dart'
;
import
'package:dio/dio.dart'
;
import
'package:dio/dio.dart'
;
import
'package:flutter_image_compress/flutter_image_compress.dart'
;
import
'package:flutter_image_compress/flutter_image_compress.dart'
;
...
@@ -26,13 +27,7 @@ class CompressImageHandler extends MessageHandler {
...
@@ -26,13 +27,7 @@ class CompressImageHandler extends MessageHandler {
throw
Exception
(
'参数错误'
);
throw
Exception
(
'参数错误'
);
}
}
var
compressedWidth
=
params
[
'compressedWidth'
]
as
int
?;
var
compressedWidth
=
params
[
'compressedWidth'
]
as
int
?;
// if (compressedWidth == null) {
// throw Exception('参数错误');
// }
var
compressedHeight
=
params
[
'compressedHeight'
]
as
int
?;
var
compressedHeight
=
params
[
'compressedHeight'
]
as
int
?;
// if (compressedHeight == null) {
// throw Exception('参数错误');
// }
if
(
compressedWidth
==
null
&&
compressedHeight
==
null
)
{
if
(
compressedWidth
==
null
&&
compressedHeight
==
null
)
{
throw
Exception
(
'参数错误'
);
throw
Exception
(
'参数错误'
);
...
@@ -40,8 +35,8 @@ class CompressImageHandler extends MessageHandler {
...
@@ -40,8 +35,8 @@ class CompressImageHandler extends MessageHandler {
if
(
compressedWidth
==
null
)
{
if
(
compressedWidth
==
null
)
{
compressedWidth
=
compressedHeight
;
compressedWidth
=
compressedHeight
;
}
else
if
(
compressedHeight
==
null
)
{
}
else
{
compressedHeight
=
compressedWidth
;
compressedHeight
??
=
compressedWidth
;
}
}
// 获取后缀名
// 获取后缀名
...
@@ -128,8 +123,19 @@ class CompressVideoHandler extends MessageHandler {
...
@@ -128,8 +123,19 @@ class CompressVideoHandler extends MessageHandler {
}
}
print
(
'原视频大小:
${originFile.lengthSync()}
'
);
print
(
'原视频大小:
${originFile.lengthSync()}
'
);
String
?
mimeType
=
await
FileTypeUtil
.
getMimeType
(
originFile
);
if
(!(
mimeType
?.
startsWith
(
'video/'
)
??
false
))
{
throw
Exception
(
'非视频文件'
);
}
final
outputPath
=
'
${tempDir.path}
/
${Uuid().v4()}
.mp4'
;
final
outputPath
=
'
${tempDir.path}
/
${Uuid().v4()}
.mp4'
;
var
result
=
await
VideoUtil
.
compressVideo
(
srcPath
,
outputPath
,
quality
);
bool
result
;
if
(
mimeType
!=
'video/mp4'
)
{
result
=
await
VideoUtil
.
convertToMp4
(
srcPath
,
outputPath
);
}
else
{
result
=
await
VideoUtil
.
compressVideo
(
srcPath
,
outputPath
,
quality
);
}
if
(!
result
)
{
if
(!
result
)
{
throw
Exception
(
'视频压缩失败'
);
throw
Exception
(
'视频压缩失败'
);
}
}
...
@@ -139,32 +145,5 @@ class CompressVideoHandler extends MessageHandler {
...
@@ -139,32 +145,5 @@ class CompressVideoHandler extends MessageHandler {
"tempFilePath"
:
'/temp
$outputPath
'
,
"tempFilePath"
:
'/temp
$outputPath
'
,
"size"
:
File
(
outputPath
).
lengthSync
(),
"size"
:
File
(
outputPath
).
lengthSync
(),
};
};
// VideoQuality videoQuality;
// switch (quality) {
// case 'low':
// videoQuality = VideoQuality.LowQuality;
// break;
// case 'middle':
// videoQuality = VideoQuality.MediumQuality;
// break;
// case 'high':
// videoQuality = VideoQuality.HighestQuality;
// break;
// default:
// throw Exception('参数错误');
// }
//
// final mediaInfo = await VideoCompress.compressVideo(
// srcPath,
// quality: videoQuality,
// deleteOrigin: false,
// includeAudio: true,
// );
//
// return {
// "tempFilePath": "/temp${mediaInfo!.path}",
// "size": mediaInfo.filesize,
// };
}
}
}
}
lib/data/repositories/message/video_info_handler.dart
View file @
fac3e49
...
@@ -3,9 +3,11 @@ import 'dart:io';
...
@@ -3,9 +3,11 @@ import 'dart:io';
import
'package:appframe/services/dispatcher.dart'
;
import
'package:appframe/services/dispatcher.dart'
;
import
'package:appframe/utils/file_type_util.dart'
;
import
'package:appframe/utils/file_type_util.dart'
;
import
'package:dio/dio.dart'
;
import
'package:dio/dio.dart'
;
import
'package:ffmpeg_kit_flutter_new/ffprobe_kit.dart'
;
import
'package:ffmpeg_kit_flutter_new/media_information_session.dart'
;
import
'package:ffmpeg_kit_flutter_new/return_code.dart'
;
import
'package:path/path.dart'
as
path
;
import
'package:path/path.dart'
as
path
;
import
'package:path_provider/path_provider.dart'
;
import
'package:path_provider/path_provider.dart'
;
import
'package:video_compress/video_compress.dart'
;
class
VideoInfoHandler
extends
MessageHandler
{
class
VideoInfoHandler
extends
MessageHandler
{
@override
@override
...
@@ -15,8 +17,26 @@ class VideoInfoHandler extends MessageHandler {
...
@@ -15,8 +17,26 @@ class VideoInfoHandler extends MessageHandler {
}
}
final
url
=
params
[
'url'
]
as
String
;
final
url
=
params
[
'url'
]
as
String
;
final
filePath
=
await
_getFilePath
(
url
);
final
file
=
File
(
filePath
);
if
(!
file
.
existsSync
())
{
throw
Exception
(
'视频文件不存在'
);
}
// 使用 ffmpeg_kit_flutter_new 获取视频信息
final
mediaInfoSession
=
await
FFprobeKit
.
getMediaInformation
(
filePath
);
final
returnCode
=
await
mediaInfoSession
.
getReturnCode
();
if
(!
ReturnCode
.
isSuccess
(
returnCode
))
{
throw
Exception
(
'获取视频信息失败'
);
}
final
result
=
await
_extractVideoInfo
(
mediaInfoSession
,
file
,
filePath
);
return
result
;
}
String
filePath
;
/// 根据URL获取文件路径,如果URL是网络地址则下载到本地
Future
<
String
>
_getFilePath
(
String
url
)
async
{
if
(
url
.
startsWith
(
'http'
))
{
if
(
url
.
startsWith
(
'http'
))
{
// 获取后缀名
// 获取后缀名
String
ext
=
path
.
extension
(
url
);
String
ext
=
path
.
extension
(
url
);
...
@@ -30,18 +50,41 @@ class VideoInfoHandler extends MessageHandler {
...
@@ -30,18 +50,41 @@ class VideoInfoHandler extends MessageHandler {
throw
Exception
(
'文件下载失败'
);
throw
Exception
(
'文件下载失败'
);
}
}
filePath
=
targetPath
;
return
targetPath
;
}
else
{
}
else
{
filePath
=
url
;
return
url
;
}
}
}
final
file
=
File
(
filePath
);
/// 提取视频信息
if
(!
file
.
existsSync
())
{
Future
<
Map
<
String
,
dynamic
>>
_extractVideoInfo
(
throw
Exception
(
'视频文件不存在'
);
MediaInformationSession
mediaInfoSession
,
File
file
,
String
filePath
)
async
{
final
mediaInformation
=
mediaInfoSession
.
getMediaInformation
();
if
(
mediaInformation
==
null
)
{
throw
Exception
(
'获取视频信息失败'
);
}
// 获取视频时长
final
durationStr
=
mediaInformation
.
getDuration
();
if
(
durationStr
==
null
)
{
throw
Exception
(
'获取视频信息失败'
);
}
var
duration
=
(
double
.
tryParse
(
durationStr
)
??
0
).
ceil
();
// 获取视频流信息
final
videoStreams
=
mediaInformation
.
getStreams
()
.
where
((
stream
)
=>
stream
.
getAllProperties
()
!=
null
&&
stream
.
getAllProperties
()![
'codec_type'
]
==
'video'
)
.
toList
();
if
(
videoStreams
.
isEmpty
)
{
throw
Exception
(
'获取视频信息失败'
);
}
}
// 使用video_compress获取视频信息
final
videoStream
=
videoStreams
[
0
];
final
mediaInfo
=
await
VideoCompress
.
getMediaInfo
(
filePath
);
final
properties
=
videoStream
.
getAllProperties
();
int
width
=
properties
![
'width'
]
??
0
;
int
height
=
properties
[
'height'
]
??
0
;
// 获取文件大小
// 获取文件大小
final
size
=
await
file
.
length
();
final
size
=
await
file
.
length
();
...
@@ -52,10 +95,10 @@ class VideoInfoHandler extends MessageHandler {
...
@@ -52,10 +95,10 @@ class VideoInfoHandler extends MessageHandler {
return
{
return
{
'tempFilePath'
:
'/temp
$filePath
'
,
'tempFilePath'
:
'/temp
$filePath
'
,
'width'
:
mediaInfo
.
width
??
0
,
'width'
:
width
,
'height'
:
mediaInfo
.
height
??
0
,
'height'
:
height
,
'type'
:
fileExtension
,
'type'
:
fileExtension
,
'duration'
:
(
mediaInfo
.
duration
??
0
)
/
1000
,
// 转换为秒
'duration'
:
duration
,
// 已经是秒单位
'size'
:
size
,
'size'
:
size
,
};
};
}
}
...
...
lib/utils/thumbnail_util.dart
View file @
fac3e49
import
'dart:io'
;
import
'dart:io'
;
import
'package:ffmpeg_kit_flutter_new/ffmpeg_kit.dart'
;
import
'package:ffmpeg_kit_flutter_new/return_code.dart'
;
import
'package:flutter_image_compress/flutter_image_compress.dart'
;
import
'package:flutter_image_compress/flutter_image_compress.dart'
;
import
'package:video_compress/video_compress.dart'
;
/// 缩略图工具类
/// 缩略图工具类
///
///
...
@@ -28,28 +29,29 @@ class ThumbnailUtil {
...
@@ -28,28 +29,29 @@ class ThumbnailUtil {
/// 返回缩略图路径
/// 返回缩略图路径
static
Future
<
String
?>
genVideoThumbnail
(
String
videoPath
,
Directory
dir
)
async
{
static
Future
<
String
?>
genVideoThumbnail
(
String
videoPath
,
Directory
dir
)
async
{
try
{
try
{
var
fileThumbnail
=
await
VideoCompress
.
getFileThumbnail
(
videoPath
,
quality:
50
,
position:
-
1
);
final
thumbnailPath
=
'
${dir.path}
/video_thumb_
${DateTime.now().millisecondsSinceEpoch}
.jpg'
;
return
fileThumbnail
.
path
;
// 使用 ffmpeg_kit_flutter_new 生成视频缩略图
// 构建FFmpeg命令行参数
String
cmd
=
'-i "
$videoPath
" '
// 指定输入文件路径
'-ss 1 '
// 从视频第1秒处截取画面
'-vframes 1 '
// 只截取一帧画面
'-vf scale=128:-1 '
// 设置缩略图宽度为128像素,高度按比例缩放
'-y '
// 覆盖已存在的输出文件
'"
$thumbnailPath
"'
;
// 指定输出文件路径
final
session
=
await
FFmpegKit
.
execute
(
cmd
);
final
returnCode
=
await
session
.
getReturnCode
();
if
(
ReturnCode
.
isSuccess
(
returnCode
))
{
return
thumbnailPath
;
}
else
{
print
(
'生成视频缩略图失败:
${await session.getFailStackTrace()}
'
);
return
null
;
}
}
catch
(
e
)
{
}
catch
(
e
)
{
print
(
'生成视频缩略图出错:
$e
'
);
print
(
'生成视频缩略图出错:
$e
'
);
return
null
;
return
null
;
}
}
// try {
// final thumbnailPath = '${dir.path}/video_thumb_${DateTime.now().millisecondsSinceEpoch}.jpg';
//
// final thumbPath = await VideoThumbnail.thumbnailFile(
// video: videoPath,
// thumbnailPath: thumbnailPath,
// imageFormat: ImageFormat.JPEG,
// maxWidth: 128, // 缩略图最大宽度
// quality: 75, // 图片质量
// );
//
// return thumbPath;
// } catch (e) {
// print('生成视频缩略图出错: $e');
// return null;
// }
}
}
}
}
lib/utils/video_util.dart
View file @
fac3e49
...
@@ -9,25 +9,25 @@ class VideoUtil {
...
@@ -9,25 +9,25 @@ class VideoUtil {
/// 转码的同时,进行压缩
/// 转码的同时,进行压缩
///
///
static
Future
<
bool
>
convertToMp4
(
String
inputPath
,
String
outputPath
)
async
{
static
Future
<
bool
>
convertToMp4
(
String
inputPath
,
String
outputPath
)
async
{
String
cmd
;
String
cmd
;
if
(
Platform
.
isIOS
)
{
if
(
Platform
.
isIOS
)
{
// 构建命令
cmd
=
'-i "
$inputPath
" '
// 1. -c:v h264_videotoolbox : 启用 iOS 硬件加速
'-c:v h264_videotoolbox '
// 启用 iOS 硬件加速
// 2. -b:v 1500k : 限制视频码率为 1.5Mbps (体积小,手机看足够)
'-b:v 1500k '
// 限制视频码率为 1.5Mbps (体积小,手机看足够)
// 3. -vf scale=1280:-2 : 缩放到 720p (保持比例)
'-vf scale=1280:-2 '
// 缩放到 720p (保持比例)
// 4. -c:a aac : 音频转为 AAC (兼容性最好)
'-c:a aac '
// 音频转为 AAC (兼容性最好)
// 5. -b:a 128k : 音频码率
'-b:a 128k '
// 音频码率
cmd
=
'-i "
$inputPath
" '
'-c:v h264_videotoolbox -b:v 1500k '
'-vf scale=1280:-2 '
'-c:a aac -b:a 128k '
'"
$outputPath
"'
;
'"
$outputPath
"'
;
print
(
"开始极速转码:
$cmd
"
);
}
else
{
}
else
{
cmd
=
'-i "
$inputPath
" -c:v libx264 -crf 28 -c:a aac -b:a 128k -strict experimental -movflags faststart -f mp4 "
$outputPath
"'
;
cmd
=
'-i "
$inputPath
" '
// 指定输入文件路径
'-c:v libx264 '
// 设置视频编码器为libx264(H.264)
'-crf 28 '
// 设置恒定速率因子CRF为28(中等压缩质量)
'-c:a aac '
// 设置音频编码器为AAC
'-b:a 128k '
// 设置音频比特率为128kbps
'-strict experimental '
// 允许使用实验性编解码器功能
'-movflags faststart '
// 优化MP4文件结构,使视频可以快速启动播放
'-f mp4 '
// 指定输出格式为MP4
'"
$outputPath
"'
;
// 指定输出文件路径
}
}
final
session
=
await
FFmpegKit
.
execute
(
cmd
);
final
session
=
await
FFmpegKit
.
execute
(
cmd
);
final
returnCode
=
await
session
.
getReturnCode
();
final
returnCode
=
await
session
.
getReturnCode
();
...
@@ -56,8 +56,15 @@ class VideoUtil {
...
@@ -56,8 +56,15 @@ class VideoUtil {
default
:
default
:
throw
Exception
(
'参数错误'
);
throw
Exception
(
'参数错误'
);
}
}
final
session
=
await
FFmpegKit
.
execute
(
String
cmd
=
'-i "
$inputPath
" '
// 输入文件
'-i "
$inputPath
" -c:v libx264 -crf
$crf
-c:a aac -b:a 128k -preset medium -movflags faststart "
$outputPath
"'
);
'-c:v libx264 '
// 视频编码器
'-crf
$crf
'
// 恒定速率因子(质量控制)
'-c:a aac '
// 音频编码器
'-b:a 128k '
// 音频比特率
'-preset medium '
// 编码预设
'-movflags faststart '
// 优化MP4文件结构
'"
$outputPath
"'
;
// 输出文件
final
session
=
await
FFmpegKit
.
execute
(
cmd
);
final
returnCode
=
await
session
.
getReturnCode
();
final
returnCode
=
await
session
.
getReturnCode
();
return
ReturnCode
.
isSuccess
(
returnCode
);
return
ReturnCode
.
isSuccess
(
returnCode
);
}
}
...
...
pubspec.yaml
View file @
fac3e49
...
@@ -37,8 +37,7 @@ dependencies:
...
@@ -37,8 +37,7 @@ dependencies:
flutter_bloc
:
^9.1.1
flutter_bloc
:
^9.1.1
flutter_localization
:
^0.3.3
flutter_localization
:
^0.3.3
flutter_image_compress
:
^2.4.0
flutter_image_compress
:
^2.4.0
ffmpeg_kit_flutter_new
:
^4.1.0
# 建议:如果项目中不需要 image_picker(被 wechat_assets_picker 替代),则保持注释或删除
# 建议:如果项目中不需要 image_picker(被 wechat_assets_picker 替代),则保持注释或删除
# image_picker: ^1.2.0
# image_picker: ^1.2.0
...
@@ -55,8 +54,8 @@ dependencies:
...
@@ -55,8 +54,8 @@ dependencies:
# --- 音视频与直播 (重灾区) ---
# --- 音视频与直播 (重灾区) ---
# 确保 ffmpeg_kit 版本与你的架构兼容。
# 确保 ffmpeg_kit 版本与你的架构兼容。
# 如果只是为了压缩视频,建议评估是否移除 video_compress,直接用 ffmpeg
# 如果只是为了压缩视频,建议评估是否移除 video_compress,直接用 ffmpeg
#ffmpeg_kit_flutter_new: ^3.2
.0
ffmpeg_kit_flutter_new
:
^4.1
.0
video_compress
:
^3.1.4
# video_compress: ^3.1.4
video_player
:
^2.10.0
video_player
:
^2.10.0
# video_thumbnail 已被注释,确认是否需要生成缩略图,如果需要,ffmpeg_kit 也能做
# video_thumbnail 已被注释,确认是否需要生成缩略图,如果需要,ffmpeg_kit 也能做
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment