Browse Source

修改bug

jinshihui 1 month ago
parent
commit
8385405a62

+ 115 - 25
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TbFileServiceImpl.java

@@ -50,6 +50,21 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
     // FFmpeg 命令路径(从配置文件读取)
     @Value("${ffmpeg.path}")
     private String FFMPEG_PATH;
+
+    /**
+     * 是否启用Docker模式
+     */
+    @Value("${ffmpeg.docker-enabled:false}")
+    private boolean dockerEnabled;
+    // Docker镜像名称
+    @Value("${ffmpeg.docker-image:jrottenberg/ffmpeg}")
+    private String dockerImage;
+    // Docker容器内工作目录
+    @Value("${ffmpeg.container-work-dir:/data}")
+    private String containerWorkDir;
+    // 宿主机路径映射(Docker volume映射的源路径)
+    @Value("${ffmpeg.host-volume-path}")
+    private String hostVolumePath;
     // 截取时间点(秒)
     private static final int CAPTURE_TIME_SECOND = 1;
     // 命令执行超时时间(秒)
@@ -258,6 +273,44 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
         return thumbnailPathStr;
     }
 
+    /**
+     * 将宿主机路径转换为Docker容器内路径
+     * <p>
+     * 例如:宿主机路径 /usr/local/java/nightFragrance/uploadPath/upload/2026/02/03/video.mp4
+     * 转换为容器内路径 /data/upload/2026/02/03/video.mp4
+     * </p>
+     *
+     * @param hostPath 宿主机上的绝对路径
+     * @return Docker容器内的对应路径
+     */
+    private String convertToContainerPath(String hostPath) {
+        if (hostPath == null || hostPath.isEmpty()) {
+            return hostPath;
+        }
+        // 规范化路径分隔符(Windows风格转Linux风格)
+        String normalizedPath = hostPath.replace("\\", "/");
+        // 移除可能存在的重复斜杠
+        normalizedPath = normalizedPath.replaceAll("/+", "/");
+
+        //添加指定的前缀
+        normalizedPath = "/usr/local/java" + normalizedPath;
+
+        // 获取配置的宿主机映射路径(规范化)
+        String normalizedVolumePath = hostVolumePath.replace("\\", "/").replaceAll("/+", "/");
+        if (!normalizedVolumePath.endsWith("/")) {
+            normalizedVolumePath += "/";
+        }
+
+        // 如果路径以宿主机映射路径开头,则替换为容器工作目录
+        if (normalizedPath.startsWith(normalizedVolumePath)) {
+            String relativePath = normalizedPath.substring(normalizedVolumePath.length());
+            return containerWorkDir + "/" + relativePath;
+        }
+        // 如果路径不匹配,直接返回原路径
+        log.warn("路径 {} 不在Docker卷映射路径 {} 下,使用原路径", hostPath, hostVolumePath);
+        return normalizedPath;
+    }
+
     /**
      * 获取不带扩展名的文件名
      *
@@ -275,40 +328,77 @@ public class TbFileServiceImpl extends ServiceImpl<TbFileMapper, TbFile> impleme
 
     /**
      * 执行 FFmpeg 命令截取封面
+     * <p>
+     * 支持两种模式:
+     * 1. 本地模式:直接调用本地FFmpeg可执行文件
+     * 2. Docker模式:通过docker run命令调用容器内的FFmpeg
+     * </p>
      *
-     * @param videoPath 视频文件路径
-     * @param thumbnailPath 封面图片保存路径
+     * @param videoPath 视频文件路径(宿主机路径)
+     * @param thumbnailPath 封面图片保存路径(宿主机路径)
      */
     private void executeFfmpegCommand(String videoPath, String thumbnailPath) throws IOException, InterruptedException, VideoThumbnailService.VideoProcessException {
-        log.info("开始执行FFmpeg命令,视频文件路径: {}, 封面图片保存路径: {}", videoPath, thumbnailPath);
-        // 构建 FFmpeg 命令
-        // -ss: 截取时间点
-        // -i: 输入文件
-        // -vframes 1: 只截取一帧
-        // -q:v 2: 图片质量(1-31,数字越小质量越高)
-        // -y: 覆盖输出文件
+        log.info("开始执行FFmpeg命令,Docker模式: {}, 视频文件路径: {}, 封面图片保存路径: {}", dockerEnabled, videoPath, thumbnailPath);
         List<String> command = new ArrayList<>();
-        command.add(FFMPEG_PATH);
-        command.add("-ss");
-        command.add(String.valueOf(CAPTURE_TIME_SECOND));
-        command.add("-i");
-        command.add(videoPath);
-        command.add("-vframes");
-        command.add("1");
-        command.add("-q:v");
-        command.add("2");
-        command.add("-y");
-        command.add(thumbnailPath);
-        log.info("执行FFmpeg命令: {}", String.join(" ", command));
+        if (dockerEnabled) {
+            // Docker模式:构建 docker run 命令
+            // 命令格式:docker run --rm -v /host/path:/data -w /data jrottenberg/ffmpeg -ss 1 -i /data/input.mp4 -vframes 1 -q:v 2 -y /data/output.jpg
+            command.add("docker");
+            command.add("run");
+            command.add("--rm");
 
+            // 添加volume映射:将宿主机路径映射到容器内
+            command.add("-v");
+            // 规范化路径(处理Windows风格的路径分隔符)
+            String normalizedVolumePath = hostVolumePath.replace("\\", "/");
+            if (!normalizedVolumePath.startsWith("/")) {
+                // Windows路径需要特殊处理,转换为 /host 形式或使用完整路径
+                normalizedVolumePath = "/" + normalizedVolumePath.replace(":", "").replace("\\", "/");
+            }
+            String volumeMapping = normalizedVolumePath + ":" + containerWorkDir;
+            command.add(volumeMapping);
+
+            // 设置工作目录
+            command.add("-w");
+            command.add(containerWorkDir);
+
+            // Docker镜像名称
+            command.add(dockerImage);
+
+            // 将宿主机路径转换为容器内路径
+            String containerVideoPath = convertToContainerPath(videoPath);
+            String containerThumbnailPath = convertToContainerPath(thumbnailPath);
+
+            // FFmpeg参数
+            command.add("-ss");
+            command.add(String.valueOf(CAPTURE_TIME_SECOND));
+            command.add("-i");
+            command.add(containerVideoPath);
+            command.add("-vframes");
+            command.add("1");
+            command.add("-q:v");
+            command.add("2");
+            command.add("-y");
+            command.add(containerThumbnailPath);
+        } else {
+            // 本地模式:直接调用FFmpeg可执行文件
+            command.add(FFMPEG_PATH);
+            command.add("-ss");
+            command.add(String.valueOf(CAPTURE_TIME_SECOND));
+            command.add("-i");
+            command.add(videoPath);
+            command.add("-vframes");
+            command.add("1");
+            command.add("-q:v");
+            command.add("2");
+            command.add("-y");
+            command.add(thumbnailPath);
+        }
+        log.info("执行命令: {}", String.join(" ", command));
         // 执行命令
         ProcessBuilder processBuilder = new ProcessBuilder(command);
-        Map<String, String> env = processBuilder.environment();
-        env.put("LD_LIBRARY_PATH", "/usr/local/ffmpeg-8.0/lib");
-        env.put("PATH", env.get("PATH") + ":/usr/local/ffmpeg-8.0/bin");
         processBuilder.redirectErrorStream(true);
         Process process = processBuilder.start();
-
         // 读取命令输出(用于日志和调试)
         StringBuilder output = new StringBuilder();
         try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {