Flutter视频压缩问题:无法将视频压缩至指定大小上限
解决Flutter中按指定大小上限压缩视频的问题
我太懂这个痛点了——flutter_video_compress确实没提供直接设置压缩大小上限的功能,要把20MB的视频精准压到2MB这种需求,得换个思路来实现。下面是我实践过的可行方案:
核心思路:通过迭代调整比特率实现目标大小
视频文件大小的核心计算公式是:文件大小(字节)= 比特率(bps)× 时长(秒)/ 8。我们可以反向推导目标比特率,然后通过多次迭代调整,直到压缩后的文件符合大小要求。
具体步骤
- 获取原视频基础信息:先拿到视频的时长、原比特率等数据,这是计算的基础
- 计算初始目标比特率:根据目标大小和时长,算出第一次压缩要用的比特率
- 迭代压缩+校验:第一次压缩后检查大小,若超出就降低比特率再次压缩,直到满足要求或达到最低画质阈值
代码实现
import 'package:flutter_video_compress/flutter_video_compress.dart'; import 'dart:io'; Future<File?> compressVideoToTargetSize(String inputPath, int targetSizeInBytes) async { final videoCompressor = FlutterVideoCompress(); // 第一步:获取原视频的媒体信息 final mediaInfo = await videoCompressor.getMediaInfo(inputPath); if (mediaInfo == null) { print('无法获取视频信息'); return null; } final durationSeconds = mediaInfo.duration / 1000; if (durationSeconds <= 0) { print('视频时长异常'); return null; } // 第二步:计算初始目标比特率(留出10%的冗余空间) double targetBitrate = (targetSizeInBytes * 8 * 0.9) / durationSeconds; // 设置最低比特率阈值,避免画质过于模糊 const minAllowedBitrate = 400 * 1000; // 400kbps const maxAttempts = 6; // 最多尝试6次,防止无限循环 File? finalCompressedFile; int attemptCount = 0; while (attemptCount < maxAttempts) { attemptCount++; print('第$attemptCount次压缩,目标比特率:${(targetBitrate/1000).toStringAsFixed(2)}kbps'); // 执行压缩 final compressionResult = await videoCompressor.compressVideo( inputPath, bitrate: targetBitrate.toInt(), quality: VideoQuality.DefaultQuality, // 用默认质量,重点靠比特率控制 deleteOrigin: false, // 保留原文件,可根据需求修改 ); if (compressionResult == null || compressionResult.path == null) { print('压缩失败'); break; } final compressedFile = File(compressionResult.path!); final currentSize = await compressedFile.length(); if (currentSize <= targetSizeInBytes) { // 达到目标大小,返回结果 finalCompressedFile = compressedFile; print('压缩成功,最终大小:${(currentSize/1024/1024).toStringAsFixed(2)}MB'); break; } else if (targetBitrate <= minAllowedBitrate) { // 已经降到最低比特率,无法再压缩 print('已达到最低比特率,无法满足目标大小'); finalCompressedFile = compressedFile; break; } // 未达到目标,降低比特率(每次乘以0.7,可根据情况调整) targetBitrate *= 0.7; } return finalCompressedFile; } // 使用示例:将视频压缩至最大2MB void exampleUsage() async { const targetSizeMB = 2; final targetSizeBytes = targetSizeMB * 1024 * 1024; final originalVideoPath = '/storage/emulated/0/DCIM/Camera/test.mp4'; // 替换为你的视频路径 final compressedVideo = await compressVideoToTargetSize(originalVideoPath, targetSizeBytes); if (compressedVideo != null) { // 处理压缩后的视频,比如上传、保存等 } }
额外优化建议
- 先降分辨率再压比特率:如果原视频是4K/1080p,可以先把分辨率降到720p甚至480p,再调整比特率,这样能更快达到目标大小,同时画质损失更可控
- 显示压缩进度:迭代压缩耗时较长,建议给用户显示进度条或加载提示,提升体验
- 处理异常场景:比如压缩过程中用户取消、文件被删除等,要添加try-catch块捕获异常
- 缓存压缩结果:避免重复压缩同一个视频,可根据原视频的哈希值缓存压缩后的文件
内容的提问来源于stack exchange,提问作者Khalid Mohammed




