如何用ffmpeg_kit_flutter合并多音频文件或实现连续播放
解决音频连续播放/合并失败的问题
方案一:修复FFmpeg音频合并错误
你的FFmpeg命令失败主要有两个原因:一是硬编码了3个输入文件,但实际传入了4个;二是未处理路径中的空格导致解析错误。以下是修复后的实现:
- 动态生成适配任意数量音频的FFmpeg命令
根据传入的音频文件列表自动生成输入参数和concat滤镜参数,避免固定数量的硬编码。 - 用引号包裹文件路径
临时目录路径可能包含空格,必须用双引号包裹每个文件路径,防止FFmpeg解析出错。 - 依赖全功能版FFmpegKit
在pubspec.yaml中替换为全功能版本,避免缺少concat滤镜:dependencies: ffmpeg_kit_flutter_full: ^5.1.0
修改后的combineAudio函数:
Future<void> combineAudio(List<String> audioFiles) async { Directory tempDir = await getTemporaryDirectory(); String combinedAudioPath = '${tempDir.path}/output.mp3'; // 生成输入参数:每个文件前加 -i "路径" String inputArgs = audioFiles.map((path) => '-i "$path"').join(' '); // 生成滤镜链:[0:a][1:a]...[n-1:a]concat=n=文件数:v=0:a=1[out] String filterInputs = audioFiles.asMap().keys.map((idx) => '[$idx:a]').join(''); int fileCount = audioFiles.length; String filterComplex = '$filterInputsconcat=n=$fileCount:v=0:a=1[out]'; // 完整FFmpeg命令 String cmd = '$inputArgs -filter_complex "$filterComplex" -map "[out]" "$combinedAudioPath"'; FFmpegKit.execute(cmd).then((session) async { final returnCode = await session.getReturnCode(); if (ReturnCode.isSuccess(returnCode)) { print('音频合并成功: $combinedAudioPath'); // 此处可调用播放器播放合并后的文件 } else { // 打印错误日志排查问题 final logs = await session.getAllLogs(); logs.forEach((log) => print(log.getMessage())); print('合并失败,错误码: $returnCode'); } }); }
方案二:无需合并,实现无缝连续播放
如果合并音频的配置成本太高,推荐使用just_audio包实现队列无缝播放,彻底避免音频间的停顿:
- 添加依赖到
pubspec.yaml:
dependencies: just_audio: ^0.9.34 audio_session: ^0.1.16 # 可选,优化系统音频焦点与行为
- 实现队列播放逻辑:
import 'package:just_audio/just_audio.dart'; import 'package:audio_session/audio_session.dart'; final _player = AudioPlayer(); Future<void> setupSeamlessPlayback(List<String> localFilePaths) async { // 初始化音频会话(可选,提升系统兼容性) final session = await AudioSession.instance; await session.configure(const AudioSessionConfiguration.speech()); // 构建播放队列,开启预加载避免停顿 final playlist = ConcatenatingAudioSource( children: localFilePaths.map((path) => AudioSource.uri(Uri.file(path))).toList(), useLazyPreparation: true, ); await _player.setAudioSource(playlist); await _player.play(); // 启动播放,自动无缝切换到下一个音频 } // 在你的启动函数中调用: void combineAndPlayAudio() async { List<String> localFilePaths = await copyAssetFilesToStorage(); await setupSeamlessPlayback(localFilePaths); }
这个方案无需合并文件,通过预加载机制实现音频间的无间隙衔接,体验更流畅,也省去了FFmpeg的配置调试成本。
内容的提问来源于stack exchange,提问作者sunil kalwani
相关产品推荐
相关产品推荐

