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命令
原始命令存在三个核心问题,修正后可解决大部分合并失败场景:
- 路径未加引号:若视频路径包含空格或特殊字符,会导致命令解析错误,需用双引号包裹路径
- 未指定编码器:concat滤镜后显式指定编码器(如libx264、aac),避免自动编码兼容性问题
- 音频处理缺失:若需要保留音频,必须在滤镜中包含音频流的拼接逻辑
常用命令示例
- 保留音频的合并命令:
-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
相关产品推荐
相关产品推荐

