You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter视频压缩问题:无法将视频压缩至指定大小上限

解决Flutter中按指定大小上限压缩视频的问题

我太懂这个痛点了——flutter_video_compress确实没提供直接设置压缩大小上限的功能,要把20MB的视频精准压到2MB这种需求,得换个思路来实现。下面是我实践过的可行方案:

核心思路:通过迭代调整比特率实现目标大小

视频文件大小的核心计算公式是:文件大小(字节)= 比特率(bps)× 时长(秒)/ 8。我们可以反向推导目标比特率,然后通过多次迭代调整,直到压缩后的文件符合大小要求。

具体步骤

  1. 获取原视频基础信息:先拿到视频的时长、原比特率等数据,这是计算的基础
  2. 计算初始目标比特率:根据目标大小和时长,算出第一次压缩要用的比特率
  3. 迭代压缩+校验:第一次压缩后检查大小,若超出就降低比特率再次压缩,直到满足要求或达到最低画质阈值

代码实现

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

火山引擎 最新活动