注意需要自己在windows上安装好FFmpeg组件
教程地址:https://www.jianshu.com/p/2b609afb9800
这套代码不管在linux还是windows系统上都能使用
linux上剪辑视屏也是需要进行组件的安装:https://blog.csdn.net/L1569850979/article/details/123269527?spm=1001.2014.3001.5501
上代码
导包
<!--视屏剪辑-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>4.4-1.5.6</version>
</dependency>
返回实体
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.io.Serializable;
/**
* @author lilinchun
* @date 2022/3/2 0002 11:45
*/
@Data
@ApiModel
public class FileVideoVO implements Serializable {
/**
* 原视频url
*/
private String url;
/**
* 截取视屏url
*/
private String cutUrl;
/**
* 文件名称
*/
private String objectname;
}
主要代码
/**
*
* @param file 视屏原文件
* @param start 剪辑开始位置
* @param end 剪辑结束位置
* @return
* @throws Exception
*/
@Override
public FileVideoVO videoUpload(MultipartFile file, String start, String end) throws Exception {
FileVideoVO fileVideoVO = new FileVideoVO();
ObsClient obsClient = new ObsClient(ak, sk, endPoint);
//判断文件格式
String fileName = file.getOriginalFilename();
String fileType = fileName.substring(fileName.lastIndexOf("."));
// 判断文件格式
switch (fileType) {
case OssFormat.MP3:
break;
case OssFormat.MP4:
break;
default:
throw new BusinessException(ErrorCode.FORMAT_ERROR.getCode(), ErrorCode.FORMAT_ERROR.getMsg());
}
InputStream inputStreamOld=file.getInputStream();
//源文件上传
PutObjectResult putObjectResultold = obsClient.putObject("bks", "clipFile/" + fileName, inputStreamOld);
fileVideoVO.setUrl(putObjectResultold.getObjectUrl());
//剪辑文件上传
File file1 = TransferToFile.multipartFileToFile(file);
log.info("文件字符串位置------------------:" + file1.getAbsolutePath());
String str;
if (file1.getAbsolutePath().lastIndexOf("\\") > 0) {
str = file1.getAbsolutePath().substring(0, file1.getAbsolutePath().lastIndexOf("\\") + 1);
} else {
str = file1.getAbsolutePath().substring(0, file1.getAbsolutePath().lastIndexOf("/") + 1);
}
log.info("后传递路径-----------:" + str);
str = new String(str.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
String filPath = FfmpegUtil.cutOutVideo(file1, str, start, end);
InputStream inputStream=getInputStream(filPath);
//将剪辑文件上传到华为云服务器上
PutObjectResult putObjectResult = obsClient.putObject("bks", "clipFile/" + IdUtil.simpleUUID() + fileType, inputStream);
inputStreamOld.close();
inputStream.close();
TransferToFile.deleteTempFile(file1);
fileVideoVO.setCutUrl(putObjectResult.getObjectUrl());
obsClient.close();
//删除临时文件
FfmpegUtil.deleteFilePlace(FfmpegUtil.sortOut(filPath));
return fileVideoVO;
}
//读取临时文件
public InputStream getInputStream(String resultPath) throws Exception {
Thread.sleep(3000);
FileInputStream fis = new FileInputStream(resultPath);
int available = fis.available();
log.info("外流的大小----------:" + available);
if(available==0) {
int i = 10;
while (i > 1) {
log.info("流的大小----------:" + available);
if (available == 0) {
fis.close();
i--;
//睡三秒
Thread.sleep(3000);
} else {
i = 0;
}
fis.close();
fis = new FileInputStream(resultPath);
available = fis.available();
}
}
if (available == 0) {
log.info("文件截取失败---------");
throw new BusinessException(ErrorCode.CUT_ERROR.getCode(), ErrorCode.CUT_ERROR.getMsg());
}
return fis;
}
几个工具类
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
/**
* @author lilinchun
* @date 2022/3/1 0001 16:26
*/
public class TransferToFile {
//获取流文件
private static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* MultipartFile 转 File
*
* @param file
* @throws Exception
*/
public static File multipartFileToFile(MultipartFile file) throws Exception {
File toFile = null;
if (file.equals("") || file.getSize() <= 0) {
file = null;
} else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
inputStreamToFile(ins, toFile);
ins.close();
}
return toFile;
}
/**
* 删除本地临时文件
* @param file
*/
public static void deleteTempFile(File file) {
if (file != null) {
File del = new File(file.toURI());
del.delete();
}
}
}
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.base.Joiner;
import com.llcbk.error.BusinessException;
import com.llcbk.error.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.Loader;
import java.io.*;
import java.util.Arrays;
/**
* @author lilinchun
* @date 2022/3/1 0001 16:11
*/
@Slf4j
public class FfmpegUtil {
/**
* 视频裁剪
*
* @param file 视频 文件
* @param outputDir 临时目录
* @throws Exception 异常
*
* star 开始位置
* end 其实位置
* -i 读取源文件
* -ss 文件开始位置
* -to 文件结束文职
* -b 设置比特率
* -y 表示输出文件,如果已存在则覆盖
* -vcodec copy 使用跟原视频相同的视频编解码器
* -acodec copy 使用跟原视频相同的音频编解码器
*/
public static String cutOutVideo(File file, String outputDir,String start,String end) throws Exception {
String videoPath ;
try {
videoPath = file.getAbsolutePath();
} catch (Exception e) {
log.info("错误----------:" + e.getMessage());
throw new BusinessException(ErrorCode.CUT_ERROR.getCode(),ErrorCode.CUT_ERROR.getMsg());
}
String resultPath =
Joiner.on(File.separator).join(Arrays.asList(outputDir, IdUtil.simpleUUID() + "." + "mp4"));
ProcessBuilder builder =
new ProcessBuilder(
"ffmpeg",
"-i",
videoPath,
"-ss",
start,
"-to",
end,
"-c",
"copy",
"-y",
resultPath);
builder.inheritIO().start();
return resultPath;
}
/**
* 视频裁剪
*
* @param file 视频 文件
* @param outputDir 临时目录
* @throws Exception 异常
*
* -i 读取源文件
* -ss 文件开始位置
* -to 文件结束文职
* -b 设置比特率
* -y 表示输出文件,如果已存在则覆盖
* -vcodec copy 使用跟原视频相同的视频编解码器
* -acodec copy 使用跟原视频相同的音频编解码器
*/
public static String cutOutVideoOld(File file, String outputDir,String star,String end) throws Exception {
String videoPath = null;
try {
videoPath = file.getAbsolutePath();
} catch (Exception e) {
log.info("错误----------:" + e.getMessage());
throw new BusinessException(ErrorCode.CUT_ERROR.getCode(),ErrorCode.CUT_ERROR.getMsg());
}
String resultPath =outputDir+IdUtil.simpleUUID()+"."+"mp4";
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
ProcessBuilder builder =
new ProcessBuilder(
ffmpeg,
"-i",
videoPath,
"-codec",
"copy",
"-ss",
star,
"-to",
end,
"-b",
"2000k",
"-y",
"-threads",
"5",
"-preset",
"ultrafast",
"-strict",
"-2",
resultPath);
builder.inheritIO().start();
return resultPath;
}
/**
* 删除本地临时文件
* @param path
*/
public static void deleteFilePlace(String path) {
System.out.println("path----------------:"+path);
File file = new File(path);
File del = new File(file.toURI());
System.out.println("删除本地临时文件-------"+del.delete());
}
/**
* 整理路径
*/
public static String sortOut(String path){
if(StringUtils.isNotBlank(path)){
char[] c = path.toCharArray();
String strNew ="";
for (int i = 0; i < c.length; i++) {
if (c[i] == '\\'&&c[i]==c[i+1]) {
continue;
}
strNew=strNew+c[i];
}
return strNew;
}else {
return path;
}
}
}