shenrongliang
2025-04-03 0e7b0e885872459ad27492e84c0dce43a92a465e
配置修改,合成视频
已修改2个文件
90 ■■■■ 文件已修改
easegen-front/src/views/chooseTemplate/index.vue 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java 75 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/chooseTemplate/index.vue
@@ -1560,14 +1560,15 @@
            warningStrArr.push(
              `场景<span style="color: red; font-weight: bold;">${i + 1}</span>无有效的口播内容`
            )
          } else {
            //判断去除标签后的内容长度是否超过2000字
            if (plainText.length > 2000) {
              warningStrArr.push(
                `场景<span style="color: red; font-weight: bold;">${i + 1}</span>口播内容超过2000字,请减少或拆分场景`
              )
            }
          }
          // else {
          //   //判断去除标签后的内容长度是否超过2000字
          //   if (plainText.length > 2000) {
          //     warningStrArr.push(
          //       `场景<span style="color: red; font-weight: bold;">${i + 1}</span>口播内容超过2000字,请减少或拆分场景`
          //     )
          //   }
          // }
        }
      }
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java
@@ -26,16 +26,15 @@
import org.springframework.validation.annotation.Validated;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -97,7 +96,7 @@
        AuditionVO auditionVO = new AuditionVO();
        auditionVO.setHumanId(String.valueOf(digitalHumansDO.getId()));
        for (AppCourseScenesMegerReqVO scene : scenes) {
            //TODO 先判断是否有备注内容
            auditionVO.setText(scene.getBackground().getPptRemark());
            String audition = serviceImpl.audition(auditionVO);
            // 提取音频文件名(路径的最后一部分)
@@ -107,32 +106,58 @@
            // 提取视频文件名(路径的最后一部分)
            String substring1 = configApi.getConfigValueByKey("easegen.url") + digitalHumansDO.getFixVideoUrl().substring(digitalHumansDO.getFixVideoUrl().lastIndexOf("/"));
            String fileName1 = digitalHumansDO.getFixVideoUrl().substring(digitalHumansDO.getFixVideoUrl().lastIndexOf('/') + 1);
            String newFileName1 = "D:/heygem_data/face2face/temp/" + fileName1;
            String newFileName1 = "D:/heygem_data/face2face/temp/"+fileName1;
            //获取时间戳
            Date date = new Date();
            long timestamp = date.getTime();
            String newFileName2 = "D:/heygem_data/face2face/temp/"+timestamp+".mp4";
            //获取PPT内容
            String cover = scene.getComponents().get(1).getCover();
            String cover = scene.getComponents().get(1).getSrc();
            cover = configApi.getConfigValueByKey("easegen.url") + scene.getComponents().get(1).getSrc().substring(scene.getComponents().get(1).getSrc().lastIndexOf("/"));
            //获取背景
            String cover1 = scene.getBackground().getCover();
            cover1 = configApi.getConfigValueByKey("easegen.url") + scene.getBackground().getCover().substring(scene.getBackground().getCover().lastIndexOf("/"));
            // 去掉扩展名
            int dotIndex = fileName1.lastIndexOf('.');
            String substring2 = fileName1.substring(0, dotIndex);
            // 合成ppt背景,视频,模板
            //ffmpeg -i 2.png -i 1.mp4 -filter_complex "[0:v]scale=w=ceil(iw/2)*2:h=ceil(ih/2)*2[bg];[1:v]scale=iw/2:ih/2[v1];[bg][v1]overlay=x=0:y=H-h" output.mp4
            ProcessBuilder builder = new ProcessBuilder(
                    "ffmpeg", "-i", cover1,"-i",cover,"-i",substring1,"-filter_complex","[0:v]scale=",scene.getBackground().getWidth().toString(),":",scene.getBackground().getHeight().toString(),"[bg];[1:v]scale=",scene.getComponents().get(1).getWidth().toString(),":",scene.getComponents().get(1).getHeight().toString(),"[v1];[bg][v1]overlay=x=",scene.getComponents().get(1).getMarginLeft().toString(),":y=",scene.getComponents().get(1).getTop().toString(),"[img];[2:v]scale=",scene.getComponents().get(0).getWidth().toString(),":",scene.getComponents().get(0).getHeight().toString(),"[v2];[img][v2]overlay=x=",scene.getComponents().get(0).getMarginLeft().toString(),":y=",scene.getComponents().get(0).getTop().toString(),newFileName1
                    "ffmpeg",
                    "-i", cover1,
                    "-i", cover,
                    "-i", substring1,
                    "-filter_complex",
                    "[0:v]scale=" + Math.round(scene.getBackground().getWidth()) + ":" + Math.round(scene.getBackground().getHeight()) + "[bg];" +
                            "[1:v]scale=" + Math.round(scene.getComponents().get(1).getWidth()) + ":" + Math.round(scene.getComponents().get(1).getHeight()) + "[v1];" +
                            "[bg][v1]overlay=x=" + Math.round(scene.getComponents().get(1).getMarginLeft()) + ":y=" + Math.round(scene.getComponents().get(1).getTop()) + "[img];" +
                            "[2:v]scale=" + Math.round(scene.getComponents().get(0).getWidth()) + ":" + Math.round(scene.getComponents().get(0).getHeight()) + "[v2];" +
                            "[img][v2]overlay=x=" + Math.round(scene.getComponents().get(0).getMarginLeft()) + ":y=" + Math.round(scene.getComponents().get(0).getTop()),
                    newFileName2
            );
            System.out.println(newFileName2);
            builder.redirectErrorStream(true);
            Process process = null;
            try {
                process = builder.start();
                // 读取 FFmpeg 输出(可选)
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                System.out.println(builder.command());
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            // 读取 FFmpeg 输出(可选)
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            try {
                Files.copy(Path.of(substring), Path.of(newFileName), StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            //最大重试次数
            int maxRetries = 3;
            // 当前重试次数
@@ -145,8 +170,8 @@
                    HashMap<String, Object> objectObjectHashMap = new HashMap<>();
                    //音频路径
                    objectObjectHashMap.put("audio_url", fileName);
                    //视频路径(无声)
                    objectObjectHashMap.put("video_url", fileName1);
                    //视频路径
                    objectObjectHashMap.put("video_url",timestamp+".mp4");
                    //唯一key(用于查询)
                    String code = RandomUtil.randomString(32);
                    //固定值
@@ -191,10 +216,10 @@
                    String result = getResult(code);
                    result = "D:/heygem_data/face2face/temp" + result;
                    videoUrls.add(result);
                    System.out.println("驱动视频名"+result);
                    // 如果成功,更新状态为1(成功)
                    courseMediaDO.setStatus(1);
                    courseMediaMapper.updateById(courseMediaDO);
                    success = true;
                } catch (Exception e) {
                    retryCount++;
                    if (retryCount >= maxRetries) {
@@ -213,7 +238,9 @@
                        break;
                    }
                }
                success = true;
            }
        }
        String fileListPath = "D:/heygem_data/face2face/temp/filelist.txt";
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileListPath))) {
@@ -224,13 +251,24 @@
        } catch (IOException e) {
            e.printStackTrace();
        }
        //去掉updateReqVO.getName()中的空格和特殊字符
        String newFileName = updateReqVO.getName().replaceAll("[\\s\\p{Punct}]", "");
        ProcessBuilder builder = new ProcessBuilder(
                "ffmpeg", "-f", "concat", "-safe","0", "-i", "DD:/heygem_data/face2face/temp/filelist.txt", "-c", "copy", "D:/heygem_data/face2face/temp/生成视频.mp4"
                "ffmpeg", "-f", "concat", "-safe","0", "-i",fileListPath , "-c", "copy", "D:/heygem_data/face2face/temp/"+"111111.mp4"
        );
        builder.redirectErrorStream(true);
        Process process = null;
        try {
            process = builder.start();
            // 读取 FFmpeg 输出(可选)
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            System.out.println(builder.command());
            System.out.println("最终视频已生成");
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
@@ -238,6 +276,13 @@
    }
    // 四舍五入方法
    private static int round(double value) {
        return BigDecimal.valueOf(value)
                .setScale(0, RoundingMode.HALF_UP)
                .intValue();
    }
    public String getResult(String taskCode) {
        // 使用 do-while 循环轮询任务状态
        // 定义变量存储返回结果