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

Flutter中如何将相册多选存入数组的图片通过FFmpeg生成视频

解决Flutter中用multi_image_picker选图后通过FFmpeg生成视频的问题

核心问题分析

你的代码存在几个关键问题:

  1. 转换函数内重新定义了空的resultlist,没有使用实际选中的图片数组
  2. Asset对象不是本地文件路径,无法直接传入FFmpeg命令
  3. FFmpeg命令格式错误,多张图片的输入逻辑不符合要求

解决方案步骤

1. 将Asset图片保存到本地路径

先实现一个方法,把选中的Asset保存到本地存储,获取FFmpeg可识别的文件路径:

import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:multi_image_picker/multi_image_picker.dart';

Future<List<String>> saveAssetsToLocal(List<Asset> assets) async {
  List<String> localPaths = [];
  for (var asset in assets) {
    final byteData = await asset.getByteData();
    final file = File(
        '${(await getTemporaryDirectory()).path}/${asset.name}');
    await file.writeAsBytes(byteData.buffer.asUint8List());
    localPaths.add(file.path);
  }
  return localPaths;
}

2. 修改视频转换函数,传入选中的图片数组

调整ConvertImageToVideo函数,传入实际选中的图片数组,构造正确的FFmpeg命令:

import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter/return_code.dart';
import 'package:permission_handler/permission_handler.dart';

Future<void> convertImageToVideo(List<Asset> selectedImages) async {
  const String BASE_PATH = '/storage/emulated/0/Download/';
  const String AUDIO_PATH = BASE_PATH + 'audiio.mp3';
  const String OUTPUT_PATH = BASE_PATH + 'output02.mp4';

  if (await Permission.storage.request().isGranted) {
    // 将选中的Asset保存到本地
    List<String> imagePaths = await saveAssetsToLocal(selectedImages);
    if (imagePaths.isEmpty) {
      print("没有选中的图片");
      return;
    }

    // 构造FFmpeg命令:每张图片展示2秒,自动匹配音频时长
    String concatFilter = "";
    for (int i = 0; i < imagePaths.length; i++) {
      concatFilter += "[$i:v]trim=duration=2,setpts=PTS-STARTPTS[v$i];";
    }
    concatFilter += imagePaths.map((e) => "[v${imagePaths.indexOf(e)}]").join("");
    concatFilter += "concat=n=${imagePaths.length}:v=1:a=0[v]";

    String commandToExecute =
        "-i ${AUDIO_PATH} " +
        imagePaths.map((path) => "-i $path").join(" ") +
        " -filter_complex \"$concatFilter\" " +
        "-map \"[v]\" -map 0:a -shortest -y $OUTPUT_PATH";

    // 执行FFmpeg命令
    await FFmpegKit.execute(commandToExecute).then((session) async {
      final returnCode = await session.getReturnCode();
      if (ReturnCode.isSuccess(returnCode)) {
        print("视频生成成功,返回码:${returnCode.toString()}");
      } else if (ReturnCode.isCancel(returnCode)) {
        print("视频生成被取消,返回码:${returnCode.toString()}");
      } else {
        print("视频生成失败,返回码:${returnCode.toString()}");
        // 打印错误日志排查问题
        final log = await session.getAllLogs();
        log.forEach((log) => print(log.getMessage()));
      }
    });
  } else if (await Permission.storage.isPermanentlyDenied) {
    openAppSettings();
  }
}

3. 调用转换函数

在完成图片选择后,直接传入选中的resultList调用转换函数:

// 假设已通过multi_image_picker获取到选中的resultList
convertImageToVideo(resultList);

关键说明

  • 可通过修改trim=duration=2中的2调整单张图片的展示时长(单位:秒)
  • -shortest参数会让视频时长与音频时长保持一致,避免时长不匹配
  • 若不需要音频,可删除命令中与音频相关的输入和映射参数
  • 保存图片的路径可根据需求调整为Download目录,而非临时目录

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:40:41