Explorar o código

视频模板合并代码调试

syh %!s(int64=5) %!d(string=hai) anos
pai
achega
8c66934a08
Modificáronse 43 ficheiros con 2541 adicións e 349 borrados
  1. 9 3
      jeecg-boot-module-system/pom.xml
  2. 0 4
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IFfmpegService.java
  3. 0 140
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/FfmpegServiceImpl.java
  4. 0 83
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/VideoProcessing.java
  5. 164 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoCompositeInfoController.java
  6. 176 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoInfoConfigController.java
  7. 180 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoInfoController.java
  8. 248 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoInfoTagController.java
  9. 63 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoCompositeInfo.java
  10. 76 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoInfo.java
  11. 117 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoInfoConfig.java
  12. 73 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoInfoTag.java
  13. 15 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoCompositeInfoMapper.java
  14. 15 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoInfoConfigMapper.java
  15. 15 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoInfoMapper.java
  16. 15 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoInfoTagMapper.java
  17. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoCompositeInfoMapper.xml
  18. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoInfoConfigMapper.xml
  19. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoInfoMapper.xml
  20. 5 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoInfoTagMapper.xml
  21. 19 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IFfmpegService.java
  22. 15 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoCompositeInfoService.java
  23. 16 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoInfoConfigService.java
  24. 15 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoInfoService.java
  25. 15 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoInfoTagService.java
  26. 369 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/FfmpegServiceImpl.java
  27. 19 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoCompositeInfoServiceImpl.java
  28. 27 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoInfoConfigServiceImpl.java
  29. 19 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoInfoServiceImpl.java
  30. 19 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoInfoTagServiceImpl.java
  31. 282 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/utils/Avutils.java
  32. 181 35
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/CornerCheck.java
  33. 126 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/utils/ImageUtils.java
  34. 4 7
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Perspective.java
  35. 23 16
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Test.java
  36. 101 0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/utils/VideoProcessing.java
  37. 2 1
      jeecg-boot-module-system/src/main/resources/application-prod.yml
  38. 8 15
      jeecg-boot-module-system/src/test/java/org/jeecg/SampleTest.java
  39. 6 0
      module-common/src/main/java/cn/com/ctop/common/module/utils/LoadFileUtil.java
  40. 73 42
      module-common/src/main/java/cn/com/ctop/common/module/utils/OSSUtils.java
  41. 2 1
      module-common/src/main/java/cn/com/ctop/common/module/utils/StatusCode.java
  42. 1 1
      module-common/src/main/resources/config.properties
  43. 13 1
      module-kuaishou/src/main/resources/kuaishou_config.properties

+ 9 - 3
jeecg-boot-module-system/pom.xml

@@ -175,10 +175,16 @@
             <version>3.17</version>
         </dependency>-->
         <!--<dependency>
-            <groupId>cn.com.ctop</groupId>
-            <artifactId>moudule-opencv</artifactId>
-            <version>4.20.0</version>
+            <groupId>com.test</groupId>
+            <artifactId>opencv</artifactId>
+            <scope>system</scope>
+            <systemPath>${basedir}/docs/opencv-420.jar</systemPath>
         </dependency>-->
+        <dependency>
+            <groupId>cn.com.ctop</groupId>
+            <artifactId>opencv</artifactId>
+            <version>4.2.0</version>
+        </dependency>
     </dependencies>
 
     <dependencyManagement>

+ 0 - 4
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/IFfmpegService.java

@@ -1,4 +0,0 @@
-package org.jeecg.modules.ctop.service;
-
-public interface IFfmpegService {
-}

+ 0 - 140
jeecg-boot-module-system/src/main/java/org/jeecg/modules/ctop/service/impl/FfmpegServiceImpl.java

@@ -1,140 +0,0 @@
-package org.jeecg.modules.ctop.service.impl;
-
-import lombok.extern.slf4j.Slf4j;
-import org.jeecg.modules.ctop.service.IFfmpegService;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Service
-@Slf4j
-public class FfmpegServiceImpl implements IFfmpegService {
-    /**
-     * FFmpeg全路径
-     */
-    @Value("${jeecg.ffmpeg.bin}")
-    private String FFMPEG_PATH;
-
-    /**
-     * 从视频中抽取音频文件
-     */
-    public void getM4aFromMp4(String videoPath, String m4apath) {
-        /**
-         * D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\video.mp4 -vn -y -acodec copy D:\data\test\\video.m4a
-         */
-        List<String> command = new ArrayList<>();
-        command.add(FFMPEG_PATH);
-        command.add("-i");
-        command.add(videoPath);
-        command.add("-vn");
-        command.add("-y");
-        command.add("-acodec");
-        command.add("copy");
-        command.add(m4apath);
-        runCommand(command);
-    }
-
-    /**
-     * 截取音频文件
-     */
-    public void cutM4a(String srcPath, String targetPath, String startSecond, String endSecond) {
-        /**
-         *D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\video.m4a -vn -acodec copy -ss 00:00:00.000 -t 00:00:08.000 D:\data\test\\cut.m4a
-         */
-        List<String> command = new ArrayList<>();
-        command.add(FFMPEG_PATH);
-        command.add("-i");
-        command.add(srcPath);
-        command.add("-vn");
-        command.add("-acodec");
-        command.add("copy");
-        command.add("-ss");
-        command.add(startSecond);
-        command.add("-t");
-        command.add(endSecond);
-        command.add(targetPath);
-        runCommand(command);
-    }
-
-    /**
-     * 音频拼接
-     * D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\cut.m4a -i D:\data\test\\fill.m4a -filter_complex "[0:0] [1:0] concat=n=2:v=0:a=1 [a]" -map [a] D:\data\test\\final.m4a
-     */
-    public void audioMosaic(String audioPart1, String audioPart2, String finalAudio) {
-        List<String> command = new ArrayList<>();
-        command.add(FFMPEG_PATH);
-        command.add("-i");
-        command.add(audioPart1);
-        command.add("-i");
-        command.add(audioPart2);
-        command.add("-filter_complex");
-        command.add("\"[0:0] [1:0] concat=n=2:v=0:a=1 [a]\"");
-        command.add("-map");
-        command.add("[a]");
-        command.add(finalAudio);
-        runCommand(command);
-    }
-
-    /**
-     * 音频+视频合成视频
-     *
-     * @param srcVideoPath
-     * @param srcAudioPath
-     * @param finalVideoPath D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\merge.mp4 -i D:\data\test\\final.m4a -c:v copy -c:a aac -strict experimental D:\data\test\\final.mp4
-     */
-    public void mergeAudioAndVideo(String srcVideoPath, String srcAudioPath, String finalVideoPath) {
-        List<String> command = new ArrayList<>();
-        command.add(FFMPEG_PATH);
-        command.add("-i");
-        command.add(srcVideoPath);
-        command.add("-i");
-        command.add(srcAudioPath);
-        command.add("-c:v");
-        command.add("copy");
-        command.add("-c:a");
-        command.add("aac");
-        command.add("-strict");
-        command.add("experimental");
-        command.add(finalVideoPath);
-        runCommand(command);
-    }
-
-    /**
-     * D:\java\ffmpeg\bin\ffmpeg.exe -f image2 -i D:\\data\\video\\%d.jpg  -vcodec libx264 -r 25  D:\\data\\merge.mp4
-     *
-     * @param imagePath
-     * @param frameNumber
-     * @param videoFilePath
-     */
-    public void MergeImageToVideo(String imagePath, Integer frameNumber, String videoFilePath) {
-        List<String> command = new ArrayList<>();
-        command.add(FFMPEG_PATH);
-        command.add("-i");
-        command.add("image2");
-        command.add("-i");
-        command.add(imagePath + "%d.jpg");
-        command.add("-vcodec");
-        command.add("copy");
-        command.add("libx264");
-        command.add("-r");
-        command.add(frameNumber + "");
-        command.add(videoFilePath);
-        runCommand(command);
-    }
-
-    private void runCommand(List<String> command) {
-        try {
-            ProcessBuilder builder = new ProcessBuilder();
-            builder.command(command);
-            builder.redirectErrorStream(true);
-            Process process = builder.start();
-            // 等待进程执行结束
-            process.waitFor();
-            log.info("ffmpeg命令执行完成");
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}

+ 0 - 83
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/VideoProcessing.java

@@ -1,83 +0,0 @@
-
-package org.jeecg.modules.demo.opencv;
-
-import org.bytedeco.javacv.FFmpegFrameGrabber;
-import org.bytedeco.javacv.Frame;
-import org.bytedeco.javacv.Java2DFrameConverter;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.File;
-
-/**
- * 视频截帧处理
- */
-public class VideoProcessing {
-    public static String videoPath = "D:/data";
-
-    //存放截取视频某一帧的图片
-    public static String videoFramesPath = "D:/data/images/";
-
-    /**
-     * 将视频文件帧处理并以“jpg”格式进行存储。
-     * 依赖FrameToBufferedImage方法:将frame转换为bufferedImage对象
-     *
-     * @param videoFileName
-     */
-
-    public static String grabberVideoFramer(String videoFileName) {
-        //最后获取到的视频的图片的路径
-        String videPicture = "";
-        //Frame对象
-        Frame frame = null;
-        //标识
-        int flag = 0;
-        try {
-
-            /*
-            获取视频文件
-            */
-
-            FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoPath + "/" + videoFileName);
-            fFmpegFrameGrabber.start();
-
-            //获取视频总帧数
-            int ftp = fFmpegFrameGrabber.getLengthInFrames();
-
-            while (flag <= ftp) {
-                frame = fFmpegFrameGrabber.grabImage();
-
-                /*
-				对视频的第五帧进行处理
-				 */
-
-                if (frame != null) {
-                    //文件绝对路径+名字
-                    String fileName = videoFramesPath + String.valueOf(flag) + ".jpg";
-
-                    //文件储存对象
-                    File outPut = new File(fileName);
-                    ImageIO.write(FrameToBufferedImage(frame), "jpg", outPut);
-                }
-                flag++;
-            }
-            fFmpegFrameGrabber.stop();
-            fFmpegFrameGrabber.close();
-        } catch (Exception E) {
-            E.printStackTrace();
-        }
-        return videPicture;
-    }
-
-    public static BufferedImage FrameToBufferedImage(Frame frame) {
-        //创建BufferedImage对象
-        Java2DFrameConverter converter = new Java2DFrameConverter();
-        BufferedImage bufferedImage = converter.getBufferedImage(frame);
-        return bufferedImage;
-    }
-
-    public static void main(String[] args) {
-        String videoFileName = "video.mp4";
-        grabberVideoFramer(videoFileName);
-    }
-}

+ 164 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoCompositeInfoController.java

@@ -0,0 +1,164 @@
+package org.jeecg.modules.opencv.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.opencv.entity.ModelVideoCompositeInfo;
+import org.jeecg.modules.opencv.service.IModelVideoCompositeInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+
+/**
+ * 模板合成视频
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Slf4j
+@Api(tags = "模板合成视频")
+@RestController
+@RequestMapping("/ctop/modelVideoCompositeInfo")
+public class ModelVideoCompositeInfoController {
+    @Autowired
+    private IModelVideoCompositeInfoService modelVideoCompositeInfoService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param modelVideoCompositeInfo
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @AutoLog(value = "模板合成视频-分页列表查询")
+    @ApiOperation(value = "模板合成视频-分页列表查询", notes = "模板合成视频-分页列表查询")
+    @GetMapping(value = "/list")
+    public Result<IPage<ModelVideoCompositeInfo>> queryPageList(ModelVideoCompositeInfo modelVideoCompositeInfo,
+                                                                @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                                HttpServletRequest req) {
+        Result<IPage<ModelVideoCompositeInfo>> result = new Result<IPage<ModelVideoCompositeInfo>>();
+        QueryWrapper<ModelVideoCompositeInfo> queryWrapper = QueryGenerator.initQueryWrapper(modelVideoCompositeInfo, req.getParameterMap());
+        Page<ModelVideoCompositeInfo> page = new Page<ModelVideoCompositeInfo>(pageNo, pageSize);
+        IPage<ModelVideoCompositeInfo> pageList = modelVideoCompositeInfoService.page(page, queryWrapper);
+        result.setSuccess(true);
+        result.setResult(pageList);
+        return result;
+    }
+
+    /**
+     * 添加
+     *
+     * @param modelVideoCompositeInfo
+     * @return
+     */
+    @AutoLog(value = "模板合成视频-添加")
+    @ApiOperation(value = "模板合成视频-添加", notes = "模板合成视频-添加")
+    @PostMapping(value = "/add")
+    public Result<ModelVideoCompositeInfo> add(@RequestBody ModelVideoCompositeInfo modelVideoCompositeInfo) {
+        Result<ModelVideoCompositeInfo> result = new Result<ModelVideoCompositeInfo>();
+        try {
+            modelVideoCompositeInfoService.save(modelVideoCompositeInfo);
+            result.success("添加成功!");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("操作失败");
+        }
+        return result;
+    }
+
+    /**
+     * 编辑
+     *
+     * @param modelVideoCompositeInfo
+     * @return
+     */
+    @AutoLog(value = "模板合成视频-编辑")
+    @ApiOperation(value = "模板合成视频-编辑", notes = "模板合成视频-编辑")
+    @PutMapping(value = "/edit")
+    public Result<ModelVideoCompositeInfo> edit(@RequestBody ModelVideoCompositeInfo modelVideoCompositeInfo) {
+        Result<ModelVideoCompositeInfo> result = new Result<ModelVideoCompositeInfo>();
+        ModelVideoCompositeInfo modelVideoCompositeInfoEntity = modelVideoCompositeInfoService.getById(modelVideoCompositeInfo.getId());
+        if (modelVideoCompositeInfoEntity == null) {
+            result.error500("未找到对应实体");
+        } else {
+            boolean ok = modelVideoCompositeInfoService.updateById(modelVideoCompositeInfo);
+            if (ok) {
+                result.success("修改成功!");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "模板合成视频-通过id删除")
+    @ApiOperation(value = "模板合成视频-通过id删除", notes = "模板合成视频-通过id删除")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        try {
+            modelVideoCompositeInfoService.removeById(id);
+        } catch (Exception e) {
+            log.error("删除失败", e.getMessage());
+            return Result.error("删除失败!");
+        }
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @AutoLog(value = "模板合成视频-批量删除")
+    @ApiOperation(value = "模板合成视频-批量删除", notes = "模板合成视频-批量删除")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<ModelVideoCompositeInfo> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        Result<ModelVideoCompositeInfo> result = new Result<ModelVideoCompositeInfo>();
+        if (ids == null || "".equals(ids.trim())) {
+            result.error500("参数不识别!");
+        } else {
+            this.modelVideoCompositeInfoService.removeByIds(Arrays.asList(ids.split(",")));
+            result.success("删除成功!");
+        }
+        return result;
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "模板合成视频-通过id查询")
+    @ApiOperation(value = "模板合成视频-通过id查询", notes = "模板合成视频-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<ModelVideoCompositeInfo> queryById(@RequestParam(name = "id", required = true) String id) {
+        Result<ModelVideoCompositeInfo> result = new Result<ModelVideoCompositeInfo>();
+        ModelVideoCompositeInfo modelVideoCompositeInfo = modelVideoCompositeInfoService.getById(id);
+        if (modelVideoCompositeInfo == null) {
+            result.error500("未找到对应实体");
+        } else {
+            result.setResult(modelVideoCompositeInfo);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+}

+ 176 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoInfoConfigController.java

@@ -0,0 +1,176 @@
+package org.jeecg.modules.opencv.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoConfig;
+import org.jeecg.modules.opencv.service.IFfmpegService;
+import org.jeecg.modules.opencv.service.IModelVideoInfoConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * 模板视频配置信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Slf4j
+@Api(tags = "模板视频配置信息")
+@RestController
+@RequestMapping("/ctop/modelVideoInfoConfig")
+public class ModelVideoInfoConfigController {
+    @Autowired
+    private IModelVideoInfoConfigService modelVideoInfoConfigService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param modelVideoInfoConfig
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @AutoLog(value = "模板视频配置信息-分页列表查询")
+    @ApiOperation(value = "模板视频配置信息-分页列表查询", notes = "模板视频配置信息-分页列表查询")
+    @GetMapping(value = "/list")
+    public Result<IPage<ModelVideoInfoConfig>> queryPageList(ModelVideoInfoConfig modelVideoInfoConfig,
+                                                             @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                             @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                             HttpServletRequest req) {
+        Result<IPage<ModelVideoInfoConfig>> result = new Result<IPage<ModelVideoInfoConfig>>();
+        QueryWrapper<ModelVideoInfoConfig> queryWrapper = QueryGenerator.initQueryWrapper(modelVideoInfoConfig, req.getParameterMap());
+        Page<ModelVideoInfoConfig> page = new Page<ModelVideoInfoConfig>(pageNo, pageSize);
+        IPage<ModelVideoInfoConfig> pageList = modelVideoInfoConfigService.page(page, queryWrapper);
+        result.setSuccess(true);
+        result.setResult(pageList);
+        return result;
+    }
+
+    @RequestMapping("/videoMerge")
+    public Map<String, Object> videoMerge(@RequestBody JSONObject data) {
+        System.out.println(data.toJSONString());
+        return ffmpegService.videoMerge(data);
+    }
+
+    @Autowired
+    IFfmpegService ffmpegService;
+
+    /**
+     * 添加
+     *
+     * @param modelVideoInfoConfig
+     * @return
+     */
+    @AutoLog(value = "模板视频配置信息-添加")
+    @ApiOperation(value = "模板视频配置信息-添加", notes = "模板视频配置信息-添加")
+    @PostMapping(value = "/add")
+    public Result<ModelVideoInfoConfig> add(@RequestBody ModelVideoInfoConfig modelVideoInfoConfig) {
+        Result<ModelVideoInfoConfig> result = new Result<ModelVideoInfoConfig>();
+        try {
+            modelVideoInfoConfigService.save(modelVideoInfoConfig);
+            result.success("添加成功!");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("操作失败");
+        }
+        return result;
+    }
+
+    /**
+     * 编辑
+     *
+     * @param modelVideoInfoConfig
+     * @return
+     */
+    @AutoLog(value = "模板视频配置信息-编辑")
+    @ApiOperation(value = "模板视频配置信息-编辑", notes = "模板视频配置信息-编辑")
+    @PutMapping(value = "/edit")
+    public Result<ModelVideoInfoConfig> edit(@RequestBody ModelVideoInfoConfig modelVideoInfoConfig) {
+        Result<ModelVideoInfoConfig> result = new Result<ModelVideoInfoConfig>();
+        ModelVideoInfoConfig modelVideoInfoConfigEntity = modelVideoInfoConfigService.getById(modelVideoInfoConfig.getId());
+        if (modelVideoInfoConfigEntity == null) {
+            result.error500("未找到对应实体");
+        } else {
+            boolean ok = modelVideoInfoConfigService.updateById(modelVideoInfoConfig);
+            if (ok) {
+                result.success("修改成功!");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "模板视频配置信息-通过id删除")
+    @ApiOperation(value = "模板视频配置信息-通过id删除", notes = "模板视频配置信息-通过id删除")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        try {
+            modelVideoInfoConfigService.removeById(id);
+        } catch (Exception e) {
+            log.error("删除失败", e.getMessage());
+            return Result.error("删除失败!");
+        }
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @AutoLog(value = "模板视频配置信息-批量删除")
+    @ApiOperation(value = "模板视频配置信息-批量删除", notes = "模板视频配置信息-批量删除")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<ModelVideoInfoConfig> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        Result<ModelVideoInfoConfig> result = new Result<ModelVideoInfoConfig>();
+        if (ids == null || "".equals(ids.trim())) {
+            result.error500("参数不识别!");
+        } else {
+            this.modelVideoInfoConfigService.removeByIds(Arrays.asList(ids.split(",")));
+            result.success("删除成功!");
+        }
+        return result;
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "模板视频配置信息-通过id查询")
+    @ApiOperation(value = "模板视频配置信息-通过id查询", notes = "模板视频配置信息-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<ModelVideoInfoConfig> queryById(@RequestParam(name = "id", required = true) String id) {
+        Result<ModelVideoInfoConfig> result = new Result<ModelVideoInfoConfig>();
+        ModelVideoInfoConfig modelVideoInfoConfig = modelVideoInfoConfigService.getById(id);
+        if (modelVideoInfoConfig == null) {
+            result.error500("未找到对应实体");
+        } else {
+            result.setResult(modelVideoInfoConfig);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+}

+ 180 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoInfoController.java

@@ -0,0 +1,180 @@
+package org.jeecg.modules.opencv.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.opencv.entity.ModelVideoInfo;
+import org.jeecg.modules.opencv.service.IModelVideoInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+
+/**
+ * 模板视频信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Slf4j
+@Api(tags = "模板视频信息")
+@RestController
+@RequestMapping("/ctop/modelVideoInfo")
+public class ModelVideoInfoController {
+    @Autowired
+    private IModelVideoInfoService modelVideoInfoService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param modelVideoInfo
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @AutoLog(value = "模板视频信息-分页列表查询")
+    @ApiOperation(value = "模板视频信息-分页列表查询", notes = "模板视频信息-分页列表查询")
+    @GetMapping(value = "/list")
+    public Result<IPage<ModelVideoInfo>> queryPageList(ModelVideoInfo modelVideoInfo,
+                                                       @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                       @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                       HttpServletRequest req) {
+        Result<IPage<ModelVideoInfo>> result = new Result<>();
+        String title = modelVideoInfo.getTitle();
+        modelVideoInfo.setTitle(null);
+        Integer orderType = modelVideoInfo.getOrderType();
+        modelVideoInfo.setOrderType(null);
+        QueryWrapper<ModelVideoInfo> queryWrapper = QueryGenerator.initQueryWrapper(modelVideoInfo, req.getParameterMap());
+        if (null != orderType && orderType == 1) {
+            queryWrapper.orderByDesc("model_type", "id");
+        } else if (orderType == 2) {
+            queryWrapper.orderByDesc("id");
+        }
+        if (null != title && !title.trim().equals("")) {
+            queryWrapper.like("title", title);
+        }
+        Page<ModelVideoInfo> page = new Page<>(pageNo, pageSize);
+        IPage<ModelVideoInfo> pageList = modelVideoInfoService.page(page, queryWrapper);
+        result.setSuccess(true);
+        result.setResult(pageList);
+        return result;
+    }
+
+
+    /**
+     * 添加
+     *
+     * @param modelVideoInfo
+     * @return
+     */
+    @AutoLog(value = "模板视频信息-添加")
+    @ApiOperation(value = "模板视频信息-添加", notes = "模板视频信息-添加")
+    @PostMapping(value = "/add")
+    public Result<ModelVideoInfo> add(@RequestBody ModelVideoInfo modelVideoInfo) {
+        Result<ModelVideoInfo> result = new Result<>();
+        try {
+            modelVideoInfo.setModelVideoUrl("https:" + modelVideoInfo.getModelVideoUrl());
+            modelVideoInfo.setStatus(1);
+            modelVideoInfo.setModelType(1);
+            modelVideoInfoService.save(modelVideoInfo);
+            result.success("添加成功!");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("操作失败");
+        }
+        return result;
+    }
+
+    /**
+     * 编辑
+     *
+     * @param modelVideoInfo
+     * @return
+     */
+    @AutoLog(value = "模板视频信息-编辑")
+    @ApiOperation(value = "模板视频信息-编辑", notes = "模板视频信息-编辑")
+    @PutMapping(value = "/edit")
+    public Result<ModelVideoInfo> edit(@RequestBody ModelVideoInfo modelVideoInfo) {
+        Result<ModelVideoInfo> result = new Result<>();
+        ModelVideoInfo modelVideoInfoEntity = modelVideoInfoService.getById(modelVideoInfo.getId());
+        if (modelVideoInfoEntity == null) {
+            result.error500("未找到对应实体");
+        } else {
+            boolean ok = modelVideoInfoService.updateById(modelVideoInfo);
+            if (ok) {
+                result.success("修改成功!");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id id
+     * @return 操作结果
+     */
+    @AutoLog(value = "模板视频信息-通过id删除")
+    @ApiOperation(value = "模板视频信息-通过id删除", notes = "模板视频信息-通过id删除")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        try {
+            modelVideoInfoService.removeById(id);
+        } catch (Exception e) {
+            log.error("删除失败", e.getMessage());
+            return Result.error("删除失败!");
+        }
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids id信息
+     * @return 操作结果
+     */
+    @AutoLog(value = "模板视频信息-批量删除")
+    @ApiOperation(value = "模板视频信息-批量删除", notes = "模板视频信息-批量删除")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<ModelVideoInfo> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        Result<ModelVideoInfo> result = new Result<>();
+        if (ids == null || "".equals(ids.trim())) {
+            result.error500("参数不识别!");
+        } else {
+            this.modelVideoInfoService.removeByIds(Arrays.asList(ids.split(",")));
+            result.success("删除成功!");
+        }
+        return result;
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id id
+     * @return 查询结果信息
+     */
+    @AutoLog(value = "模板视频信息-通过id查询")
+    @ApiOperation(value = "模板视频信息-通过id查询", notes = "模板视频信息-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<ModelVideoInfo> queryById(@RequestParam(name = "id", required = true) String id) {
+        Result<ModelVideoInfo> result = new Result<>();
+        ModelVideoInfo modelVideoInfo = modelVideoInfoService.getById(id);
+        if (modelVideoInfo == null) {
+            result.error500("未找到对应实体");
+        } else {
+            result.setResult(modelVideoInfo);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+}

+ 248 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/controller/ModelVideoInfoTagController.java

@@ -0,0 +1,248 @@
+package org.jeecg.modules.opencv.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoTag;
+import org.jeecg.modules.opencv.service.IModelVideoInfoTagService;
+import org.jeecgframework.poi.excel.ExcelImportUtil;
+import org.jeecgframework.poi.excel.def.NormalExcelConstants;
+import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.ImportParams;
+import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 模板视频分类信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Slf4j
+@Api(tags = "模板视频分类信息")
+@RestController
+@RequestMapping("/ctop/modelVideoInfoTag")
+public class ModelVideoInfoTagController {
+    @Autowired
+    private IModelVideoInfoTagService modelVideoInfoTagService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param modelVideoInfoTag
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @AutoLog(value = "模板视频分类信息-分页列表查询")
+    @ApiOperation(value = "模板视频分类信息-分页列表查询", notes = "模板视频分类信息-分页列表查询")
+    @GetMapping(value = "/list")
+    public Result<IPage<ModelVideoInfoTag>> queryPageList(ModelVideoInfoTag modelVideoInfoTag,
+                                                          @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                          @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                          HttpServletRequest req) {
+        Result<IPage<ModelVideoInfoTag>> result = new Result<IPage<ModelVideoInfoTag>>();
+        QueryWrapper<ModelVideoInfoTag> queryWrapper = QueryGenerator.initQueryWrapper(modelVideoInfoTag, req.getParameterMap());
+        Page<ModelVideoInfoTag> page = new Page<ModelVideoInfoTag>(pageNo, pageSize);
+        IPage<ModelVideoInfoTag> pageList = modelVideoInfoTagService.page(page, queryWrapper);
+        result.setSuccess(true);
+        result.setResult(pageList);
+        return result;
+    }
+
+    /**
+     * 添加
+     *
+     * @param modelVideoInfoTag
+     * @return
+     */
+    @AutoLog(value = "模板视频分类信息-添加")
+    @ApiOperation(value = "模板视频分类信息-添加", notes = "模板视频分类信息-添加")
+    @PostMapping(value = "/add")
+    public Result<ModelVideoInfoTag> add(@RequestBody ModelVideoInfoTag modelVideoInfoTag) {
+        Result<ModelVideoInfoTag> result = new Result<ModelVideoInfoTag>();
+        try {
+            modelVideoInfoTagService.save(modelVideoInfoTag);
+            result.success("添加成功!");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("操作失败");
+        }
+        return result;
+    }
+
+    /**
+     * 编辑
+     *
+     * @param modelVideoInfoTag
+     * @return
+     */
+    @AutoLog(value = "模板视频分类信息-编辑")
+    @ApiOperation(value = "模板视频分类信息-编辑", notes = "模板视频分类信息-编辑")
+    @PutMapping(value = "/edit")
+    public Result<ModelVideoInfoTag> edit(@RequestBody ModelVideoInfoTag modelVideoInfoTag) {
+        Result<ModelVideoInfoTag> result = new Result<ModelVideoInfoTag>();
+        ModelVideoInfoTag modelVideoInfoTagEntity = modelVideoInfoTagService.getById(modelVideoInfoTag.getId());
+        if (modelVideoInfoTagEntity == null) {
+            result.error500("未找到对应实体");
+        } else {
+            boolean ok = modelVideoInfoTagService.updateById(modelVideoInfoTag);
+            if (ok) {
+                result.success("修改成功!");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "模板视频分类信息-通过id删除")
+    @ApiOperation(value = "模板视频分类信息-通过id删除", notes = "模板视频分类信息-通过id删除")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        try {
+            modelVideoInfoTagService.removeById(id);
+        } catch (Exception e) {
+            log.error("删除失败", e.getMessage());
+            return Result.error("删除失败!");
+        }
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @AutoLog(value = "模板视频分类信息-批量删除")
+    @ApiOperation(value = "模板视频分类信息-批量删除", notes = "模板视频分类信息-批量删除")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<ModelVideoInfoTag> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        Result<ModelVideoInfoTag> result = new Result<ModelVideoInfoTag>();
+        if (ids == null || "".equals(ids.trim())) {
+            result.error500("参数不识别!");
+        } else {
+            this.modelVideoInfoTagService.removeByIds(Arrays.asList(ids.split(",")));
+            result.success("删除成功!");
+        }
+        return result;
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "模板视频分类信息-通过id查询")
+    @ApiOperation(value = "模板视频分类信息-通过id查询", notes = "模板视频分类信息-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<ModelVideoInfoTag> queryById(@RequestParam(name = "id", required = true) String id) {
+        Result<ModelVideoInfoTag> result = new Result<ModelVideoInfoTag>();
+        ModelVideoInfoTag modelVideoInfoTag = modelVideoInfoTagService.getById(id);
+        if (modelVideoInfoTag == null) {
+            result.error500("未找到对应实体");
+        } else {
+            result.setResult(modelVideoInfoTag);
+            result.setSuccess(true);
+        }
+        return result;
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param request
+     * @param response
+     */
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, HttpServletResponse response) {
+        // Step.1 组装查询条件
+        QueryWrapper<ModelVideoInfoTag> queryWrapper = null;
+        try {
+            String paramsStr = request.getParameter("paramsStr");
+            if (oConvertUtils.isNotEmpty(paramsStr)) {
+                String deString = URLDecoder.decode(paramsStr, "UTF-8");
+                ModelVideoInfoTag modelVideoInfoTag = JSON.parseObject(deString, ModelVideoInfoTag.class);
+                queryWrapper = QueryGenerator.initQueryWrapper(modelVideoInfoTag, request.getParameterMap());
+            }
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+
+        //Step.2 AutoPoi 导出Excel
+        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
+        List<ModelVideoInfoTag> pageList = modelVideoInfoTagService.list(queryWrapper);
+        //导出文件名称
+        mv.addObject(NormalExcelConstants.FILE_NAME, "模板视频分类信息列表");
+        mv.addObject(NormalExcelConstants.CLASS, ModelVideoInfoTag.class);
+        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("模板视频分类信息列表数据", "导出人:Jeecg", "导出信息"));
+        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
+        return mv;
+    }
+
+    /**
+     * 通过excel导入数据
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
+        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
+            MultipartFile file = entity.getValue();
+            ImportParams params = new ImportParams();
+            params.setTitleRows(2);
+            params.setHeadRows(1);
+            params.setNeedSave(true);
+            try {
+                List<ModelVideoInfoTag> listModelVideoInfoTags = ExcelImportUtil.importExcel(file.getInputStream(), ModelVideoInfoTag.class, params);
+                modelVideoInfoTagService.saveBatch(listModelVideoInfoTags);
+                return Result.ok("文件导入成功!数据行数:" + listModelVideoInfoTags.size());
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+                return Result.error("文件导入失败:" + e.getMessage());
+            } finally {
+                try {
+                    file.getInputStream().close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return Result.ok("文件导入失败!");
+    }
+
+}

+ 63 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoCompositeInfo.java

@@ -0,0 +1,63 @@
+package org.jeecg.modules.opencv.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.util.Date;
+
+/**
+ * 模板合成视频
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Data
+@TableName("ctop_model_video_composite_info")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_model_video_composite_info对象", description = "模板合成视频")
+public class ModelVideoCompositeInfo {
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.UUID)
+    @ApiModelProperty(value = "id")
+    private Integer id;
+    /**
+     * videoUrl
+     */
+    @Excel(name = "videoUrl", width = 15)
+    @ApiModelProperty(value = "videoUrl")
+    private String videoUrl;
+    /**
+     * 模板id
+     */
+    @Excel(name = "模板id", width = 15)
+    @ApiModelProperty(value = "模板id")
+    private Integer modelId;
+    /**
+     * userId
+     */
+    @Excel(name = "userId", width = 15)
+    @ApiModelProperty(value = "userId")
+    private String userId;
+    /**
+     * createTime
+     */
+    @ApiModelProperty(value = "createTime")
+    private Date createTime;
+    /**
+     * updateTime
+     */
+    @ApiModelProperty(value = "updateTime")
+    private Date updateTime;
+}

+ 76 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoInfo.java

@@ -0,0 +1,76 @@
+package org.jeecg.modules.opencv.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.util.Date;
+
+/**
+ * 模板视频信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Data
+@TableName("ctop_model_video_info")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_model_video_info对象", description = "模板视频信息")
+public class ModelVideoInfo {
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "id")
+    private Long id;
+    /**
+     * 视频链接
+     */
+    private String modelVideoUrl;
+    private String title;
+    /**
+     * 封面链接
+     */
+    private String coverImageUrl;
+    /**
+     * 模板类型
+     */
+    private Integer modelType;
+    /**
+     * 尺寸类型 1:竖版 2:横版
+     */
+    private Integer sizeType;
+    /**
+     * 状态
+     */
+    @Excel(name = "状态", width = 15)
+    @ApiModelProperty(value = "状态")
+    private Integer status;
+    /**
+     * MD5
+     */
+    private String signature;
+    /**
+     * createTime
+     */
+    @ApiModelProperty(value = "createTime")
+    private Date createTime;
+    /**
+     * updateTime
+     */
+    @ApiModelProperty(value = "updateTime")
+    private Date updateTime;
+
+    @TableField(exist = false)
+    private Integer orderType;
+}

+ 117 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoInfoConfig.java

@@ -0,0 +1,117 @@
+package org.jeecg.modules.opencv.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.util.Date;
+
+/**
+ * 模板视频配置信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Data
+@TableName("ctop_model_video_info_config")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_model_video_info_config对象", description = "模板视频配置信息")
+public class ModelVideoInfoConfig {
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.UUID)
+    @ApiModelProperty(value = "id")
+    private Integer id;
+    /**
+     * name
+     */
+    @Excel(name = "name", width = 15)
+    @ApiModelProperty(value = "name")
+    private String name;
+    /**
+     * 文件路径
+     */
+    @Excel(name = "文件路径", width = 15)
+    @ApiModelProperty(value = "文件路径")
+    private String fileUrl;
+    /**
+     * modelId
+     */
+    @Excel(name = "modelId", width = 15)
+    @ApiModelProperty(value = "modelId")
+    private Integer modelId;
+    /**
+     * 1:简单后接模板2:复杂投影模板
+     */
+    @Excel(name = "1:简单后接模板2:复杂投影模板", width = 15)
+    @ApiModelProperty(value = "1:简单后接模板2:复杂投影模板")
+    private Integer type;
+    /**
+     * 矩形替换开始帧数
+     */
+    @Excel(name = "矩形替换开始帧数", width = 15)
+    @ApiModelProperty(value = "矩形替换开始帧数")
+    private Integer rectangleStartFrame;
+    /**
+     * 矩形替换结束帧数
+     */
+    @Excel(name = "矩形替换结束帧数", width = 15)
+    @ApiModelProperty(value = "矩形替换结束帧数")
+    private Integer rectangleEndFrame;
+    /**
+     * 全屏替换开始帧数
+     */
+    @Excel(name = "全屏替换开始帧数", width = 15)
+    @ApiModelProperty(value = "全屏替换开始帧数")
+    private Integer fullScreenStartFrame;
+    /**
+     * 全屏替换结束帧数
+     */
+    @Excel(name = "全屏替换结束帧数", width = 15)
+    @ApiModelProperty(value = "全屏替换结束帧数")
+    private Integer fullScreenEndFrame;
+    /**
+     * rectangleStartX
+     */
+    @Excel(name = "rectangleStartX", width = 15)
+    @ApiModelProperty(value = "rectangleStartX")
+    private Integer rectangleStartX;
+    /**
+     * rectangleEndX
+     */
+    @Excel(name = "rectangleEndX", width = 15)
+    @ApiModelProperty(value = "rectangleEndX")
+    private Integer rectangleEndX;
+    /**
+     * rectangleStartY
+     */
+    @Excel(name = "rectangleStartY", width = 15)
+    @ApiModelProperty(value = "rectangleStartY")
+    private Integer rectangleStartY;
+    /**
+     * rectangleEndY
+     */
+    @Excel(name = "rectangleEndY", width = 15)
+    @ApiModelProperty(value = "rectangleEndY")
+    private Integer rectangleEndY;
+    /**
+     * createTime
+     */
+    @ApiModelProperty(value = "createTime")
+    private Date createTime;
+    /**
+     * updateTime
+     */
+    @ApiModelProperty(value = "updateTime")
+    private Date updateTime;
+}

+ 73 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/entity/ModelVideoInfoTag.java

@@ -0,0 +1,73 @@
+package org.jeecg.modules.opencv.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+/**
+ * 模板视频分类信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Data
+@TableName("ctop_model_video_industry_tag")
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "ctop_model_video_industry_tag对象", description = "模板视频分类信息")
+public class ModelVideoInfoTag {
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.UUID)
+    @ApiModelProperty(value = "id")
+    private Integer id;
+    /**
+     * tagName
+     */
+    @Excel(name = "tagName", width = 15)
+    @ApiModelProperty(value = "tagName")
+    private String tagName;
+    /**
+     * tagCode
+     */
+    @Excel(name = "tagCode", width = 15)
+    @ApiModelProperty(value = "tagCode")
+    private String tagCode;
+    /**
+     * parentId
+     */
+    @Excel(name = "parentId", width = 15)
+    @ApiModelProperty(value = "parentId")
+    private Integer parentId;
+    /**
+     * level
+     */
+    @Excel(name = "level", width = 15)
+    @ApiModelProperty(value = "level")
+    private Integer level;
+    /**
+     * createTime
+     */
+    @ApiModelProperty(value = "createTime")
+    private Date createTime;
+    /**
+     * updateTime
+     */
+    @ApiModelProperty(value = "updateTime")
+    private Date updateTime;
+}

+ 15 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoCompositeInfoMapper.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.opencv.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.opencv.entity.ModelVideoCompositeInfo;
+
+/**
+ * 模板合成视频
+ *
+ * @author: jeecg-boot
+ * @date: 2020-04-17
+ * @cersion: V1.0
+ */
+public interface ModelVideoCompositeInfoMapper extends BaseMapper<ModelVideoCompositeInfo> {
+
+}

+ 15 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoInfoConfigMapper.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.opencv.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoConfig;
+
+/**
+ * 模板视频配置信息
+ *
+ * @author: jeecg-boot
+ * @date: 2020-04-17
+ * @cersion: V1.0
+ */
+public interface ModelVideoInfoConfigMapper extends BaseMapper<ModelVideoInfoConfig> {
+
+}

+ 15 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoInfoMapper.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.opencv.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.opencv.entity.ModelVideoInfo;
+
+/**
+ * 模板视频信息
+ *
+ * @author: jeecg-boot
+ * @date: 2020-04-17
+ * @cersion: V1.0
+ */
+public interface ModelVideoInfoMapper extends BaseMapper<ModelVideoInfo> {
+
+}

+ 15 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/ModelVideoInfoTagMapper.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.opencv.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoTag;
+
+/**
+ * 模板视频分类信息
+ *
+ * @author: jeecg-boot
+ * @date: 2020-04-17
+ * @cersion: V1.0
+ */
+public interface ModelVideoInfoTagMapper extends BaseMapper<ModelVideoInfoTag> {
+
+}

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoCompositeInfoMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.com.ctop.ctop.mapper.ModelVideoCompositeInfoMapper">
+
+</mapper>

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoInfoConfigMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.com.ctop.ctop.mapper.ModelVideoInfoConfigMapper">
+
+</mapper>

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoInfoMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.com.ctop.ctop.mapper.ModelVideoInfoMapper">
+
+</mapper>

+ 5 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/mapper/xml/ModelVideoInfoTagMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.com.ctop.ctop.mapper.ModelVideoInfoTagMapper">
+
+</mapper>

+ 19 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IFfmpegService.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.opencv.service;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.Map;
+
+public interface IFfmpegService {
+    void getM4aFromMp4(String videoPath, String m4apath);
+
+    void cutM4a(String srcPath, String targetPath, String startSecond, String endSecond);
+
+    void audioMosaic(String audioPart1, String audioPart2, String finalAudio);
+
+    void mergeAudioAndVideo(String srcVideoPath, String srcAudioPath, String finalVideoPath);
+
+    void mergeImageToVideo(String imagePath, Integer frameNumber, String videoFilePath);
+
+    Map<String, Object> videoMerge(JSONObject data);
+}

+ 15 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoCompositeInfoService.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.opencv.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.opencv.entity.ModelVideoCompositeInfo;
+
+/**
+ * 模板合成视频
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+public interface IModelVideoCompositeInfoService extends IService<ModelVideoCompositeInfo> {
+
+}

+ 16 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoInfoConfigService.java

@@ -0,0 +1,16 @@
+package org.jeecg.modules.opencv.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoConfig;
+
+/**
+ * 模板视频配置信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+public interface IModelVideoInfoConfigService extends IService<ModelVideoInfoConfig> {
+
+    ModelVideoInfoConfig getByModelId(Long id);
+}

+ 15 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoInfoService.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.opencv.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.opencv.entity.ModelVideoInfo;
+
+/**
+ * 模板视频信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+public interface IModelVideoInfoService extends IService<ModelVideoInfo> {
+
+}

+ 15 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/IModelVideoInfoTagService.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.opencv.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoTag;
+
+/**
+ * 模板视频分类信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+public interface IModelVideoInfoTagService extends IService<ModelVideoInfoTag> {
+
+}

+ 369 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/FfmpegServiceImpl.java

@@ -0,0 +1,369 @@
+package org.jeecg.modules.opencv.service.impl;
+
+import cn.com.ctop.common.module.utils.*;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.modules.opencv.entity.ModelVideoInfo;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoConfig;
+import org.jeecg.modules.opencv.service.IFfmpegService;
+import org.jeecg.modules.opencv.service.IModelVideoInfoConfigService;
+import org.jeecg.modules.opencv.service.IModelVideoInfoService;
+import org.jeecg.modules.opencv.utils.ImageUtils;
+import org.jeecg.modules.opencv.utils.VideoProcessing;
+import org.opencv.core.Core;
+import org.opencv.core.Mat;
+import org.opencv.core.Size;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class FfmpegServiceImpl implements IFfmpegService {
+    /**
+     * FFmpeg全路径
+     */
+    @Value("${jeecg.ffmpeg.bin}")
+    private String FFMPEG_PATH;
+
+    /**
+     * 从视频中抽取音频文件
+     */
+    @Override
+    public void getM4aFromMp4(String videoPath, String m4apath) {
+        /**
+         * D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\video.mp4 -vn -y -acodec copy D:\data\test\\video.m4a
+         */
+        List<String> command = new ArrayList<>();
+        command.add(FFMPEG_PATH);
+        command.add("-i");
+        command.add(videoPath);
+        command.add("-vn");
+        command.add("-y");
+        command.add("-acodec");
+        command.add("copy");
+        command.add(m4apath);
+        runCommand(command);
+    }
+
+    /**
+     * 截取音频文件
+     */
+    @Override
+    public void cutM4a(String srcPath, String targetPath, String startSecond, String endSecond) {
+        /**
+         *D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\video.m4a -vn -acodec copy -ss 00:00:00.000 -t 00:00:08.000 D:\data\test\\cut.m4a
+         */
+        List<String> command = new ArrayList<>();
+        command.add(FFMPEG_PATH);
+        command.add("-i");
+        command.add(srcPath);
+        command.add("-vn");
+        command.add("-acodec");
+        command.add("copy");
+        command.add("-ss");
+        command.add(startSecond);
+        command.add("-t");
+        command.add(endSecond);
+        command.add(targetPath);
+        runCommand(command);
+    }
+
+    /**
+     * 音频拼接
+     * D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\cut.m4a -i D:\data\test\\fill.m4a -filter_complex "[0:0] [1:0] concat=n=2:v=0:a=1 [a]" -map [a] D:\data\test\\final.m4a
+     */
+    @Override
+    public void audioMosaic(String audioPart1, String audioPart2, String finalAudio) {
+        List<String> command = new ArrayList<>();
+        command.add(FFMPEG_PATH);
+        command.add("-i");
+        command.add(audioPart1);
+        command.add("-i");
+        command.add(audioPart2);
+        command.add("-filter_complex");
+        command.add("\"[0:0] [1:0] concat=n=2:v=0:a=1 [a]\"");
+        command.add("-map");
+        command.add("[a]");
+        command.add(finalAudio);
+        runCommand(command);
+    }
+
+    /**
+     * 音频+视频合成视频
+     *
+     * @param srcVideoPath
+     * @param srcAudioPath
+     * @param finalVideoPath D:\java\ffmpeg\bin\ffmpeg.exe -i D:\data\test\\merge.mp4 -i D:\data\test\\final.m4a -c:v copy -c:a aac -strict experimental D:\data\test\\final.mp4
+     */
+    @Override
+    public void mergeAudioAndVideo(String srcVideoPath, String srcAudioPath, String finalVideoPath) {
+        List<String> command = new ArrayList<>();
+        command.add(FFMPEG_PATH);
+        command.add("-i");
+        command.add(srcVideoPath);
+        command.add("-i");
+        command.add(srcAudioPath);
+        command.add("-c:v");
+        command.add("copy");
+        command.add("-c:a");
+        command.add("aac");
+        command.add("-strict");
+        command.add("experimental");
+        command.add(finalVideoPath);
+        runCommand(command);
+    }
+
+    /**
+     * 将图片合成为视频
+     * D:\java\ffmpeg\bin\ffmpeg.exe -f image2 -i D:\\data\\video\\%d.jpg  -vcodec libx264 -r 25  D:\\data\\merge.mp4
+     *
+     * @param imagePath
+     * @param frameNumber
+     * @param videoFilePath
+     */
+    @Override
+    public void mergeImageToVideo(String imagePath, Integer frameNumber, String videoFilePath) {
+        List<String> command = new ArrayList<>();
+        command.add(FFMPEG_PATH);
+        command.add("-f");
+        command.add("image2");
+        command.add("-i");
+        command.add(imagePath + "%d.jpg");
+        command.add("-vcodec");
+        command.add("libx264");
+        command.add("-r");
+        command.add(frameNumber + "");
+        command.add(videoFilePath);
+        runCommand(command);
+    }
+
+    private void runCommand(List<String> command) {
+        try {
+            ProcessBuilder builder = new ProcessBuilder();
+            builder.command(command);
+            builder.redirectErrorStream(true);
+            Process process = builder.start();
+            // 等待进程执行结束
+            process.waitFor();
+            log.info("ffmpeg命令执行完成");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public Map<String, Object> videoMerge(JSONObject data) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            Long modelId = data.getLong("modelId");
+            String url = data.getString("url");
+            if (null == modelId || modelId == 0 || null == url || "".equals(url.trim())) {
+                ResultMapUtils.setResultMap(result, StatusCode.MODEL_VIDEO_NOT_EXIST);
+                return result;
+            }
+            ModelVideoInfo videoInfo = modelVideoInfoService.getById(modelId);
+            if (null == videoInfo || videoInfo.getStatus() == 0) {
+                ResultMapUtils.setResultMap(result, StatusCode.MODEL_VIDEO_NOT_EXIST);
+                return result;
+            }
+            //1:
+            url = "https:" + url;
+            String getUrl = mergeVideo(videoInfo, url);
+            ResultMapUtils.setResultMap(result, StatusCode.COMMON_SUCCESS);
+            result.put("url", getUrl);
+            return result;
+        } catch (Exception e) {
+            e.printStackTrace();
+            ResultMapUtils.setResultMap(result, StatusCode.COMMON_SERVER_ERROR);
+            return result;
+        }
+    }
+
+    @Autowired
+    private IModelVideoInfoConfigService configService;
+
+    private String mergeVideo(ModelVideoInfo videoInfo, String url) throws Exception {
+        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+        //根据url下载视频
+        String srcVideoPath = PropertiesUtils.getValue("kuaishou_config", "model_video_src_path_test");
+        String fillVideoPath = PropertiesUtils.getValue("kuaishou_config", "model_video_fill_path_test");
+        String finalVideoPath = PropertiesUtils.getValue("kuaishou_config", "model_video_final_path_test");
+
+        String fillFilePath = LoadFileUtil.downLoadFromUrl(url, fillVideoPath);
+        String srcFilePath = LoadFileUtil.downLoadFromUrl(videoInfo.getModelVideoUrl(), srcVideoPath);
+
+        Long current = System.currentTimeMillis();
+        String splitSrcPath = srcVideoPath + current + File.separator;
+        String splitFillPath = fillVideoPath + current + File.separator;
+        String splitFinalPath = finalVideoPath + current + File.separator;
+        LoadFileUtil.checkFile(splitFinalPath);
+        //1:切分视频
+        VideoProcessing.grabberVideoFramer(srcFilePath, splitSrcPath);
+        VideoProcessing.grabberVideoFramer(fillFilePath, splitFillPath);
+        ModelVideoInfoConfig config = configService.getByModelId(videoInfo.getId());
+        if (null == config) {
+            log.error("配置文件尚未配置=>modelId:{}", videoInfo.getId());
+            return null;
+        }
+        if (config.getType() == 1) {
+            //简单的最终追加
+            //2:合并图片
+            //视频替换开始帧数
+            int exchangeStartFrameNum = config.getFullScreenStartFrame();
+            //视频替换结束帧数
+            int exchangeEndFrameNum = config.getFullScreenEndFrame();
+            //2.1 复制原始视频无变化图片
+            for (int i = 0; i < exchangeStartFrameNum; i++) {
+                Mat srcNoChangeImage = Imgcodecs.imread(splitSrcPath + i + ".jpg");
+                Imgcodecs.imwrite(splitFinalPath + i + ".jpg", srcNoChangeImage);
+            }
+
+            //2.2 转场动画(从fill文件夹的第一帧开始)
+            String getImageName = splitFillPath + "0.jpg";
+            Mat image = Imgcodecs.imread(getImageName, Imgcodecs.IMREAD_COLOR);
+            //(1)径向模糊图片
+            Mat radialBlur = ImageUtils.radialBlur(image);
+            Imgcodecs.imwrite(splitFinalPath + exchangeStartFrameNum + ".jpg", radialBlur);
+            exchangeStartFrameNum++;
+            //(2)放大后径向模糊图片
+            Mat bigImamge = new Mat();
+            Imgproc.resize(image, bigImamge, new Size(image.cols() * 1.25, image.rows() * 1.25));
+            Mat destBigImamge = ImageUtils.cutFromCenter(bigImamge, image.width(), image.height());
+            Mat radialBlurDestBigImamge = ImageUtils.radialBlur(destBigImamge);
+            Imgcodecs.imwrite(splitFinalPath + exchangeStartFrameNum + ".jpg", radialBlurDestBigImamge);
+            exchangeStartFrameNum++;
+            //(3)缩小之后重复平铺加径向模糊
+            Mat smallImage = new Mat();
+            Mat halfImage = new Mat();
+            Mat wholeImage = new Mat();
+            Imgproc.resize(image, smallImage, new Size(image.cols() / 2, image.rows() / 2));
+            ImageUtils.hconcat(smallImage, smallImage, halfImage);
+            ImageUtils.vconcat(halfImage, halfImage, wholeImage);
+            wholeImage = ImageUtils.radialBlur(wholeImage);
+            Imgcodecs.imwrite(splitFinalPath + exchangeStartFrameNum + ".jpg", wholeImage);
+            exchangeStartFrameNum++;
+            //2.3复制填充视频无变化图片
+            int checkNum = 1;
+            for (int i = exchangeStartFrameNum; i < exchangeEndFrameNum; i++) {
+                String fillImagePath = splitFillPath + checkNum + ".jpg";
+                File file = new File(fillImagePath);
+                if (file.exists()) {
+                    Mat srcMat = Imgcodecs.imread(fillImagePath);
+                    Imgcodecs.imwrite(splitFinalPath + i + ".jpg", srcMat);
+                } else {
+                    break;
+                }
+                checkNum++;
+            }
+            //3开始合成视频
+            //3.1 抽取音频文件
+            String srcM4aFilePath = splitSrcPath + "src.m4a";
+            getM4aFromMp4(srcFilePath, srcM4aFilePath);
+            String fillM4aFilePath = splitSrcPath + "fill.m4a";
+            getM4aFromMp4(fillFilePath, fillM4aFilePath);
+            //3.2 截取源模板音频文件
+            String cutM4aFilePath = splitSrcPath + "cut.m4a";
+            //计算需要截取的音频时长
+            String secondStr = getSecond(exchangeStartFrameNum);
+            cutM4a(srcM4aFilePath, cutM4aFilePath, "00:00:00.000", secondStr);
+            //3.3 合并两个音频文件
+            String finalM4aFilePath = splitSrcPath + "final.m4a";
+            audioMosaic(cutM4aFilePath, fillM4aFilePath, finalM4aFilePath);
+            //3.4 将最终生成的图片合成为视频
+            String noVoiceVideoFilePath = splitSrcPath + "novoice.mp4";
+            mergeImageToVideo(splitFinalPath, 25, noVoiceVideoFilePath);
+            //3.5 合并视频和音频
+            String finalVideoFilePath = splitSrcPath + "final.mp4";
+            mergeAudioAndVideo(noVoiceVideoFilePath, finalM4aFilePath, finalVideoFilePath);
+            //3.6 上传视频文件至OSS并返回url存入数据库
+            InputStream inputStream = new FileInputStream(finalM4aFilePath);
+            String finalUrl = OSSUtils.uploadFile2OSS(inputStream, "/model/final/", videoInfo.getTitle() + current + ".mp4");
+            System.out.println(finalUrl);
+        } else if (config.getType() == 2) {
+            //2:合并图片
+
+        } else {
+            log.error("此类模板视频尚未配置=>type:{}", config.getType());
+        }
+        return null;
+    }
+
+    private String getSecond(int exchangeStartFrameNum) {
+        BigDecimal second = new BigDecimal(exchangeStartFrameNum).divide(new BigDecimal("25"), 3, RoundingMode.HALF_UP);
+        if (second.compareTo(new BigDecimal("10")) < 0) {
+            return "00:00:0" + second.toString();
+        } else {
+            return "00:00:" + second.toString();
+        }
+    }
+
+    @Autowired
+    private IModelVideoInfoService modelVideoInfoService;
+
+//    public void cornerCheck(){
+//        int srcPhoneFrameNumFrom = 163;
+//        int changeSenceFrameNumFrom = 234;
+//        //2.1 复制原始视频无变化图片
+//        for (int i = 1; i < srcPhoneFrameNumFrom; i++) {
+//            Mat srcNoChangeImage = Imgcodecs.imread(srcPath + i + ".jpg");
+//            Imgcodecs.imwrite(targetPath + i + ".jpg", srcNoChangeImage);
+//        }
+//        String getImageName = "";
+//        //2.2 填充手机内部图片画面
+//        for (int i = 163; i < changeSenceFrameNumFrom; i++) {
+//            String backImg = srcPath + (i) + ".jpg";
+//            String phoneImg = fillPath + (i - 162) + ".jpg";
+//            String targetImg = targetPath + i + ".jpg";
+//            Perspective.perpectiveImg(backImg, phoneImg, targetImg);
+//            getImageName = targetImg;
+//        }
+//        //2.3 转场动画
+//        Mat image = Imgcodecs.imread(getImageName, Imgcodecs.IMREAD_COLOR);
+//        //(1)径向模糊图片
+//        Mat radialBlur = ImageUtils.radialBlur(image);
+//        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", radialBlur);
+//        changeSenceFrameNumFrom++;
+//        //(2)放大后径向模糊图片
+//        Mat bigImamge = new Mat();
+//        Imgproc.resize(image, bigImamge, new Size(image.cols() * 1.25, image.rows() * 1.25));
+//        Mat destBigImamge = ImageUtils.cutFromCenter(bigImamge, image.width(), image.height());
+//        Mat radialBlurDestBigImamge = ImageUtils.radialBlur(destBigImamge);
+//        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", radialBlurDestBigImamge);
+//        changeSenceFrameNumFrom++;
+//        //(3)缩小之后重复平铺加径向模糊
+//        Mat smallImage = new Mat();
+//        Mat halfImage = new Mat();
+//        Mat wholeImage = new Mat();
+//        Imgproc.resize(image, smallImage, new Size(image.cols() / 2, image.rows() / 2));
+//        ImageUtils.hconcat(smallImage, smallImage, halfImage);
+//        ImageUtils.vconcat(halfImage, halfImage, wholeImage);
+//        wholeImage = ImageUtils.radialBlur(wholeImage);
+//        Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", wholeImage);
+//        changeSenceFrameNumFrom++;
+//        //复制填充视频无变化图片
+//        for (int i = changeSenceFrameNumFrom; i < 100000; i++) {
+//            int checkNum = i - 3 - srcPhoneFrameNumFrom + 1;
+//            String fillImagePath = fillPath + checkNum + ".jpg";
+//            File file = new File(fillImagePath);
+//            if (file.exists()) {
+//                Mat srcMat = Imgcodecs.imread(fillImagePath);
+//                Imgcodecs.imwrite(targetPath + i + ".jpg", srcMat);
+//            } else {
+//                break;
+//            }
+//        }
+//    }
+}

+ 19 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoCompositeInfoServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.opencv.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.opencv.entity.ModelVideoCompositeInfo;
+import org.jeecg.modules.opencv.mapper.ModelVideoCompositeInfoMapper;
+import org.jeecg.modules.opencv.service.IModelVideoCompositeInfoService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 模板合成视频
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Service
+public class ModelVideoCompositeInfoServiceImpl extends ServiceImpl<ModelVideoCompositeInfoMapper, ModelVideoCompositeInfo> implements IModelVideoCompositeInfoService {
+
+}

+ 27 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoInfoConfigServiceImpl.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.opencv.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoConfig;
+import org.jeecg.modules.opencv.mapper.ModelVideoInfoConfigMapper;
+import org.jeecg.modules.opencv.service.IModelVideoInfoConfigService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 模板视频配置信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Service
+public class ModelVideoInfoConfigServiceImpl extends ServiceImpl<ModelVideoInfoConfigMapper, ModelVideoInfoConfig> implements IModelVideoInfoConfigService {
+
+    @Override
+    public ModelVideoInfoConfig getByModelId(Long modelId) {
+        QueryWrapper<ModelVideoInfoConfig> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("model_id", modelId);
+        queryWrapper.orderByDesc("id").last("limit 1");
+        return this.getOne(queryWrapper);
+    }
+}

+ 19 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoInfoServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.opencv.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.opencv.entity.ModelVideoInfo;
+import org.jeecg.modules.opencv.mapper.ModelVideoInfoMapper;
+import org.jeecg.modules.opencv.service.IModelVideoInfoService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 模板视频信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Service
+public class ModelVideoInfoServiceImpl extends ServiceImpl<ModelVideoInfoMapper, ModelVideoInfo> implements IModelVideoInfoService {
+
+}

+ 19 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/service/impl/ModelVideoInfoTagServiceImpl.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.opencv.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.opencv.entity.ModelVideoInfoTag;
+import org.jeecg.modules.opencv.mapper.ModelVideoInfoTagMapper;
+import org.jeecg.modules.opencv.service.IModelVideoInfoTagService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 模板视频分类信息
+ *
+ * @author jeecg-boot
+ * @version V1.0
+ * @date 2020-04-17
+ */
+@Service
+public class ModelVideoInfoTagServiceImpl extends ServiceImpl<ModelVideoInfoTagMapper, ModelVideoInfoTag> implements IModelVideoInfoTagService {
+
+}

+ 282 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/utils/Avutils.java

@@ -0,0 +1,282 @@
+package org.jeecg.modules.opencv.utils;
+
+public class Avutils {
+    /**
+     * 平面YUV 4:2:0,12bpp,(1 Cr&每2×2个样本的Cb样本)
+     **/
+    public static int AV_PIX_FMT_YUV420P = 0;
+    /**
+     * 打包YUV 4:2:2,16bpp,Y0 Cb Y1 Cr
+     */
+    public static int AV_PIX_FMT_YUYV422 = 1;
+    /**
+     * 打包RGB 8:8:8,24bpp,RGBRGB ...
+     */
+    public static int AV_PIX_FMT_RGB24 = 2;
+    /**
+     * 打包RGB 8:8:8,24bpp,BGRBGR ...
+     */
+    public static int AV_PIX_FMT_BGR24 = 3;
+    /**
+     * 平面YUV 4:2:2,16bpp,(每2×1个样本1 Cr& Cb样本)
+     */
+    public static int AV_PIX_FMT_YUV422P = 4;
+    /**
+     * 平面YUV 4:4:4,24bpp,(每1×1个样本1个Cr& Cb样本)
+     */
+    public static int AV_PIX_FMT_YUV444P = 5;
+    /**
+     * 平面YUV 4:1 :0,9bpp,(每4x4Y样品1 Cr& Cb样品)
+     */
+    public static int AV_PIX_FMT_YUV410P = 6;
+    /**
+     * 平面YUV 4:1:1,12bpp,(1 Cr& Cb每4x1 Y样本的样本)
+     **/
+    public static int AV_PIX_FMT_YUV411P = 7;
+    /**
+     * Y,8bpp
+     */
+    public static int AV_PIX_FMT_GRAY8 = 8;
+    /**
+     * Y,1bpp,0为白色,1是黑色的,每个字节的像素都是从msb到lsb的顺序
+     */
+    public static int AV_PIX_FMT_MONOWHITE = 9;
+    /**
+     * Y,1bpp,0为黑色,1为白色,每个字节中的像素从msb排序到lsb
+     */
+    public static int AV_PIX_FMT_MONOBLACK = 10;
+    /**
+     * 8使用PIX_FMT_RGB32调色板
+     */
+    public static int AV_PIX_FMT_PAL8 = 11;
+    /**
+     * 平面YUV 4:2:0,12bpp,满刻度(JPEG),弃用PIX_FMT_YUV420P并设置color_range
+     */
+    public static int AV_PIX_FMT_YUVJ420P = 12;
+    /**
+     * 平面YUV 4:2:2,16bpp,满量程(JPEG),弃用PIX_FMT_YUV422P并设置color_range
+     */
+    public static int AV_PIX_FMT_YUVJ422P = 13;
+    /**
+     * 平面YUV 4:4:4,24bpp,满量程(JPEG),不利于PIX_FMT_YUV444P并设置color_range
+     */
+    public static int AV_PIX_FMT_YUVJ444P = 14;
+    /**
+     * 通过公共数据包的XVideo运动加速通过
+     */
+    public static int AV_PIX_FMT_XVMC_MPEG2_MC = 15;
+    public static int AV_PIX_FMT_XVMC_MPEG2_IDCT = 16;
+    /**
+     * 打包YUV 4:2:2,16bpp,Cb Y0 Cr Y1
+     */
+    public static int AV_PIX_FMT_UYVY422 = 17;
+    /**
+     * 打包YUV 4:1:1,12bpp,Cb Y0 Y1 Cr Y2 Y3
+     */
+    public static int AV_PIX_FMT_UYYVYY411 = 18;
+    /**
+     * 打包RGB 3:3:2,8bpp,(msb)2B 3G 3R(lsb)
+     */
+    public static int AV_PIX_FMT_BGR8 = 19;
+    /**
+     * 打包RGB 1:2:1比特流,4bpp,(msb)1B 2G 1R(lsb),一个字节包含两个像素,字节中的第一个像素是4 msb位
+     */
+    public static int AV_PIX_FMT_BGR4 = 20;
+    /**
+     * 打包RGB 1:2:1,8bpp,(msb)1B 2G 1R(lsb)
+     */
+    public static int AV_PIX_FMT_BGR4_BYTE = 21;
+    /**
+     * 打包RGB 3:3:2,8bpp,(msb)2R 3G 3B(lsb)
+     */
+    public static int AV_PIX_FMT_RGB8 = 22;
+    /**
+     * 打包RGB 1:2:1比特流,4bpp,( msb)1R 2G 1B(lsb),
+     * 一个字节包含两个像素,字节中的第一个像素是由4 msb位组成的一个
+     */
+    public static int AV_PIX_FMT_RGB4 = 23;
+    /**
+     * 打包RGB 1 :2:1,8bpp,(msb)1R 2G 1B(lsb)
+     */
+    public static int AV_PIX_FMT_RGB4_BYTE = 24;
+    /**
+     * 平面YUV 4:2:0,12bpp,1和1个交织的平面(第一个字节U和随后的字节V)
+     */
+    public static int AV_PIX_FMT_NV12 = 25;
+    /**
+     * 如上所述,但U和V字节被交换
+     */
+    public static int AV_PIX_FMT_NV21 = 26;
+
+    /**
+     * 打包ARGB 8:8:8:8,32bpp,ARGBARGB ...
+     */
+    public static int AV_PIX_FMT_ARGB = 27;
+    /**
+     * 包装RGBA 8:8:8:8,3bpp,RGBARGBA ...
+     */
+    public static int AV_PIX_FMT_RGBA = 28;
+    /**
+     * 打包ABGR 8:8:8:8,332pp,ABGRABGR .. 。
+     */
+    public static int AV_PIX_FMT_ABGR = 29;
+    /**
+     * 包装BGRA 8:8:8:8,32bpp,BGRABGRA ...
+     */
+    public static int AV_PIX_FMT_BGRA = 30;
+
+    /**
+     * Y,16bpp,big-endian
+     */
+    public static int AV_PIX_FMT_GRAY16BE = 31;
+    /**
+     * Y,16bpp,little-endian
+     */
+    public static int AV_PIX_FMT_GRAY16LE = 32;
+    /**
+     * 平面YUV 4:4:0(1 Cr&每个1x2 Y样本的Cb样本)
+     */
+    public static int AV_PIX_FMT_YUV440P = 33;
+    /**
+     * 平面YUV 4:4:0满量程(JPEG),弃用PIX_FMT_YUV440P并设置color_range
+     */
+    public static int AV_PIX_FMT_YUVJ440P = 34;
+    /**
+     * 平面YUV 4:2:0,20bpp,(每2X& A样本1 Cr& Cb样本)
+     */
+    public static int AV_PIX_FMT_YUVA420P = 35;
+    /**
+     * 使用VDPAU的H.264硬件解码,数据[0]包含一个vdpau_render_state结构,
+     * 其中包含片段的比特流以及从头部提取的各种字段
+     */
+    public static int AV_PIX_FMT_VDPAU_H264 = 36;
+    /**
+     * 使用VDPAU的MPEG-1硬件解码,数据[0]包含一个vdpau_render_state结构,
+     * 其中包含片段的比特流以及从标题中提取的各种字段
+     */
+    public static int AV_PIX_FMT_VDPAU_MPEG1 = 37;
+    /**
+     * 使用VDPAU的MPEG-2硬件解码,数据[0]包含一个vdpau_render_state结构,
+     * 其中包含片段的比特流以及从头部提取的各种字段
+     */
+    public static int AV_PIX_FMT_VDPAU_MPEG2 = 38;
+    /**
+     * 使用VDPAU的WMV3硬件解码,数据[0]包含一个包含片段的比特流的vdpau_render_state结构以及从头提取的各种字段
+     */
+    public static int AV_PIX_FMT_VDPAU_WMV3 = 39;
+    /**
+     * 使用VDPAU的VC-1 HW解码,数据[0]包含一个vdpau_render_state结构,
+     * 其中包含片段的比特流以及从标题中提取的各种字段
+     */
+    public static int AV_PIX_FMT_VDPAU_VC1 = 40;
+    /**
+     * 打包RGB 16:16:16,48bpp,16R,16G,16B,每个R / G / B组件的2字节值存储为big-endian
+     */
+    public static int AV_PIX_FMT_RGB48BE = 41;
+    /**
+     * 打包RGB 16:16:16,48bpp,16R,16G,16B,每个R / G / B组件的2字节值存储为小尾数
+     */
+    public static int AV_PIX_FMT_RGB48LE = 42;
+
+    /**
+     * 打包RGB 5:6:5,16bpp,(msb)5R 6G 5B(lsb),big-endian
+     */
+    public static int AV_PIX_FMT_RGB565BE = 43;
+    /**
+     * 包装RGB 5:6:5,16bpp,(msb)5R 6G 5B(lsb),little-endian
+     */
+    public static int AV_PIX_FMT_RGB565LE = 44;
+    /**
+     * 打包RGB 5:5:5,16bpp,(msb)1A 5R 5G 5B(lsb),大端,最高有效位为0
+     */
+    public static int AV_PIX_FMT_RGB555BE = 45;
+    /**
+     * 包装RGB 5:5:5,16bpp,(msb)1A 5R 5G 5B(lsb),小端,最高有效位为0
+     */
+    public static int AV_PIX_FMT_RGB555LE = 46;
+
+    /**
+     * 包装BGR 5:6:5,16bpp,(msb)5B 6G 5R(lsb),big-endian
+     */
+    public static int AV_PIX_FMT_BGR565BE = 47;
+    /**
+     * 打包BGR 5:6:5,16bpp ,(msb)5B 6G 5R(lsb),little-endian
+     */
+    public static int AV_PIX_FMT_BGR565LE = 48;
+    /**
+     * 打包BGR 5:5:5,16bpp,(msb)1A 5B 5G 5R(lsb ),big-endian,最高有效位到1
+     */
+    public static int AV_PIX_FMT_BGR555BE = 49;
+    /**
+     * 打包BGR 5:5:5,16bpp,(msb)1A 5B 5G 5R(lsb) -endian,最高有效位到1
+     */
+    public static int AV_PIX_FMT_BGR555LE = 50;
+
+    /**
+     * 通过VA API在运动补偿入口处的HW加速,Picture.
+     * data [3]包含一个vaapi_render_state struct包含宏块以及从头文件提取的各种字段
+     */
+    public static int AV_PIX_FMT_VAAPI_MOCO = 51;
+    /**
+     * 通过IDC入口点的VA API加速硬件,Picture.data [3]包含一个vaapi_render_state结构,其中包含从头部提取的字段
+     */
+    public static int AV_PIX_FMT_VAAPI_IDCT = 52;
+    /**
+     * 通过VA API进行HW解码,Picture.data [3]包含一个vaapi_render_state结构,其中包含片段的比特流以及从标题中提取的各种字段
+     */
+    public static int AV_PIX_FMT_VAAPI_VLD = 53;
+
+    /**
+     * 平面YUV 4:2:0,24bpp,(1 Cr&每个2x2 Y样本的Cb样本),little-endian
+     */
+    public static int AV_PIX_FMT_YUV420P16LE = 54;
+    /**
+     * 平面YUV 4:2:0,248pp,(每2×2个样本1 Cr& Cb样本) ,big-endian
+     */
+    public static int AV_PIX_FMT_YUV420P16BE = 55;
+    /**
+     * 平面YUV 4:2:2,32bpp,(每2×1个样本1 Cr& Cb样本),little-endian
+     */
+    public static int AV_PIX_FMT_YUV422P16LE = 56;
+    /**
+     * 平面YUV 4:2:2,32bpp,(每2×1个样本1 Cr& Cb样本),big-endian
+     */
+    public static int AV_PIX_FMT_YUV422P16BE = 57;
+    /**
+     * 平面YUV 4:4:4,48bpp,(每1×1个样本1 Cr& Cb样本),小尾数
+     */
+    public static int AV_PIX_FMT_YUV444P16LE = 58;
+    /**
+     * 平面YUV 4:4:4,48bpp,(每1×1个样品1 Cr& Cb样品),big-endian
+     */
+    public static int AV_PIX_FMT_YUV444P16BE = 59;
+    /**
+     * 使用VDPAU的MPEG4硬件解码,数据[0]包含一个vdpau_render_state结构,其中包含片段的比特流以及从头部提取的各种字段
+     */
+    public static int AV_PIX_FMT_VDPAU_MPEG4 = 60;
+    /**
+     * 硬解码thr哦DXVA2,Picture.data [3]包含一个LPDIRECT3DSURFACE9指针
+     */
+    public static int AV_PIX_FMT_DXVA2_VLD = 61;
+
+    /**
+     * 打包RGB 4:4:4,16bpp,(msb)4A 4R 4G 4B(lsb),小端,最高有效位为0
+     */
+    public static int AV_PIX_FMT_RGB444LE = 62;
+    /**
+     * 打包RGB 4:4:4,16bpp,(msb)4A 4R 4G 4B(lsb ),big-endian,最高有效位为0
+     */
+    public static int AV_PIX_FMT_RGB444BE = 63;
+    /**
+     * 打包BGR 4:4:4,16bpp,(msb)4A 4B 4G 4R(lsb) -endian,最高有效位为1
+     */
+    public static int AV_PIX_FMT_BGR444LE = 64;
+    /**
+     * 打包BGR 4:4:4,16bpp,(msb)4A 4B 4G 4R(lsb),big-endian,最高有效位为1
+     */
+    public static int AV_PIX_FMT_BGR444BE = 65;
+    /**
+     * 8位灰色,8位alpha
+     */
+    public static int AV_PIX_FMT_YA8 = 66;
+}

+ 181 - 35
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/CornerCheck.java

@@ -1,5 +1,4 @@
-
-package org.jeecg.modules.demo.opencv;
+package org.jeecg.modules.opencv.utils;
 
 import cn.com.ctop.common.module.utils.ResultMapUtils;
 import cn.com.ctop.common.module.utils.StatusCode;
@@ -12,6 +11,7 @@ import java.util.*;
 /**
  * 角点检测
  */
+
 public class CornerCheck {
     static {
         System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
@@ -19,27 +19,11 @@ public class CornerCheck {
 
     private static int EXPAND_SIZE = 3;
     public static void main(String[] args) {
+//        harris();
+//        detectConers();
         channelSplit();
     }
 
-    public static void channelSplit() {
-        Mat srcImage = Imgcodecs.imread("D:\\data\\235.jpg", Imgcodecs.IMREAD_COLOR);
-        List<Mat> channels = new ArrayList<>();
-        Core.split(srcImage, channels);
-
-        //创建类型为Mat,数组长度为3的变量mbgr
-        List<Mat> mbgr = new ArrayList<>();
-        Mat hideChannel = new Mat(srcImage.size(), CvType.CV_8UC1, new Scalar(0));
-
-        Mat imageB = new Mat(srcImage.size(), CvType.CV_8UC3);
-        mbgr.add(channels.get(0));
-        mbgr.add(hideChannel);
-        mbgr.add(hideChannel);
-        Core.merge(mbgr, imageB);
-        Imgcodecs.imwrite("D:\\data\\imageB.jpg", imageB);
-
-    }
-
     public static Map<String, Object> detectConers() {
         Map<String, Object> result = new HashMap<>();
         try {
@@ -58,7 +42,6 @@ public class CornerCheck {
             Mat gray = new Mat();
             //灰度
             Imgproc.cvtColor(src, gray, Imgproc.COLOR_RGB2GRAY);
-            Imgcodecs.imwrite("D:\\data\\gray.jpg", gray);
             Mat binary = new Mat();
             //二值化
             Imgproc.threshold(gray, binary, 1, 255, Imgproc.THRESH_TOZERO);
@@ -141,25 +124,56 @@ public class CornerCheck {
         return matCornerList;
     }
 
-    public static List<Point> detectConerList() {
+    public static List<Point> detectConerList(String filePath) {
         List<Point> result = new ArrayList<>();
         try {
             System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
-
-            final int maxCorners = 50, blockSize = 3;
-            final double qualityLevel = 0.01, minDistance = 20.0, k = 0.04;
+            Mat src = Imgcodecs.imread(filePath);
+            if (src.empty()) {
+                throw new Exception("no file");
+            }
+            final int maxCorners = 1000, blockSize = 5;
+            final double qualityLevel = 0.05, minDistance = 10.0, k = 0.04;
             final boolean useHarrisDetector = false;
             MatOfPoint corners = new MatOfPoint();
 
-            Mat src = Imgcodecs.imread("D:\\data\\167.jpg");
-            if (src.empty()) {
-                throw new Exception("no file");
+            for (int i = 0; i < src.cols(); i++) {
+                for (int j = 0; j < src.rows(); j++) {
+                    if (i > 160 && i < 470 && j > 250 && j < 750) {
+                        Imgproc.circle(src, new Point(i, j), 1, new Scalar(0, 236, 2), Imgproc.FILLED);
+                    }
+                }
             }
+//            //卷积
+//            Mat kernel = new Mat(3, 3, CvType.CV_16SC1);
+//            kernel.put(0, 0, 0, -1, 0, -1, 5, -1, 0, -1, 0);
+//            Imgproc.filter2D(src, src, src.depth(), kernel);
+//            //降噪
+//            Imgproc.GaussianBlur(src, src, new Size(3, 3), 0, 0, 1);
             Mat dst = src.clone();
             Mat gray = new Mat();
+            //灰度
             Imgproc.cvtColor(src, gray, Imgproc.COLOR_RGB2GRAY);
-            Imgproc.goodFeaturesToTrack(gray, corners, maxCorners, qualityLevel, minDistance,
-                    new Mat(), blockSize, useHarrisDetector, k);
+//            //归一处理
+//            Core.normalize(gray,gray);
+            //Sobel算子
+//            Mat grad_x = new Mat(), grad_y = new Mat();
+//            Mat abs_grad_x = new Mat(), abs_grad_y = new Mat();
+//            int scale = 1;
+//            int delta = 0;
+//            //Gradient X
+//            Imgproc.Sobel(gray, grad_x, CvType.CV_16S, 1, 0, 3, scale, delta, 1);
+//            //Gradient y
+//            Imgproc.Sobel(gray, grad_y, CvType.CV_16S, 0, 1, 3, scale, delta, 1);
+//
+//            Core.convertScaleAbs(grad_x, abs_grad_x);
+//            Core.convertScaleAbs(grad_y, abs_grad_y);
+//
+//            /// Total Gradient (approximate)
+//            Mat grad = new Mat();
+//            Core.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
+
+            Imgproc.goodFeaturesToTrack(gray, corners, maxCorners, qualityLevel, minDistance, new Mat(), blockSize, useHarrisDetector, k);
             Point[] pCorners = corners.toArray();
             List<Point> pointList = new ArrayList<>();
             double maxX = 0d;
@@ -167,7 +181,8 @@ public class CornerCheck {
             double minX = 10000d;
             double minY = 100000d;
             for (int i = 0; i < pCorners.length; i++) {
-                if (pCorners[i].x > 130 && pCorners[i].x < 570 && pCorners[i].y > 200 && pCorners[i].y < 850) {
+//                Imgproc.circle(dst, pCorners[i], 4, new Scalar(255, 0, 255), Imgproc.FILLED);
+                if (pCorners[i].x > 120 && pCorners[i].x < 555 && pCorners[i].y > 200 && pCorners[i].y < 860) {
                     if (pCorners[i].x >= maxX) {
                         maxX = pCorners[i].x;
                     }
@@ -185,17 +200,62 @@ public class CornerCheck {
                     pointList.add(pCorners[i]);
                 }
             }
+            Imgproc.line(dst, new Point(minX, minY), new Point(minX, maxY), new Scalar(255, 255, 255));
+            Imgproc.line(dst, new Point(minX, maxY), new Point(maxX, maxY), new Scalar(255, 255, 255));
+            Imgproc.line(dst, new Point(maxX, maxY), new Point(maxX, minY), new Scalar(255, 255, 255));
+            Imgproc.line(dst, new Point(maxX, minY), new Point(minX, minY), new Scalar(255, 255, 255));
             List<Point> cornerPoints = new ArrayList<>();
             for (Point point : pointList) {
                 double getX = point.x;
                 double getY = point.y;
-                if ((getY >= (minY + 20) && getY <= (maxY - 20))) {
-                    Imgproc.circle(dst, point, 4, new Scalar(255, 255, 255), Imgproc.FILLED);
+                if ((getY >= (minY + 50) && getY <= (maxY - 50)) || (getX >= (minX + 25) && getX <= (maxX - 70))) {
+                    Imgproc.circle(dst, point, 4, new Scalar(0, 255, 0), Imgproc.FILLED);
                 } else {
+                    Imgproc.circle(dst, point, 4, new Scalar(255, 0, 255), Imgproc.FILLED);
                     cornerPoints.add(point);
-                    Imgproc.circle(dst, point, 4, new Scalar(0, 0, 255), Imgproc.FILLED);
                 }
             }
+            Point[] cornerArray = new Point[cornerPoints.size()];
+
+            for (int i = 0; i < cornerPoints.size(); i++) {
+                cornerArray[i] = cornerPoints.get(i);
+            }
+            /*MatOfPoint2f srcPoint = new MatOfPoint2f(cornerArray);
+            MatOfPoint2f destPoint = new MatOfPoint2f();
+            Imgproc.approxPolyDP(srcPoint,destPoint,100,true);
+            Point []des = destPoint.toArray();
+            for (int i=0;i<des.length-2;i++) {
+                Imgproc.line(dst,des[i],des[i+1],new Scalar(255,255,255));
+            }*/
+            Collections.sort(cornerPoints, new Comparator<Point>() {
+                @Override
+                public int compare(Point p1, Point p2) {
+                    return (int) (p1.x + p1.y - p2.x - p2.y);
+                }
+            });
+            List<Mat> channels = new ArrayList<>();
+            Core.split(src, channels);
+            List<Mat> mbgr = new ArrayList<>();
+            Mat hideChannel = new Mat(src.size(), CvType.CV_8UC1, new Scalar(0));
+            Mat imageGR = new Mat(src.size(), CvType.CV_8UC3);
+            mbgr = new ArrayList<>();
+            mbgr.add(hideChannel);
+            mbgr.add(channels.get(1));
+            mbgr.add(channels.get(2));
+            Core.merge(mbgr, imageGR);
+            List<Point> checkPoints = new ArrayList<>();
+            Point rightDown = cornerPoints.get(cornerPoints.size() - 1);
+            for (Point point : cornerPoints) {
+                System.out.println("cornerPoint:" + point.toString());
+                System.out.println(imageGR.get((int) point.y, (int) point.x)[1]);
+                if (imageGR.get((int) point.y, (int) point.x)[1] >= 120) {
+                    if (point.x <= rightDown.x) {
+                        System.out.println("greenPoint:" + point.toString());
+                        checkPoints.add(point);
+                    }
+                }
+            }
+            cornerPoints = checkPoints;
             Collections.sort(cornerPoints, new Comparator<Point>() {
                 @Override
                 public int compare(Point p1, Point p2) {
@@ -216,11 +276,97 @@ public class CornerCheck {
                 result.add(new Point(cornerPoints.get(1).x - EXPAND_SIZE, cornerPoints.get(1).y + EXPAND_SIZE));
             }
             //右下
-            result.add(new Point(cornerPoints.get(3).x + EXPAND_SIZE, cornerPoints.get(3).y + EXPAND_SIZE));
+            result.add(new Point(cornerPoints.get(cornerPoints.size() - 1).x + EXPAND_SIZE, cornerPoints.get(cornerPoints.size() - 1).y + EXPAND_SIZE));
+
+            for (Point point : result) {
+                Imgproc.circle(dst, point, 10, new Scalar(255, 0, 255), Imgproc.FILLED);
+            }
+            Imgcodecs.imwrite("D:\\data\\allConers.jpg", dst);
             return result;
         } catch (Exception e) {
             e.printStackTrace();
             return result;
         }
     }
+
+    public static void channelSplit() {
+        Mat srcImage = Imgcodecs.imread("D:\\data\\163.jpg", Imgcodecs.IMREAD_COLOR);
+        List<Mat> channels = new ArrayList<>();
+        Core.split(srcImage, channels);
+
+        //创建类型为Mat,数组长度为3的变量mbgr
+        List<Mat> mbgr = new ArrayList<>();
+        Mat hideChannel = new Mat(srcImage.size(), CvType.CV_8UC1, new Scalar(0));
+
+        Mat imageB = new Mat(srcImage.size(), CvType.CV_8UC3);
+        mbgr.add(channels.get(0));
+        mbgr.add(hideChannel);
+        mbgr.add(hideChannel);
+        Core.merge(mbgr, imageB);
+        List<Point> points = detectConerList("D:\\data\\imageB.jpg");
+        for (Point point : points) {
+            Imgproc.circle(imageB, point, 5, new Scalar(0, 0, 0));
+        }
+        Imgcodecs.imwrite("D:\\data\\imageB.jpg", imageB);
+
+        mbgr = new ArrayList<>();
+        Mat imageG = new Mat(srcImage.size(), CvType.CV_8UC3);
+        mbgr.add(hideChannel);
+        mbgr.add(channels.get(1));
+        mbgr.add(hideChannel);
+        Core.merge(mbgr, imageG);
+        points = detectConerList("D:\\data\\imageG.jpg");
+        for (Point point : points) {
+            Imgproc.circle(imageG, point, 5, new Scalar(0, 0, 0));
+        }
+        Imgcodecs.imwrite("D:\\data\\imageG.jpg", imageG);
+
+        mbgr = new ArrayList<>();
+        Mat imageR = new Mat(srcImage.size(), CvType.CV_8UC3);
+        mbgr.add(hideChannel);
+        mbgr.add(hideChannel);
+        mbgr.add(channels.get(2));
+        Core.merge(mbgr, imageR);
+        points = detectConerList("D:\\data\\imageR.jpg");
+        for (Point point : points) {
+            Imgproc.circle(imageR, point, 5, new Scalar(0, 0, 0));
+        }
+        Imgcodecs.imwrite("D:\\data\\imageR.jpg", imageR);
+
+        mbgr = new ArrayList<>();
+        Mat imageBG = new Mat(srcImage.size(), CvType.CV_8UC3);
+        mbgr.add(channels.get(0));
+        mbgr.add(channels.get(1));
+        mbgr.add(hideChannel);
+        Core.merge(mbgr, imageBG);
+        points = detectConerList("D:\\data\\imageBG.jpg");
+        for (Point point : points) {
+            Imgproc.circle(imageBG, point, 5, new Scalar(0, 0, 0));
+        }
+        Imgcodecs.imwrite("D:\\data\\imageBG.jpg", imageBG);
+
+        Mat imageGR = new Mat(srcImage.size(), CvType.CV_8UC3);
+        mbgr = new ArrayList<>();
+        mbgr.add(hideChannel);
+        mbgr.add(channels.get(1));
+        mbgr.add(channels.get(2));
+        Core.merge(mbgr, imageGR);
+        points = detectConerList("D:\\data\\imageGR.jpg");
+        for (Point point : points) {
+            Imgproc.circle(imageGR, point, 5, new Scalar(0, 0, 0));
+        }
+        Imgcodecs.imwrite("D:\\data\\imageGR.jpg", imageGR);
+
+        mbgr = new ArrayList<>();
+        Mat imageBR = new Mat(srcImage.size(), CvType.CV_8UC3);
+        mbgr.add(channels.get(0));
+        mbgr.add(hideChannel);
+        mbgr.add(channels.get(2));
+        Core.merge(mbgr, imageBR);
+        points = detectConerList("D:\\data\\imageBR.jpg");
+        for (Point point : points) {
+            Imgproc.circle(imageBR, point, 5, new Scalar(0, 0, 0));
+        }
+        Imgcodecs.imwrite("D:\\data\\imageBR.jpg", imageBR);
+    }
 }

+ 126 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/utils/ImageUtils.java

@@ -0,0 +1,126 @@
+package org.jeecg.modules.opencv.utils;
+
+import org.opencv.core.*;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+
+public class ImageUtils {
+
+    /**
+     * 按照指定的尺寸截取Mat,坐标原点为左上角
+     *
+     * @param src    源Mat
+     * @param width  width
+     * @param height height
+     * @return 截取后的Mat
+     */
+    public static Mat cutFromCenter(Mat src, int width, int height) {
+        if (width > src.width()) {
+            width = src.width();
+        }
+        if (height > src.height()) {
+            height = src.height();
+        }
+        int originX = (src.width() - width) / 2;
+        int originy = (src.height() - height) / 2;
+        // 截取尺寸
+        Rect rect = new Rect(originX, originy, width, height);
+        return new Mat(src, rect);
+    }
+
+    public static Mat radialBlur(Mat src) {
+        Mat returnMat = new Mat(src.size(), CvType.CV_32FC3);
+        src.convertTo(returnMat, CvType.CV_32FC3);
+        int width = src.width();
+        int height = src.height();
+        double r;
+        double angle;
+        Point center = new Point(width / 2, height / 2);
+        double t1, t2, t3;
+        int new_x, new_y;
+        int Num = 20;
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x++) {
+                t1 = 0;
+                t2 = 0;
+                t3 = 0;
+                r = Math.sqrt((y - center.y) * (y - center.y) + (x - center.x) * (x - center.x));
+                angle = Math.atan2((y - center.y), (x - center.x));
+                for (int mm = 0; mm < Num; mm++) {
+                    double tmR = r - mm > 0 ? r - mm : 0.0;
+                    new_x = (int) (tmR * Math.cos(angle) + center.x);
+                    new_y = (int) (tmR * Math.sin(angle) + center.y);
+                    if (new_x < 0) {
+                        new_x = 0;
+                    }
+                    if (new_x > width - 1) {
+                        new_x = width - 1;
+                    }
+                    if (new_y < 0) {
+                        new_y = 0;
+                    }
+                    if (new_y > height - 1) {
+                        new_y = height - 1;
+                    }
+                    t1 = t1 + src.get(new_y, new_x)[0];
+                    t2 = t2 + src.get(new_y, new_x)[1];
+                    t3 = t3 + src.get(new_y, new_x)[2];
+                }
+                returnMat.put(y, x, t1 / Num, t2 / Num, t3 / Num);
+            }
+        }
+        return returnMat;
+    }
+
+    /**
+     * 矩阵横向拼接
+     *
+     * @param matrix1
+     * @param matrix2
+     * @param matrixCom
+     * @return
+     */
+    public static Mat hconcat(Mat matrix1, Mat matrix2, Mat matrixCom) {
+        matrixCom.create(matrix1.rows(), matrix1.cols() + matrix2.cols(), matrix1.type());
+        Mat temp = matrixCom.colRange(0, matrix1.cols());
+        matrix1.copyTo(temp);
+        Mat temp1 = matrixCom.colRange(matrix1.cols(), matrix1.cols() + matrix2.cols());
+        matrix2.copyTo(temp1);
+        return matrixCom;
+    }
+
+    /**
+     * 矩阵纵向拼接
+     *
+     * @param matrix1
+     * @param matrix2
+     * @param matrixCom
+     * @return
+     */
+    public static Mat vconcat(Mat matrix1, Mat matrix2, Mat matrixCom) {
+        matrixCom.create(matrix1.rows() + matrix2.rows(), matrix1.cols(), matrix1.type());
+        Mat temp = matrixCom.rowRange(0, matrix1.rows());
+        matrix1.copyTo(temp);
+        Mat temp1 = matrixCom.rowRange(matrix1.rows(), matrix1.rows() + matrix2.rows());
+        matrix2.copyTo(temp1);
+        return matrixCom;
+    }
+
+    public static void main(String[] args) {
+        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+        Mat image = Imgcodecs.imread("D:\\data\\167.jpg", Imgcodecs.IMREAD_COLOR);
+        Mat bigImamge = new Mat();
+        Mat smallImage = new Mat();
+        Mat halfImage = new Mat();
+        Mat wholeImage = new Mat();
+        Imgproc.resize(image, bigImamge, new Size(image.cols() * 1.25, image.rows() * 1.25));
+        Imgproc.resize(image, smallImage, new Size(image.cols() / 2, image.rows() / 2));
+        hconcat(smallImage, smallImage, halfImage);
+        vconcat(halfImage, halfImage, wholeImage);
+        Mat destImage = cutFromCenter(bigImamge, image.width(), image.height());
+        wholeImage = radialBlur(wholeImage);
+        Mat radialBlur = radialBlur(destImage);
+        Imgcodecs.imwrite("D:\\data\\radialBlur.jpg", radialBlur);
+        Imgcodecs.imwrite("D:\\data\\whole.jpg", wholeImage);
+    }
+}

+ 4 - 7
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Perspective.java

@@ -1,4 +1,4 @@
-package org.jeecg.modules.demo.opencv;
+package org.jeecg.modules.opencv.utils;
 
 
 import org.opencv.core.*;
@@ -11,11 +11,8 @@ import java.util.List;
 /**
  * 透视变换
  */
-public class Perspective {
-    public static void main(String[] args) {
-
-    }
 
+public class Perspective {
     public static void perpectiveImg(String backgroundImgPath, String phoneImgPath, String targetFileName) {
         try {
             System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
@@ -24,7 +21,7 @@ public class Perspective {
             Mat dst = Imgcodecs.imread(backgroundImgPath);
             Mat dst1 = dst.clone();
             //透视变换点位
-            List<Point> perspectivePoints = CornerCheck.detectConerList();
+            List<Point> perspectivePoints = CornerCheck.detectConerList(backgroundImgPath);
             //矩形点位
             List<Point> matPoints = CornerCheck.matCornerList(perspectivePoints);
             //读取图像到矩阵中
@@ -51,6 +48,7 @@ public class Perspective {
             Imgcodecs.imwrite(targetFileName, dst);
         } catch (Exception e) {
             e.printStackTrace();
+            System.out.println("例外:" + e);
         }
     }
 
@@ -108,7 +106,6 @@ public class Perspective {
         return (iSum % 2) != 0;
     }
 
-
     /**
      * 判断点是否在多边形内,如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
      *

+ 23 - 16
jeecg-boot-module-system/src/main/java/org/jeecg/modules/demo/opencv/Test.java

@@ -1,4 +1,4 @@
-package org.jeecg.modules.demo.opencv;
+package org.jeecg.modules.opencv.utils;
 
 import org.opencv.core.Core;
 import org.opencv.core.Mat;
@@ -6,6 +6,8 @@ import org.opencv.core.Size;
 import org.opencv.imgcodecs.Imgcodecs;
 import org.opencv.imgproc.Imgproc;
 
+import java.io.File;
+
 public class Test {
     public static void initVideo() {
         System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
@@ -19,10 +21,10 @@ public class Test {
         int srcPhoneFrameNumFrom = 163;
         int changeSenceFrameNumFrom = 234;
         //2.1 复制原始视频无变化图片
-//        for(int i=1;i<srcPhoneFrameNumFrom;i++){
-//            Mat srcNoChangeImage = Imgcodecs.imread(srcPath+i+".jpg");
-//            Imgcodecs.imwrite(targetPath+i+".jpg",srcNoChangeImage);
-//        }
+        for (int i = 1; i < srcPhoneFrameNumFrom; i++) {
+            Mat srcNoChangeImage = Imgcodecs.imread(srcPath + i + ".jpg");
+            Imgcodecs.imwrite(targetPath + i + ".jpg", srcNoChangeImage);
+        }
         String getImageName = "";
         //2.2 填充手机内部图片画面
         for (int i = 163; i < changeSenceFrameNumFrom; i++) {
@@ -56,17 +58,22 @@ public class Test {
         Imgcodecs.imwrite(targetPath + changeSenceFrameNumFrom + ".jpg", wholeImage);
         changeSenceFrameNumFrom++;
         //复制填充视频无变化图片
-//        for(int i=changeSenceFrameNumFrom;i<100000;i++){
-//            int checkNum = i-3-srcPhoneFrameNumFrom+1;
-//            String fillImagePath = fillPath+checkNum+".jpg";
-//            File file = new File(fillImagePath);
-//            if(file.exists()){
-//                Mat srcMat = Imgcodecs.imread(fillImagePath);
-//                Imgcodecs.imwrite(targetPath+i+".jpg",srcMat);
-//            }else{
-//                break;
-//            }
-//        }
+        for (int i = changeSenceFrameNumFrom; i < 100000; i++) {
+            int checkNum = i - 3 - srcPhoneFrameNumFrom + 1;
+            String fillImagePath = fillPath + checkNum + ".jpg";
+            File file = new File(fillImagePath);
+            if (file.exists()) {
+                Mat srcMat = Imgcodecs.imread(fillImagePath);
+                Imgcodecs.imwrite(targetPath + i + ".jpg", srcMat);
+            } else {
+                break;
+            }
+        }
+    }
+
+
+    public static void main(String[] args) {
+        initVideo();
     }
 
 }

+ 101 - 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/opencv/utils/VideoProcessing.java

@@ -0,0 +1,101 @@
+package org.jeecg.modules.opencv.utils;
+
+import cn.com.ctop.common.module.utils.LoadFileUtil;
+import org.bytedeco.javacpp.avcodec;
+import org.bytedeco.javacpp.opencv_core;
+import org.bytedeco.javacv.*;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.File;
+
+import static org.bytedeco.javacpp.opencv_imgcodecs.cvLoadImage;
+
+/**
+ * 视频截帧处理
+ */
+public class VideoProcessing {
+    /**
+     * 将视频文件帧处理并以“jpg”格式进行存储。
+     * 依赖FrameToBufferedImage方法:将frame转换为bufferedImage对象
+     * 视频帧拆分
+     * @param videoFileName
+     */
+    public static String grabberVideoFramer(String videoFileName, String filePackageName) {
+        //最后获取到的视频的图片的路径
+        String videPicture = "";
+        //Frame对象
+        Frame frame = null;
+        //标识
+        int flag = 0;
+        try {
+
+            /*获取视频文件*/
+            FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoFileName);
+            fFmpegFrameGrabber.start();
+
+            //获取视频总帧数
+            int ftp = fFmpegFrameGrabber.getLengthInFrames();
+            System.out.println("时长 " + ftp / fFmpegFrameGrabber.getFrameRate() / 60);
+            LoadFileUtil.checkFile(filePackageName);
+            while (flag <= ftp) {
+                frame = fFmpegFrameGrabber.grabImage();
+                /*对视频的第五帧进行处理*/
+                if (frame != null) {
+                    //文件绝对路径+名字
+                    String fileName = filePackageName + String.valueOf(flag) + ".jpg";
+                    //文件储存对象
+                    File outPut = new File(fileName);
+                    ImageIO.write(FrameToBufferedImage(frame), "jpg", outPut);
+                }
+                flag++;
+            }
+            fFmpegFrameGrabber.stop();
+            fFmpegFrameGrabber.close();
+        } catch (Exception E) {
+            E.printStackTrace();
+        }
+        return videPicture;
+    }
+
+    public static void videoMerge(String videoFileName, String imagePackage) throws FrameRecorder.Exception {
+        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(videoFileName, 720, 1280);
+//
+        recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4); // 28
+//		recorder.setFormat("mp4");
+        //	recorder.setFormat("mov,mp4,m4a,3gp,3g2,mj2,h264,ogg,MPEG4");
+        recorder.setFrameRate(25);
+        recorder.setPixelFormat(Avutils.AV_PIX_FMT_YUV422P); // yuv420p
+        recorder.start();
+        //
+        OpenCVFrameConverter.ToIplImage conveter = new OpenCVFrameConverter.ToIplImage();
+        // 列出目录中所有的图片,都是jpg的,以1.jpg,2.jpg的方式,方便操作
+        File file = new File(imagePackage);
+        File[] flist = file.listFiles();
+        // 循环所有图片
+        for (int i = 1; i <= flist.length; i++) {
+            String fname = imagePackage + i + ".jpg";
+            opencv_core.IplImage image = cvLoadImage(fname); // 非常吃内存!!
+            recorder.record(conveter.convert(image));
+            // 释放内存? cvLoadImage(fname); // 非常吃内存!!
+            opencv_core.cvReleaseImage(image);
+        }
+        recorder.stop();
+        recorder.release();
+    }
+
+    public static BufferedImage FrameToBufferedImage(Frame frame) {
+        //创建BufferedImage对象
+        Java2DFrameConverter converter = new Java2DFrameConverter();
+        BufferedImage bufferedImage = converter.getBufferedImage(frame);
+        return bufferedImage;
+    }
+
+    public static void main(String[] args) {
+        try {
+            videoMerge("D:\\data\\merge.mp4", "D:\\data\\video\\");
+        } catch (FrameRecorder.Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 2 - 1
jeecg-boot-module-system/src/main/resources/application-prod.yml

@@ -142,7 +142,8 @@ mybatis-plus:
 #jeecg专用配置
 jeecg:
   ffmpeg:
-    bin: /mnt/ffmpeg/bin
+    #    bin: /mnt/ffmpeg/bin
+    bin: D:\java\ffmpeg\bin\ffmpeg.exe
   path:
     #文件上传根目录 设置
     upload: /mnt/upload

+ 8 - 15
jeecg-boot-module-system/src/test/java/org/jeecg/SampleTest.java

@@ -7,6 +7,7 @@ import cn.com.ctop.common.module.service.ICtopOauthTokenService;
 import cn.com.ctop.common.module.service.IUserAllocationService;
 import cn.com.ctop.common.module.utils.CtopAdConstant;
 import cn.com.ctop.common.module.utils.HttpUtils;
+import cn.com.ctop.common.module.utils.OSSUtils;
 import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouCreativeService;
 import cn.com.ctop.kuaishou.modules.batch.service.IKuaiShouHistoryReportTaskService;
 import cn.com.ctop.kuaishou.modules.batch.service.IKuaishouInterfaceService;
@@ -24,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.io.FileInputStream;
+import java.io.InputStream;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
@@ -295,22 +298,12 @@ public class SampleTest {
         Long accountId = 3917130L;
         String token = "0a42e23921e486108105263e75561404";
         kuaishouInterfaceService.getVideoList("e91c778d7de1bd0e9d8f3213d1e0e57c",3820093L, null,null,1);
+    }
 
-      /*  String url = "https://ad.e.kuaishou.com/rest/openapi/v1/file/ad/video/su_zao/list";
-
-
-        Map<String, String> headers = new HashMap<String, String>();
-        headers.put("Content-Type", "application/json");
-        headers.put("Access-Token", token);
-        Map<String, Object> param = new HashMap<String, Object>();
-
-        param.put("advertiser_id", accountId);
-        param.put("temporal_granularity", "HOURLY");
-        param.put("page", 1);
-        String result = HttpUtils.httpPostRequest(url, param, headers);
-        System.err.println(result);*/
-
-
+    @Test
+    public void test() throws Exception {
+        InputStream file = new FileInputStream("D:\\data\\模板视频\\原始模板4.mp4");
+        OSSUtils.uploadFile2OSS(file, "/model/video/", "123.mp4");
     }
 
 

+ 6 - 0
module-common/src/main/java/cn/com/ctop/common/module/utils/LoadFileUtil.java

@@ -106,4 +106,10 @@ public class LoadFileUtil {
         System.out.println(LoadFileUtil.getMD5("D://video/BMjAyMDAzMDQxODMyMTlfMTU3ODQ0ODY5MV8yNDQ1ODc0Mzk1OF8wXzM=_b_Bd696ca7f28234aac3713b18edd139469.mp4"));
     }
 
+    public static void checkFile(String filePackageName) {
+        File file = new File(filePackageName);
+        if (!file.exists()) {
+            file.mkdir();
+        }
+    }
 }

+ 73 - 42
module-common/src/main/java/cn/com/ctop/common/module/utils/OSSUtils.java

@@ -1,25 +1,21 @@
 package cn.com.ctop.common.module.utils;
 
+import com.aliyun.oss.ClientException;
 import com.aliyun.oss.OSS;
 import com.aliyun.oss.OSSClientBuilder;
-import com.aliyun.oss.model.Bucket;
-import com.aliyun.oss.model.OSSObject;
-import com.aliyun.oss.model.ObjectMetadata;
-import com.aliyun.oss.model.PutObjectResult;
+import com.aliyun.oss.OSSException;
+import com.aliyun.oss.model.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.PropertySource;
 
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
+import java.io.*;
 import java.util.Date;
 
 /**
- * @author yumeng
+ * @author syh
  * 2019年11月12日10:04:00
  */
 @Configuration
@@ -57,6 +53,45 @@ public class OSSUtils {
         return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
     }
 
+    public static void uploadFile(String fileName) throws IOException {
+
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+        try {
+            UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, "sadsda");
+            // The local file to upload---it must exist.
+            uploadFileRequest.setUploadFile(fileName);
+            // Sets the concurrent upload task number to 5.
+            uploadFileRequest.setTaskNum(5);
+            // Sets the part size to 1MB.
+            uploadFileRequest.setPartSize(1024 * 1024 * 1);
+            // Enables the checkpoint file. By default it's off.
+            uploadFileRequest.setEnableCheckpoint(true);
+
+            UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);
+
+            CompleteMultipartUploadResult multipartUploadResult = uploadResult.getMultipartUploadResult();
+            System.out.println(multipartUploadResult.getETag());
+
+        } catch (OSSException oe) {
+            System.out.println("Caught an OSSException, which means your request made it to OSS, "
+                    + "but was rejected with an error response for some reason.");
+            System.out.println("Error Message: " + oe.getErrorMessage());
+            System.out.println("Error Code:       " + oe.getErrorCode());
+            System.out.println("Request ID:      " + oe.getRequestId());
+            System.out.println("Host ID:           " + oe.getHostId());
+        } catch (ClientException ce) {
+            System.out.println("Caught an ClientException, which means the client encountered "
+                    + "a serious internal problem while trying to communicate with OSS, "
+                    + "such as not being able to access the network.");
+            System.out.println("Error Message: " + ce.getMessage());
+        } catch (Throwable e) {
+            e.printStackTrace();
+        } finally {
+            ossClient.shutdown();
+        }
+    }
+
     /**
      * 创建存储空间
      *
@@ -158,7 +193,6 @@ public class OSSUtils {
             // 上传文件 (上传文件流的形式)
             PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, is, metadata);
             Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
-            String url = ossClient.generatePresignedUrl(bucketName, folder + fileName, expiration).toString();
             // 解析结果
             resultStr = putResult.getETag();
         } catch (Exception e) {
@@ -169,45 +203,42 @@ public class OSSUtils {
     }
 
     /**
-     * 上传文件至OSS
+     * 上传到OSS服务器 如果同名文件会覆盖服务器上的
      *
-     * @param file 上传文件(文件全路径如:D:\\image\\cake.jpg)
-     * @return String 返回访问链接
+     * @param instream
+     *            文件流
+     * @param remoteFileName
+     *            文件名称 包括后缀名
+     * @return 出错返回"" ,唯一MD5数字签名
      */
-    public static String uploadFile2Oss(File file) {
-        String resultStr = null;
+    public static String uploadFile2OSS(InputStream instream, String folder, String remoteFileName) {
+        String ret = "";
         try {
             OSS ossClient = OSSUtils.getOssClient();
-            // 以输入流的形式上传文件
-            InputStream is = new FileInputStream(file);
-            // 文件名
-            String fileName = file.getName();
-            // 文件大小
-            Long fileSize = file.length();
             // 创建上传Object的Metadata
-            ObjectMetadata metadata = new ObjectMetadata();
-            // 上传的文件的长度
-            metadata.setContentLength(is.available());
-            // 指定该Object被下载时的网页的缓存行为
-            metadata.setCacheControl("no-cache");
-            // 指定该Object下设置Header
-            metadata.setHeader("Pragma", "no-cache");
-            // 指定该Object被下载时的内容编码格式
-            metadata.setContentEncoding("utf-8");
-            // 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,
-            // 如果没有扩展名则填默认值application/octet-stream
-            metadata.setContentType(getContentType(fileName));
-            // 指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称)
-            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
-            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
-            resultStr = ossClient.generatePresignedUrl(bucketName, folder + fileName, expiration).toString();
-        } catch (Exception e) {
-            e.printStackTrace();
-            logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
+            ObjectMetadata objectMetadata = new ObjectMetadata();
+            objectMetadata.setContentLength(instream.available());
+            objectMetadata.setCacheControl("no-cache");
+            objectMetadata.setHeader("Pragma", "no-cache");
+            objectMetadata.setContentType(getContentType(remoteFileName));
+            objectMetadata.setContentDisposition("inline;filename=" + remoteFileName);
+            createFolder(bucketName, folder);
+            // 上传文件
+            ossClient.putObject(bucketName, folder + remoteFileName, instream, objectMetadata);
+            return folder + remoteFileName;
+        } catch (IOException e) {
+            logger.error(e.getMessage(), e);
+        } finally {
+            try {
+                if (instream != null) {
+                    instream.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
         }
-        return resultStr;
+        return ret;
     }
-
     /**
      * 通过文件名判断并获取OSS服务文件上传时文件的contentType
      *

+ 2 - 1
module-common/src/main/java/cn/com/ctop/common/module/utils/StatusCode.java

@@ -46,7 +46,8 @@ public enum StatusCode {
     KUAISHOU_CRAWLER_APP_SUCCESS("爬虫运行正常", 0, true),
     KUAISHOU_CRAWLER_APP_TASK_END("爬虫任务运行结束", 1, true),
     KUAISHOU_CRAWLER_APP_JOB_StART("任务开始执行开始", 0, true),
-    KUAISHOU_CRAWLER_APP_JOB_END("任务运行结束", 1, true);
+    KUAISHOU_CRAWLER_APP_JOB_END("任务运行结束", 1, true),
+    MODEL_VIDEO_NOT_EXIST("模板视频不存在或者已经被删除", 0, false);
     private String desc;
     private int code;
     private boolean flag;

+ 1 - 1
module-common/src/main/resources/config.properties

@@ -4,4 +4,4 @@ aliyun.accessKeySecret=1rkPz7JNoXk8sJevPaeYHWqfkQXBGh
 # Aliyun OSS Config
 aliyun.oss.endpoint=http://oss-cn-beijing.aliyuncs.com
 aliyun.oss.bucketName=ctop-media
-aliyun.oss.folder=file
+aliyun.oss.folder=model/video/

+ 13 - 1
module-kuaishou/src/main/resources/kuaishou_config.properties

@@ -8,4 +8,16 @@ kuaishou_callback_url=http://adsp.c-top.com.cn:8080/jeecg-boot/kuaishou
 
 apk_sava_path=/mnt/file/apk
 image_sava_path=/mnt/file/image
-video_sava_path=/mnt/file/video
+video_sava_path=/mnt/file/video
+## 模板视频存放路径
+model_video_src_path=/mnt/file/model/video/src/
+## 片段合成视频存放路径
+model_video_fill_path=/mnt/file/model/video/fill/
+##
+model_video_final_path=/mnt/file/model/video/final/
+## 模板视频存放路径
+model_video_src_path_test=D:\\data\\model\\src\\
+## 片段合成视频存放路径
+model_video_fill_path_test=D:\\data\\model\\fill\\
+##
+model_video_final_path_test=D:\\data\\model\\final\\