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 ee8c4a0c
authored
2026-04-30 09:43:47 +0800
by
tanghuan
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Merge branch 'feature-2604-ios-videotoolbox' into feature-2604
2 parents
c0a638b5
4b30afcf
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
64 additions
and
9 deletions
lib/utils/video_util.dart
lib/utils/video_util.dart
View file @
ee8c4a0
...
@@ -24,14 +24,24 @@ class VideoUtil {
...
@@ -24,14 +24,24 @@ class VideoUtil {
final
fileSize
=
await
File
(
inputPath
).
length
();
final
fileSize
=
await
File
(
inputPath
).
length
();
String
cmd
;
String
cmd
;
if
(
Platform
.
isIOS
&&
!
_isIos18_6
()
)
{
if
(
Platform
.
isIOS
/*&& !_isIos18_6()*/
)
{
final
bitrate
=
_getBitrateByFileSize
(
fileSize
);
final
bitrate
=
_getBitrateByFileSize
(
fileSize
);
// cmd = '-i "$inputPath" '
// '-c:v h264_videotoolbox ' // 启用 iOS 硬件加速
// '-b:v ${bitrate}k ' // 根据文件大小自动计算码率
// '-vf scale=1280:-2 ' // 缩放到 720p (保持比例)
// '-c:a aac ' // 音频转为 AAC (兼容性最好)
// '-b:a 128k ' // 音频码率
// '"$outputPath"';
cmd
=
'-i "
$inputPath
" '
cmd
=
'-i "
$inputPath
" '
'-c:v h264_videotoolbox '
// 启用 iOS 硬件加速
'-c:v h264_videotoolbox '
'-b:v
${bitrate}
k '
// 根据文件大小自动计算码率
'-b:v
${bitrate}
k '
'-vf scale=1280:-2 '
// 缩放到 720p (保持比例)
'-profile:v high '
// 确保使用高压缩率 Profile
'-c:a aac '
// 音频转为 AAC (兼容性最好)
'-vf "scale=trunc(oh*a/2)*2:720,format=yuv420p" '
// 强制 720p 且确保像素格式为 yuv420p
'-b:a 128k '
// 音频码率
'-c:a aac '
'-b:a 128k '
'-movflags +faststart '
// 关键:优化 MP4 结构,支持边下边播
'-y '
// 自动覆盖已存在文件
'"
$outputPath
"'
;
'"
$outputPath
"'
;
}
else
{
}
else
{
final
crf
=
_getCrfByFileSize
(
fileSize
);
final
crf
=
_getCrfByFileSize
(
fileSize
);
...
@@ -72,7 +82,10 @@ class VideoUtil {
...
@@ -72,7 +82,10 @@ class VideoUtil {
///
///
/// 通过 ffmpeg 压缩视频
/// 通过 ffmpeg 压缩视频
/// [quality] 压缩质量,可选值: 'low' | 'middle' | 'high'
/// [quality] 压缩质量,可选值: 'low' | 'middle' | 'high'
/// 未指定时根据文件大小自动计算CRF:文件越大压缩率越高,文件越小清晰度越高
/// 未指定时根据文件大小自动计算压缩参数:文件越大压缩率越高,文件越小清晰度越高
/// iOS 18.6.x: libx264 + CRF(h264_videotoolbox在iOS 18.6.x存在稳定性问题)
/// 其它iOS版本: h264_videotoolbox 硬件加速 + 码率控制
/// Android: libx264 + CRF
/// [onProgress] 进度回调,值范围 0.0 ~ 1.0
/// [onProgress] 进度回调,值范围 0.0 ~ 1.0
///
///
static
Future
<
bool
>
compressVideo
(
static
Future
<
bool
>
compressVideo
(
...
@@ -83,6 +96,48 @@ class VideoUtil {
...
@@ -83,6 +96,48 @@ class VideoUtil {
})
async
{
})
async
{
final
duration
=
await
_getVideoDuration
(
inputPath
);
final
duration
=
await
_getVideoDuration
(
inputPath
);
String
cmd
;
if
(
Platform
.
isIOS
/*&& !_isIos18_6()*/
)
{
// iOS(非18.6+): 使用 h264_videotoolbox 硬件加速
// h264_videotoolbox 不支持 CRF,使用码率控制质量
int
bitrate
;
if
(
quality
!=
null
&&
quality
.
isNotEmpty
)
{
switch
(
quality
)
{
case
'low'
:
bitrate
=
1500
;
break
;
case
'middle'
:
bitrate
=
2500
;
break
;
case
'high'
:
bitrate
=
4000
;
break
;
default
:
throw
Exception
(
'参数错误'
);
}
}
else
{
final
fileSize
=
await
File
(
inputPath
).
length
();
bitrate
=
_getBitrateByFileSize
(
fileSize
);
}
// cmd = '-i "$inputPath" ' // 输入文件
// '-c:v h264_videotoolbox ' // iOS硬件加速视频编码器
// '-b:v ${bitrate}k ' // 根据质量/文件大小自动计算码率
// '-c:a aac ' // 音频编码器
// '-b:a 128k ' // 音频码率
// '-movflags faststart ' // 优化MP4文件结构
// '"$outputPath"'; // 输出文件
cmd
=
'-i "
$inputPath
" '
'-c:v h264_videotoolbox '
'-b:v
${bitrate}
k '
'-profile:v high '
// 使用高配置以获得更好画质
'-pix_fmt yuv420p '
// 确保像素格式兼容性
'-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" '
// 强制偶数分辨率,防止报错
'-c:a aac '
'-b:a 128k '
'-movflags +faststart '
// 允许边下边播
'"
$outputPath
"'
;
}
else
{
// iOS 18.6+ / Android: 使用 libx264 软件编码
// 使用CRF模式进行压缩,值范围0-51,建议值18-28
// 使用CRF模式进行压缩,值范围0-51,建议值18-28
// 高质量: CRF 18-20
// 高质量: CRF 18-20
// 中等质量: CRF 23-26
// 中等质量: CRF 23-26
...
@@ -103,11 +158,10 @@ class VideoUtil {
...
@@ -103,11 +158,10 @@ class VideoUtil {
throw
Exception
(
'参数错误'
);
throw
Exception
(
'参数错误'
);
}
}
}
else
{
}
else
{
// 根据文件大小自动计算CRF
final
fileSize
=
await
File
(
inputPath
).
length
();
final
fileSize
=
await
File
(
inputPath
).
length
();
crf
=
_getCrfByFileSize
(
fileSize
);
crf
=
_getCrfByFileSize
(
fileSize
);
}
}
String
cmd
=
'-i "
$inputPath
" '
// 输入文件
cmd
=
'-i "
$inputPath
" '
// 输入文件
'-c:v libx264 '
// 视频编码器
'-c:v libx264 '
// 视频编码器
'-crf
$crf
'
// 恒定速率因子(质量控制)
'-crf
$crf
'
// 恒定速率因子(质量控制)
'-c:a aac '
// 音频编码器
'-c:a aac '
// 音频编码器
...
@@ -117,6 +171,7 @@ class VideoUtil {
...
@@ -117,6 +171,7 @@ class VideoUtil {
'-threads 0 '
// 让 libx264 自动使用所有可用 CPU 核心,默认行为可能只用单核
'-threads 0 '
// 让 libx264 自动使用所有可用 CPU 核心,默认行为可能只用单核
'-movflags faststart '
// 优化MP4文件结构
'-movflags faststart '
// 优化MP4文件结构
'"
$outputPath
"'
;
// 输出文件
'"
$outputPath
"'
;
// 输出文件
}
final
completer
=
Completer
<
bool
>();
final
completer
=
Completer
<
bool
>();
...
...
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