签入版本
This commit is contained in:
+518
@@ -0,0 +1,518 @@
|
||||
// +======================================================================
|
||||
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方平台: https://www.xiaomayicloud.com
|
||||
// +======================================================================
|
||||
// | 【知识产权声明】
|
||||
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
|
||||
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
|
||||
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
|
||||
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
|
||||
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
|
||||
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
|
||||
// | 申请任何知识产权
|
||||
// | 5. 权利保留:未在本协议中明示授予的一切权利
|
||||
// | 均由小蚂蚁云团队保留
|
||||
// +======================================================================
|
||||
// | 【授权状态说明】
|
||||
// | 1. 未授权状态:用户未购买有效的商业许可证
|
||||
// | 2. 商业授权:已购买正式商业许可证的用户
|
||||
// +======================================================================
|
||||
// | 【绝对禁止条款】
|
||||
// | 无论授权状态如何,任何用户均严格禁止以下行为:
|
||||
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
|
||||
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
|
||||
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
|
||||
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
|
||||
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
|
||||
// +======================================================================
|
||||
// | 【商业授权许可范围】
|
||||
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
|
||||
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
|
||||
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
|
||||
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
|
||||
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
|
||||
// +======================================================================
|
||||
// | 【许可证获取】
|
||||
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
|
||||
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
|
||||
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
|
||||
// +======================================================================
|
||||
// | 【合法使用要求】
|
||||
// | 1. 仅限用于合法合规的软件研发
|
||||
// | 2. 严禁用于任何违法、侵权或恶意行为
|
||||
// | 3. 严禁违反我国法律法规和政策
|
||||
// +======================================================================
|
||||
// | 【免责声明】
|
||||
// | 因使用本框架导致的以下情况,我们概不负责:
|
||||
// | 1. 项目研发中的意外、疏忽、违约等风险
|
||||
// | 2. 侵犯第三方知识产权或其他合法权益
|
||||
// | 3. 任何直接、间接、附带或衍生一切损失
|
||||
// | 4. 用户违规违法行为的一切法律后果
|
||||
// +======================================================================
|
||||
// | 【协议重要提示】
|
||||
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
|
||||
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
|
||||
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
|
||||
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
|
||||
// +======================================================================
|
||||
// | 【侵权举报与合规】
|
||||
// | 1. 知识产权侵权举报:请联系官方客服
|
||||
// | 2. 许可证合规咨询:xiaomayicloud@163.com
|
||||
// | 3. 违规使用将终止授权并追究责任
|
||||
// | 4. 无条件配合司法机关调查取证
|
||||
// | 5. 保留一切法律追诉权利
|
||||
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
|
||||
// +======================================================================
|
||||
|
||||
package com.xiaomayi.ffmpeg.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Ffmpeg多媒体工具类
|
||||
* </p>
|
||||
*
|
||||
* @author 小蚂蚁云团队
|
||||
* @since 2024-01-16
|
||||
*/
|
||||
@Slf4j
|
||||
public class FfmpegUtils {
|
||||
|
||||
/**
|
||||
* ffmpeg安装目录
|
||||
* 特别提醒:使用此工具类本地必须安装Ffmpeg软件,切记
|
||||
*/
|
||||
public static String FFMPEG_PATH = "D:\\ffmpeg.exe";
|
||||
|
||||
/**
|
||||
* 设置图片大小
|
||||
*/
|
||||
private final static String IMG_SIZE = "1920x1080";
|
||||
|
||||
/**
|
||||
* 视频截图
|
||||
*
|
||||
* @param videoPath 视频地址
|
||||
* @param imagePath 图片地址
|
||||
* @param timePoint 截图时间点
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static boolean ffmpegToImage(String videoPath, String imagePath, int timePoint) {
|
||||
List<String> commands = new ArrayList<String>();
|
||||
FFMPEG_PATH = FFMPEG_PATH.replace("%20", " ");
|
||||
commands.add(FFMPEG_PATH);
|
||||
commands.add("-ss");
|
||||
commands.add(timePoint + "");//这个参数是设置截取视频多少秒时的画面
|
||||
commands.add("-i");
|
||||
commands.add(videoPath);
|
||||
commands.add("-y");
|
||||
commands.add("-f");
|
||||
commands.add("image2");
|
||||
commands.add("-t");
|
||||
commands.add("0.001");
|
||||
commands.add("-s");
|
||||
commands.add(IMG_SIZE); //这个参数是设置截取图片的大小
|
||||
commands.add(imagePath);
|
||||
try {
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.command(commands);
|
||||
builder.start();
|
||||
System.out.println("截取成功:" + imagePath);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("处理异常:{}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件能否被ffmpeg解析
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static int checkFileType(String fileName) {
|
||||
String type = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();
|
||||
if (type.equals("avi")) {
|
||||
return 0;
|
||||
} else if (type.equals("mov")) {
|
||||
return 0;
|
||||
} else if (type.equals("mp4")) {
|
||||
return 0;
|
||||
} else if (type.equals("flv")) {
|
||||
return 0;
|
||||
} else if (type.equals("png")) {
|
||||
return 1;
|
||||
} else if (type.equals("jpg")) {
|
||||
return 1;
|
||||
} else if (type.equals("jpeg")) {
|
||||
return 1;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频时长
|
||||
*
|
||||
* @param videoPath 视频地址
|
||||
* @return 返回结果
|
||||
*/
|
||||
static int getVideoTime(String videoPath) {
|
||||
List<String> commands = new ArrayList<String>();
|
||||
commands.add(FFMPEG_PATH);
|
||||
commands.add("-i");
|
||||
commands.add(videoPath);
|
||||
try {
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.command(commands);
|
||||
final Process p = builder.start();
|
||||
|
||||
//从输入流中读取视频信息
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
StringBuffer sb = new StringBuffer();
|
||||
String line = "";
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
br.close();
|
||||
|
||||
//从视频信息中解析时长
|
||||
String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
|
||||
Pattern pattern = Pattern.compile(regexDuration);
|
||||
Matcher m = pattern.matcher(sb.toString());
|
||||
if (m.find()) {
|
||||
int time = getTimelen(m.group(1));
|
||||
System.out.println(videoPath + ",视频时长:" + time + ", 开始时间:" + m.group(2) + ",比特率:" + m.group(3) + "kb/s");
|
||||
return time;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理异常:{}", e.getMessage());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间
|
||||
* 格式:"00:00:10.68"
|
||||
*
|
||||
* @param timeLen 时间长度
|
||||
* @return 返回结果
|
||||
*/
|
||||
private static int getTimelen(String timeLen) {
|
||||
int min = 0;
|
||||
String strs[] = timeLen.split(":");
|
||||
if (strs[0].compareTo("0") > 0) {
|
||||
min += Integer.parseInt(strs[0]) * 60 * 60;//秒
|
||||
}
|
||||
if (strs[1].compareTo("0") > 0) {
|
||||
min += Integer.parseInt(strs[1]) * 60;
|
||||
}
|
||||
if (strs[2].compareTo("0") > 0) {
|
||||
min += Math.round(Float.parseFloat(strs[2]));
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒转化成 hh:mm:ss
|
||||
*
|
||||
* @param duration 时间
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static String convertInt2Date(long duration) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
|
||||
return formatter.format(cal.getTimeInMillis() + duration * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频抽取音频文件
|
||||
*
|
||||
* @param videoPath 视频地址
|
||||
* @param type 类型
|
||||
* @param audioPath 音频输出地址
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static boolean ffmpegToAudio(String videoPath, String type, String audioPath) {
|
||||
List<String> commands = new ArrayList<>();
|
||||
FFMPEG_PATH = FFMPEG_PATH.replace("%20", " ");
|
||||
commands.add(FFMPEG_PATH);
|
||||
commands.add("-i");
|
||||
commands.add(videoPath);
|
||||
commands.add("-f");
|
||||
commands.add(type);
|
||||
commands.add("-vn");
|
||||
commands.add("-y");
|
||||
commands.add("-acodec");
|
||||
if ("wav".equals(type)) {
|
||||
commands.add("pcm_s16le");
|
||||
} else if ("mp3".equals(type)) {
|
||||
commands.add("mp3");
|
||||
}
|
||||
commands.add("-ar");
|
||||
commands.add("16000");
|
||||
commands.add("-ac");
|
||||
commands.add("1");
|
||||
commands.add(audioPath);
|
||||
try {
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.command(commands);
|
||||
Process p = builder.start();
|
||||
System.out.println("抽离成功:" + audioPath);
|
||||
|
||||
// 1. start
|
||||
BufferedReader buf = null; // 保存ffmpeg的输出结果流
|
||||
String line = null;
|
||||
|
||||
buf = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while ((line = buf.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
sb.append(line);
|
||||
continue;
|
||||
}
|
||||
p.waitFor();// 这里线程阻塞,将等待外部转换进程运行成功运行结束后,才往下执行
|
||||
// 1. end
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("处理异常:{}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wav 转 mp3
|
||||
* 备注:wav转mp3命令:ffmpeg -i test.wav -f mp3 -acodec libmp3lame -y wav2mp3.mp3
|
||||
*
|
||||
* @param wavPath WAV文件地址
|
||||
* @param mp3Path MP#文件输出地址
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static boolean ffmpegOfwavTomp3(String wavPath, String mp3Path) {
|
||||
List<String> commands = new ArrayList<String>();
|
||||
FFMPEG_PATH = FFMPEG_PATH.replace("%20", " ");
|
||||
commands.add(FFMPEG_PATH);
|
||||
commands.add("-i");
|
||||
commands.add(wavPath);
|
||||
commands.add("-f");
|
||||
commands.add("mp3");
|
||||
commands.add("-acodec");
|
||||
commands.add("libmp3lame");
|
||||
commands.add("-y");
|
||||
commands.add(mp3Path);
|
||||
try {
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.command(commands);
|
||||
Process p = builder.start();
|
||||
System.out.println("转换成功:" + mp3Path);
|
||||
|
||||
// 1. start
|
||||
BufferedReader buf = null; // 保存ffmpeg的输出结果流
|
||||
String line = null;
|
||||
|
||||
buf = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while ((line = buf.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
sb.append(line);
|
||||
continue;
|
||||
}
|
||||
p.waitFor();// 这里线程阻塞,将等待外部转换进程运行成功运行结束后,才往下执行
|
||||
// 1. end
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("处理异常:{}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝视频
|
||||
* 备注:
|
||||
* 拷贝视频,并指定新的视频的名字以及格式
|
||||
* ffmpeg.exe -i old.mp4 new.avi
|
||||
*
|
||||
* @param videoInputPath 视频的输入路径
|
||||
* @param videoOutPath 视频的输出路径
|
||||
* @throws Exception 异常处理
|
||||
*/
|
||||
public static void convetor(String videoInputPath, String videoOutPath) throws Exception {
|
||||
|
||||
List<String> command = new ArrayList<String>();
|
||||
command.add(FFMPEG_PATH);
|
||||
command.add("-i");
|
||||
command.add(videoInputPath);
|
||||
command.add(videoOutPath);
|
||||
ProcessBuilder builder = new ProcessBuilder(command);
|
||||
Process process = null;
|
||||
try {
|
||||
process = builder.start();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理
|
||||
InputStream errorStream = process.getErrorStream();
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
|
||||
BufferedReader br = new BufferedReader(inputStreamReader);
|
||||
|
||||
String line = "";
|
||||
while ((line = br.readLine()) != null) {
|
||||
}
|
||||
if (br != null) {
|
||||
br.close();
|
||||
}
|
||||
inputStreamReader.close();
|
||||
errorStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频和音频结合
|
||||
* 备注:
|
||||
* 将视频和音频结合,并指定视频的长度,同时生成结合之后的视频文件
|
||||
* ffmpeg.exe -i tsd.mp4 -i "周笔畅+-+最美的期待.mp3" -t 7 -y new.avi
|
||||
*
|
||||
* @param videoInputPath 原视频的路径
|
||||
* @param audioInputPath 音频的路径
|
||||
* @param videoOutPath 视频与音频结合之后的视频的路径
|
||||
* @param time 视频的长度 ,单位为 s
|
||||
* @throws Exception 异常处理
|
||||
*/
|
||||
public static void convetor(String videoInputPath, String audioInputPath, String videoOutPath, double time) throws Exception {
|
||||
List<String> command = new ArrayList<String>();
|
||||
command.add(FFMPEG_PATH);
|
||||
command.add("-i");
|
||||
command.add(videoInputPath);
|
||||
command.add("-i");
|
||||
command.add(audioInputPath);
|
||||
command.add("-t");
|
||||
command.add(String.valueOf(time));
|
||||
command.add("-y");
|
||||
command.add(videoOutPath);
|
||||
ProcessBuilder builder = new ProcessBuilder(command);
|
||||
Process process = null;
|
||||
try {
|
||||
process = builder.start();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理
|
||||
InputStream errorStream = process.getErrorStream();
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
|
||||
BufferedReader br = new BufferedReader(inputStreamReader);
|
||||
|
||||
String line = "";
|
||||
while ((line = br.readLine()) != null) {
|
||||
}
|
||||
if (br != null) {
|
||||
br.close();
|
||||
}
|
||||
inputStreamReader.close();
|
||||
errorStream.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 视频截图
|
||||
* 案例:ffmpeg.exe -ss 00:00:01 -y -i 视频.mp4 -vframes 1 new.jpg
|
||||
*
|
||||
* @param timeCoverImg 视频的第几秒作为封面图
|
||||
* @param videoInputPath 视频的路径
|
||||
* @param frame 帧数
|
||||
* @param coverOutputPath 视频的封面图的路径
|
||||
* @throws Exception 异常处理
|
||||
*/
|
||||
public static void convetor(String timeCoverImg, String videoInputPath, int frame, String coverOutputPath) throws Exception {
|
||||
List<String> command = new ArrayList<String>();
|
||||
command.add(FFMPEG_PATH);
|
||||
command.add("-ss");
|
||||
command.add(timeCoverImg);
|
||||
command.add("-y");
|
||||
command.add("-i");
|
||||
command.add(videoInputPath);
|
||||
command.add("-vframes");
|
||||
command.add(String.valueOf(frame));
|
||||
command.add(coverOutputPath);
|
||||
ProcessBuilder builder = new ProcessBuilder(command);
|
||||
Process process = null;
|
||||
try {
|
||||
process = builder.start();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理
|
||||
InputStream errorStream = process.getErrorStream();
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
|
||||
BufferedReader br = new BufferedReader(inputStreamReader);
|
||||
|
||||
String line = "";
|
||||
while ((line = br.readLine()) != null) {
|
||||
}
|
||||
if (br != null) {
|
||||
br.close();
|
||||
}
|
||||
if (inputStreamReader != null) {
|
||||
inputStreamReader.close();
|
||||
}
|
||||
if (errorStream != null) {
|
||||
errorStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 视频文件
|
||||
String videoRealPath = "D:\\huawei.mp4";
|
||||
// 截图的路径(输出路径)
|
||||
String imageRealPath1 = "D:\\31.jpg";
|
||||
String imageRealPath2 = "D:\\32.jpg";
|
||||
// 检查文件能否被解析
|
||||
if (checkFileType(videoRealPath) == 0) {
|
||||
ffmpegToImage(videoRealPath, imageRealPath1, 10);
|
||||
ffmpegToImage(videoRealPath, imageRealPath2, 11);
|
||||
}
|
||||
String audioRealPath = "D:\\huawei.wav";
|
||||
String audioType = "wav";
|
||||
ffmpegToAudio(videoRealPath, audioType, audioRealPath);
|
||||
|
||||
String wavPath = "D:\\huawei.wav";
|
||||
String mp3Path = "D:\\huawei.mp3";
|
||||
ffmpegOfwavTomp3(wavPath, mp3Path);
|
||||
|
||||
// 获取视频时长
|
||||
getVideoTime(videoRealPath);
|
||||
|
||||
String coverOutputPath = "D:\\33.jpg";
|
||||
try {
|
||||
convetor("00:00:01", videoRealPath, 1, coverOutputPath);
|
||||
convetor(videoRealPath, "D:\\huawei.flv");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user