Java 使用 ffmpeg 进行视频格式转换、音频和视频合并、播放和截图
最编程
2024-07-12 14:46:11
...
import java.io.*;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.time.temporal.ChronoUnit.*;
/**
* 利用ffmpeg进行音频视频操作,需先下载安装ffmpeg
*/
public class FfmpegUtils {
/**
* 下载的ffmpeg解压后的bin目录路径,可配置到环境变量通过配置文件读取
*/
private static String ffplay = "D:\\Program File\\ffmpeg-4.3.1-2021-01-01-essentials_build\\bin\\ffplay.exe";
private static String ffmpeg = "D:\\Program File\\ffmpeg-4.3.1-2021-01-01-essentials_build\\bin\\ffmpeg.exe";
private static String ffprobe = "D:\\Program File\\ffmpeg-4.3.1-2021-01-01-essentials_build\\bin\\ffprobe.exe";
/**
* 提取的音频、合成的视频存放路径,不存在会自动创建
*/
private static String saveMediaPath = "D:\\ffmpegMedia\\";
/**
* 保存音频、视频的临时文件夹,不存在会自动创建
*/
private static String tempMediaPath = "D:\\ffmpegMedia\\temp\\";
/**
* 保存图片截图的文件夹,不存在会自动创建
*/
private static String picturMediaPath = "D:\\ffmpegMedia\\pictur\\";
static {
//如果没有文件夹,则创建
File saveMediaFile = new File(saveMediaPath);
if (!saveMediaFile.exists() && !saveMediaFile.isDirectory()) {
saveMediaFile.mkdirs();
}
File tempMediaFile = new File(tempMediaPath);
if (!tempMediaFile.exists() && !tempMediaFile.isDirectory()) {
tempMediaFile.mkdirs();
}
File picturMediaFile = new File(picturMediaPath);
if (!picturMediaFile.exists() && !picturMediaFile.isDirectory()) {
picturMediaFile.mkdirs();
}
}
/**
* 播放音频和视频
*
* @param resourcesPath 文件的路径
*/
public static void playVideoAudio(String resourcesPath) {
List<String> command = new ArrayList<>();
command.add(ffplay);
command.add("-window_title");
String fileName = resourcesPath.substring(resourcesPath.lastIndexOf("\\") + 1);
command.add(fileName);
command.add(resourcesPath);
//播放完后自动退出
//command.add("-autoexit");
commandStart(command);
}
/**
* 播放音频和视频并指定循环次数
*
* @param resourcesPath 文件的路径
* @param loop 循环播放次数
*/
public static void playVideoAudio(String resourcesPath, int loop) {
List<String> command = new ArrayList<>();
command.add(ffplay);
command.add("-window_title");
String fileName = resourcesPath.substring(resourcesPath.lastIndexOf("\\") + 1);
command.add(fileName);
command.add(resourcesPath);
command.add("-loop");
command.add(String.valueOf(loop));
//播放完后自动退出
//command.add("-autoexit");
commandStart(command);
}
/**
* 播放音频和视频并指定宽、高、循环次数
*
* @param resourcesPath 文件的路径
* @param weight 宽度
* @param height 高度
* @param loop 循环播放次数
*/
public static void playVideoAudio(String resourcesPath, int weight, int height, int loop) {
List<String> command = new ArrayList<>();
command.add(ffplay);
command.add("-window_title");
String fileName = resourcesPath.substring(resourcesPath.lastIndexOf("\\") + 1);
command.add(fileName);
command.add(resourcesPath);
command.add("-x");
command.add(String.valueOf(weight));
command.add("-y");
command.add(String.valueOf(height));
command.add("-loop");
command.add(String.valueOf(loop));
//播放完后自动退出
//command.add("-autoexit");
commandStart(command);
}
/**
* 调用命令行执行
*
* @param command 命令行参数
*/
public static void commandStart(List<String> command) {
command.forEach(v -> System.out.print(v + " "));
System.out.println();
System.out.println();
ProcessBuilder builder = new ProcessBuilder();
//正常信息和错误信息合并输出
builder.redirectErrorStream(true);
builder.command(command);
//开始执行命令
Process process = null;
try {
process = builder.start();
//如果你想获取到执行完后的信息,那么下面的代码也是需要的
String line = "";
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 调用命令行执行,并返回信息
*
* @param command 命令行参数
*/
public static String getInfoStr(List<String> command) {
command.forEach(v -> System.out.print(v + " "));
System.out.println();
System.out.println();
ProcessBuilder builder = new ProcessBuilder();
//正常信息和错误信息合并输出
builder.redirectErrorStream(true);
builder.command(command);
//开始执行命令
Process process = null;
StringBuffer sb = new StringBuffer();
try {
process = builder.start();
//如果你想获取到执行完后的信息,那么下面的代码也是需要的
String line = "";
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = br.readLine()) != null) {
System.out.println(line);
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return String.valueOf(sb);
}
/**
* 从视频中提取音频为mp3
*
* @param videoResourcesPath 视频文件的路径
*/
public static void getAudioFromVideo(String videoResourcesPath) {
String fileName = videoResourcesPath.substring(videoResourcesPath.lastIndexOf("\\") + 1, videoResourcesPath.lastIndexOf("."));
List<String> command = new ArrayList<>();
command.add(ffmpeg);
command.add("-i");
command.add(videoResourcesPath);
command.add(saveMediaPath + fileName + ".mp3");
commandStart(command);
}
/**
* 从视频中去除去音频并保存视频
*
* @param videoResourcesPath 视频文件的路径
*/
public static void getVideoFromAudio(String videoResourcesPath) {
List<String> command = new ArrayList<>();
command.add(ffmpeg);
command.add("-i");
command.add(videoResourcesPath);
command.add("-vcodec");
command.add("copy");
command.add("-an");
command.add(saveMediaPath + videoResourcesPath.substring(videoResourcesPath.lastIndexOf("\\") + 1));
commandStart(command);
}
/**
* 无声视频+音频合并为一个视频
* 若音频比视频长,画面停留在最后一帧,继续播放声音。
*
* @param videoResourcesPath 视频文件的路径
* @param audioResourcesPath 音频文件的路径
*/
public static void mergeSilent_VideoAudio(String videoResourcesPath, String audioResourcesPath) {
List<String> command = new ArrayList<>();
command.add(ffmpeg);
command.add("-i");
command.add(videoResourcesPath);
command.add("-i");
command.add(audioResourcesPath);
command.add("-vcodec");
command.add("copy");
command.add("-acodec");
command.add("copy");
command.add(saveMediaPath + videoResourcesPath.substring(videoResourcesPath.lastIndexOf("\\") + 1));
commandStart(command);
}
/**
* 有声视频+音频合并为一个视频。
* 若音频比视频长,画面停留在最后一帧,继续播放声音,
* 若要以视频和音频两者时长短的为主,放开注解启用-shortest。
*
* @param videoResourcesPath 视频文件的路径
* @param audioResourcesPath 音频文件的路径
*/
public static void mergeVideoAudio(String videoResourcesPath, String audioResourcesPath) {
List<String> command = new ArrayList<>();
command.add(ffmpeg);
command.add("-i");
command.add(videoResourcesPath);
command.add("-i");
command.add(audioResourcesPath);
command.add("-filter_complex");
command.add("amix");
command.add("-map");
command.add("0:v");
command.add("-map");
command.add("0:a");
command.add("-map");
command.add("1:a");
//-shortest会取视频或音频两者短的一个为准,多余部分则去除不合并
//command.add("-shortest");
command.add(saveMediaPath + videoResourcesPath.substring(videoResourcesPath.lastIndexOf("\\") + 1));
commandStart(command);
}
/**
* 多视频拼接合并
*
* @param videoResourcesPathList 视频文件路径的List
*/
public static void mergeVideos(List<String> videoResourcesPathList) {
//时间作为合并后的视频名
String getdatatime = nowTime();
//所有要合并的视频转换为ts格式存到videoList里
List<String> videoList = new ArrayList<>();
for (String video : videoResourcesPathList) {
List<String> command = new ArrayList<>();
command.add(ffmpeg);
command.add("-i");
command.add(video);
command.add("-c");
command.add("copy");
command.add("-bsf:v");
command.add("h264_mp4toannexb");
command.add("-f");
command.add("mpegts");
String videoTempName = video.substring(video.lastIndexOf("\\") + 1, video.lastIndexOf(".")) + ".ts";
command.add(tempMediaPath + videoTempName);
commandStart(command);
videoList.add(tempMediaPath + videoTempName);
}
List<String> command1 = new ArrayList<>();
command1.add(ffmpeg);
command1.add("-i");
StringBuffer buffer = new StringBuffer("\"concat:");
for (int i = 0; i < videoList.size(); i++) {
buffer.append(videoList.get(i));
if (i != videoList.size() - 1) {
buffer.append("|");
} else {
buffer.append("\"");
}
}
command1.add(String.valueOf(buffer));
command1.add("-c");
command1.add("copy");
command1.add(saveMediaPath + "视频合并" + getdatatime + ".mp4");
commandStart(command1);
}
/**
* 多视频拼接合并。(mergeVideos1比上面的mergeVideos兼容性更好)
*
* @param videoResourcesPathList 视频文件路径的List
*/
public static void mergeVideos1(List<String> videoResourcesPathList) {
String videosPath= tempMediaPath+"videos.txt";
try(PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(videosPath, false)))) {
for (String video:videoResourcesPathList) {
writer.println(
上一篇: 合并
下一篇: java 实现将 wav 转为 mp3