方法一
<!--引入全平台windows 32/64 linux 32/64 下的ffmpeg 可执行程序,实际运行不需要这么多-->
<!--<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-all-deps</artifactId>
<version>3.2.0</version>
</dependency>-->
<!--操作ffmpeg命令的jar-->
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-core</artifactId>
<version>3.2.0</version>
</dependency>
<!--linux 引用jar,主要集成 ffmpeg-amd64-3.1.1 linux下可执行文件 -->
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-linux64</artifactId>
<version>3.2.0</version>
</dependency>
/**
* 获取播放时长
*
* @param multipartFile 文件流
*/
private int getPlayTime(MultipartFile multipartFile) {
// 获取文件名
String fileName = multipartFile.getOriginalFilename();
// 播放时长
int playTime = -1;
File file = new File(fileName);
try {
FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
MultimediaObject multimediaObject = new MultimediaObject(file);
MultimediaInfo multimediaInfo = multimediaObject.getInfo();
playTime = (int) multimediaInfo.getDuration() / 1000;
} catch (Exception e) {
BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
log.error("获取播放时长异常", e);
} finally {
file.delete();
}
return playTime;
}
?
方法二
<!-- 视觉库 -->
<!-- 总包太大,不需要这么多 -->
<!-- <dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.7</version>
</dependency> -->
<!-- javacv基础包 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.7</version>
</dependency>
<!-- ffmpeg,根据javacv总包的版本 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>5.0-1.5.7</version>
</dependency>
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class ToolVideo {
// 获取要取得的帧数
private static final int GET_FRAMES_LENGTH = 6;
/**
* 测试
*
* @param args
*/
public static void main(String[] args) throws FrameGrabber.Exception {
File file = new File("D:\\Users\\外出乞讨\\Desktop\\测试用素材\\摩托.mp4");
Map<String, Object> screenshot = getScreenshot(file);
}
/**
* 视频:获取一张视频截图并保存同名的jpg文件到指定目录
* 音频:获取播放时长
*
* @param file 文件
* @return
*/
public static Map<String, Object> getScreenshot(File file) {
log.info("视频文件[{}]截图开始", file.getName());
Map<String, Object> result = new HashMap<>();
// 文件路径
String filePath = file.getPath();
// 视频文件名
String fileName = file.getName();
// 第一帧图片存储位置(也是视频路径)
String targerFilePath = "";
if (filePath.contains("\\")) {
targerFilePath = filePath.substring(0, filePath.lastIndexOf("\\"));
targerFilePath = targerFilePath + File.separator;
} else if (filePath.contains("/")) {
targerFilePath = filePath.substring(0, filePath.lastIndexOf("/"));
targerFilePath = targerFilePath + File.separator;
}
// 图片名称
String targetFileName = fileName.substring(0, fileName.lastIndexOf("."));
// 图片的类型
String imageMat = "jpg";
// 图片的完整路径
String imagePath = targerFilePath + targetFileName + "." + imageMat;
// 创建文件
File output = new File(imagePath);
FFmpegFrameGrabber grabber;
try {
grabber = FFmpegFrameGrabber.createDefault(file);
grabber.start();
// 视频总帧数
int videoLength = grabber.getLengthInFrames();
Frame frame = null;
int i = 0;
while (i < videoLength) {
// 过滤前5帧,避免出现全黑的图片,依自己情况而定(每循环一次取一帧)
frame = grabber.grabFrame();
if ((i > GET_FRAMES_LENGTH) && (frame.image != null)) {
break;
}
i++;
}
// 视频旋转度
String rotate = grabber.getVideoMetadata("rotate");
Java2DFrameConverter converter = new Java2DFrameConverter();
// 绘制图片
BufferedImage bi = converter.getBufferedImage(frame);
if (rotate != null) {
// 旋转图片
bi = rotate(bi, Integer.parseInt(rotate));
}
// 输出图片
ImageIO.write(bi, imageMat, output);
// 拼接Map信息
result.put("videoLength", videoLength); // 视频总帧数
result.put("videoWide", bi.getWidth()); // 第一帧的宽
result.put("videoHigh", bi.getHeight());// 第一帧的高
long duration = grabber.getLengthInTime() / (1000 * 1000); // 此视频时长(s/秒)
result.put("rotate", (null == rotate || "".equals(rotate)) ? "0" : rotate); // 视频的旋转度
result.put("format", grabber.getFormat()); // 视频的格式
result.put("imgPath", output.getPath());
result.put("imgName", output.getName());
result.put("duration", duration);
log.info("视频文件[{}]截图结束,图片地址为[{}]", filePath, imagePath);
grabber.close();
} catch (Exception e) {
log.error("视频信息帧数处理发生异常 [{}]", e.getMessage());
e.printStackTrace();
BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
}
return result;
}
/**
* file 转 btye[]
*
* @param file
* @return
*/
public static byte[] fileTobyte(File file) {
byte[] buffer = null;
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
/**
* 获取音频/视频时长
* @param multipartFile 文件流
* @return
*/
public static int getPlayTime(MultipartFile multipartFile) {
// 播放时长
int playTime = -1;
File file = null;
FFmpegFrameGrabber grabberOne = null;
try {
// MultipartFile转file
file = new File(multipartFile.getOriginalFilename());
FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
// file转FFmpegFrameGrabber
grabberOne = FFmpegFrameGrabber.createDefault(file);
grabberOne.start();
// 计算时长
playTime = (int) grabberOne.getFormatContext().duration() / 1000000;
grabberOne.stop();
} catch (Exception e) {
BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
log.error("获取播放时长异常", e);
} finally {
try{
grabberOne.stop();
}catch (Exception e) {
BusinessExceptionUtil.throwErrorCodeException(ErrorCode.Status.UPLOAD_FILE_FAIL, e.toString());
log.error("关闭流异常", e);
}
file.delete();
}
return playTime;
}
// ==================== private method ====================
/**
* <h5>功能:根据视频旋转度来调整图片</h5>
*
* @param src 捕获的图像
* @param angel 视频旋转度
* @return BufferedImage
*/
private static BufferedImage rotate(BufferedImage src, int angel) {
int src_width = src.getWidth(null);
int src_height = src.getHeight(null);
int type = src.getColorModel().getTransparency();
Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
BufferedImage bi = new BufferedImage(rect_des.width, rect_des.height, type);
Graphics2D g2 = bi.createGraphics();
g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
g2.drawImage(src, 0, 0, null);
g2.dispose();
return bi;
}
/**
* <h5>功能:计算图片旋转大小</h5>
*
* @param src 屏幕坐标中捕获的矩形区域
* @param angel 视频旋转度
* @return
*/
private static Rectangle calcRotatedSize(Rectangle src, int angel) {
if (angel >= 90) {
if (angel / 90 % 2 == 1) {
int temp = src.height;
src.height = src.width;
src.width = temp;
}
angel = angel % 90;
}
double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
double angel_dalta_width = Math.atan((double) src.height / src.width);
double angel_dalta_height = Math.atan((double) src.width / src.height);
int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
int des_width = src.width + len_dalta_width * 2;
int des_height = src.height + len_dalta_height * 2;
return new Rectangle(new Dimension(des_width, des_height));
}
}
?
|