package com.ard.qs.utils;
|
|
import lombok.extern.slf4j.Slf4j;
|
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
import org.bytedeco.javacv.Frame;
|
import org.bytedeco.javacv.Java2DFrameConverter;
|
import org.springframework.stereotype.Component;
|
|
import javax.imageio.ImageIO;
|
import java.awt.image.BufferedImage;
|
import java.io.File;
|
|
@Slf4j
|
@Component
|
public class VideoSnapshotUtil {
|
|
/**
|
* 截取视频指定秒数的图片
|
*
|
* @param videoPath 视频文件路径 (本地路径或 URL)
|
* @param outputPath 图片保存路径
|
* @param frameSecond 截取第几秒的画面 (例如 1.0 表示第 1 秒)
|
* @return 截图文件
|
*/
|
public File takeSnapshot(String videoPath, String outputPath, double frameSecond) throws Exception {
|
FFmpegFrameGrabber grabber = null;
|
|
try {
|
grabber = FFmpegFrameGrabber.createDefault(videoPath);
|
grabber.start();
|
|
// 1. 获取视频元数据
|
int frameCount = grabber.getLengthInFrames();
|
double duration = grabber.getTimestamp() / 1000000; // 获取视频时长(秒) - 注意单位转换
|
// 注意:FFmpegFrameGrabber 的 seek 操作是基于关键帧的,可能不是绝对精确,
|
// 如果需要绝对精确,需要循环 grabFrame 直到目标时间。
|
|
// 2. 定位到指定时间 (微秒)
|
// 简单做法:直接 seek,但可能跳到最近的关键帧
|
grabber.setTimestamp((long) (frameSecond * 1000000));
|
|
// 3. 抓取帧
|
Frame frame = grabber.grabImage();
|
|
if (frame == null) {
|
throw new RuntimeException("无法抓取该时间点的帧,可能视频过短或格式不支持");
|
}
|
|
// 4. 转换并保存
|
Java2DFrameConverter converter = new Java2DFrameConverter();
|
BufferedImage image = converter.getBufferedImage(frame);
|
|
// 处理旋转 (手机视频常见)
|
String rotate = grabber.getVideoMetadata("rotate");
|
if (rotate != null && !rotate.isEmpty()) {
|
image = rotateImage(image, Integer.parseInt(rotate));
|
}
|
|
File outputFile = new File(outputPath);
|
// 确保父目录存在
|
if (!outputFile.getParentFile().exists()) {
|
outputFile.getParentFile().mkdirs();
|
}
|
|
ImageIO.write(image, "jpg", outputFile);
|
return outputFile;
|
|
} finally {
|
if (grabber != null) {
|
try {
|
grabber.stop();
|
} catch (Exception e) {
|
log.warn("[视频截图] 停止 grabber 失败: {}", e.getMessage());
|
}
|
try {
|
grabber.release();
|
} catch (Exception e) {
|
log.warn("[视频截图] 释放 grabber 资源失败: {}", e.getMessage());
|
}
|
}
|
}
|
}
|
|
// 简单的图片旋转辅助方法
|
private BufferedImage rotateImage(BufferedImage src, int degrees) {
|
// 这里需要实现具体的旋转逻辑,可以使用 java.awt.geom.AffineTransform
|
// 为了代码简洁,此处省略具体旋转实现,实际项目中建议使用 Thumbnailator 或 imgscalr 库
|
return src;
|
}
|
}
|