video_util.dart 3.74 KB
import 'dart:io';

import 'package:ffmpeg_kit_flutter_new/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';

class VideoUtil {
  ///
  /// 将视频格式转换为mp4
  /// 转码的同时,进行压缩
  ///
  static Future<bool> convertToMp4(String inputPath, String outputPath) async {
    String cmd;
    if (Platform.isIOS) {
      cmd = '-i "$inputPath" '
          '-c:v h264_videotoolbox ' // 启用 iOS 硬件加速
          '-b:v 1500k ' // 限制视频码率为 1.5Mbps (体积小,手机看足够)
          '-vf scale=1280:-2 ' // 缩放到 720p (保持比例)
          '-c:a aac ' // 音频转为 AAC (兼容性最好)
          '-b:a 128k ' // 音频码率
          '"$outputPath"';
    } else {
      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 returnCode = await session.getReturnCode();
    return ReturnCode.isSuccess(returnCode);
  }

  ///
  /// 通过 ffmpeg 压缩视频
  ///
  static Future<bool> compressVideo(String inputPath, String outputPath, String quality) async {
    // 使用CRF模式进行压缩,值范围0-51,建议值18-28
    // 高质量: CRF 18-20
    // 中等质量: CRF 23-26
    // 低质量: CRF 28-32
    int crf;
    switch (quality) {
      case 'low':
        crf = 32;
        break;
      case 'middle':
        crf = 26;
        break;
      case 'high':
        crf = 20;
        break;
      default:
        throw Exception('参数错误');
    }
    String cmd = '-i "$inputPath" ' // 输入文件
        '-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();
    return ReturnCode.isSuccess(returnCode);
  }

  /// 为视频文件生成缩略图
  /// [videoPath] 要生成缩略图的视频文件路径
  /// [thumbnailPath] 要生成的缩略图文件路径
  /// 返回缩略图路径
  static Future<String?> genVideoThumbnail(String videoPath, String thumbnailPath) async {
    try {
      // final thumbnailPath = '${dir.path}/video_thumb_${DateTime.now().millisecondsSinceEpoch}.jpg';

      // 使用 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) {
      print('生成视频缩略图出错: $e');
      return null;
    }
  }
}