From 072fff9b055a2b9e281961f28fe7fde572336c8a Mon Sep 17 00:00:00 2001
From: zqy <2522236926@qq.com>
Date: 星期五, 02 一月 2026 17:35:11 +0800
Subject: [PATCH] 修改bug
---
zhang-content/src/main/java/com/ruoyi/service/impl/VideoProcessService.java | 446 ++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 309 insertions(+), 137 deletions(-)
diff --git a/zhang-content/src/main/java/com/ruoyi/service/impl/VideoProcessService.java b/zhang-content/src/main/java/com/ruoyi/service/impl/VideoProcessService.java
index 199569a..7dc98db 100644
--- a/zhang-content/src/main/java/com/ruoyi/service/impl/VideoProcessService.java
+++ b/zhang-content/src/main/java/com/ruoyi/service/impl/VideoProcessService.java
@@ -24,6 +24,13 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
+import org.bytedeco.javacv.FFmpegFrameGrabber;
+import org.bytedeco.javacv.Java2DFrameConverter;
+import org.bytedeco.javacv.Frame;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+
+
@Service
@Slf4j
public class VideoProcessService {
@@ -233,50 +240,14 @@
// PNG鐨勫帇缂╃骇鍒紙0-9锛�0鏈�蹇絾鍘嬬缉鐜囦綆锛�9鏈�鎱絾鍘嬬缉鐜囬珮锛�
if (compressionLevel >= 0) {
- try {
- // 鍏堟鏌ユ槸鍚︽敮鎸佸帇缂╂ā寮�
- if (param.canWriteCompressed()) {
- param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
-
- // 妫�鏌ユ槸鍚︽敮鎸佸帇缂╃被鍨嬭缃�
- String[] compressionTypes = param.getCompressionTypes();
- if (compressionTypes != null && compressionTypes.length > 0) {
- // 灏濊瘯璁剧疆鍘嬬缉绫诲瀷
- String compressionType = compressionTypes[0];
- for (String type : compressionTypes) {
- if ("Deflate".equalsIgnoreCase(type) || "PNG".equalsIgnoreCase(type)) {
- compressionType = type;
- break;
- }
- }
- param.setCompressionType(compressionType);
- }
-
- // 璁剧疆鍘嬬缉璐ㄩ噺锛堝帇缂╃骇鍒浆鎹负0.0-1.0锛�
- float quality = Math.max(0.0f, Math.min(1.0f, compressionLevel / 9.0f));
- param.setCompressionQuality(quality);
- } else {
- // 濡傛灉涓嶆敮鎸佸帇缂╂ā寮忥紝璁板綍璀﹀憡骞剁户缁娇鐢ㄩ粯璁よ缃�
- log.warn("PNG缂栫爜鍣ㄤ笉鏀寔鍘嬬缉妯″紡锛屼娇鐢ㄩ粯璁よ缃�");
- }
- } catch (UnsupportedOperationException e) {
- // 鎹曡幏寮傚父锛岃褰曡鍛婏紝鐒跺悗浣跨敤榛樿璁剧疆缁х画
- log.warn("璁剧疆PNG鍘嬬缉鍙傛暟澶辫触: {}锛屼娇鐢ㄩ粯璁よ缃�", e.getMessage());
- // 閲嶇疆鍙傛暟涓洪粯璁ゅ��
- param = writer.getDefaultWriteParam();
- }
+ param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+ param.setCompressionType("Deflate");
+ param.setCompressionQuality(Math.max(0.0f, Math.min(1.0f, compressionLevel / 9.0f)));
}
- try {
- writer.setOutput(new MemoryCacheImageOutputStream(output));
- writer.write(null, new IIOImage(image, null, null), param);
- } catch (Exception e) {
- log.warn("浣跨敤ImageWriter鍐欏叆PNG澶辫触: {}锛屽洖閫�鍒癐mageIO.write", e.getMessage());
- // 鍥為��鍒扮畝鍗曠殑ImageIO.write
- ImageIO.write(image, "png", output);
- } finally {
- writer.dispose();
- }
+ writer.setOutput(new MemoryCacheImageOutputStream(output));
+ writer.write(null, new IIOImage(image, null, null), param);
+ writer.dispose();
}
@@ -284,23 +255,12 @@
-
-
-
-
-
-
-
/**
- * 澶勭悊瑙嗛鏂囦欢锛氱敓鎴怋ase64缂栫爜鐨勫皝闈�
+ * 澶勭悊瑙嗛鏂囦欢锛氱敓鎴怋ase64缂栫爜鐨勫皝闈� (浣跨敤JavaCV)
*/
public Map<String, Object> processVideo(File file, int width, int height,
- float quality, String format,boolean deleteY) {
+ float quality, String format, boolean deleteY) {
Map<String, Object> result = new HashMap<>();
- File tempVideoFile = file;
-
-
- System.out.println();
try {
// 1. 楠岃瘉瑙嗛鏍煎紡
@@ -310,21 +270,12 @@
return result;
}
- // 2. 淇濆瓨鍘熷鏂囦欢鍒颁复鏃剁洰褰�
-// String originalFilename = file.getName();
-// tempVideoFile = File.createTempFile("video_", ".temp");
-
- // 3. 鑾峰彇瑙嗛淇℃伅
-// MultimediaInfo info = getVideoInfo(tempVideoFile);
-// double durationSeconds = info.getDuration() / 1000.0;
-// String videoResolution = info.getVideo().getSize().getWidth() + "x" + info.getVideo().getSize().getHeight();
-
- // 4. 鐢熸垚Base64鏍煎紡鐨勫皝闈�
- String base64Thumbnail = generateBase64ThumbnailFromFile(
- tempVideoFile,
+ // 2. 浣跨敤鏂扮殑JavaCV鏂规硶鐢熸垚Base64灏侀潰
+ String base64Thumbnail = generateBase64ThumbnailWithJavaCV(
+ file,
width > 0 ? width : thumbnailWidth,
height > 0 ? height : thumbnailHeight,
- (int) quality,
+ quality, // 娉ㄦ剰锛氳繖閲屼紶鍏loat绫诲瀷鐨剄uality
format != null ? format : thumbnailFormat
);
@@ -334,25 +285,15 @@
return result;
}
- // 5. 鑾峰彇缂╃暐鍥惧ぇ灏�
+ // 3. 鑾峰彇缂╃暐鍥惧ぇ灏� (鏂规硶淇濇寔涓嶅彉锛屼緷璧朆ase64)
String thumbnailSize = extractImageSizeFromBase64(base64Thumbnail);
- String[] sizeParts = thumbnailSize.split("x");
- int thumbWidth = sizeParts.length > 0 ? Integer.parseInt(sizeParts[0]) : 0;
- int thumbHeight = sizeParts.length > 1 ? Integer.parseInt(sizeParts[1]) : 0;
- // 6. 杩斿洖缁撴灉
+ // 4. 杩斿洖缁撴灉
result.put("success", true);
result.put("type", "video");
result.put("format", format != null ? format : thumbnailFormat);
-// result.put("originalFilename", originalFilename);
-// result.put("originalWidth", info.getVideo().getSize().getWidth());
-// result.put("originalHeight", info.getVideo().getSize().getHeight());
-// result.put("originalResolution", videoResolution);
-// result.put("duration", durationSeconds);
-// result.put("videoFormat", info.getFormat());
-// result.put("compressedWidth", thumbWidth);
-// result.put("compressedHeight", thumbHeight);
result.put("base64", base64Thumbnail);
+ result.put("thumbnailSize", thumbnailSize); // 鍙�夛紝杩斿洖灏哄淇℃伅
result.put("message", "瑙嗛灏侀潰鐢熸垚鎴愬姛");
} catch (Exception e) {
@@ -361,24 +302,29 @@
result.put("message", "灏侀潰鐢熸垚澶辫触: " + e.getMessage());
} finally {
// 娓呯悊涓存椂鏂囦欢
- if (tempVideoFile != null && tempVideoFile.exists() && deleteY) {
+ if (deleteY && file != null && file.exists()) {
try {
- tempVideoFile.delete();
+ file.delete();
} catch (Exception e) {
log.warn("鍒犻櫎涓存椂瑙嗛鏂囦欢鏃跺嚭閿�", e);
}
}
}
-
return result;
}
+
+
/**
- * 鐢熸垚Base64鏍煎紡鐨勫皝闈紙鍙嚜瀹氫箟鍙傛暟锛�
+ * 銆愭牳蹇冦�戜娇鐢↗avaCV鐢熸垚Base64鏍煎紡鐨勫皝闈�
*/
- private String generateBase64ThumbnailFromFile(File videoFile, int width, int height,
- int quality, String format) {
- File tempThumbnailFile = null;
- Process process = null;
+ /**
+ * 銆愭牳蹇冦�戜娇鐢↗avaCV鐢熸垚Base64鏍煎紡鐨勫皝闈�
+ */
+ private String generateBase64ThumbnailWithJavaCV(File videoFile, int targetWidth,
+ int targetHeight, float quality,
+ String format) {
+ FFmpegFrameGrabber grabber = null;
+ Java2DFrameConverter converter = null;
try {
if (!videoFile.exists()) {
@@ -386,82 +332,308 @@
return null;
}
- // 1. 鍒涘缓涓存椂鏂囦欢鐢ㄤ簬淇濆瓨缂╃暐鍥�
- String ext = format != null ? format : thumbnailFormat;
- tempThumbnailFile = File.createTempFile("thumb_", "." + ext);
- tempThumbnailFile.deleteOnExit();
+ // 1. 鍒濆鍖栨姄鍙栧櫒
+ grabber = new FFmpegFrameGrabber(videoFile);
+ grabber.start();
- // 2. 鑾峰彇瑙嗛鏃堕暱锛岃绠楁埅鍥炬椂闂寸偣
- MultimediaInfo info = getVideoInfo(videoFile);
- double durationSeconds = info.getDuration() / 1000.0;
+ // 鑾峰彇瑙嗛鏃堕暱
+ long durationMicroseconds = grabber.getLengthInTime();
+ double durationSeconds = durationMicroseconds / 1_000_000.0;
double screenshotTime = calculateScreenshotTime(durationSeconds);
- // 3. 鏋勫缓FFmpeg鍛戒护
- String ffmpegCmd = String.format(
- "ffmpeg -y -i \"%s\" -ss %.2f -vframes 1 -q:v %d -s %dx%d -f image2 \"%s\"",
- videoFile.getAbsolutePath(),
- screenshotTime,
- quality,
- width,
- height,
- tempThumbnailFile.getAbsolutePath()
- );
+ log.info("瑙嗛淇℃伅 - 鏂囦欢鍚�: {}, 鏃堕暱: {}s, 鎴浘鏃堕棿: {}s, 鍘熷灏哄: {}x{}",
+ videoFile.getName(), durationSeconds, screenshotTime,
+ grabber.getImageWidth(), grabber.getImageHeight());
- // 4. 鎵цFFmpeg鍛戒护
- ProcessBuilder processBuilder = new ProcessBuilder();
- String[] command = isWindows() ?
- new String[]{"cmd.exe", "/c", ffmpegCmd} :
- new String[]{"bash", "-c", ffmpegCmd};
+ // 2. 璺宠浆鍒版寚瀹氭椂闂寸偣
+ grabber.setTimestamp((long) (screenshotTime * 1_000_000));
- processBuilder.command(command);
- processBuilder.redirectErrorStream(true);
- process = processBuilder.start();
+ // 3. 鎶撳彇甯�
+ Frame frame = null;
+ BufferedImage bufferedImage = null;
+ converter = new Java2DFrameConverter();
- // 5. 绛夊緟鍛戒护瀹屾垚
- boolean finished = process.waitFor(30, TimeUnit.SECONDS);
- if (!finished) {
- process.destroyForcibly();
+ // 灏濊瘯鎶撳彇澶氬抚
+ for (int i = 0; i < 10; i++) {
+ frame = grabber.grabImage();
+ if (frame != null && frame.image != null) {
+ bufferedImage = converter.convert(frame);
+ if (bufferedImage != null) {
+ log.info("鎴愬姛鎶撳彇绗瑊}甯э紝鍥剧墖灏哄: {}x{}",
+ i, bufferedImage.getWidth(), bufferedImage.getHeight());
+ break;
+ }
+ }
+ }
+
+ if (bufferedImage == null) {
+ log.error("鏃犳硶浠庤棰戜腑鎶撳彇鏈夋晥鍥惧儚甯�");
return null;
}
- int exitCode = process.waitFor();
- if (exitCode != 0 || !tempThumbnailFile.exists() || tempThumbnailFile.length() == 0) {
+ // 4. 璋冩暣鍥剧墖灏哄
+ int originalWidth = bufferedImage.getWidth();
+ int originalHeight = bufferedImage.getHeight();
+
+ if (targetWidth > 0 || targetHeight > 0) {
+ bufferedImage = resizeImage(bufferedImage, targetWidth, targetHeight, true);
+ log.info("璋冩暣灏哄: {}x{} -> {}x{}",
+ originalWidth, originalHeight,
+ bufferedImage.getWidth(), bufferedImage.getHeight());
+ }
+
+ // 5. 鍘嬬缉骞惰浆鎹负Base64
+ byte[] compressedBytes;
+ String actualFormat = (format != null && !format.isEmpty()) ? format : "jpg";
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ try {
+ if ("jpg".equalsIgnoreCase(actualFormat) || "jpeg".equalsIgnoreCase(actualFormat)) {
+ compressAsJpeg(bufferedImage, baos, quality);
+ } else if ("png".equalsIgnoreCase(actualFormat)) {
+ compressAsPng(bufferedImage, baos, (int)(quality * 9));
+ } else {
+ if (!ImageIO.write(bufferedImage, actualFormat, baos)) {
+ // 濡傛灉涓嶆敮鎸佽鏍煎紡锛屽洖閫�鍒癹pg
+ log.warn("涓嶆敮鎸佹牸寮�: {}锛屽洖閫�鍒癹pg", actualFormat);
+ actualFormat = "jpg";
+ baos.reset();
+ compressAsJpeg(bufferedImage, baos, quality);
+ }
+ }
+
+ compressedBytes = baos.toByteArray();
+
+ if (compressedBytes == null || compressedBytes.length == 0) {
+ log.error("鍘嬬缉鍚庣殑鍥剧墖鏁版嵁涓虹┖");
+ return null;
+ }
+
+ log.info("鍥剧墖鍘嬬缉鎴愬姛锛屽ぇ灏�: {} bytes", compressedBytes.length);
+
+ } catch (Exception e) {
+ log.error("鍥剧墖鍘嬬缉澶辫触: {}", e.getMessage());
+ // 灏濊瘯浣跨敤榛樿鏂瑰紡
+ baos.reset();
+ if (ImageIO.write(bufferedImage, actualFormat, baos)) {
+ compressedBytes = baos.toByteArray();
+ } else {
+ return null;
+ }
+ }
+
+ // 6. 鏋勫缓Data URL
+ String base64 = Base64.getEncoder().encodeToString(compressedBytes);
+ if (base64 == null || base64.isEmpty()) {
+ log.error("Base64缂栫爜澶辫触");
return null;
}
- // 6. 璇诲彇鍥剧墖鏂囦欢骞惰浆鎹负Base64
- byte[] fileContent = Files.readAllBytes(tempThumbnailFile.toPath());
+ String mimeType = getMimeType(actualFormat);
+ String dataUrl = "data:" + mimeType + ";base64," + base64;
- if (!isValidImage(fileContent)) {
- return null;
- }
+ log.info("鐢熸垚Base64 Data URL鎴愬姛锛岄暱搴�: {}, 鏍煎紡: {}",
+ dataUrl.length(), actualFormat);
- // 7. 杞崲涓築ase64
- String base64 = Base64.getEncoder().encodeToString(fileContent);
- String mimeType = getMimeType(ext);
-
- return "data:" + mimeType + ";base64," + base64;
+ return dataUrl;
} catch (Exception e) {
- log.error("鐢熸垚Base64灏侀潰澶辫触", e);
+ log.error("浣跨敤JavaCV鐢熸垚灏侀潰澶辫触: {}", e.getMessage(), e);
return null;
} finally {
- // 娓呯悊璧勬簮
- if (process != null && process.isAlive()) {
- process.destroy();
+ // 7. 閲婃斁璧勬簮
+ if (converter != null) {
+ try {
+ converter.close();
+ } catch (Exception e) {
+ log.warn("鍏抽棴Java2DFrameConverter鏃跺嚭閿�", e);
+ }
}
- if (tempThumbnailFile != null && tempThumbnailFile.exists()) {
+ if (grabber != null) {
try {
- tempThumbnailFile.delete();
+ grabber.stop();
+ grabber.release();
} catch (Exception e) {
- // ignore
+ log.warn("閲婃斁FFmpegFrameGrabber璧勬簮鏃跺嚭閿�", e);
}
}
}
}
+
+// /**
+// * 澶勭悊瑙嗛鏂囦欢锛氱敓鎴怋ase64缂栫爜鐨勫皝闈�
+// */
+// public Map<String, Object> processVideo(File file, int width, int height,
+// float quality, String format,boolean deleteY) {
+// Map<String, Object> result = new HashMap<>();
+// File tempVideoFile = file;
+//
+//
+// System.out.println();
+//
+// try {
+// // 1. 楠岃瘉瑙嗛鏍煎紡
+// if (!isVideoFile(file)) {
+// result.put("success", false);
+// result.put("message", "涓嶆敮鎸佺殑瑙嗛鏍煎紡");
+// return result;
+// }
+//
+// // 2. 淇濆瓨鍘熷鏂囦欢鍒颁复鏃剁洰褰�
+//// String originalFilename = file.getName();
+//// tempVideoFile = File.createTempFile("video_", ".temp");
+//
+// // 3. 鑾峰彇瑙嗛淇℃伅
+//// MultimediaInfo info = getVideoInfo(tempVideoFile);
+//// double durationSeconds = info.getDuration() / 1000.0;
+//// String videoResolution = info.getVideo().getSize().getWidth() + "x" + info.getVideo().getSize().getHeight();
+//
+// // 4. 鐢熸垚Base64鏍煎紡鐨勫皝闈�
+// String base64Thumbnail = generateBase64ThumbnailFromFile(
+// tempVideoFile,
+// width > 0 ? width : thumbnailWidth,
+// height > 0 ? height : thumbnailHeight,
+// (int) quality,
+// format != null ? format : thumbnailFormat
+// );
+//
+// if (base64Thumbnail == null || base64Thumbnail.isEmpty()) {
+// result.put("success", false);
+// result.put("message", "灏侀潰鐢熸垚澶辫触");
+// return result;
+// }
+//
+// // 5. 鑾峰彇缂╃暐鍥惧ぇ灏�
+// String thumbnailSize = extractImageSizeFromBase64(base64Thumbnail);
+// String[] sizeParts = thumbnailSize.split("x");
+// int thumbWidth = sizeParts.length > 0 ? Integer.parseInt(sizeParts[0]) : 0;
+// int thumbHeight = sizeParts.length > 1 ? Integer.parseInt(sizeParts[1]) : 0;
+//
+// // 6. 杩斿洖缁撴灉
+// result.put("success", true);
+// result.put("type", "video");
+// result.put("format", format != null ? format : thumbnailFormat);
+//// result.put("originalFilename", originalFilename);
+//// result.put("originalWidth", info.getVideo().getSize().getWidth());
+//// result.put("originalHeight", info.getVideo().getSize().getHeight());
+//// result.put("originalResolution", videoResolution);
+//// result.put("duration", durationSeconds);
+//// result.put("videoFormat", info.getFormat());
+//// result.put("compressedWidth", thumbWidth);
+//// result.put("compressedHeight", thumbHeight);
+// result.put("base64", base64Thumbnail);
+// result.put("message", "瑙嗛灏侀潰鐢熸垚鎴愬姛");
+//
+// } catch (Exception e) {
+// log.error("瑙嗛灏侀潰鐢熸垚澶辫触", e);
+// result.put("success", false);
+// result.put("message", "灏侀潰鐢熸垚澶辫触: " + e.getMessage());
+// } finally {
+// // 娓呯悊涓存椂鏂囦欢
+// if (tempVideoFile != null && tempVideoFile.exists() && deleteY) {
+// try {
+// tempVideoFile.delete();
+// } catch (Exception e) {
+// log.warn("鍒犻櫎涓存椂瑙嗛鏂囦欢鏃跺嚭閿�", e);
+// }
+// }
+// }
+//
+// return result;
+// }
+// /**
+// * 鐢熸垚Base64鏍煎紡鐨勫皝闈紙鍙嚜瀹氫箟鍙傛暟锛�
+// */
+// private String generateBase64ThumbnailFromFile(File videoFile, int width, int height,
+// int quality, String format) {
+// File tempThumbnailFile = null;
+// Process process = null;
+//
+// try {
+// if (!videoFile.exists()) {
+// log.error("瑙嗛鏂囦欢涓嶅瓨鍦�: {}", videoFile.getAbsolutePath());
+// return null;
+// }
+//
+// // 1. 鍒涘缓涓存椂鏂囦欢鐢ㄤ簬淇濆瓨缂╃暐鍥�
+// String ext = format != null ? format : thumbnailFormat;
+// tempThumbnailFile = File.createTempFile("thumb_", "." + ext);
+// tempThumbnailFile.deleteOnExit();
+//
+// // 2. 鑾峰彇瑙嗛鏃堕暱锛岃绠楁埅鍥炬椂闂寸偣
+// MultimediaInfo info = getVideoInfo(videoFile);
+// double durationSeconds = info.getDuration() / 1000.0;
+// double screenshotTime = calculateScreenshotTime(durationSeconds);
+//
+// // 3. 鏋勫缓FFmpeg鍛戒护
+// String ffmpegCmd = String.format(
+// "ffmpeg -y -i \"%s\" -ss %.2f -vframes 1 -q:v %d -s %dx%d -f image2 \"%s\"",
+// videoFile.getAbsolutePath(),
+// screenshotTime,
+// quality,
+// width,
+// height,
+// tempThumbnailFile.getAbsolutePath()
+// );
+//
+// // 4. 鎵цFFmpeg鍛戒护
+// ProcessBuilder processBuilder = new ProcessBuilder();
+// String[] command = isWindows() ?
+// new String[]{"cmd.exe", "/c", ffmpegCmd} :
+// new String[]{"bash", "-c", ffmpegCmd};
+//
+// processBuilder.command(command);
+// processBuilder.redirectErrorStream(true);
+// process = processBuilder.start();
+//
+// // 5. 绛夊緟鍛戒护瀹屾垚
+// boolean finished = process.waitFor(30, TimeUnit.SECONDS);
+// if (!finished) {
+// process.destroyForcibly();
+// return null;
+// }
+//
+// int exitCode = process.waitFor();
+// if (exitCode != 0 || !tempThumbnailFile.exists() || tempThumbnailFile.length() == 0) {
+// return null;
+// }
+//
+// // 6. 璇诲彇鍥剧墖鏂囦欢骞惰浆鎹负Base64
+// byte[] fileContent = Files.readAllBytes(tempThumbnailFile.toPath());
+//
+// if (!isValidImage(fileContent)) {
+// return null;
+// }
+//
+// // 7. 杞崲涓築ase64
+// String base64 = Base64.getEncoder().encodeToString(fileContent);
+// String mimeType = getMimeType(ext);
+//
+// return "data:" + mimeType + ";base64," + base64;
+//
+// } catch (Exception e) {
+// log.error("鐢熸垚Base64灏侀潰澶辫触", e);
+// return null;
+// } finally {
+// // 娓呯悊璧勬簮
+// if (process != null && process.isAlive()) {
+// process.destroy();
+// }
+//
+// if (tempThumbnailFile != null && tempThumbnailFile.exists()) {
+// try {
+// tempThumbnailFile.delete();
+// } catch (Exception e) {
+// // ignore
+// }
+// }
+// }
+// }
+
+
/**
* 鐢熸垚Base64鏍煎紡鐨勫皝闈紙涓嶅瓨鍌ㄦ枃浠讹級
*/
--
Gitblit v1.9.1