wangyunpeng 2 hete
szülő
commit
21dfe85593

+ 3 - 3
core/src/main/java/com/tzld/supply/api/AigcFFmpegApiService.java → core/src/main/java/com/tzld/supply/api/FFmpegApiService.java

@@ -20,9 +20,9 @@ import java.util.List;
 
 @Slf4j
 @Component
-public class AigcFFmpegApiService {
+public class FFmpegApiService {
 
-    @Value("${ffmpeg.base.url:http://ffmpegapi.piaoquantv.com/aigc}")
+    @Value("${ffmpeg.base.url:http://ffmpegapi-supply-internal.piaoquantv.com}")
     private String FFMPEG_BASE_URL;
 
     private final CloseableHttpClient client = HttpClientFactory.create(
@@ -176,7 +176,7 @@ public class AigcFFmpegApiService {
      * @return 接口返回数据(CommonResponse.data)
      */
     private <T> T post(String endpoint, Object param, Class<T> dataType) {
-        String url = FFMPEG_BASE_URL + "/infrastructure/ffmpeg" + endpoint;
+        String url = FFMPEG_BASE_URL + "/ffmpeg" + endpoint;
         try {
             HttpPost httpPost = new HttpPost(url);
             // 设置请求体

+ 4 - 4
core/src/main/java/com/tzld/supply/handle/GlobalExceptionHandle.java

@@ -33,7 +33,7 @@ public class GlobalExceptionHandle {
             CommonException e = (CommonException) exception;
             response.setCode(e.getCode());
             response.setMsg(e.getMsg());
-            LOGGER.info("uri:" + uri + "\n" + "CustomException log.", exception);
+            LOGGER.info("uri:" + uri + "\n" + "CustomException log.", exception, exception.getMessage());
         } else if (exception instanceof MethodArgumentNotValidException) {
             // 参数校验异常
             MethodArgumentNotValidException e = (MethodArgumentNotValidException) exception;
@@ -47,7 +47,7 @@ public class GlobalExceptionHandle {
             }
             response.setCode(ExceptionEnum.PARAM_ERROR.getCode());
             response.setMsg(errorMsg.toString());
-            LOGGER.error("uri:" + uri + "\n" + "MethodArgumentNotValidException log.", exception);
+            LOGGER.error("uri:" + uri + "\n" + "MethodArgumentNotValidException log.", exception, exception.getMessage());
         } else if (exception instanceof BindException) {
             // 参数绑定异常
             BindException e = (BindException) exception;
@@ -61,11 +61,11 @@ public class GlobalExceptionHandle {
             }
             response.setCode(ExceptionEnum.PARAM_ERROR.getCode());
             response.setMsg(errorMsg.toString());
-            LOGGER.error("uri:" + uri + "\n" + "BindException log.", exception);
+            LOGGER.error("uri:" + uri + "\n" + "BindException log.", exception, exception.getMessage());
         } else {
             response.setCode(ExceptionEnum.SYSTEM_ERROR.getCode());
             response.setMsg(ExceptionEnum.SYSTEM_ERROR.getMsg());
-            LOGGER.error("uri:" + uri + "\n" + "unknownException log.", exception);
+            LOGGER.error("uri:" + uri + "\n" + "unknownException log.", exception, exception.getMessage());
         }
         return response;
     }

+ 57 - 23
core/src/main/java/com/tzld/supply/job/VideoGenerateJob.java

@@ -4,7 +4,7 @@ package com.tzld.supply.job;
 import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.tzld.supply.api.AigcFFmpegApiService;
+import com.tzld.supply.api.FFmpegApiService;
 import com.tzld.supply.api.fish.FishApiService;
 import com.tzld.supply.common.enums.ProduceVideoStatusEnum;
 import com.tzld.supply.common.enums.SpiderContentStatusEnum;
@@ -26,10 +26,12 @@ import lombok.experimental.Accessors;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Component
@@ -52,7 +54,10 @@ public class VideoGenerateJob {
     @Autowired
     private ProduceVideoMaterialMapper produceVideoMaterialMapper;
     @Autowired
-    private AigcFFmpegApiService ffmpegApiService;
+    private FFmpegApiService ffmpegApiService;
+
+    @Value("${produce.video.max.size:10}")
+    private Integer maxProduceSize;
 
     /**
      * 生成音频
@@ -68,9 +73,16 @@ public class VideoGenerateJob {
         }
         Long endTime = startTime + 86400 * 1000;
         List<SpiderContent> contentList = new ArrayList<>();
+        Integer produceCount = maxProduceSize;
         if (StringUtils.isNotBlank(param)) {
             contentList.add(spiderContentMapper.selectByPrimaryKey(Long.parseLong(param)));
         } else {
+            // 检查是否有正在处理的视频
+            Long processingCount = countProcessionVideo();
+            if (processingCount >= maxProduceSize) {
+                return ReturnT.FAIL;
+            }
+            produceCount = Math.toIntExact(produceCount - processingCount);
             contentList = spiderMapperExt.getVideoGenerateContent(SpiderContentStatusEnum.PASSED.getCode(),
                     startTime, endTime);
         }
@@ -78,6 +90,10 @@ public class VideoGenerateJob {
             return ReturnT.SUCCESS;
         }
         for (SpiderContent content : contentList) {
+            if (produceCount == 0) {
+                break;
+            }
+            produceCount--;
             // 检查是否存在模型
             List<AiModelTts> ttsList = ttsMapper.selectByExample(new AiModelTtsExample());
             // 随机选择一个模型
@@ -116,6 +132,12 @@ public class VideoGenerateJob {
         return ReturnT.SUCCESS;
     }
 
+    private Long countProcessionVideo() {
+        ProduceVideoExample example = new ProduceVideoExample();
+        example.createCriteria().andStatusEqualTo(ProduceVideoStatusEnum.PROCESSING.getCode());
+        return produceVideoMapper.countByExample(example);
+    }
+
     @Getter
     @Setter
     @Accessors(chain = true)
@@ -170,8 +192,8 @@ public class VideoGenerateJob {
 
     // 线程池
     private final ExecutorService pool = new ThreadPoolExecutor(
-            5,
-            5,
+            1,
+            1,
             0L, TimeUnit.SECONDS,
             new LinkedBlockingQueue<>(10000),
             new ThreadFactoryBuilder().setNameFormat("imageToVideo-%d").build(),
@@ -190,6 +212,7 @@ public class VideoGenerateJob {
                         String command = randomImageToVideoAnimation(image.getOssKey(), outputVideoName);
                         CommandParam commandParam = CommandParam.builder()
                                 .ffmpegCommand(command)
+                                .inputFile(image.getOssKey())
                                 .outputFile(outputVideoName)
                                 .outputType("video")
                                 .build();
@@ -219,24 +242,18 @@ public class VideoGenerateJob {
         switch (new Random().nextInt(2)) {
             // 放大
             case 0:
-                command = String.format("ffmpeg -loop 1 -i %s -filter_complex " +
-                                "\"[0:v]scale=720:1280:force_original_aspect_ratio=increase,boxblur=40:40,crop=720:1280[bg];" +
-                                "[0:v]scale=720:1280:force_original_aspect_ratio=decrease,setsar=1[fg];" +
-                                "[bg][fg]overlay=(W-w)/2:(H-h)/2,format=yuv420p[base];" +
-                                "[base]zoompan=z='min(zoom+0.003,1.3)':d=75:x='(iw/2)-(iw/zoom/2)':y='(ih/2)-(ih/zoom/2)':s=720x1280:fps=25[zoom]\" " +
-                                "-map \"[zoom]\" -t 3 -y \"%s\"",
+                command = String.format("ffmpeg -y -loop 1 -i %s -t 3 -vf " +
+                                "\"scale=720:1280:force_original_aspect_ratio=decrease,pad=720:1280:(ow-iw)/2:(oh-ih)/2:black\" " +
+                                "-c:v libx264 -pix_fmt yuv420p %s",
                         imageUrl, outputVideoName);
                 break;
             // 平移
             case 1:
                 // 背景模糊
             default:
-                command = String.format("ffmpeg -y -loop 1 -i %s -t 3 -r 25 -filter_complex " +
-                                "\"[0:v]scale=720:1280:force_original_aspect_ratio=increase,crop=720:1280,boxblur=10:1[bg];" +
-                                "[0:v]scale=720:1280:force_original_aspect_ratio=decrease,pad=720:1280:(ow-iw)/2:(oh-ih)/2:color=black@0[fg];" +
-                                "[fg]zoompan=z='min(1.00+0.0003*on,1.03)':d=75:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=720x1280[fg_anim];" +
-                                "[bg][fg_anim]overlay=0:0:format=auto,format=yuv420p\" " +
-                                "-c:v libx264 -pix_fmt yuv420p -movflags +faststart %s",
+                command = String.format("ffmpeg -y -loop 1 -i %s -t 3 -vf " +
+                                "\"scale=720:1280:force_original_aspect_ratio=decrease,pad=720:1280:(ow-iw)/2:(oh-ih)/2:black\" " +
+                                "-c:v libx264 -pix_fmt yuv420p %s",
                         imageUrl, outputVideoName);
         }
         return command;
@@ -282,7 +299,7 @@ public class VideoGenerateJob {
                             String endTime = formatSecondsToTime(endSeconds);
                             // 截取视频片段
                             VideoTimeCutParam timeCutParam = VideoTimeCutParam.builder()
-                                    .videoUrl(video.getUrl())
+                                    .videoUrl(video.getOssKey())
                                     .startTime(lastEndTime)
                                     .endTime(endTime)
                                     .build();
@@ -362,15 +379,20 @@ public class VideoGenerateJob {
             return ReturnT.SUCCESS;
         }
         for (ProduceVideo produceVideo : produceList) {
-            // 检查是否存在素材
+            // 检查是否存在素材 todo 判断素材是否生成完成
+            List<SpiderContentMedia> mediaList = getSpiderContentMediaByContentId(produceVideo.getContentId());
+            Integer totalMediaSize = mediaList.size();
             List<ProduceVideoMaterial> materialList = getVideoMaterialList(produceVideo);
-            if (materialList.size() < 10) {
+            List<Long> existMediaIds = materialList.stream().map(ProduceVideoMaterial::getSourceMediaId).collect(Collectors.toList());
+            mediaList.removeIf(o -> existMediaIds.contains(o.getId()));
+            if (materialList.size() < 10 || (mediaList.size() * 1.0 / totalMediaSize) > 0.2) {
                 continue;
             }
             ProduceVideoAudio audio = getProduceAudio(produceVideo);
             if (audio == null) {
                 continue;
             }
+            audio.setDuration(audio.getDuration() + 500);
             // short video to long video
             // 视频素材拼接长视频 随机排序
             Collections.shuffle(materialList);
@@ -381,11 +403,14 @@ public class VideoGenerateJob {
                     .pretreatmentSwitch(1)
                     .build();
             String concatVideoUrl = ffmpegApiService.videoConcat(concatParam);
+            if (StringUtils.isBlank(concatVideoUrl)) {
+                continue;
+            }
             // 按音频时长剪切
             VideoTimeCutParam timeCutParam = VideoTimeCutParam.builder()
                     .videoUrl(concatVideoUrl)
                     .startTime("00:00:00")
-                    .endTime(formatSecondsToTime(audio.getDuration() / 1000))
+                    .endTime(formatSecondsToTime(audio.getDuration() / 1000 ))
                     .build();
             String cutVideoUrl = ffmpegApiService.timeCutVideo(timeCutParam);
             // add audio
@@ -394,6 +419,7 @@ public class VideoGenerateJob {
                     cutVideoUrl, audio.getUrl(), videoName);
             CommandParam commandParam = CommandParam.builder()
                     .ffmpegCommand(command)
+                    .inputFile(cutVideoUrl)
                     .outputFile(videoName)
                     .outputType("video")
                     .build();
@@ -401,13 +427,21 @@ public class VideoGenerateJob {
             String fileName = String.format("supply/produce/video/%s", videoName);
             String finalVideoUrl = AliOssFileTool.downloadAndSaveInOSS(fileName, commandResponseData, "video/mp4");
             // 更新视频地址
-            produceVideo.setUrl(finalVideoUrl);
-            produceVideo.setStatus(ProduceVideoStatusEnum.PASSED.getCode());
-            produceVideoMapper.updateByPrimaryKeySelective(produceVideo);
+            if (StringUtils.isNotBlank(finalVideoUrl)) {
+                produceVideo.setUrl(finalVideoUrl);
+                produceVideo.setStatus(ProduceVideoStatusEnum.PASSED.getCode());
+                produceVideoMapper.updateByPrimaryKeySelective(produceVideo);
+            }
         }
         return ReturnT.SUCCESS;
     }
 
+    private List<SpiderContentMedia> getSpiderContentMediaByContentId(Long contentId) {
+        SpiderContentMediaExample example = new SpiderContentMediaExample();
+        example.createCriteria().andContentIdEqualTo(contentId).andStatusEqualTo(1);
+        return spiderContentMediaMapper.selectByExample(example);
+    }
+
     private List<String> selectMaterial(List<ProduceVideoMaterial> materialList, ProduceVideoAudio audio) {
         Integer duration = audio.getDuration();
         List<String> videoUrls = new ArrayList<>();

+ 1 - 0
core/src/main/java/com/tzld/supply/model/param/FFmpeg/CommandParam.java

@@ -9,6 +9,7 @@ import lombok.Setter;
 @Builder
 public class CommandParam {
     private String ffmpegCommand;
+    private String inputFile;
     private String outputFile;
     // video audio image text unknown
     private String outputType;

+ 3 - 0
core/src/main/java/com/tzld/supply/util/AliOssFileTool.java

@@ -1494,6 +1494,9 @@ public class AliOssFileTool extends AliOssConfig {
 
     public static String downloadAndSaveInOSS(String fileName, String url, String contentType) {
         try {
+            if (url.startsWith(CdnUtil.VIDEO_CDN_URL_HOST)) {
+                return url;
+            }
             byte[] fileData = HttpUtil.downloadBytes(url);
             if (fileData == null || fileData.length == 0) {
                 log.warn("下载media失败,URL: {}", url);