欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

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(