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

如何用ffmpeg_kit_flutter合并多音频文件或实现连续播放

解决音频连续播放/合并失败的问题

方案一:修复FFmpeg音频合并错误

你的FFmpeg命令失败主要有两个原因:一是硬编码了3个输入文件,但实际传入了4个;二是未处理路径中的空格导致解析错误。以下是修复后的实现:

  1. 动态生成适配任意数量音频的FFmpeg命令
    根据传入的音频文件列表自动生成输入参数和concat滤镜参数,避免固定数量的硬编码。
  2. 用引号包裹文件路径
    临时目录路径可能包含空格,必须用双引号包裹每个文件路径,防止FFmpeg解析出错。
  3. 依赖全功能版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包实现队列无缝播放,彻底避免音频间的停顿:

  1. 添加依赖到pubspec.yaml:
dependencies:
  just_audio: ^0.9.34
  audio_session: ^0.1.16 # 可选,优化系统音频焦点与行为
  1. 实现队列播放逻辑:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 17:34:54