forked from dyf/fys-Multi-tenant
uploadVideo
This commit is contained in:
@ -6,6 +6,7 @@ import com.fuyuanshen.app.service.VideoProcessService;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.equipment.utils.FileHashUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -28,18 +29,30 @@ public class AppVideoController extends BaseController {
|
||||
|
||||
private final VideoProcessService videoProcessService;
|
||||
private final AudioProcessService audioProcessService;
|
||||
private final FileHashUtil fileHashUtil;
|
||||
|
||||
|
||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS,message = "请勿重复提交!")
|
||||
public R<List<String>> uploadVideo(@RequestParam("file") MultipartFile file) {
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "请勿重复提交!")
|
||||
public R<List<String>> uploadVideo(@RequestParam("file") MultipartFile file) throws IOException {
|
||||
// 输出文件基本信息
|
||||
System.out.println("FileName: " + file.getOriginalFilename());
|
||||
System.out.println("FileSize: " + file.getSize());
|
||||
System.out.println("ContentType: " + file.getContentType());
|
||||
|
||||
String fileHash = fileHashUtil.hash(file);
|
||||
System.out.println("fileHash:" + fileHash);
|
||||
|
||||
// 可以添加更多视频属性检查
|
||||
return R.ok(videoProcessService.processVideo(file));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 上传音频文件并转码
|
||||
*/
|
||||
@PostMapping(value = "/audio", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS,message = "请勿重复提交!")
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "请勿重复提交!")
|
||||
public R<List<String>> uploadAudio(@RequestParam("file") MultipartFile file) {
|
||||
return R.ok(audioProcessService.processAudio(file));
|
||||
}
|
||||
@ -48,7 +61,7 @@ public class AppVideoController extends BaseController {
|
||||
* 文字转音频TTS服务
|
||||
*/
|
||||
@GetMapping("/audioTTS")
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS,message = "请勿重复提交!")
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "请勿重复提交!")
|
||||
public R<List<String>> uploadAudioTTS(@RequestParam String text) throws IOException {
|
||||
return R.ok(audioProcessService.generateStandardPcmData(text));
|
||||
}
|
||||
@ -57,8 +70,8 @@ public class AppVideoController extends BaseController {
|
||||
* 提取文本内容(只支持txt/docx)
|
||||
*/
|
||||
@PostMapping(value = "/extract", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS,message = "请勿重复提交!")
|
||||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "请勿重复提交!")
|
||||
public R<String> extract(@RequestParam("file") MultipartFile file) throws Exception {
|
||||
return R.ok("Success",audioProcessService.extract(file));
|
||||
return R.ok("Success", audioProcessService.extract(file));
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,52 +48,82 @@ public class VideoProcessUtil {
|
||||
return bytesToHexList(binaryData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从视频中提取帧
|
||||
*
|
||||
* @param videoFile 视频文件对象
|
||||
* @param frameRate 每秒提取的帧数(帧率)
|
||||
* @param duration 需要提取的视频时长(秒)
|
||||
* @param width 提取帧的宽度
|
||||
* @param height 提取帧的高度
|
||||
* @return 提取的帧图像列表
|
||||
* @throws Exception 如果在提取过程中发生错误
|
||||
*/
|
||||
private List<BufferedImage> extractFramesFromVideo(File videoFile, int frameRate, int duration, int width, int height) throws Exception {
|
||||
// 初始化帧列表
|
||||
List<BufferedImage> frames = new ArrayList<>();
|
||||
// 计算需要提取的总帧数 = 帧率 × 时长
|
||||
int totalFramesToExtract = frameRate * duration;
|
||||
|
||||
// 使用FFmpegFrameGrabber从视频文件中抓取帧
|
||||
try (FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(videoFile)) {
|
||||
// 启动抓取器
|
||||
grabber.start();
|
||||
|
||||
// 获取视频总帧数
|
||||
long totalFramesInVideo = grabber.getLengthInFrames();
|
||||
// 获取视频帧率,如果获取不到则默认为30fps
|
||||
int fps = (int) Math.round(grabber.getFrameRate());
|
||||
if (fps <= 0) fps = 30;
|
||||
|
||||
// 计算视频总时长(秒)
|
||||
double durationSeconds = (double) totalFramesInVideo / fps;
|
||||
// 检查视频时长是否满足要求
|
||||
if (durationSeconds < duration) {
|
||||
throw new IllegalArgumentException("视频太短,至少需要 " + duration + " 秒");
|
||||
}
|
||||
|
||||
// 计算帧间隔,用于均匀分布提取的帧
|
||||
double frameInterval = (double) totalFramesInVideo / totalFramesToExtract;
|
||||
|
||||
// 循环提取指定数量的帧
|
||||
for (int i = 0; i < totalFramesToExtract; i++) {
|
||||
// 计算目标帧号
|
||||
int targetFrameNumber = (int) Math.round(i * frameInterval);
|
||||
|
||||
// 检查目标帧号是否超出视频范围
|
||||
if (targetFrameNumber >= totalFramesInVideo) {
|
||||
throw new IllegalArgumentException("目标帧超出范围: " + targetFrameNumber);
|
||||
}
|
||||
|
||||
// 设置抓取器到目标帧
|
||||
grabber.setFrameNumber(targetFrameNumber);
|
||||
// 抓取当前帧
|
||||
Frame frame = grabber.grab();
|
||||
|
||||
// 如果成功抓取到帧且帧图像不为空
|
||||
if (frame != null && frame.image != null) {
|
||||
// 将帧转换为BufferedImage并裁剪到指定尺寸
|
||||
BufferedImage bufferedImage = Java2DFrameUtils.toBufferedImage(frame);
|
||||
frames.add(cropImage(bufferedImage, width, height));
|
||||
} else {
|
||||
// 如果无法获取帧则抛出异常
|
||||
throw new IllegalArgumentException("无法获取第 " + targetFrameNumber + "帧");
|
||||
}
|
||||
}
|
||||
|
||||
// 停止抓取器
|
||||
grabber.stop();
|
||||
}
|
||||
|
||||
// 记录提取的帧数
|
||||
log.debug("从视频中提取了 {} 帧", frames.size());
|
||||
// 返回提取的帧列表
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将所有帧转换为 RGB565 格式字节数组
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user