1.引入依赖
截图主要用ffmpeg和opencv
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5</version>
<exclusions>
<exclusion>
<!-- 去除不需要的jar包 -->
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>4.1.3-1.5</version>
</dependency>
<!-- 此处引用的是包含所有Linux环节的jar包,根据自己的环境选择对应的依赖就好,没必要这么多。以下opencv的依赖与此处相似 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>4.1.3-1.5</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv</artifactId>
<version>4.0.1-1.4.4</version>
</dependency>
<!-- 环境 -->
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv</artifactId>
<version>4.0.1-1.4.4</version>
<classifier>linux-x86_64</classifier>
</dependency>
例如需要在Windows环境运行该程序,则引用对应的依赖
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>ffmpeg</artifactId>
<version>4.1.3-1.5</version>
<classifier>windows-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv</artifactId>
<version>4.0.1-1.4.4</version>
<classifier>windows-x86_64</classifier>
</dependency>
2.使用
截取视频第6帧的图片,返回图片流
/**
* 根据视频流截取第 6 帧的图片
* @param videoFile 视频流
* @throws Exception
*/
private InputStream fetchFrame(InputStream videoFile) throws Exception{
FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoFile);
fFmpegFrameGrabber.start();
int length = fFmpegFrameGrabber.getLengthInFrames();
int index = 0;
Frame frame = null;
while (index < length){
frame = fFmpegFrameGrabber.grabImage();
if (index > 5 && frame.image != null) {
break;
}
index++;
}
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(frame);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", os);
fFmpegFrameGrabber.close();
return new ByteArrayInputStream(os.toByteArray());
}
3.将视频和图片上传到阿里云OSS上
/**
* 视频文件上传
* 仅支持inux-x86_64 环境
*/
@Override
public String uploadVideo(String tempPath,MultipartFile file)throws Exception{
//文件名前缀
String prefix=merchant==null?String.format("%04d",0):String.format("%04d",merchant.getMerchantId());
String videoUrl=AliyunOssUtil.uploadFile(file.getInputStream(),AliyunOssUtil.generateNewFileName(file.getOriginalFilename(),prefix,""), "");
String videoPoster=AliyunOssUtil.uploadFile(fetchFrame(file.getInputStream()),AliyunOssUtil.generateNewFileName("",prefix,".jpg"),"");
return new ResultObject(XXXX)).toJSONString();
}
public class AliyunOssUtil {
private static Logger logger = LoggerFactory.getLogger(AliyunOssUtil.class);
private static final String ENDPOINT = "xxxxxxxxx";
public static String ACCESS_URL;
private static String BUCKET;
private static final String ACCESS_KEY_ID = "xxxxxxxxxxxxxxxxxxxxxx";
private static final String ACCESS_KEY_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxx";
static {
if ("idc".equals(CommonUtil.getServerMode())) {
ACCESS_URL = "xxxxxxxxxxxxxxxxxxxxx";
BUCKET = "xxxxxxxxxxxxxxxxxxxxxx";
} else {
ACCESS_URL = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
BUCKET = "xxxxxxxxxxxxxxxxxxx";
}
}
/**
* 生成新的文件名
*
* @param originalFileName 原始的文件名
* @param prefix 前缀
* @param suffix 后缀
* @return
*/
public static String generateNewFileName(String originalFileName, String prefix, String suffix) {
//随机生成的字符串
String generateStr = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + RandomUtil.generateRandomNumber(5);
//文件类型后缀
String fileTypeStr = "";
int fileTypeIndex = originalFileName.lastIndexOf(".");
if (fileTypeIndex >= 0) {
fileTypeStr = originalFileName.substring(fileTypeIndex);
}
return CommonUtil.getServerMode().substring(0, 1) + prefix + generateStr + suffix + fileTypeStr;
}
/**
* 上传文件到OSS
*
* @param file
* @param fileName
* @return
* @throws Exception
*/
public static String uploadFile(File file, String fileName) throws Exception {
return uploadFile(new FileInputStream(file), fileName);
}
/**
* 上传文件流到OSS
*
* @param inputStream
* @param fileName
* @return
* @throws Exception
*/
public static String uploadFile(InputStream inputStream, String fileName) throws Exception {
// 创建ClientConfiguration。ClientConfiguration是OSSClient的配置类,可配置代理、连接超时、最大连接数等参数。
ClientConfiguration conf = new ClientConfiguration();
// 设置OSSClient允许打开的最大HTTP连接数,默认为1024个。
// conf.setMaxConnections(200);
// 设置Socket层传输数据的超时时间,默认为50000毫秒。
// conf.setSocketTimeout(10000);
// 设置建立连接的超时时间,默认为50000毫秒。
// conf.setConnectionTimeout(10000);
// 设置从连接池中获取连接的超时时间(单位:毫秒),默认不超时。
// conf.setConnectionRequestTimeout(1000);
// 设置连接空闲超时时间。超时则关闭连接,默认为60000毫秒 。
// conf.setIdleConnectionTime(10000);
// 设置失败请求重试次数,默认为3次。
// conf.setMaxErrorRetry(5);
// 设置是否支持将自定义域名作为Endpoint,默认支持。
// conf.setSupportCname(true);
// 设置是否开启二级域名的访问方式,默认不开启。
// conf.setSLDEnabled(true);
// 设置连接OSS所使用的协议(HTTP/HTTPS),默认为HTTP。
// conf.setProtocol(Protocol.HTTP);
// 设置用户代理,指HTTP的User-Agent头,默认为aliyun-sdk-java。
// conf.setUserAgent("aliyun-sdk-java");
// 设置代理服务器端口。
// conf.setProxyHost("<yourProxyHost>");
// 设置代理服务器验证的用户名。
// conf.setProxyUsername("<yourProxyUserName>");
// 设置代理服务器验证的密码。
// conf.setProxyPassword("<yourProxyPassword>");
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, conf);
// 创建上传文件的元信息,可以通过文件元信息设置HTTP header
ObjectMetadata meta = new ObjectMetadata();
// String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5(content.getBytes()));
// 开启文件内容MD5校验。开启后OSS会把您提供的MD5与文件的MD5比较,不一致则抛出异常。
// meta.setContentMD5(md5);
// 指定上传的内容类型。内容类型决定浏览器将以什么形式、什么编码读取文件。如果没有指定则根据文件的扩展名生成,如果没有扩展名则为默认值application/octet-stream。
// meta.setContentType("text/plain");
// 设置内容被下载时的名称。
// meta.setContentDisposition("Download File Name");
// 设置上传文件的长度。如超过此长度,则会被截断,为设置的长度。如不足,则为上传文件的实际长度。
// meta.setContentLength(content.length());
// 设置内容被下载时网页的缓存行为。
// meta.setCacheControl("Download Action");
// 设置缓存过期时间,格式是格林威治时间(GMT)。
// meta.setExpirationTime(DateUtil.parseIso8601Date("2022-10-12T00:00:00.000Z"));
// 设置内容被下载时的编码格式。
// meta.setContentEncoding("utf-8");
// 设置header。
// meta.setHeader("<yourHeader>", "<yourHeaderValue>");
// 上传文件流
ossClient.putObject(BUCKET, fileName, inputStream, meta);
// 关闭OSSClient
ossClient.shutdown();
return ACCESS_URL + URLEncoder.encode(fileName, "utf-8");
}
/**
* 上传文件流到OSS
* 若上传到BUCKET下的子目录,则在原有的文件名加上前缀,如:video/视频名称.mp4
* @param inputStream
* @param fileName
* @return
* @throws Exception
*/
public static String uploadFile(InputStream inputStream, String fileName, String subdirectory) throws Exception {
ClientConfiguration conf = new ClientConfiguration();
OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, conf);
ObjectMetadata meta = new ObjectMetadata();
ossClient.putObject(BUCKET, subdirectory + fileName, inputStream, meta);
ossClient.shutdown();
return ACCESS_URL + subdirectory + URLEncoder.encode(fileName, "utf-8");
}
//BUCKET下的子目录
public static void deleteVideoFile(String keyFile){
ClientConfiguration conf = new ClientConfiguration();
String fileNameTemp = keyFile.substring(0, keyFile.indexOf("?"));
String fileVideoName = fileNameTemp.substring(fileNameTemp.lastIndexOf("/video") + 1);
String fileImageName = keyFile.substring(keyFile.lastIndexOf("/video") + 1);
OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, conf);
ossClient.deleteObject(BUCKET, fileVideoName);
ossClient.deleteObject(BUCKET, fileImageName);
}
}
若上传到BUCKET下的子目录,则在原有的文件名加上前缀,如:video/视频名称.mp4