Commit ee8c4a0c by tanghuan

Merge branch 'feature-2604-ios-videotoolbox' into feature-2604

2 parents c0a638b5 4b30afcf
...@@ -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,40 +96,82 @@ class VideoUtil { ...@@ -83,40 +96,82 @@ class VideoUtil {
}) async { }) async {
final duration = await _getVideoDuration(inputPath); final duration = await _getVideoDuration(inputPath);
// 使用CRF模式进行压缩,值范围0-51,建议值18-28 String cmd;
// 高质量: CRF 18-20 if (Platform.isIOS /*&& !_isIos18_6()*/) {
// 中等质量: CRF 23-26 // iOS(非18.6+): 使用 h264_videotoolbox 硬件加速
// 低质量: CRF 28-32 // h264_videotoolbox 不支持 CRF,使用码率控制质量
int crf; int bitrate;
if (quality != null && quality.isNotEmpty) { if (quality != null && quality.isNotEmpty) {
switch (quality) { switch (quality) {
case 'low': case 'low':
crf = 32; bitrate = 1500;
break; break;
case 'middle': case 'middle':
crf = 26; bitrate = 2500;
break; break;
case 'high': case 'high':
crf = 20; bitrate = 4000;
break; break;
default: default:
throw Exception('参数错误'); 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 { } else {
// 根据文件大小自动计算CRF // iOS 18.6+ / Android: 使用 libx264 软件编码
final fileSize = await File(inputPath).length(); // 使用CRF模式进行压缩,值范围0-51,建议值18-28
crf = _getCrfByFileSize(fileSize); // 高质量: CRF 18-20
// 中等质量: CRF 23-26
// 低质量: CRF 28-32
int crf;
if (quality != null && quality.isNotEmpty) {
switch (quality) {
case 'low':
crf = 32;
break;
case 'middle':
crf = 26;
break;
case 'high':
crf = 20;
break;
default:
throw Exception('参数错误');
}
} else {
final fileSize = await File(inputPath).length();
crf = _getCrfByFileSize(fileSize);
}
cmd = '-i "$inputPath" ' // 输入文件
'-c:v libx264 ' // 视频编码器
'-crf $crf ' // 恒定速率因子(质量控制)
'-c:a aac ' // 音频编码器
'-b:a 128k ' // 音频比特率
// '-preset medium ' // 编码预设
'-preset fast ' // 编码预设,编码速度显著提升,体积损失很小
'-threads 0 ' // 让 libx264 自动使用所有可用 CPU 核心,默认行为可能只用单核
'-movflags faststart ' // 优化MP4文件结构
'"$outputPath"'; // 输出文件
} }
String cmd = '-i "$inputPath" ' // 输入文件
'-c:v libx264 ' // 视频编码器
'-crf $crf ' // 恒定速率因子(质量控制)
'-c:a aac ' // 音频编码器
'-b:a 128k ' // 音频比特率
// '-preset medium ' // 编码预设
'-preset fast ' // 编码预设,编码速度显著提升,体积损失很小
'-threads 0 ' // 让 libx264 自动使用所有可用 CPU 核心,默认行为可能只用单核
'-movflags faststart ' // 优化MP4文件结构
'"$outputPath"'; // 输出文件
final completer = Completer<bool>(); final completer = Completer<bool>();
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!