使用ffmpeg 将图片合成为视频,填充模糊背景,并添加两段音乐

1.输入3张图片,每张播放一次,播放两秒,视频分辨率设置为1920:1080,每张图片前0.3秒淡入,后0.3秒淡出,图片宽高比不变,用白色填充空白区域

复制代码
ffmpeg -loop 1 -t 2 -i "img1.jpg" \
       -loop 1 -t 2 -i "img2.jpg" \
       -loop 1 -t 2 -i "img3.jpg" \
       -filter_complex "
           [0:v]scale=1920:1080:force_original_aspect_ratio=1,
                pad=1920:1080:(ow-iw)/2:(oh-ih)/2:color=white,
                setsar=1,
                format=yuv420p,
                fade=t=in:st=0:d=0.3,
                fade=t=out:st=1.7:d=0.3[img1];
           [1:v]scale=1920:1080:force_original_aspect_ratio=1,
                pad=1920:1080:(ow-iw)/2:(oh-ih)/2:color=white,
                setsar=1,
                format=yuv420p,
                fade=t=in:st=0:d=0.3,
                fade=t=out:st=1.7:d=0.3[img2];
           [2:v]scale=1920:1080:force_original_aspect_ratio=1,
                pad=1920:1080:(ow-iw)/2:(oh-ih)/2:color=white,
                setsar=1,
                format=yuv420p,
                fade=t=in:st=0:d=0.3,
                fade=t=out:st=1.7:d=0.3[img3];
           [img1][img2][img3]concat=n=3:v=1:a=0[vfinal]
       " \
       -map "[vfinal]" \
       -c:v libx264 \
       -preset slow \
       -profile:v high \
       -crf 18 \
       -pix_fmt yuv420p \
       -movflags +faststart \
       -r 30 \
       output.mp4

2.输入一张图片,视频分辨率为1920:1080,生成两张图片,一张模糊用作背景,一张前端宽高比保持一致,生成5秒的视频

复制代码
ffmpeg -loop 1 -t 5 -i img1.jpg \
       -vf "
           split=2[original][blurred];
           [blurred]scale=1920:1080,boxblur=20[blurred];
           [original]scale=1920:1080:force_original_aspect_ratio=1[original];
           [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1
       " \
       -c:v libx264 \
       -s 1920x1080 \
       output222.mp4

3.输入3张图片,设置视频分辨率为1920:1080,每张图片生成模糊背景和一致宽高比前景

复制代码
ffmpeg -loop 1 -t 5 -i "img1.jpg" \
       -loop 1 -t 5 -i "img2.jpg" \
       -loop 1 -t 5 -i "img3.jpg" \
       -filter_complex "
           [0:v]split=2[original][blurred];
           [blurred]scale=1920:1080,boxblur=20[blurred];
           [original]scale=1920:1080:force_original_aspect_ratio=1[original];
           [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3[img1];
           [1:v]split=2[original][blurred];
           [blurred]scale=1920:1080,boxblur=20[blurred];
           [original]scale=1920:1080:force_original_aspect_ratio=1[original];
           [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3[img2];
           [2:v]split=2[original][blurred];
           [blurred]scale=1920:1080,boxblur=20[blurred];
           [original]scale=1920:1080:force_original_aspect_ratio=1[original];
           [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3[img3];
           [img1][img2][img3]concat=n=3:v=1:a=0[vfinal]
       " \
       -map "[vfinal]" \
       -c:v libx264 \
       -preset slow \
       -profile:v high \
       -crf 18 \
       -pix_fmt yuv420p \
       -movflags +faststart \
       -r 30 \
       output444.mp4

4.输入3张图片,设置视频分辨率为1920:1080,每张图片生成模糊背景和一致宽高比前景,添加两段音频合成视频

复制代码
ffmpeg -loop 1 -t 5 -i "img1.jpg" \
       -loop 1 -t 5 -i "img2.jpg" \
       -loop 1 -t 5 -i "img3.jpg" \
       -i "搀扶.mp3" \
       -i "青花瓷.mp3" \
       -filter_complex "
           [0:v]split=2[original][blurred];
           [blurred]scale=1920:1080,boxblur=20[blurred];
           [original]scale=1920:1080:force_original_aspect_ratio=1[original];
           [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3[img1];
           [1:v]split=2[original][blurred];
           [blurred]scale=1920:1080,boxblur=20[blurred];
           [original]scale=1920:1080:force_original_aspect_ratio=1[original];
           [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3[img2];
           [2:v]split=2[original][blurred];
           [blurred]scale=1920:1080,boxblur=20[blurred];
           [original]scale=1920:1080:force_original_aspect_ratio=1[original];
           [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3[img3];
           [img1][img2][img3]concat=n=3:v=1:a=0[vfinal];
           [3:a][4:a]amix=inputs=2[afinal]
       " \
       -map "[vfinal]" \
       -map "[afinal]" \
       -c:v libx264 \
       -c:a aac \
       -b:a 192k \
       -preset slow \
       -profile:v high \
       -crf 18 \
       -pix_fmt yuv420p \
       -movflags +faststart \
       -r 30 \
       -t 15 \
       output666.mp4

详细解释

输入部分
  • -loop 1 -t 5 -i "img1.jpg":将图片 img1.jpg 作为输入,循环显示 5 秒。

  • -loop 1 -t 5 -i "img2.jpg":将图片 img2.jpg 作为输入,循环显示 5 秒。

  • -loop 1 -t 5 -i "img3.jpg":将图片 img3.jpg 作为输入,循环显示 5 秒。

  • -i "搀扶.mp3":将音频文件 搀扶.mp3 作为输入。

  • -i "青花瓷.mp3":将音频文件 青花瓷.mp3 作为输入。

滤镜链部分
  1. 处理每张图片:

    • [0:v]split=2[original][blurred]:将输入流分成两个分支,分别标记为 [original] 和 [blurred]。

    • [blurred]scale=1920:1080,boxblur=20[blurred]:

      • 将 [blurred] 流缩放到 1920x1080。

      • 对 [blurred] 流应用 boxblur 滤镜,模糊程度为 20。

    • [original]scale=1920:1080:force_original_aspect_ratio=1[original]:

      • 将 [original] 流缩放到 1920x1080,保持原始宽高比。
    • [blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st=4.7:d=0.3[img1]:

      • 将 [original] 流覆盖到 [blurred] 流上,居中对齐。

      • 使用 setsar=1 设置采样宽高比为 1:1。

      • 将像素格式设置为 yuv420p。

      • 添加淡入效果:fade=t=in:st=0:d=0.3,在开始时持续 0.3 秒。

      • 添加淡出效果:fade=t=out:st=4.7:d=0.3,在结束前 0.3 秒。

      • 将处理后的流标记为 [img1]。

    同样的处理步骤应用于 img2.jpg 和 img3.jpg,分别标记为 [img2] 和 [img3]。

  2. 拼接处理后的流:

    • [img1][img2][img3]concat=n=3:v=1:a=0[vfinal]:将三个处理后的流拼接在一起,生成最终的视频流 [vfinal]。
  3. 混合音频:

    • [3:a][4:a]amix=inputs=2[afinal]:将两个音频流混合,生成最终的音频流 [afinal]。
输出部分
  • -map "[vfinal]":指定输出流为 [vfinal]。

  • -map "[afinal]":指定输出流为 [afinal]。

  • -c:v libx264:使用 H.264 编码器。

  • -c:a aac:使用 AAC 编码器。

  • -b:a 192k:设置音频比特率为 192 kbps。

  • -preset slow:使用 slow 预设,以获得更好的压缩效果。

  • -profile:v high:使用 high 配置文件。

  • -crf 18:设置质量为 18(较低的值表示更高的质量)。

  • -pix_fmt yuv420p:设置像素格式为 yuv420p。

  • -movflags +faststart:优化视频文件,使其更适合网络播放。

  • -r 30:设置帧率为 30 帧/秒。

  • -t 15:设置输出视频的总时长为 15 秒。

  • output666.mp4:输出文件名。

可以去官网下载ffmpeg

输入文件下载

通过网盘分享的文件:图片生成视频.rar

链接: https://pan.baidu.com/s/1Vc4JbnCjvP_PFHwF-TyfvA?pwd=fiy1 提取码: fiy1

5.使用java生成命令行,并调用ffmpeg执行

复制代码
package com.ruoyi.image.utils.ffmpeg.dto;

import lombok.Data;

import java.util.List;

@Data
public class CommandLineParameterDto {
    //视频宽
    private String videoWidth;
    //视频高
    private String videoHigh;

    //背景音乐
    private String backgroundMusicUrl;
    //朗读音乐
    private String recitationMp3Url;


    //图片list
    private List<ImgDto> imgList;
}

package com.ruoyi.image.utils.ffmpeg.dto;

import lombok.Data;

@Data
public class ImgDto {
    //图片地址
    private String imgUrl;
    //图片播放时间
    private Integer time;
}

package com.ruoyi.image.utils.ffmpeg;

import com.ruoyi.common.core.utils.uuid.UUID;
import com.ruoyi.image.utils.ffmpeg.dto.CommandLineParameterDto;
import com.ruoyi.image.utils.ffmpeg.dto.ImgDto;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class FfmpegUtil {
    public static String ffmpegPath = "/opt/ffmpeg/bin/ffmpeg";

    static {
        String envPath = System.getenv("FFMPEG_PATH");
        if (envPath != null && !envPath.trim().isEmpty()) {
            ffmpegPath = envPath;
        }
    }

    public static String getCreateVideo(CommandLineParameterDto dto){

        if(dto == null){
            return null;
        }
        if(dto.getImgList() == null || dto.getImgList().isEmpty()){
            return null;
        }

        UUID uuid = UUID.randomUUID();
        String uuidString = uuid.toString().replace("-", "");

        String tempDir = System.getProperty("java.io.tmpdir");
        String out=tempDir+uuidString+".mp4";

        int sum = dto.getImgList().stream().mapToInt(i -> i.getTime()).sum();

        StringBuffer stringBuffer=new StringBuffer();
        stringBuffer.append(ffmpegPath+ " ");
        for (ImgDto dto1:dto.getImgList()){
            stringBuffer.append("-loop 1 -t "+dto1.getTime()+" -i "+dto1.getImgUrl()+" ");
        }
        stringBuffer.append("-i "+dto.getBackgroundMusicUrl()+" ");
        stringBuffer.append("-i "+dto.getRecitationMp3Url()+" ");

        StringBuffer filterComplex=new StringBuffer();
        StringBuffer imgs=new StringBuffer();
        for (int i=0;i<dto.getImgList().size();i++){
            ImgDto imgDto = dto.getImgList().get(i);
            Integer time = imgDto.getTime();
            double v = time - 0.3d;
            filterComplex.append("["+i+":v]split=2[original][blurred];[blurred]scale="+dto.getVideoWidth()+":"+dto.getVideoHigh()+",boxblur=20[blurred];[original]scale="+dto.getVideoWidth()+":"+dto.getVideoHigh()+":force_original_aspect_ratio=1[original];[blurred][original]overlay=(W-w)/2:(H-h)/2,setsar=1,format=yuv420p,fade=t=in:st=0:d=0.3,fade=t=out:st="+v+":d=0.3[img"+i+"];");
            imgs.append("[img"+i+"]");
        }
        filterComplex.append(imgs.toString()+"concat=n="+dto.getImgList().size()+":v=1:a=0[vfinal];");
        filterComplex.append("["+dto.getImgList().size()+":a]["+(dto.getImgList().size()+1)+":a]amix=inputs=2[afinal];");

        stringBuffer.append("-filter_complex \""+filterComplex.toString()+"\" ");
        stringBuffer.append("-map \"[vfinal]\" ");
        stringBuffer.append("-map \"[afinal]\" ");
        stringBuffer.append("-c:v libx264 ");
        stringBuffer.append("-c:a aac ");
        stringBuffer.append("-b:a 192k ");
        stringBuffer.append("-preset slow ");
        stringBuffer.append("-profile:v high ");
        stringBuffer.append("-crf 18 ");
        stringBuffer.append("-pix_fmt yuv420p ");
        stringBuffer.append("-movflags +faststart ");
        stringBuffer.append("-r 30 ");
        stringBuffer.append("-t "+sum+" ");
        stringBuffer.append(out+" ");

        try {
            Process process = Runtime.getRuntime().exec(stringBuffer.toString());
            // 创建线程读取输出流
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println("Output: " + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            // 创建线程读取错误流
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println("Error: " + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            // 等待命令执行完成
            int exitCode = process.waitFor(); // 阻塞当前线程,直到命令执行完成
        } catch (IOException e) {
            throw new RuntimeException(e);
        }catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return out;
    }

    public static void main(String[] args) {
        List<ImgDto> list=new ArrayList<>();

        ImgDto img1=new ImgDto();
        img1.setTime(5);
        img1.setImgUrl("https://mmwz.obs.cn-east-3.myhuaweicloud.com/img1.jpg");
        list.add(img1);

        ImgDto img2=new ImgDto();
        img2.setTime(5);
        img2.setImgUrl("https://mmwz.obs.cn-east-3.myhuaweicloud.com/img2.jpg");
        list.add(img2);

        CommandLineParameterDto dto=new CommandLineParameterDto();
        dto.setImgList(list);

        dto.setVideoWidth("1920");
        dto.setVideoHigh("1080");

        dto.setBackgroundMusicUrl("https://mmwz.obs.cn-east-3.myhuaweicloud.com/%E6%90%80%E6%89%B6.mp3");
        dto.setRecitationMp3Url("https://mmwz.obs.cn-east-3.myhuaweicloud.com/%E9%9D%92%E8%8A%B1%E7%93%B7.mp3");

        String createVideo = getCreateVideo(dto);
        System.out.println(createVideo);
    }
}
相关推荐
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
2601_955662463 天前
短剧多人对白怎么配?2026年多角色配音工具对比
大数据·人工智能·音视频·语音识别
开发笔记-阿牛3 天前
蓝牙音乐灯拆解,又一次拆到蓝牙音乐灯芯片CK6865L
人工智能·单片机·嵌入式硬件·音视频·音频
旺仔小馒头wang3 天前
AI 智能手机发布会:赋予人类的五种新能力
人工智能·学习·音视频
纳祥科技3 天前
拆机拆到芯片级:ARC功放机里的NX7026、NX8420、NX6805
单片机·音视频·智能音箱
youandyouyou3 天前
律所内部培训共享的内网部署方案:架构、参数与三步落地
音视频
爱吃提升3 天前
文生视频核心
人工智能·音视频
2601_955662463 天前
抖音视频怎么做多语言配音?2026年AI配音工具与制作流程详解
人工智能·音视频·语音识别·视频
音视频牛哥3 天前
Android与HarmonyOS NEXT如何接入GB28181:从SIP到PS/RTP的完整链路
音视频·gb28181-2022对接·鸿蒙next gb28181·gb/t 28181-2022·gb/t 28181-2016·gb28181-2022平台
美狐美颜SDK开放平台3 天前
直播APP源码与视频美颜sdk如何配合?一套完整开发思路
android·人工智能·计算机视觉·音视频·直播美颜sdk