You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter使用ffmpeg_kit_flutter合并视频失败的问题排查

解决Flutter中ffmpeg_kit_flutter合并视频失败的问题

问题现象

使用ffmpeg_kit_flutter库合并两段视频时,触发ErrorMergeVideos状态,日志显示返回码对应任务仍处于运行状态,同时FFmpeg concat命令存在潜在问题。

解决方案

一、修复FFmpeg任务调用逻辑

你的代码同时调用了FFmpegKit.execute()和FFmpegKit.executeAsync(),导致命令重复执行,且异步回调中过早获取返回码,无法正确判断任务执行状态。以下是修正后的实现:

修正后的mergeVideos方法

Future<void> mergeVideos(String inputPath1, String inputPath2) async {
  final String outputPath = "/storage/emulated/0/merged_video_${now()}.mp4";
  // 修正后的FFmpeg命令(保留音频版本,无需音频可调整)
  final String command = 
      '-i "$inputPath1" -i "$inputPath2" -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" -c:v libx264 -c:a aac -y "$outputPath"';
  
  print("FFmpeg process starting with command: $command");
  emit(LoadMergeVideos());

  // 使用同步execute等待任务完成(后台场景适用,UI线程建议用异步方案)
  final session = await FFmpegKit.execute(command);
  final returnCode = await session.getReturnCode();
  final sessionId = await session.getSessionId();

  print("Session ID: $sessionId");

  if (ReturnCode.isSuccess(returnCode)) {
    print("SUCCESS: Video merged successfully at $outputPath");
    emit(SuccessMergeVideos());
  } else if (ReturnCode.isCancel(returnCode)) {
    print("CANCELLED: Video merging was cancelled.");
    emit(CancelMergeVideos());
  } else {
    print("ERROR: Failed to merge videos.");
    final failLog = await session.getAllLogsAsString();
    print("FFmpeg Failure Log: $failLog");
    emit(ErrorMergeVideos());
  }

  // 异步方案(不阻塞UI场景适用)
  // FFmpegKit.executeAsync(command, (session) async {
  //   final returnCode = await session.getReturnCode();
  //   if (ReturnCode.isSuccess(returnCode)) {
  //     print("SUCCESS: Video merged successfully at $outputPath");
  //     emit(SuccessMergeVideos());
  //   } else if (ReturnCode.isCancel(returnCode)) {
  //     print("CANCELLED: Video merging was cancelled.");
  //     emit(CancelMergeVideos());
  //   } else {
  //     print("ERROR: Failed to merge videos.");
  //     final failLog = await session.getAllLogsAsString();
  //     print("FFmpeg Failure Log: $failLog");
  //     emit(ErrorMergeVideos());
  //   }
  // });
}

二、修正FFmpeg concat命令

原始命令存在三个核心问题,修正后可解决大部分合并失败场景:

  1. 路径未加引号:若视频路径包含空格或特殊字符,会导致命令解析错误,需用双引号包裹路径
  2. 未指定编码器:concat滤镜后显式指定编码器(如libx264、aac),避免自动编码兼容性问题
  3. 音频处理缺失:若需要保留音频,必须在滤镜中包含音频流的拼接逻辑

常用命令示例

  • 保留音频的合并命令:
-i "$inputPath1" -i "$inputPath2" -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" -c:v libx264 -c:a aac -y "$outputPath"
  • 仅保留视频的合并命令:
-i "$inputPath1" -i "$inputPath2" -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0[outv]" -map "[outv]" -c:v libx264 -y "$outputPath"

三、其他优化建议

  • 权限检查:确保应用拥有外部存储写入权限(Android 10及以下需WRITE_EXTERNAL_STORAGE,Android 11+建议使用MediaStore)
  • 路径规范:使用path_provider库获取合法存储路径,避免硬编码/storage/emulated/0/
  • 日志排查:用getAllLogsAsString()替代getFailStackTrace(),获取完整的FFmpeg执行日志,便于定位问题
  • 视频兼容性处理:若两段视频分辨率、编码格式不一致,添加scale滤镜统一参数:
-i "$inputPath1" -i "$inputPath2" -filter_complex "[0:v]scale=1920:1080[v0];[1:v]scale=1920:1080[v1];[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" -c:v libx264 -c:a aac -y "$outputPath"

内容的提问来源于stack exchange,提问作者Hani Kanakri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:54:58