这篇文章完全转自(感谢大神):

https://blog.csdn.net/qq_33697094/article/details/112718101
https://blog.csdn.net/qq_33697094/article/details/112847624

1.ffmpeg下载
首先打开 ffmpeg官网下载
或者用 百度云 下载(https://pan.baidu.com/s/1dCK-TrOcUfC6pdKi2Y1e6g 提取码:2pdo)

然后点击 windows 对应的图标,再点击下面的”Windows EXE File”随便选一个点进去选择一个版本下载。

2.下载后解压,配置环境变量
下载解压后就能在 bin 文件夹下能看到三个可执行程序:ffmpeg、ffplay、ffprobe,配置好环境变量后即可使用。

验证是否成功:
cmd窗口输入ffmpeg -version 。如下图则安装成功。

3.介绍FFmpeg组成
构成FFmpeg主要有三个部分

3.1第一部分是四个作用不同的工具软件,分别是:
ffmpeg.exe,
ffplay.exe,
ffprobe.exe。

ffmpeg.exe:音视频转码、转换器
ffplay.exe:简单的音视频播放器
ffprobe.exe:简单的多媒体码流分析器

3.2第二部分是可以供开发者使用的SDK,为各个不同平台编译完成的库。
如果说上面的四个工具软件都是完整成品形式的玩具,那么这些库就相当于乐高积木一样,我们可以根据自己的需求使用这些库开发自己的应用程序。这些库有:

libavcodec:包含音视频编码器和解码器
libavutil:包含多媒体应用常用的简化编程的工具,如随机数生成器、数据结构、数学函数等功能
libavformat:包含多种多媒体容器格式的封装、解封装工具
libavfilter:包含多媒体处理常用的滤镜功能
libavdevice:用于音视频数据采集和渲染等功能的设备相关
libswscale:用于图像缩放和色彩空间和像素格式转换功能
libswresample:用于音频重采样和格式转换等功能

3.3第三部分是整个工程的源代码,无论是编译出来的可执行程序还是SDK,都是由这些源代码编译出来的。
FFmpeg的源代码由C语言实现,主要在Linux平台上进行开发。FFmpeg不是一个孤立的工程,它还存在多个依赖的第三方工程来增强它自身的功能。在当前这一系列的博文/视频中,我们暂时不会涉及太多源代码相关的内容,主要以FFmpeg的工具和SDK的调用为主。到下一系列我们将专门研究如何编译源代码并根据源代码来进行二次开发。

4.简单使用:
比如,使用ffmpeg获取视频的一些信息:

ffprobe -show_format D:\507-#网愈云故事收藏馆.mp4

播放音频文件的命令:

ffplay D:\507-#网愈云故事收藏馆.mp4

这时候就会弹出来一个窗口,一边播放MP3文件,一边将播放音频的图画到该窗口上。针对该窗口的操作如下:

点击该窗口的任意一个位置,ffplay会按照点击的位置计算出时间的进度,然后seek到计算出来的时间点继续播放。
按下键盘的左键默认快退10s,右键默认快进10s,上键默认快进1min,下键默认快退1min。
按ESC就退出播放进程,按W会绘制音频的波形图。

5.使用Java调用ffmpeg,进行音视频的转换、音视频提取、音视频截取:


package com.jzai.weblab.util.ffmpegConvert;import cn.hutool.core.io.FileUtil;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* @author WeiDaPang*/
public class FfmpegUtil {/*** 下载的ffmpeg解压后的bin目录路径,可配置到环境变量通过配置文件读取*/private static final String FFMPEG_BIN_PATH = "D:/360Downloads/ffmpeg/bin/";/*** [描述] 转换以后文件保存根路径*/private static final String SAVE_MEDIA_PATH = "D:/360Downloads/ffmpegMedia/";private static final String FFPLAY = FFMPEG_BIN_PATH+"ffplay";private static final String FFMPEG = FFMPEG_BIN_PATH+"ffmpeg";private static final String FFPROBE = FFMPEG_BIN_PATH+"ffprobe";/*** 提取的音频、合成的视频存放路径,不存在会自动创建*/private static final String SAVE_MEDIA_FILE = SAVE_MEDIA_PATH+"outFile/";/*** 保存音频、视频的临时文件夹,不存在会自动创建*/private static final String TEMP_MEDIA_PATH = SAVE_MEDIA_PATH+"temp/";/*** 保存图片截图的文件夹,不存在会自动创建*/private static final String PICTURE_MEDIA_PATH = SAVE_MEDIA_PATH+"picture/";static {//如果没有文件夹,则创建File saveMediaFile = new File(SAVE_MEDIA_FILE);if (!saveMediaFile.exists() && !saveMediaFile.isDirectory()) {boolean b = saveMediaFile.mkdirs();}File tempMediaFile = new File(TEMP_MEDIA_PATH);if (!tempMediaFile.exists() && !tempMediaFile.isDirectory()) {boolean b = tempMediaFile.mkdirs();}File pictureMediaFile = new File(PICTURE_MEDIA_PATH);if (!pictureMediaFile.exists() && !pictureMediaFile.isDirectory()) {boolean b = pictureMediaFile.mkdirs();}}private static List<String> getList(){return new ArrayList<>();}private static String createDirectoryByTime(){String newPath = SAVE_MEDIA_FILE + nowTime() + "/";File file = new File(newPath);if (!file.exists()){boolean b = file.mkdirs();}return newPath;}/*** 播放音频和视频** @param resourcesPath 文件的路径*/public static void playVideoAudio(String resourcesPath) {List<String> command = getList();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 = getList();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 = getList();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) {System.out.println("----- 执行的命令 -----");command.forEach(v -> System.out.print(v + " "));System.out.println();System.out.println("----- 执行的命令 end -----");System.out.println();ProcessBuilder builder = new ProcessBuilder();//正常信息和错误信息合并输出builder.redirectErrorStream(true);builder.command(command);//开始执行命令Process process;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();}System.out.println("...命令执行完成...");}/*** 调用命令行执行,并返回信息** @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;StringBuilder sb = new StringBuilder();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 newPath = createDirectoryByTime();//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(newPath + nowTime() + ".mp3");commandStart(command);}/*** 从视频中去除去音频并保存视频** @param videoResourcesPath 视频文件的路径*/public static void getVideoFromAudio(String videoResourcesPath) {String newPath = createDirectoryByTime();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(newPath + videoResourcesPath.substring(videoResourcesPath.lastIndexOf("/") + 1));commandStart(command);}/*** 无声视频+音频合并为一个视频* 若音频比视频长,画面停留在最后一帧,继续播放声音。* @param videoResourcesPath 视频文件的路径* @param audioResourcesPath 音频文件的路径*/public static void mergeSilent_VideoAudio(String videoResourcesPath, String audioResourcesPath) {String newPath = createDirectoryByTime();List<String> command = getList();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(newPath + videoResourcesPath.substring(videoResourcesPath.lastIndexOf("/") + 1));commandStart(command);}/*** 有声视频+音频合并为一个视频。* 若音频比视频长,画面停留在最后一帧,继续播放声音,* 若要以视频和音频两者时长短的为主,放开注解启用-shortest。** @param videoResourcesPath 视频文件的路径* @param audioResourcesPath 音频文件的路径*/public static void mergeVideoAudio(String videoResourcesPath, String audioResourcesPath) {String newPath = createDirectoryByTime();List<String> command = getList();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(newPath + videoResourcesPath.substring(videoResourcesPath.lastIndexOf("/") + 1));commandStart(command);}/*** 多视频拼接合并** @param videoResourcesPathList 视频文件路径的List*/public static void mergeVideos(List<String> videoResourcesPathList) {String newPath = createDirectoryByTime();//时间作为合并后的视频名String getNowTime = 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(TEMP_MEDIA_PATH + videoTempName);commandStart(command);videoList.add(TEMP_MEDIA_PATH + videoTempName);}List<String> command1 = getList();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(newPath + "视频合并" + getNowTime + ".mp4");commandStart(command1);}/*** 多视频拼接合并。(mergeVideos1比上面的mergeVideos兼容性更好)* @param videoResourcesPathList 视频文件路径的List*/public static void mergeVideos1(List<String> videoResourcesPathList) {String newPath = createDirectoryByTime();String videosPath= TEMP_MEDIA_PATH+"videos.txt";try(PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(videosPath, false)))) {for (String video:videoResourcesPathList) {writer.println("file '"+video+"'");}}catch (IOException e) {e.printStackTrace();}List<String> command = getList();command.add(FFMPEG);command.add("-f");command.add("concat");command.add("-safe");command.add("0");command.add("-i");command.add(videosPath);command.add("-c");command.add("copy");//时间作为合并后的视频名String getNowTime = nowTime();command.add(newPath + "视频合并" + getNowTime + ".mp4");commandStart(command);}/*** 多音频拼接合并为一个音频(在每个音频结尾追加另一个音频,即同一时间只播放一个音频)。* @param audioResourcesPathList 音频文件路径的List*/public static void mergeAudios(List<String> audioResourcesPathList) {String newPath = createDirectoryByTime();//时间作为合并后的音频名String getNowTime = nowTime();List<String> command = getList();command.add(FFMPEG);command.add("-i");StringBuilder buffer = new StringBuilder("\"concat:");for (int i = 0; i < audioResourcesPathList.size(); i++) {buffer.append(audioResourcesPathList.get(i));if (i != audioResourcesPathList.size() - 1) {buffer.append("|");} else {buffer.append("\"");}}command.add(String.valueOf(buffer));command.add("-acodec");command.add("copy");command.add(newPath + "音频合并" + getNowTime + ".mp3");commandStart(command);}/*** 视频格式转换** @param videoResourcesPath 视频文件的路径* @param format             要转换为的格式* @param b             是否压缩视频 true压缩  false 不压缩* @param preset   是否加速压缩视频(由快到慢): ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow*/public static void videoFormatConversion(String videoResourcesPath, String format , boolean b,String preset,boolean copyResourceFile) {String newPath = createDirectoryByTime();if (copyResourceFile){String suffix = videoResourcesPath.substring(videoResourcesPath.lastIndexOf(".")).toLowerCase();FileUtil.copy(videoResourcesPath,newPath+"resource-index"+suffix,true);}List<String> command = getList();command.add(FFMPEG);command.add("-i");command.add(videoResourcesPath);if (b){command.add("-s");command.add("1280*720");command.add("-pix_fmt");command.add("yuv420p");command.add("-b:a");command.add("63k");command.add("-b:v");command.add("753k");command.add("-r");command.add("18");}command.add("-hls_list_size");command.add("-0");command.add("-hls_time");command.add("120");if(preset != null){command.add("-preset "+ preset);}command.add(newPath + nowTime() + "." + format);commandStart(command);}/*** 获取音频或视频信息** @param videoAudioResourcesPath 音频或视频文件的路径*/public static List<String> videoAudioInfo(String videoAudioResourcesPath) {List<String> command = getList();command.add(FFPROBE);command.add("-i");command.add(videoAudioResourcesPath);//调用命令行获取视频信息String infoStr = getInfoStr(command);System.out.println(" ");String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (/d*) kb//s";String regexVideo = "Video: (.*?) tbr";String regexAudio = "Audio: (.*?), (.*?) Hz, (.*?) kb//s";List<String> list = new ArrayList<>();Pattern pattern = Pattern.compile(regexDuration);Matcher matcher = pattern.matcher(infoStr);if (matcher.find()) {list.add("视频/音频整体信息: ");list.add("视频/音频名称:" + videoAudioResourcesPath);list.add("开始时间:" + matcher.group(2));list.add("结束时间:" + matcher.group(1));list.add("比特率: " + matcher.group(3) + " kb/s");list.add("------------------------------------ ");}Pattern patternVideo = Pattern.compile(regexVideo);Matcher matcherVideo = patternVideo.matcher(infoStr);if (matcherVideo.find()) {String videoInfo = matcherVideo.group(1);String[] sp = videoInfo.split(",");list.add("视频流信息: ");list.add("视频编码格式: " + sp[0]);int ResolutionPosition = 2;if (sp[1].contains("(") && sp[2].contains(")")) {list.add("YUV: " + sp[1] + "," + sp[2]);ResolutionPosition = 3;} else if (sp[1].contains("(") && !sp[2].contains(")") && sp[3].contains(")")) {list.add("YUV: " + sp[1] + "," + sp[2] + "," + sp[3]);ResolutionPosition = 4;} else {list.add("YUV: " + sp[1]);}list.add("分辨率: " + sp[ResolutionPosition]);list.add("视频比特率: " + sp[ResolutionPosition + 1]);list.add("帧率: " + sp[ResolutionPosition + 2]);list.add("------------------------------------ ");}Pattern patternAudio = Pattern.compile(regexAudio);Matcher matcherAudio = patternAudio.matcher(infoStr);if (matcherAudio.find()) {list.add("音频流信息: ");list.add("音频编码格式: " + matcherAudio.group(1));list.add("采样率: " + matcherAudio.group(2) + " HZ");list.add("声道: " + matcherAudio.group(3).split(",")[0]);list.add("音频比特率: " + matcherAudio.group(3).split(",")[2] + " kb/s");}return list;}/*** 视频或音频剪切* 参考@link:https://zhuanlan.zhihu.com/p/27366331* @param videoAudioResourcesPath 视频或音频文件的路径* @param startTime               开始时间* @param endTime                 结束时间*/public static void cutVideoAudio(String videoAudioResourcesPath, String startTime, String endTime) {String newPath = createDirectoryByTime();String fileName = videoAudioResourcesPath.substring(videoAudioResourcesPath.lastIndexOf("/") + 1);//时间作为剪切后的视频名String getNowTime = nowTime();List<String> command = getList();command.add(FFMPEG);command.add("-ss");command.add(startTime);command.add("-t");command.add(calculationEndTime(startTime, endTime));command.add("-i");command.add(videoAudioResourcesPath);command.add("-c:v");command.add("libx264");command.add("-c:a");command.add("aac");command.add("-strict");command.add("experimental");command.add("-b:a");command.add("98k");command.add(newPath + "剪切视频" + getNowTime + fileName);commandStart(command);}/*** 视频裁剪大小尺寸(根据leftDistance和topDistance确定裁剪的起始点,再根据finallywidth和finallyHeight确定裁剪的宽和长)* 参考@link:https://www.cnblogs.com/yongfengnice/p/7095846.html*     @link:http://www.jq-school.com/show.aspx?id=737** @param videoAudioResourcesPath 视频文件的路径* @param finallyWidth            裁剪后最终视频的宽度* @param finallyHeight           裁剪后最终视频的高度* @param leftDistance            开始裁剪的视频左边到y轴的距离(视频左下角为原点)* @param topDistance             开始裁剪的视频上边到x轴的距离(视频左下角为原点)**/public static void cropVideoSize(String videoAudioResourcesPath, String finallyWidth, String finallyHeight, String leftDistance, String topDistance) {String newPath = createDirectoryByTime();String fileName = videoAudioResourcesPath.substring(videoAudioResourcesPath.lastIndexOf("/") + 1);//时间作为剪切后的视频名String getNowTime = nowTime();List<String> command = getList();command.add(FFMPEG);command.add("-i");command.add(videoAudioResourcesPath);command.add("-vf");//获取视频信息得到原始视频长、宽List<String> list = videoAudioInfo(videoAudioResourcesPath);String resolution = list.stream().filter(v -> v.contains("分辨率")).findFirst().get();String[] sp = resolution.split("x");String originalWidth = sp[0].substring(sp[0].indexOf(":") + 1).trim();String originalHeight = sp[1].substring(0, 4).trim();int cropStartWidth = Integer.parseInt(originalWidth) - Integer.parseInt(leftDistance);int cropStartHeight = Integer.parseInt(originalHeight) - Integer.parseInt(topDistance);command.add("crop=" + finallyWidth + ":" + finallyHeight + ":" + cropStartWidth + ":" + cropStartHeight);command.add(newPath + "裁剪视频" + getNowTime + fileName);commandStart(command);}/*** 计算两个时间的时间差** @param starTime 开始时间,如:00:01:09* @param endTime  结束时间,如:00:08:27* @return 返回xx:xx:xx形式,如:00:07:18*/public static String calculationEndTime(String starTime, String endTime) {LocalTime timeStart = LocalTime.parse(starTime);LocalTime timeEnd = LocalTime.parse(endTime);long hour = HOURS.between(timeStart, timeEnd);long minutes = MINUTES.between(timeStart, timeEnd);long seconds = SECONDS.between(timeStart, timeEnd);minutes = minutes > 59 ? minutes % 60 : minutes;String hourStr = hour < 10 ? "0" + hour : String.valueOf(hour);String minutesStr = minutes < 10 ? "0" + minutes : String.valueOf(minutes);long getSeconds = seconds - (hour * 60 + minutes) * 60;String secondsStr = getSeconds < 10 ? "0" + getSeconds : String.valueOf(getSeconds);return hourStr + ":" + minutesStr + ":" + secondsStr;}/*** 视频截图** @param videoResourcesPath 视频文件的路径* @param screenshotTime     截图的时间,如:00:01:06*/public static void videoScreenshot(String videoResourcesPath, String screenshotTime) {//时间作为截图后的视频名String getNowTime = nowTime();List<String> command = getList();command.add(FFMPEG);command.add("-ss");command.add(screenshotTime);command.add("-i");command.add(videoResourcesPath);command.add("-f");command.add("image2");//String fileName = videoResourcesPath.substring(videoResourcesPath.lastIndexOf("/") + 1, videoResourcesPath.lastIndexOf("."));command.add(PICTURE_MEDIA_PATH + getNowTime + ".jpg");commandStart(command);}/*** 整个视频截图** @param videoResourcesPath 视频文件的路径* @param fps  截图的速度。1则表示每秒截一张;0.1则表示每十秒一张;10则表示每秒截十张图片*/public static void videoAllScreenshot(String videoResourcesPath, String fps) {/* 时间作为截图后的视频名String getNowTime = nowTime();*/List<String> command = getList();command.add(FFMPEG);command.add("-i");command.add(videoResourcesPath);command.add("-vf");command.add("fps=" + fps);//String fileName = videoResourcesPath.substring(videoResourcesPath.lastIndexOf("/") + 1, videoResourcesPath.lastIndexOf("."));command.add(PICTURE_MEDIA_PATH + nowTime() + "%d" + ".jpg");commandStart(command);}/*** 多图片+音频合并为视频** @param pictureResourcesPath 图片文件路径(数字编号和后缀不要)。如:D:\ffmpegMedia\picture\101-你也不必耿耿于怀1.jpg 和D:\ffmpegMedia\picture\101-你也不必耿耿于怀2.jpg。只需传D:\ffmpegMedia\picture\101-你也不必耿耿于怀* @param audioResourcesPath   音频文件的路径*  @param fps   帧率,每张图片的播放时间(数值越小则每张图停留的越长)。0.5则两秒播放一张,1则一秒播放一张,10则一秒播放十张*/public static void pictureAudioMerge(String pictureResourcesPath, String audioResourcesPath,String fps) {String newPath = createDirectoryByTime();//时间作为截图后的视频名String getNowTime = nowTime();List<String> command = new ArrayList<>();command.add(FFMPEG);command.add("-threads");command.add("2");command.add("-y");command.add("-r");//帧率command.add(fps);command.add("-i");command.add(pictureResourcesPath+"%d.jpg");command.add("-i");command.add(audioResourcesPath);command.add("-absf");command.add("aac_adtstoasc");//-shortest会取视频或音频两者短的一个为准,多余部分则去除不合并command.add("-shortest");//String fileName = pictureResourcesPath.substring(pictureResourcesPath.lastIndexOf("/") + 1);command.add(newPath +"视频合成" + getNowTime + ".mp4");commandStart(command);}/*** 绘制音频波形图保存.jpg后缀可改为png** @param audioResourcesPath 音频文件的路径*/public static void audioWaveform(String audioResourcesPath) {String newPath = createDirectoryByTime();List<String> command = new ArrayList<>();command.add(FFMPEG);command.add("-i");command.add(audioResourcesPath);command.add("-filter_complex");command.add("\"showwavespic=s=1280*240\"");command.add("-frames:v");command.add("1");//String fileName = audioResourcesPath.substring(audioResourcesPath.lastIndexOf("/") + 1, audioResourcesPath.lastIndexOf("."));//jpg可换为pngcommand.add(newPath  + nowTime() + ".jpg");commandStart(command);}/*** 两个音频混缩合并为一个音频(即同一时间播放两首音频)。* 音量参考:@link:https://blog.csdn.net/sinat_14826983/article/details/82975561** @param audioResourcesPath1 音频1文件路径* @param audioResourcesPath1 音频2文件路径的*/public static void mergeAudios(String audioResourcesPath1, String audioResourcesPath2) {String newPath = createDirectoryByTime();//时间作为混缩后的音频名String getNowTime = nowTime();List<String> command = new ArrayList<>();command.add(FFMPEG);command.add("-i");command.add(audioResourcesPath1);command.add("-i");command.add(audioResourcesPath2);command.add("-filter_complex");command.add("amix=inputs=2:duration=longest");command.add(newPath + "音频混缩" + getNowTime + ".mp3");commandStart(command);}/*** 两个音频混缩合并为一个音频(即同一时间播放两首音频)。* 音量参考:@link:https://blog.csdn.net/sinat_14826983/article/details/82975561* @param audioResourcesPath1 音频1文件路径* @param  number1           音频1的音量,如取 0.4 表示音量是原来的40%  ,取1.5表示音量是原来的150%* @param audioResourcesPath1 音频2文件路径的* @param  number2          音频2的音量,如取 0.4 表示音量是原来的40%  ,取1.5表示音量是原来的150%*/public static void mergeAudios(String audioResourcesPath1,String number1, String audioResourcesPath2,String number2) {String newPath = createDirectoryByTime();//时间作为混缩后的音频名String getNowTime = nowTime();List<String> command = new ArrayList<>();command.add(FFMPEG);command.add("-i");command.add(audioResourcesPath1);command.add("-i");command.add(audioResourcesPath2);command.add("-filter_complex");command.add("[0:a]volume=1"+number1+"[a1];[1:a]volume="+number2+"[a2];[a1][a2]amix=inputs=2:duration=longest");command.add(newPath + "音频混缩" + getNowTime + ".mp3");commandStart(command);}/*** 两个音频混缩合并为一个音频的不同声道(即一只耳机播放一个音频)。* 声道参考:@link:https://www.itranslater.com/qa/details/2583879740000044032** @param audioResourcesPath1 音频1文件路径* @param audioResourcesPath1 音频2文件路径的*/public static void mergeAudiosSoundtrack(String audioResourcesPath1, String audioResourcesPath2) {String newPath = createDirectoryByTime();//时间作为混缩后的音频名String getNowTime = nowTime();List<String> command = new ArrayList<>();command.add(FFMPEG);command.add("-i");command.add(audioResourcesPath1);command.add("-i");command.add(audioResourcesPath2);command.add("-filter_complex");command.add("\"amerge=inputs=2,pan=stereo|c0<c0+c1|c1<c2+c3\"");command.add(newPath + "音频混缩" + getNowTime + ".mp3");commandStart(command);}/*** 获取当前时间,用于作为文件名*/public static String nowTime() {DateTimeFormatter f3 = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss");LocalDate nowDate = LocalDate.now();LocalTime nowTime = LocalTime.now();return nowDate.atTime(nowTime).format(f3);}
}

测试工具类:

import utils.FfmpegUtils;
import java.io.IOException;
import java.util.*;public class Test {public static void main(String[] args) throws IOException {//视频播放FfmpegUtils.playVideoAudio("D:/16-这几句真假声转换太好听了.mp4");//视频播放并指定循环次数FfmpegUtils.playVideoAudio("D:/16-这几句真假声转换太好听了.mp4",1);//视频播放并指定宽高和循环次数FfmpegUtils.playVideoAudio("D:/16-这几句真假声转换太好听了.mp4",400,700,1);//从视频中提取音频为mp3FfmpegUtils.getAudioFromVideo("D:/16-这几句真假声转换太好听了.mp4");//从视频中提取视频为无声视频FfmpegUtils.getVideoFromAudio("D:/16-这几句真假声转换太好听了.mp4");//无声视频+音频合并FfmpegUtils.mergeSilent_VideoAudio("D:/507-#网愈云故事收藏馆.mp4","D:/mp3/16-这几句真假声转换太好听了.mp3");//格式转换FfmpegUtils.videoFormatConversion("D:/507-#网愈云故事收藏馆.mp4","flv");//多视频拼接合并为一个mp4格式视频List<String> video = new ArrayList<>();video.add("D:/16-这几句真假声转换太好听了.mp4");video.add("D:/507-#网愈云故事收藏馆.mp4");video.add("D:/101-你也不必耿耿于怀.mp4");//FfmpegUtils.mergeVideos(video);FfmpegUtils.mergeVideos1(video);//获取音频或视频信息List<String> list = FfmpegUtils.videoAudioInfo("D:/ffmpegMedia/16-这几句真假声转换太好听了.mp3");list.forEach(v -> System.out.println(v));//剪切视频或音频,startTime开始时间,endTime结束时间FfmpegUtils.cutVideoAudio("D:/苏打绿带我走.mp4","00:00:00","00:01:05");//裁剪视频尺寸大小FfmpegUtils.cropVideoSize("D:/张国荣.mp4", "600", "600", "720", "940");//有声视频+音频合并FfmpegUtils.mergeVideoAudio("D:/507-#网愈云故事收藏馆.mp4","D:/ffmpegMedia/16-这几句真假声转换太好听了.mp3");//视频截图,screenshotTime是截图的时间FfmpegUtils.videoScreenshot("D:/101-你也不必耿耿于怀.mp4","00:00:05");//视频完全截图,fps是截图的速度即多少秒截一张图FfmpegUtils.videoAllScreenshot("D:/101-你也不必耿耿于怀.mp4","1");//多图片+音频合并为视频。0.5则两秒播放一张,1则一秒播放一张,10则一秒播放十张(数值越小则每张图停留的越长)FfmpegUtils.pictureAudioMerge("D:/ffmpegMedia/pictur/101-你也不必耿耿于怀","D:/ffmpegMedia/101-你也不必耿耿于怀.mp3","0.5");//多音频拼接合并为一个mp3格式视频List<String> audio = new ArrayList<>();audio.add("D:/ffmpegMedia/16-这几句真假声转换太好听了.mp3");audio.add("D:/ffmpegMedia/忽然之间.mp3");audio.add("D:/ffmpegMedia/天空之城-李志.mp3");FfmpegUtils.mergeAudios(audio);//绘制音频波形图保存FfmpegUtils.audioWaveform("D:/ffmpegMedia/16-这几句真假声转换太好听了.mp3");//两个音频混缩合并为一个音频FfmpegUtils.mergeAudios("D:/ffmpegMedia/16-这几句真假声转换太好听了.mp3","D:/ffmpegMedia/天空之城-李志.mp3");//两个音频混缩合并为一个音频并调整两个音频的音量大小FfmpegUtils.mergeAudios("D:/ffmpegMedia/忽然之间.mp3","1","D:/ffmpegMedia/天空之城-李志.mp3","0.5");//两个音频混缩合并为一个音频的不同声道(即一只耳机播放一个音频)。FfmpegUtils.mergeAudiosSoundtrack("D:/ffmpegMedia/16-这几句真假声转换太好听了.mp3","D:/ffmpegMedia/天空之城-李志.mp3");}
}

上面测试中的一些用法已经基本满足基本使用。可以灵活组合运用。
举个例子:
现在网上的很多视频是分段成多段的ts视频,
我们可以写代码把所有的ts视频都下载下来,
然后转换成mp4格式,
最后合并为一个mp4视频格式。

ffmpeg的下载及安装JAVA工具类相关推荐

  1. Java工具类实现word转pdf结果几乎一模一样

    Background [封装好的工具类][转换效果99%][无水印] 实现技术[Aspose] 这里给出需要的依赖包 aspose-words-15.8.0.jar和word-license.xml, ...

  2. Java 图片添加文字或者logo水印(附代码) | Java工具类

    目录 前言 环境依赖 代码 总结 前言 本文提供java工具类,给图片添加文字或者logo图片的水印效果. 环境依赖 工具库maven依赖添加 <dependency><groupI ...

  3. Java修改图片分辨率(附代码) | Java工具类

    目录 前言 环境依赖 代码 总结 前言 本文提供可以修改图片分辨率的java工具类,实用主义的狂欢. 环境依赖 添加必要的一些maven依赖. <dependency><groupI ...

  4. java xml最火的的工具_几种高效的Java工具类推荐

    本文将介绍了十二种常用的.高效的Java工具类 在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类. 在开发中,使用这些工具类,不仅可以提高编码效率,还 ...

  5. Java 实现图片裁剪(附代码) | Java工具类

    目录 前言 Maven依赖 代码 总结 前言 本文提供将图片按照自定义尺寸进行裁剪的Java工具类,一如既往的实用主义. Maven依赖 <dependency><groupId&g ...

  6. Java 实现视频时间维度剪切 | Java工具类

    目录 前言 Maven依赖 代码 总结 前言 本文提供将视频按照时间维度进行剪切的Java工具类,一如既往的实用主义. Maven依赖 <dependency><groupId> ...

  7. Java 音频提升音量工具(附代码) | Java工具类

    目录 前言 Maven依赖 代码 总结 前言 本文提供将音频提升音量的java工具类代码,一如既往的实用主义分享. Maven依赖 <dependency><groupId>c ...

  8. 学习日志day41(2021-09-03)(1、文件的上传 2、文件的查看 3、文件的下载 4、使用工具类上传文件 5、基于servlet3.0以上的文件上传 )

    学习内容:学习JavaWeb(Day41) 1.文件的上传 2.文件的查看 3.文件的下载 4.使用工具类上传文件 5.基于servlet3.0以上的文件上传 1.文件的上传 (1)实现文件的上传需要 ...

  9. (6)常用的Java工具类

    目录 前言: 第一部分:常用的16个工具类 一.org.apache.commons.io.IOUtils 二.org.apache.commons.io.FileUtils 三.org.apache ...

最新文章

  1. Docker 新网络 overlay 网络
  2. You have new mail
  3. mybatis做批量删除时写SQL语句时遇到的问题
  4. IntersectionObserve初试
  5. pb自定义控件 事件_Android WebView与下拉刷新控件滑动冲突的解决方法
  6. 仿58 php框架源码,转转最新源码
  7. 发光的二次元克拉克拉 满足年轻用户个性化、碎片化的文娱需求
  8. Python set集合 - Python零基础入门教程
  9. 火狐浏览器如何更改字体 火狐浏览器字体更改方法分享
  10. sqlserve 热备用状态更新_什么是核心交换机的链路聚合、冗余、堆叠、热备份
  11. 2022 年值得尝试的 7 个 MQTT 客户端工具
  12. Mysql的explain,你真的会用吗?
  13. 海康web插件视频播放异常
  14. 判断系统(服务器)中是否存在后门程序的2个工具
  15. CLH Lock 原理
  16. CenterNet2的深入浅出(CVPR2021)
  17. PIL+pyqt 写了一个图片批量无损压缩工具python
  18. 三个团队的站立会议旁观笔记
  19. dedecms织梦模板|响应式粉红色母婴月嫂源码 母婴育儿类网站模板(自适应手机版)
  20. 思科无线认证服务器,思科服务器认证配置

热门文章

  1. 一篇文章读懂少儿机器人编程课程学什么?
  2. qsort函数的使用
  3. 小型企业5种实惠的品牌建立策略
  4. ACWing 908.最大不相交区间数量
  5. 生日悖论MATLAB仿真
  6. python3代码编程规范(命名、空格、注释、代码布局、编程建议等)
  7. 常用的conda命令
  8. 用趋势突破策略回测CTA
  9. C语言链表怎么合并同类项,求一个关于合并同类项的编程
  10. 服务器配置jdk环境