dsx 2 vuotta sitten
vanhempi
commit
3645a60150

+ 54 - 0
pom.xml

@@ -46,6 +46,7 @@
         <protobuf-java.version>3.2.0</protobuf-java.version>
         <commons-pool2.version>2.5.0</commons-pool2.version>
         <zxing.version>2.1</zxing.version>
+        <javacv.version>1.5.7</javacv.version>
     </properties>
 
     <dependencies>
@@ -63,6 +64,14 @@
                     <groupId>com.alibaba.cloud</groupId>
                     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>org.bytedeco</groupId>
+                    <artifactId>javacv</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.bytedeco</groupId>
+                    <artifactId>javacpp</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
 
@@ -82,6 +91,16 @@
             <groupId>com.fdkankan</groupId>
             <artifactId>4dkankan-utils-model</artifactId>
             <version>3.0.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.bytedeco</groupId>
+                    <artifactId>javacv</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.bytedeco</groupId>
+                    <artifactId>javacpp</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
 <!--        <dependency>-->
@@ -155,6 +174,41 @@
             <version>1.5.26</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>javacv</artifactId>
+            <version>${javacv.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>javacpp</artifactId>
+            <version>${javacv.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>opencv</artifactId>
+            <classifier>windows-x86_64</classifier>
+            <version>4.5.5-${javacv.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>openblas</artifactId>
+            <version>0.3.19-${javacv.version}</version>
+            <classifier>windows-x86_64</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>opencv</artifactId>
+            <version>4.5.5-${javacv.version}</version>
+            <classifier>linux-x86_64</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>openblas</artifactId>
+            <version>0.3.19-${javacv.version}</version>
+            <classifier>linux-x86_64</classifier>
+        </dependency>
+
 
     </dependencies>
 

+ 5 - 0
src/main/java/com/fdkankan/scene/schedule/ScheduleJob.java

@@ -39,4 +39,9 @@ public class ScheduleJob {
         sceneDownLoadService.processV3();
     }
 
+    @Scheduled(cron = "0/2 * * * * ? ")
+    public void transferTourVideo() throws Exception {
+        sceneDownLoadService.processV3();
+    }
+
 }

+ 2 - 0
src/main/java/com/fdkankan/scene/service/IDownloadTourVideoService.java

@@ -21,6 +21,8 @@ public interface IDownloadTourVideoService extends IService<DownloadTourVideo> {
 
     ResultData uploadTourVideo(String num, MultipartFile file) throws Exception;
 
+    void transferTourVideoProcess();
+
     void transferTourVideo(DownloadTourVideo downloadTourVideo);
 
     ResultData downloadTourVideo(String num);

+ 27 - 11
src/main/java/com/fdkankan/scene/service/impl/DownloadTourVideoServiceImpl.java

@@ -1,7 +1,10 @@
 package com.fdkankan.scene.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.exceptions.ExceptionUtil;
 import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.common.constant.ErrorCode;
@@ -9,10 +12,12 @@ import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
 import com.fdkankan.model.utils.CreateObjUtil;
+import com.fdkankan.redis.util.RedisUtil;
 import com.fdkankan.scene.entity.DownloadTourVideo;
 import com.fdkankan.scene.mapper.IDownloadTourVideoMapper;
 import com.fdkankan.scene.oss.OssUtil;
 import com.fdkankan.scene.service.IDownloadTourVideoService;
+import com.fdkankan.scene.util.MergeVideoUtil;
 import com.fdkankan.scene.vo.DownloadTourVideoVO;
 import com.fdkankan.web.response.ResultData;
 import org.apache.http.HttpHeaders;
@@ -22,9 +27,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 
 /**
  * <p>
@@ -37,15 +40,10 @@ import java.util.Objects;
 @Service
 public class DownloadTourVideoServiceImpl extends ServiceImpl<IDownloadTourVideoMapper, DownloadTourVideo> implements IDownloadTourVideoService {
 
-    @Value("${queue.scene.transfer-tour-video}")
-    private String downloadTourVideoQueue;
-    @Value("${fyun.type}")
-    private String type;
-    @Value("${fyun.bucket:4dkankan}")
-    private String bucket;
-
     @Autowired
     private OssUtil ossUtil;
+    @Autowired
+    private RedisUtil redisUtil;
 
     @Override
     public DownloadTourVideo getWaitingByNum(String num) {
@@ -91,11 +89,29 @@ public class DownloadTourVideoServiceImpl extends ServiceImpl<IDownloadTourVideo
 
         //发送mq
 //        rabbitMqProducer.sendByWorkQueue(downloadTourVideoQueue, downloadTourVideo);
+        redisUtil.lRightPush("transfer:tour:video", JSON.toJSONString(downloadTourVideo));
 
         return ResultData.ok();
     }
 
     @Override
+    public void transferTourVideoProcess() {
+        List<DownloadTourVideo> list = new ArrayList<>();
+        for(int i = 0; i < 8; i++){
+            String str = redisUtil.lLeftPop("transfer:tour:video");
+            if(StrUtil.isEmpty(str)){
+                continue;
+            }
+            redisUtil.lLeftPush("transfer:tour:video:ing", str);
+            list.add(JSON.parseObject(str, DownloadTourVideo.class));
+        }
+        if(CollUtil.isEmpty(list)){
+            return;
+        }
+        list.parallelStream().forEach(downloadTourVideo->this.transferTourVideo(downloadTourVideo));
+    }
+
+    @Override
     public void transferTourVideo(DownloadTourVideo downloadTourVideo) {
 
         String destPath = null;
@@ -107,7 +123,7 @@ public class DownloadTourVideoServiceImpl extends ServiceImpl<IDownloadTourVideo
                 destFile.getParentFile().mkdir();
             }
             String srcPath = downloadTourVideo.getLocalPath();
-            CreateObjUtil.formatMp4(srcPath, destPath);
+            MergeVideoUtil.ffmpegFormatMp4(srcPath, destPath);
             //上传到oss
             String ossPath = String.format(UploadFilePath.DOWNLOADS_TOUR_VIDEO, downloadTourVideo.getNum()) + downloadTourVideo.getFileName();
             Map<String, String> headers = new HashMap<>();

+ 36 - 0
src/main/java/com/fdkankan/scene/service/impl/TransferTourVideoRunnerImpl.java

@@ -0,0 +1,36 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.fdkankan.redis.util.RedisUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 应用启动校验是否有下载任务正在进行,如有过就重新入队头,从新下载
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/22
+ **/
+@Component
+public class TransferTourVideoRunnerImpl implements CommandLineRunner {
+
+    @Autowired
+    RedisUtil redisUtil;
+
+    @Override
+    public void run(String... args) throws Exception {
+        List<String> list = redisUtil.lGet("transfer:tour:video:ing", 0, -1);
+        if(CollUtil.isEmpty(list)){
+            return;
+        }
+        //删除还没执行完毕的场景缓存
+        redisUtil.del("transfer:tour:video:ing");
+
+        redisUtil.lLeftPushAll("transfer:tour:video", list);
+    }
+}

+ 189 - 0
src/main/java/com/fdkankan/scene/util/MergeVideoUtil.java

@@ -0,0 +1,189 @@
+package com.fdkankan.scene.util;
+
+import cn.hutool.core.io.FileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.bytedeco.javacpp.Loader;
+import org.bytedeco.javacv.FFmpegFrameGrabber;
+import org.bytedeco.javacv.Frame;
+import org.bytedeco.javacv.Java2DFrameConverter;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.*;
+
+/**
+ * @author Xiewj
+ * @date 2022/7/28
+ */
+@Slf4j
+public class MergeVideoUtil {
+    private volatile static String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
+
+
+    private static boolean fetchFrame(File inFile, File outFile) {
+        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(inFile);
+        try {
+            ff.start();
+            int lenght = ff.getLengthInFrames();
+            int i = 0;
+            Frame f = null;
+            while (i < lenght) {
+                // 过滤前1帧,避免出现全黑的图片,依自己情况而定
+                f = ff.grabFrame();
+                if ((i > 0) && (f.image != null)) {
+                    break;
+                }
+                i++;
+            }
+            int owidth = f.imageWidth;
+            int oheight = f.imageHeight;
+            // 对截取的帧进行等比例缩放
+            int width = 800;
+            int height = (int) (((double) width / owidth) * oheight);
+            Java2DFrameConverter converter = new Java2DFrameConverter();
+            BufferedImage fecthedImage = converter.getBufferedImage(f);
+            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
+            bi.getGraphics().drawImage(fecthedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH),
+                    0, 0, null);
+            //ff.flush();
+            return ImageIO.write(bi, "jpg", outFile);
+        } catch (Exception e) {
+            e.printStackTrace();
+            MergeVideoUtil.log.error(" 截取失败-{}", e.getMessage());
+            return false;
+        } finally {
+            try {
+                ff.stop();
+            } catch (FFmpegFrameGrabber.Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+    }
+
+    /**
+     * @param sourceFile 原文件路径
+     * @param thumbFile   目标文件路径
+     * @param thumbWidth  宽度
+     * @param thumbHigh   高度
+     * @return ffmpeg -i bb.mp4 -y -vframes 1 -vf scale=100:100/a thumb.jpg
+     */
+    public static boolean ffmpegVideoThumb(String sourceFile, String thumbFile, String thumbWidth, String thumbHigh) {
+        String cmd = MergeVideoUtil.ffmpeg + "  -i " + sourceFile + " -y -vframes 1 -vf scale=" + thumbWidth + ":" + thumbHigh + "/a " + thumbFile;
+        try {
+            MergeVideoUtil.execCommand(cmd);
+        } catch (IOException e) {
+            e.printStackTrace();
+            MergeVideoUtil.log.error(" 截图失败-{}", e.getMessage());
+            return false;
+        }
+        File file = new File(thumbFile);
+        if (!file.exists()) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @param sourceFile 原文件路径
+     * @param thumbFile   目标文件路径
+     * @param thumbWidth  宽度
+     * @param thumbHigh   高度
+     * @return ffmpeg -i bb.mp4 -y -vframes 1 -vf scale=100:100/a thumb.jpg
+     */
+    public static boolean ffmpegFormatMp4(String sourceFile, String targetFile) {
+        String cmd = MergeVideoUtil.ffmpeg + "  -i " + sourceFile + " -vcodec copy -bsf:a aac_adtstoasc -movflags +faststart " + targetFile + " -y";
+        try {
+            MergeVideoUtil.execCommand(cmd);
+        } catch (IOException e) {
+            e.printStackTrace();
+            MergeVideoUtil.log.error(" 截图失败-{}", e.getMessage());
+            return false;
+        }
+        File file = new File(targetFile);
+        if (!file.exists()) {
+            return false;
+        }
+        return true;
+    }
+
+    public static Boolean mergeVideo(List<String> fromVideoFileList, String newVideoFile) {
+        try {
+            List<String> voidTS = new ArrayList<>();
+
+            for (String fromVideoFile : fromVideoFileList) {
+                String format = "%s -y -i %s -vcodec copy -bsf:v h264_mp4toannexb -f mpegts %s";
+                String name = fromVideoFile.substring(0, fromVideoFile.lastIndexOf("."));
+                String command = String.format(format, MergeVideoUtil.ffmpeg, fromVideoFile, name + ".ts");
+                MergeVideoUtil.execCommand(command);
+                voidTS.add(name + ".ts");
+            }
+            StringBuffer tsPath = new StringBuffer();
+            tsPath.append(MergeVideoUtil.ffmpeg);
+            tsPath.append(" -i ");
+            tsPath.append("concat:");
+            for (int t = 0; t < voidTS.size(); t++) {
+                if (t != voidTS.size() - 1) {
+                    tsPath.append(voidTS.get(t) + "|");
+                } else {
+                    tsPath.append(voidTS.get(t));
+                }
+            }
+            tsPath.append(" -vcodec ");
+            tsPath.append(" copy ");
+            tsPath.append(" -bsf:a ");
+            tsPath.append(" aac_adtstoasc ");
+            tsPath.append(" -movflags ");
+            tsPath.append(" +faststart ");
+            tsPath.append(newVideoFile);
+            MergeVideoUtil.execCommand(tsPath.toString());
+            //删除生成的ts文件
+            for (String filePath : voidTS) {
+                File file = new File(filePath);
+                file.delete();
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            MergeVideoUtil.log.error(" 合并失败-{}", e.getMessage());
+            return false;
+        }
+    }
+
+    private static void execCommand(String command) throws IOException {
+        Process pr = Runtime.getRuntime().exec(command);
+        pr.getOutputStream().close();
+        pr.getInputStream().close();
+        pr.getErrorStream().close();
+        try {
+            pr.waitFor();
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        } finally {
+            pr.destroy();
+        }
+    }
+
+
+    //测试
+    public static void main(String[] args) throws Exception {//定义需要复制文件的路径
+
+        String srcPath = "H:\\mergevideo\\";
+        String destName = "mergedVideo.mp4";
+        String destFullPath = "H:\\mergevideo\\" + destName;
+        Set<String> list = new HashSet<>();
+        List<String> list1 = new LinkedList<>();
+        list1.add(srcPath + "1.mp4");
+        list1.add(srcPath + "2.mp4");
+        list1.add(srcPath + "3.mp4");
+
+        MergeVideoUtil.mergeVideo(list1, destFullPath);
+
+        MergeVideoUtil.fetchFrame(FileUtil.file(destFullPath), FileUtil.file(srcPath + "1.jpg"));
+    }
+}