From 072fff9b055a2b9e281961f28fe7fde572336c8a Mon Sep 17 00:00:00 2001
From: zqy <2522236926@qq.com>
Date: 星期五, 02 一月 2026 17:35:11 +0800
Subject: [PATCH] 修改bug
---
ruoyi-admin/pom.xml | 6
ruoyi-common/src/main/java/com/ruoyi/common/config/ElasticSearchConfig.java | 1
zhang-content/src/main/java/com/ruoyi/service/impl/VideoProcessService.java | 398 +++++++++++++++++++++++++++++++++++++++++++-------------
zhang-content/pom.xml | 5
4 files changed, 314 insertions(+), 96 deletions(-)
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 3c2856d..6cadb66 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -135,6 +135,12 @@
<version>2.4.6</version>
<scope>runtime</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.bytedeco</groupId>
+ <artifactId>javacv-platform</artifactId>
+ <version>1.5.8</version>
+ </dependency>
</dependencies>
<build>
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/ElasticSearchConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/ElasticSearchConfig.java
index 26f2dfe..828d2d7 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/ElasticSearchConfig.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/ElasticSearchConfig.java
@@ -37,7 +37,6 @@
8087,
-
"http"
)
diff --git a/zhang-content/pom.xml b/zhang-content/pom.xml
index 938b663..396abeb 100644
--- a/zhang-content/pom.xml
+++ b/zhang-content/pom.xml
@@ -127,6 +127,11 @@
<scope>runtime</scope>
</dependency>
+ <dependency>
+ <groupId>org.bytedeco</groupId>
+ <artifactId>javacv-platform</artifactId>
+ <version>1.5.8</version>
+ </dependency>
</dependencies>
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 1b60a01..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 {
@@ -248,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. 楠岃瘉瑙嗛鏍煎紡
@@ -274,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
);
@@ -298,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) {
@@ -325,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()) {
@@ -350,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