2025-10-24 11:22:35 +08:00
|
|
|
|
package com.fuyuanshen.app.service;
|
|
|
|
|
|
|
|
|
|
|
|
import com.fuyuanshen.web.util.VideoProcessUtil;
|
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 视频处理服务
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
@Service
|
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
|
public class VideoProcessService {
|
|
|
|
|
|
|
|
|
|
|
|
// 配置参数
|
|
|
|
|
|
private static final int MAX_VIDEO_SIZE = 10 * 1024 * 1024;
|
|
|
|
|
|
private static final List<String> SUPPORTED_FORMATS = Arrays.asList(".mp4", ".avi", ".mov", ".mkv");
|
|
|
|
|
|
private static final int FRAME_RATE = 15;
|
|
|
|
|
|
private static final int DURATION = 2;
|
|
|
|
|
|
private static final int WIDTH = 160;
|
|
|
|
|
|
private static final int HEIGHT = 80;
|
|
|
|
|
|
|
|
|
|
|
|
private final VideoProcessUtil videoProcessUtil;
|
|
|
|
|
|
|
2025-11-20 16:24:45 +08:00
|
|
|
|
public List<String> processVideo(MultipartFile file, int code) {
|
2025-10-24 11:22:35 +08:00
|
|
|
|
// 1. 参数校验
|
|
|
|
|
|
validateVideoFile(file);
|
|
|
|
|
|
|
|
|
|
|
|
File tempFile = null;
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 2. 创建临时文件
|
|
|
|
|
|
tempFile = videoProcessUtil.createTempVideoFile(file);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 处理视频并提取帧数据
|
|
|
|
|
|
List<String> hexList = videoProcessUtil.processVideoToHex(
|
2025-11-20 16:24:45 +08:00
|
|
|
|
tempFile, FRAME_RATE, DURATION, WIDTH, HEIGHT, code
|
2025-10-24 11:22:35 +08:00
|
|
|
|
);
|
2025-11-20 16:24:45 +08:00
|
|
|
|
log.info("code: {} hexList(前100个): {}", code,
|
|
|
|
|
|
hexList.subList(0, Math.min(100, hexList.size())));
|
2025-10-24 11:22:35 +08:00
|
|
|
|
log.info("视频处理成功,生成Hex数据长度: {}", hexList.size());
|
|
|
|
|
|
return hexList;
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("视频处理失败", e);
|
|
|
|
|
|
throw new RuntimeException("视频处理失败", e);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
// 4. 清理临时文件
|
|
|
|
|
|
videoProcessUtil.deleteTempFile(tempFile);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 验证视频文件
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void validateVideoFile(MultipartFile file) {
|
|
|
|
|
|
if (file == null || file.isEmpty()) {
|
|
|
|
|
|
throw new IllegalArgumentException("上传文件不能为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isVideoFile(file.getOriginalFilename())) {
|
|
|
|
|
|
throw new IllegalArgumentException("只允许上传视频文件");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (file.getSize() > MAX_VIDEO_SIZE) {
|
|
|
|
|
|
throw new IllegalArgumentException("视频大小不能超过10MB");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 判断是否是支持的视频格式
|
|
|
|
|
|
*/
|
|
|
|
|
|
private boolean isVideoFile(String filename) {
|
|
|
|
|
|
if (filename == null || filename.lastIndexOf('.') == -1) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
String ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
|
|
|
|
|
|
return SUPPORTED_FORMATS.contains(ext);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|