概述
实现原理是,使用FFmpeg命令对音视频文件,按照需求进行重新编解码并存储。
注意:代码重点是方法formatConverter(File fileInput, File fileOutPut, boolean isVideo),方法任务是FFmpeg命令拼接,每一行都有注释帮助使用者理解并使用,按需求进行更改,然后命令执行方法不用过多关注!
第一步
复制下方工具类代码放入项目
public class FormatConverterUtils {
/**
* FFmpeg程序执行路径
* 当前系统安装好ffmpeg程序并配置好相应的环境变量后,值为ffmpeg.exe可执行程序文件在实际系统中的绝对路径
*/
private static String FFMPEG_PATH;
static {
Properties props = new Properties();
try (
InputStream in = FormatConverterUtils.class.getClassLoader().getResourceAsStream("FFmpeg.properties");
) {
props.load(in);
String osName = System.getProperties().getProperty("os.name");
if (osName.startsWith("Windows")) {
FFMPEG_PATH = props.getProperty("FFmpeg.exe.path");
} else {
FFMPEG_PATH = props.getProperty("FFmpeg.path");
}
} catch (Exception e) {
log.error("静态配置文件内容读取失败!");
}
}
/**
* 音频转换器
* @param resourcePath 需要被转换的音频文件全路径带文件名
* @param targetPath 转换之后的音频文件全路径带文件名
*/
public static void audioConverter(String resourcePath, String targetPath) {
formatConverter(new File(resourcePath), new File(targetPath), false);
}
/**
* 视频转换器
* @param resourcePath 需要被转换的视频文件全路径带文件名
* @param targetPath 转换之后的视频文件全路径带文件名
*/
public static void videoConverter(String resourcePath, String targetPath) {
formatConverter(new File(resourcePath), new File(targetPath), true);
}
/**
* 文件格式转换器
* 注意!此方法为按照需求进行拼接命令来完成音频视频文件的处理 命令拼接需要根据自己需求进行更改
* 视频 或 音频
* @param fileInput 源文件路径
* @param fileOutPut 转换后的文件路径
* @param isVideo 源文件是视频文件
*
*/
public static void formatConverter(File fileInput, File fileOutPut, boolean isVideo) {
if (null == fileInput || !fileInput.exists()) {
throw new RuntimeException("源文件不存在,请检查源路径");
}
if (null == fileOutPut) {
throw new RuntimeException("转换后的路径为空,请检查转换后的存放路径是否正确");
}
if (!fileOutPut.exists()) {
try {
fileOutPut.createNewFile();
} catch (IOException e) {
log.error("转换时新建输出文件失败");
}
}
List<String> commond = new ArrayList<String>();
//输出直接覆盖文件
commond.add("-y");
commond.add("-i");
commond.add(fileInput.getAbsolutePath());
if (isVideo) {
//为视频流设置编码器
commond.add("-c:v");
//编码格式处理为H.264
commond.add("libx264");
//设置比特率
commond.add("-b:v");
//bit/s
commond.add("1M");
//设置分辨率
commond.add("-s");
commond.add("1280x720");
//设置帧率
commond.add("-r");
//ftps
commond.add("25");
}
//设置音频编码器
commond.add("-c:a");
commond.add("aac");
//音频采样率
commond.add("-ar");
//Hz
commond.add("44.1K");
//音频比特率
commond.add("-b:a");
//bps
commond.add("96K");
//音频声道
commond.add("-ac");
//stereo 立体声
commond.add("2");
commond.add(fileOutPut.getAbsolutePath());
//执行命令
executeCommand(commond);
}
/**
* 执行FFmpeg命令
* @param commonds 要执行的FFmpeg命令
* @return FFmpeg程序在执行命令过程中产生的各信息,执行出错时返回null
*/
public static String executeCommand(List<String> commonds) {
if (CollectionUtils.isEmpty(commonds)) {
log.error("--- 指令执行失败,因为要执行的FFmpeg指令为空! ---");
return null;
}
LinkedList<String> ffmpegCmds = new LinkedList<>(commonds);
ffmpegCmds.addFirst(FFMPEG_PATH); // 设置ffmpeg程序所在路径
log.info("--- 待执行的FFmpeg指令为:---" + ffmpegCmds);
Runtime runtime = Runtime.getRuntime();
Process ffmpeg = null;
try {
// 执行ffmpeg指令
ProcessBuilder builder = new ProcessBuilder();
builder.command(ffmpegCmds);
ffmpeg = builder.start();
log.info("--- 开始执行FFmpeg指令:--- 执行线程名:" + builder.toString());
// 取出输出流和错误流的信息
// 注意:必须要取出ffmpeg在执行命令过程中产生的输出信息,如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时,线程就回阻塞住
PrintStream errorStream = new PrintStream(ffmpeg.getErrorStream());
PrintStream inputStream = new PrintStream(ffmpeg.getInputStream());
errorStream.start();
inputStream.start();
// 等待ffmpeg命令执行完
ffmpeg.waitFor();
// 获取执行结果字符串
String result = errorStream.stringBuffer.append(inputStream.stringBuffer).toString();
// 输出执行的命令信息
String cmdStr = Arrays.toString(ffmpegCmds.toArray()).replace(",", "");
String resultStr = StringUtils.isBlank(result) ? "【异常】" : "正常";
log.info("--- 已执行的FFmepg命令: ---" + cmdStr + " 已执行完毕,执行结果: " + resultStr);
return result;
} catch (Exception e) {
log.error("--- FFmpeg命令执行出错! --- 出错信息: " + e.getMessage());
return null;
} finally {
if (null != ffmpeg) {
ProcessKiller ffmpegKiller = new ProcessKiller(ffmpeg);
// JVM退出时,先通过钩子关闭FFmepg进程
runtime.addShutdownHook(ffmpegKiller);
}
}
}
/**
* 用于取出ffmpeg线程执行过程中产生的各种输出和错误流的信息
*/
static class PrintStream extends Thread {
InputStream inputStream = null;
BufferedReader bufferedReader = null;
StringBuffer stringBuffer = new StringBuffer();
public PrintStream(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public void run() {
try {
if (null == inputStream) {
log.error("--- 读取输出流出错!因为当前输出流为空!---");
}
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
log.info(line);
stringBuffer.append(line);
}
} catch (Exception e) {
log.error("--- 读取输入流出错了!--- 错误信息:" + e.getMessage());
} finally {
try {
if (null != bufferedReader) {
bufferedReader.close();
}
if (null != inputStream) {
inputStream.close();
}
} catch (IOException e) {
log.error("--- 调用PrintStream读取输出流后,关闭流时出错!---");
}
}
}
}
/**
* 在程序退出前结束已有的FFmpeg进程
*/
private static class ProcessKiller extends Thread {
private Process process;
public ProcessKiller(Process process) {
this.process = process;
}
@Override
public void run() {
this.process.destroy();
log.info("--- 已销毁FFmpeg进程 --- 进程名: " + process.toString());
}
}
}
第二步
将下方配置文件下载放入项目resource文件下,具体配置内容修改,配置文件中有具体注释
配置文件链接:https://pan.baidu.com/s/15Lk4uU17oqBmz9MuQPbdnQ?pwd=jjjj
提取码:jjjj
第三步
下载下方文件(内含Linux和Windows的FFmpeg软件安装包(绿色免安装版,解压就能用)),按文件记录步骤进行解压,修改配置文件,就完事儿!
按照配置说明文件链接:https://pan.baidu.com/s/1yPZBSusCAIv2RFk7BCQgcQ?pwd=jjjj
提取码:jjjj
小助手:配置说明文件包含两个压缩包,鼠标右击包含的那个文件,选择“保存到文件”选项,如果还不行就下载WPS有此功能
愿君享用愉快!
最后
以上就是畅快小蜜蜂为你收集整理的Java FFmpeg的音视频处理的全部内容,希望文章能够帮你解决Java FFmpeg的音视频处理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复