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 1920×1080 \\
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 作为输入。
滤镜链部分
处理每张图片:
-
[0:v]split=2[original][blurred]:将输入流分成两个分支,分别标记为 [original] 和 [blurred]。
-
[blurred]scale=1920:1080,boxblur=20[blurred]:
-
将 [blurred] 流缩放到 1920×1080。
-
对 [blurred] 流应用 boxblur 滤镜,模糊程度为 20。
-
-
[original]scale=1920:1080:force_original_aspect_ratio=1[original]:
-
将 [original] 流缩放到 1920×1080,保持原始宽高比。
-
-
[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]。
拼接处理后的流:
-
[img1][img2][img3]concat=n=3:v=1:a=0[vfinal]:将三个处理后的流拼接在一起,生成最终的视频流 [vfinal]。
混合音频:
-
[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);
}
}
评论前必须登录!
注册