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