java用到的 ffmpeg一些方法

package com.ruoyi.svm.utils;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.ruoyi.svm.dto.WordAndCoverStyleDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.bytedeco.ffmpeg.ffmpeg;
import org.bytedeco.javacpp.Loader;
import org.springframework.stereotype.Component;
import ws.schild.jave.EncoderException;
import ws.schild.jave.MultimediaObject;
import ws.schild.jave.info.MultimediaInfo;
import ws.schild.jave.process.ProcessWrapper;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Component
public class MyFFmpegUtil {

    /**
     * 等待命令执行成功,退出
     *
     * @param br
     * @throws IOException
     */
    private static void blockFfmpeg(BufferedReader br) throws IOException {
        String line;
        // 该方法阻塞线程,直至合成成功
        while ((line = br.readLine()) != null) {
            doNothing(line);
        }
    }

    /**
     * 打印日志,调试阶段可解开注释,观察执行情况
     *
     * @param line
     */
    private static void doNothing(String line) {
//        log.info(line);
    }

    /**
     * 音频格式转换
     *
     * @param sourcePath 源
     * @param targetPath 目标
     * @throws Exception
     */
    public static void formatAudio(String sourcePath, String targetPath, String ss, String t) throws Exception {
        ProcessWrapper ffmpeg = null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //下面两行都是为了可以直接接受url作为输入
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            if (StringUtils.isNotEmpty(ss) || StringUtils.isNotEmpty(t)) {
                ffmpeg.addArgument("-ss");
                ffmpeg.addArgument(ss);
                ffmpeg.addArgument("-to");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("转换格式成功失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 视频格式转换
     *
     * @param sourcePath 源视频
     * @param targetPath 目标视频
     * @throws Exception
     */
    public static void formatVideo(String sourcePath, String targetPath, String ss, String t) throws Exception {
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //下面两行都是为了可以直接接受url作为输入
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            if (StringUtils.isNotEmpty(ss) || StringUtils.isNotEmpty(t)) {
                ffmpeg.addArgument("-ss");
                ffmpeg.addArgument(ss);
                ffmpeg.addArgument("-to");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            //直接复制音视频,不经过重新编码(这样比较快)
            ffmpeg.addArgument("-codec");
            ffmpeg.addArgument("copy");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("转换格式成功失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 提取视频
     *
     * @param sourcePath
     * @param targetPath
     * @throws Exception
     */
    public static void extractVideo(String sourcePath, String targetPath, String ss, String t) throws Exception {
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //下面两行都是为了可以直接接受url作为输入
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            if (StringUtils.isNotEmpty(ss) || StringUtils.isNotEmpty(t)) {
                ffmpeg.addArgument("-ss");
                ffmpeg.addArgument(ss);
                ffmpeg.addArgument("-to");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            //去掉音频
            ffmpeg.addArgument("-an");
            //直接复制视频,不经过重新编码(这样比较快)
            ffmpeg.addArgument("-vcodec");
            ffmpeg.addArgument("copy");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("提取视频失败");
        }
        finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 提取音频
     * 音频需要对应视频保存的音频格式才行
     *
     * @param sourcePath
     * @param targetPath
     * @throws Exception
     */
    public static void extractAudio(String sourcePath, String targetPath, String vol, String ss, String t) throws Exception {
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //下面两行都是为了可以直接接受url作为输入
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            if (StringUtils.isNotEmpty(ss) || StringUtils.isNotEmpty(t)) {
                ffmpeg.addArgument("-ss");
                ffmpeg.addArgument(ss);
                ffmpeg.addArgument("-to");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            //音量设置
            if (null != vol) {
                String s1 = "volume = " + vol;
                ffmpeg.addArgument("-af");
                ffmpeg.addArgument(s1);
            }
            //去掉视频
            ffmpeg.addArgument("-vn");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("提取音频失败");
        }
        finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * @return void
     * @Author liufangli
     * @Description 修改视频分辨率
     * @Date 9:02 2022/7/21
     * @Param [sourcePath, targetPath, height, width]
     **/
    public static void updateDpiAudio(String pathHead, String sourcePath, String targetPath) throws Exception {
        String tmp = pathHead + IdWorker.getId() + ".mp4";
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //下面两行都是为了可以直接接受url作为输入
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            ffmpeg.addArgument("-vf");
            //视频宽:720 高:等比例自适应 背景:720*1280 视频居中背景
            ffmpeg.addArgument("scale=720:-1,pad=720:1280:0:(1280-ih)/2:black");
            ffmpeg.addArgument(tmp);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
            ffmpeg.close();
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(tmp);
            ffmpeg.addArgument("-vf");
            //设置sar 后期拼接视频才不会报错
            ffmpeg.addArgument("setsar=1");
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("mp4");
            //统一帧数25 保证后期合并视频不出错
            ffmpeg.addArgument("-r");
            ffmpeg.addArgument("25");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("转化视频分辨率失败");
        } finally {
            File file = new File(tmp);
            if (file.exists()) {
                file.delete();
            }
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }


    /**
     * 随机深色背景
     **/
    public static void randomDarkBack(String pathHead, String sourcePath, String targetPath, String color) throws Exception {
        String tmp = pathHead + IdWorker.getId() + ".mp4";
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //下面两行都是为了可以直接接受url作为输入
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            //设置sar 视频宽:720 高:等比例自适应 背景:720*1280 视频居中背景
            ffmpeg.addArgument("-vf");
            ffmpeg.addArgument("setsar=1,scale=720:-1,pad=720:1280:0:(1280-ih)/2:" + color);
            ffmpeg.addArgument(tmp);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
            ffmpeg.close();
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(tmp);
            //统一帧数25 保证后期合并视频不出错
            ffmpeg.addArgument("-r");
            ffmpeg.addArgument("25");
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("mp4");
            //去掉音频
            ffmpeg.addArgument("-an");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("转化视频分辨率失败");
        } finally {
            File file = new File(tmp);
            if (file.exists()) {
                file.delete();
            }
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }



    /**
     * 视频加声音
     * 必须是纯视频和纯音频
     *
     * @param videoPath       视频
     * @param megerAudioPath  音频
     * @param videoTargetPath 目标地址
     * @throws Exception
     */
    public static void mergeVideoAndAudio(
            String videoPath, String megerAudioPath, String videoTargetPath) throws Exception {
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //下面两行都是为了可以直接接受url作为输入
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(videoPath);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(megerAudioPath);
            //合成对象长度以最短的一方为准
            ffmpeg.addArgument("-shortest");
            ffmpeg.addArgument("-c:v");
            ffmpeg.addArgument("libx264");
            ffmpeg.addArgument("-strict");
            ffmpeg.addArgument("-2");
            ffmpeg.addArgument(videoTargetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("音视频拼接");
        }
        finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 合并多个视频(有声)
     *
     * @throws Exception
     */
//    public static void mergeVideoAndAudio(List<String> paths, String targetPath) throws Exception {
//        ProcessWrapper ffmpeg=null;
//        try {
//            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
//            ffmpeg.addArgument("-protocol_whitelist");
//            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
//            String s0 = "\"";
//            String s1 = "concat=n=" + paths.size() + ":v=1:a=1 [v] [a]\" -map \"[v]\" -map \"[a]\"";
//            for (Integer i = 0; i < paths.size(); i++) {
//                s0 += "[s:v] [s:a] ".replaceAll("s", i.toString());
//                ffmpeg.addArgument("-i");
//                ffmpeg.addArgument(paths.get(i));
//            }
//            String s = s0 + s1;
//            ffmpeg.addArgument("-filter_complex");
//
//            ffmpeg.addArgument(s);
//
//            ffmpeg.addArgument(targetPath);
//            ffmpeg.execute();
//            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
//                blockFfmpeg(br);
//            }
            log.debug("合并视频成功={}", targetPath);
//        } catch (IOException e) {
//            throw new Exception("合并视频失败");
//        }finally{
//            if (null!=ffmpeg){
//                ffmpeg.close();
//            }
//        }
//    }

    /**
     * 合并多个视频(无声)
     *
     * @throws Exception
     */
    public static void mergeVideo(List<String> paths, String targetPath, String t) throws Exception {
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            String s0 = "\"";
            String s1 = "concat=n=" + paths.size() + ":v=1 [v]\" -map \"[v]\"";
            String s2 = "";
            for (Integer i = 0; i < paths.size(); i++) {
                s0 += "[@:v] scale=720:1280:force_original_aspect_ratio=1[v@];".replaceAll("@", i.toString());
                s2 += "[v@]".replaceAll("@", i.toString());
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument(paths.get(i));
            }
            String s = s0 + s2 + s1;
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument(s);
            if (null != t) {
                ffmpeg.addArgument("-t");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /***
     * 合成视频带有过渡
     * @param paths 要合成的视频
     * @param targetPath 输出路径
     * @param offset 要合成的视频时间长度
     * @param duration 过渡长度 要合成视频长度必须要是过渡长度的两倍或以上
     * @param t 最终视频时长,传null 就不做截取
     * @param fade 每次的过渡效果
     * @throws Exception
     */
    public static void mergeVideo1(List<String> paths, String targetPath, List<String> offset, Integer duration, String t, List<String> fade) throws Exception {
        Random random = new Random();
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            String s1 = "[0]";
            String s2 = "";
            for (Integer i = 0; i < paths.size(); i++) {
                //非第一个
                if (i != 0 ) {
                    String tmp = ("[s@]").replaceAll("@", i.toString());
                    s2 += s1 + ("[@]xfade=transition=" + fade.get(random.nextInt(fade.size())) + ":duration=" + duration + ":offset=" + offset.get(i - 1)).replaceAll("@", i.toString());
                    //非最后一个 分号隔开
                    if (i != paths.size() - 1) {
                        s2 += tmp + ";";
                    }
                    s1 = tmp;
                }
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument(paths.get(i));
            }
            String s = "\"" + s2 + "\"";
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument(s);
            if (null != t) {
                ffmpeg.addArgument("-t");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 合成视频带有过渡 场景顺序专用
     *
     * @throws Exception
     */
    public static void mergeVideo2(List<String> paths, String targetPath, List<String> offset, Integer duration, String t, List<String> fade, List<String> scene, List<String> curScene) throws Exception {

        Random random = new Random();
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            String s1 = "[0]";
            String s2 = "";
            Integer index=0;
            for (Integer i = 0; i < paths.size(); i++) {
                //非第一个
                if (i != 0 ) {
                    if (scene.contains(curScene.get(i-1))){
                        index++;
                        BigDecimal subtract = new BigDecimal(offset.get(i - 1)).subtract(new BigDecimal(index * duration));
                        String tmp = ("[s@]").replaceAll("@", i.toString());
                        s2 += s1 + ("[@]xfade=transition=" + fade.get(random.nextInt(fade.size())) + ":duration=" + duration + ":offset=" + subtract.toString()).replaceAll("@", i.toString());
                        //非最后一个 分号隔开
                        if (i != paths.size() - 1) {
                            s2 += tmp + ";";
                        }
                        s1 = tmp;
                    }
                    else
                        {
                        index++;
                        BigDecimal subtract = new BigDecimal(offset.get(i - 1)).subtract(new BigDecimal(index * 1));
                        String tmp = ("[s@]").replaceAll("@", i.toString());
                        s2 += s1 + ("[@]xfade=transition=" + fade.get(random.nextInt(fade.size())) + ":duration=" + 0 + ":offset=" + subtract.toString()).replaceAll("@", i.toString());
                        //非最后一个 分号隔开
                        if (i != paths.size() - 1) {
                            s2 += tmp + ";";
                        }
                        s1 = tmp;
                    }
                }
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument(paths.get(i));
            }
            String s = "\"" + s2 + "\"";
            if (!"".equals(s2)){
                ffmpeg.addArgument("-filter_complex");
                ffmpeg.addArgument(s);
            }
            if (null != t) {
                ffmpeg.addArgument("-t");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 和mergeVideo1是一样的
     * @param paths
     * @param targetPath
     * @param offset
     * @param duration
     * @param t
     * @param fade
     * @throws Exception
     */
    public static void mergeVideo3(List<String> paths, String targetPath, List<String> offset, Integer duration, String t, List<String> fade) throws Exception {
        Random random = new Random();
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            String s1 = "[0]";
            String s2 = "";
            for (Integer i = 0; i < paths.size(); i++) {
                //非第一个
                if (i != 0 ) {
                    BigDecimal subtract = new BigDecimal(offset.get(i - 1)).subtract(new BigDecimal(i * duration));
                    String tmp = ("[s@]").replaceAll("@", i.toString());
                    s2 += s1 + ("[@]xfade=transition=" + fade.get(random.nextInt(fade.size())) + ":duration=" + duration + ":offset=" +subtract.toString() ).replaceAll("@", i.toString());
                    //非最后一个 分号隔开
                    if (i != paths.size() - 1) {
                        s2 += tmp + ";";
                    }
                    s1 = tmp;
                }
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument(paths.get(i));
            }
            String s = "\"" + s2 + "\"";
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument(s);
            if (null != t) {
                ffmpeg.addArgument("-t");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 生成的是gif
     * @param paths
     * @param targetPath
     * @param offset
     * @param duration
     * @param t
     * @param fade
     * @throws Exception
     */
    public static void mergeVideo4(List<String> paths, String targetPath, List<String> offset, Integer duration, String t, List<String> fade) throws Exception {
        ProcessWrapper ffmpeg=null;
        Random random = new Random();
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            String s1 = "[0]";
            String s2 = "";
            for (Integer i = 0; i < paths.size(); i++) {
                //非第一个
                if (i != 0 ) {
                    BigDecimal subtract = new BigDecimal(offset.get(i - 1)).subtract(new BigDecimal(i * duration));
                    String tmp = ("[s@]").replaceAll("@", i.toString());
                    s2 += s1 + ("[@]xfade=transition=" + fade.get(random.nextInt(fade.size())) + ":duration=" + duration + ":offset=" +subtract.toString() ).replaceAll("@", i.toString());
                    //非最后一个 分号隔开
                    if (i != paths.size() - 1) {
                        s2 += tmp + ";";
                    }
                    s1 = tmp;
                }
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument(paths.get(i));
            }
            String s = "\"" + s2 + "\"";
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument(s);
            if (null != t) {
                ffmpeg.addArgument("-t");
                ffmpeg.addArgument(t);
            }
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * 合并多个视频(无声)
     *
     * @throws Exception
     */
//    public static void mergeVideo2(List<String> paths, String targetPath, List<String> offset, Integer duration, String t) throws Exception {
//        Random random = new Random();
//        List<String> fade = new ArrayList<>();
//        fade.add("dissolve");
//        fade.add("hblur");
//        fade.add("hrslice");
//        fade.add("hlslice");
//        fade.add("pixelize");
//        fade.add("radial");
//        fade.add("rectcrop");
//        fade.add("slidedown");
//        fade.add("slideleft");
//        fade.add("slideright");
//        fade.add("slideup");
//        fade.add("smoothdown");
//        fade.add("smoothleft");
//        fade.add("smoothright");
//        fade.add("smoothup");
//        fade.add("squeezeh");
//        fade.add("squeezev");
//        fade.add("vdslice");
//        fade.add("wipebr");
//        fade.add("wipebl");
//        fade.add("circleclose");
//        fade.add("circlecrop");
//        fade.add("circleopen");
//        try {
//            ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor();
//            ffmpeg.addArgument("-protocol_whitelist");
//            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
//            String s1 = "[0]";
//            String s2 = "";
//            for (Integer i = 0; i < paths.size(); i++) {
//                //非第一个
//                if (i != 0) {
//                    String tmp = ("[s@]").replaceAll("@", i.toString());
//                    s2 += s1 + ("[@]xfade=transition=" + fade.get(random.nextInt(fade.size())) + ":duration=" + duration + ":offset=" + offset.get(i - 1)).replaceAll("@", i.toString());
//                    //非最后一个 分号隔开
//                    if (i != paths.size() - 1) {
//                        s2 += tmp + ";";
//                    }
//                    s1 = tmp;
//                }
//
//                ffmpeg.addArgument("-i");
//                ffmpeg.addArgument(paths.get(i));
//            }
//            String s = "\"" + s2 + "\"";
//            ffmpeg.addArgument("-filter_complex");
//            ffmpeg.addArgument(s);
//            if (null != t) {
//                ffmpeg.addArgument("-t");
//                ffmpeg.addArgument(t);
//            }
//            ffmpeg.addArgument(targetPath);
//            ffmpeg.execute();
//            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
//                blockFfmpeg(br);
//            }
//        } catch (IOException e) {
//            throw new Exception("合并视频失败");
//        }
//    }
    


    /**
     * 循环拼接音频
     *
     * @throws Exception
     */
    public static void mergeAudio(String pathHead,int size, String sourcePath, String targetPath, String vol) throws Exception {
        ProcessWrapper ffmpeg =null;
        List<File> files=new ArrayList<>();
        try {
            String tmp=pathHead+IdWorker.getId()+".mp3";
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //去除静默
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            ffmpeg.addArgument("-c:v");
            ffmpeg.addArgument("copy");
            ffmpeg.addArgument("-ac");
            ffmpeg.addArgument("2");
            ffmpeg.addArgument(tmp);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
            ffmpeg.close();

            File tmpFile=new File(tmp);
            files.add(tmpFile);
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            String s = "concat:";
            for (int i = 0; i < size; i++) {
                if (i == size - 1) {
                    s += tmp;
                } else {
                    s += tmp + "|";
                }
            }
            ffmpeg.addArgument(s);
            String s1 = "volume = " + vol;
            ffmpeg.addArgument("-af");
            ffmpeg.addArgument(s1);
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (CollectionUtils.isNotEmpty(files)){
                for (File file:files){
                    if (null!=file&&file.exists()){
                        file.delete();
                    }
                }
            }
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }


    /**
     * 循环拼接音频
     *
     * @throws Exception
     */
    public static void mergeAudioAndAudio(List<String> paths, String targetPath, String vol) throws Exception {
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            String s = "concat:";
            for (int i = 0; i < paths.size(); i++) {
                if (i == paths.size() - 1) {
                    s += paths.get(i);
                } else {
                    s += paths.get(i) + "|";
                }
            }
            ffmpeg.addArgument(s);
            String s1 = "volume = " + vol;
            ffmpeg.addArgument("-af");
            ffmpeg.addArgument(s1);
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    
//    public static void picToVideo(String sourcePath, String width, String height, String time, String targetPath, Integer tran) throws Exception {
        ffmpeg -r 25 -loop 1 -i xinjinping.jpg -pix_fmt yuv420p -vcodec libx264 -b:v 600k -r:v 25 -preset medium -crf 30 -s 720x576 -vframes 250 -r 25 -t 10 a.mp4
        -r 25 -loop 1 -i ~/IMG_8679.JPG -pix_fmt yuv420p -vcodec libx264 -b:v 600k -r:v 25 -preset medium -crf 30 -s 720x576 -vframes 250 -r 25 -t 10 ~/a.mp4[/mw_shl_code]
//
//        try {
//            ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor();
//            ffmpeg.addArgument("-protocol_whitelist");
//            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
//
//            ffmpeg.addArgument("-r");
//            if (tran == 1) {
//                ffmpeg.addArgument("1");
//            } else {
//                ffmpeg.addArgument("8");
//            }
//            ffmpeg.addArgument("-f");
//            ffmpeg.addArgument("image2");
//
//            ffmpeg.addArgument("-s");
//            ffmpeg.addArgument(width + "x" + height);
//            ffmpeg.addArgument("-pix_fmt");
//            ffmpeg.addArgument("yuv420p");
//            ffmpeg.addArgument("-loop");
//            ffmpeg.addArgument("1");
//            ffmpeg.addArgument("-i");
//            ffmpeg.addArgument(sourcePath);
//            ffmpeg.addArgument("-t");
//            ffmpeg.addArgument(time);
//            ffmpeg.addArgument("-vcodec");
//            ffmpeg.addArgument("libx264");
//            ffmpeg.addArgument(targetPath);
//            ffmpeg.execute();
//            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
//                blockFfmpeg(br);
//            }
            log.debug("合并视频成功={}", targetPath);
//        } catch (IOException e) {
//            throw new Exception("合并视频失败");
//        }
//    }

    public static void picToVideo1(File sourcePath, String pathHead, Integer frame, Integer time, String targetPath) throws Exception {
        String tmp = pathHead + IdWorker.getId() + "/";
        File file = new File(tmp);
        if (!file.exists()) {
            file.mkdirs();
        }
        //生成对应的图片
        int i1 = frame * time;
        for (int i = 1; i <= i1; i++) {
            File file1 = new File(file, (i + ".jpg"));
            FileUtils.copyFile(sourcePath, file1);
        }
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("image2");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(tmp + "%d.jpg");
            ffmpeg.addArgument("-r");
            ffmpeg.addArgument(frame.toString());
            ffmpeg.addArgument("-vf");
            ffmpeg.addArgument("setsar=1");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        } finally {
            if (sourcePath != null && sourcePath.exists()) {
                sourcePath.delete();
            }
            File[] files = file.listFiles();
            for (File file1 : files) {
                file1.delete();
            }
            file.delete();
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }


    /**
     * 图片宽高修改
     *
     * @throws Exception
     */
    public static void modifyResolution(String imagePath, String resultPath, String width, String height) throws Exception {
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(imagePath);
            ffmpeg.addArgument("-vf");
            ffmpeg.addArgument(MessageFormat.format("scale={0}:{1}", width, height, "setsar=1"));
            ffmpeg.addArgument(resultPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    /**
     * @return void
     * @Author liufangli
     * @Description 图片添加文字处理
     * @Date 10:34 2022/8/17
     * @Param [imagePath, text, targetPath]
     **/
//    public static void picMergeWords1(String imagePath,String resultPath,String s) throws Exception {
//        try {
//            ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor();
//            ffmpeg.addArgument("-protocol_whitelist");
//            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
//            ffmpeg.addArgument("-i");
//            ffmpeg.addArgument(imagePath);
//            int size = 640 / 50;
//            String s2 = lineFeed(s, size,0);
//            String[] split = s2.split("\n");
//            Integer w=640;
//            Integer h=50;
//            if (split.length==1){
//                w=s.length()*50;
//            }else {
//                h=57*split.length;
//            }
//            String s1 = "color=White:s="+w+"x"+h+"[v1];[v1]";
//            List<String> list = new ArrayList<>();
//            for (Integer i=0;i<split.length;i++){
//                list.add("drawtext=fontcolor=#AACC00:fontsize=50:fontfile='D\\:/ymt/java/font/d.ttf':line_spacing=7:text='"+split[i]+"':x=0:y="+i*57);
//            }
//            String join = String.join(",", list);
//            s1+=join;
//            String s4="[v2]rotate=a=-PI*30/180:fillcolor=White@0[o1];[o1]colorkey=White:0.01:1[o2];[0:v][o2]overlay=x=(W-w)/2:y=(H-h)/2";
//            ffmpeg.addArgument("-filter_complex");
//            String s3 = "\"" + join  + "\"";
//            ffmpeg.addArgument(s3);
            ffmpeg.addArgument("\"color=White:s=720x1280[v1];[v1]drawtext=fontcolor=black:fontfile='D\\:/ymt/java/font/d.ttf':text='这是什么东西?':x=60:y=50:fontsize=40\"");
//            ffmpeg.addArgument("-y");
//            ffmpeg.addArgument(resultPath);
//            ffmpeg.execute();
//            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
//                blockFfmpeg(br);
//            }
            log.debug("合并视频成功={}", targetPath);
//        } catch (IOException e) {
//            throw new Exception("合并视频失败");
//        }
//    }


    public static boolean picMergeWords(WordAndCoverStyleDto dto) throws Exception {
        Integer fontSize = dto.getCoverTitleSize();
        String text = dto.getCoverTitle();
        String imagePath = dto.getVideoCover();
        String fontPath = dto.getCoverTitleFont();
        String targetPath = dto.getTargetCoverUrl();
        String fontColor = dto.getCoverTitleColor();
        Integer rotate = dto.getCoverTitleRotate();
        String bgmColor = dto.getCoverTitleBgmColor();
        Integer coverTitleAlign = dto.getCoverTitleAlign();
        String noColor = "";
        for (int i = 0; i < 3; i++) {
            noColor = RandomColor.getColor();
            if (!(noColor.equals(fontColor) || noColor.equals(bgmColor))) {
                break;
            }
        }
        if (StringUtils.isAnyEmpty(text, imagePath, fontPath, targetPath, fontColor)) {
            return false;
        }
        //计算单行最多几个字
        int size = 640 / fontSize;
        //字幕超出限定长度640就进行换行
        text = lineFeed(text, size, 1);
        //分离出每行字幕
        String[] split = text.split("\n");
        
        Map<String, Object> map = handleWordsPosition1(dto.getCoverTitleLocation(), split, fontSize, 7);
        Object x = map.get("x");
        List list = (List) map.get("y");
        List list1=new ArrayList();
        for (int i=0;i<split.length;i++){
            String s = "drawtext=fontfile='" + fontPath + "':text='" + split[i] + "':x=" + x.toString() + ":y=" + list.get(i).toString()+ ":fontsize=" + fontSize + ":fontcolor=" + fontColor + "";
            if (StringUtils.isNotEmpty(bgmColor)){
                s+=":box=1:boxcolor="+bgmColor+":boxborderw=10";
            }else {
                s += ":box=0:boxborderw=0";
            }
            list1.add(s);
        }

        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(imagePath);
            ffmpeg.addArgument("-filter_complex");
 
            ffmpeg.addArgument("\"color="+noColor+":s=720x1280[v1];" +
                    "[v1]"+String.join(",",list1)+"[o1];" +
                    "[o1]rotate=a=PI*"+rotate+"/180:fillcolor="+noColor+"@0[o1];[o1]colorkey="+noColor+":0.01:0[o2];[0:v][o2]overlay=x=(W-w)/2:y=(H-h)/2"+
                    "\"");
            ffmpeg.addArgument("-y");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("视频合并封面文字失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
        return true;
    }


    /**
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @Author liufangli
     * @Description 处理文字所在位置
     * @Date 10:41 2022/8/20
     * @Param [location 标题所在位置默认0中间,下拉框的值:1左上角,2右上角、3左下角、4右下角、5中上、6中间、7中下、8左中 9右中, map]
     **/
    private static Map<String, Object> handleWordsPosition(int location, Map<String, Object> map, int i) {
        String xLocation = "";
        String yLocation = "";
        if (0 == location || 6 == location) {
            return map;
        }
        //处理x轴
        if (location == 1 || location == 3 || location == 8) {
            //x轴左
            xLocation = "30";
        } else if (location == 2 || location == 4 || location == 9) {
            //x轴右
            xLocation = "(w-text_w)-text_w*" + i;
        } else {
            //x轴居中
            xLocation = "(w-text_w)/2";
        }
        //处理y轴
        if (location == 1 || location == 5 || location == 2) {
            //y轴 上
            yLocation = "30";
        } else if (location == 3 || location == 4 || location == 7) {
            //y轴 下
            yLocation = "(h-text_h)-30";
        } else {
            //x轴居中
            yLocation = "(h-text_h)/2+text_h";
        }

        map.put("x", xLocation);
        map.put("y", yLocation);
        return map;
    }


    /**
     * 字幕位置
     * @param location 标题所在位置 默认0中间,下拉框的值:1左上角,2右上角、3左下角、4右下角、5中上、6中间、7中下、8左中 9右中
     * @Param split 字幕内容
     * @Param size 字体大小
     * @Param num 单行字数
     * @Param line 行间距
     * @return
     */
    private static Map<String, Object> handleWordsPosition1(int location,String[] split,int size,int line) {
        Map map=new HashMap();
        //x左
        if (location == 1 || location == 3 || location == 8) {
            map.put("x","30");
        }
        //x右
        else if (location == 2 || location == 4 || location == 9) {
            map.put("x","w-text_w-30");
        }
        //x中
        else {
            map.put("x","(w-text_w)/2");
        }
        //y上
        if (location == 1 || location == 2|| location == 5) {
            List<String> y=new ArrayList<>();
            for (int i=0;i<split.length;i++){
                y.add("30+" + (i * (size + line)));
            }
            map.put("y",y);
        }
        //y下
        else if (location == 3 || location == 4|| location == 7){
            List<String> y=new ArrayList<>();
            for (int i=split.length;i>0;i--){
                y.add("h-30-" + (i * (size + line)));
            }
            map.put("y",y);
        }
        //y中
        else {
            List<String> y=new ArrayList<>();
            int i1 = split.length * (size + line);
            for (int i=0;i<split.length;i++){
                y.add("(h-"+i1+")/2+" + (i * (size + line)));
            }
            map.put("y",y);
        }
        return map;
    }

    /**
     * 获取视频第一帧
     * @throws Exception
     */
    public static boolean getPicFromVideo(String sourcePath, String targetPath) throws Exception {
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            ffmpeg.addArgument("-ss");
            ffmpeg.addArgument("1");
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("image2");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            log.error("截图视频第一帧失败,{}",e.getMessage());
            return false;
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
 
    }
    

    /**
     * 获取视频信息
     *
     * @param url
     * @return
     */
    public static MultimediaInfo getVideoInfo(URL url) throws Exception {
        log.info("URL:"+url);
        try {
            MultimediaObject multimediaObject = new MultimediaObject(url);
            return multimediaObject.getInfo();
        } catch (EncoderException e) {
            e.printStackTrace();
            log.error("获取视频信息报错={}", e.getMessage());
            throw new Exception("获取视频信息报错");
        }
    }

    /**
     * 获取视频时长
     */
    public static long readVideoTime(String filePath) throws IOException {
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(filePath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                StringBuilder outInfo = new StringBuilder();
                String line = "";
                while ((line = br.readLine()) != null) {
                    outInfo.append(line);
                }
                br.close();
                // 通过正则获取时长信息
                String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
                Pattern pattern = Pattern.compile(regexDuration);
                Matcher matcher = pattern.matcher(outInfo.toString());
                if (matcher.find()) {
                    return getTime(matcher.group(1));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
        return 0;
    }

    private static long getTime(String time) {
        String ZERO = "0";
        int min = 0;
        String[] strs = time.split(":");
        if (strs[0].compareTo(ZERO) > 0) {
            // 秒
            min += Long.parseLong(strs[0]) * 60 * 60 * 1000;
        }
        if (strs[1].compareTo(ZERO) > 0) {
            min += Long.parseLong(strs[1]) * 60 * 1000;
        }
        if (strs[2].compareTo(ZERO) > 0) {
            min += Math.round(Double.parseDouble(strs[2]) * 1000);
        }
        return min;
    }


    /**
     * 高斯模糊背景
     */
    public static void gaussianBlur(String pathHead, String path, String out, Integer deg) throws Exception {
        String tmp1 = pathHead + IdWorker.getId() + ".mp4";
        //先生成背景视频
        File file0 = new File(path);
        File file1 = new File(tmp1);
        FileUtils.copyFile(file0, file1);
        ProcessWrapper ffmpeg=null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(path);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(tmp1);
            ffmpeg.addArgument("-filter_complex");
            String s = "[0:v]scale=1720:1280[bv0];[bv0]crop=720:1280:500:0[bv1];[bv1]gblur=sigma=" + deg + "[bv2];[bv2]eq=contrast=1:brightness=-0.1[bv];[bv][1:v]overlay=x=0:y=372[out];[out]setsar=1";
            ffmpeg.addArgument(s);
            ffmpeg.addArgument("-y");
            ffmpeg.addArgument(out);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        } finally {
            if (file1 != null && file1.exists()) {
                file1.delete();
            }
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }

    }

    /**
     * 高斯模糊背景
     */
    public static void gaussianBlur1(String pathHead, String path, String out, Integer deg) throws Exception {
        String tmp0 = pathHead + IdWorker.getId() + ".mp4";
        String tmp1 = pathHead + IdWorker.getId() + ".mp4";

        //先生成背景视频
        File file0 = new File(tmp0);
        File file1 = new File(tmp1);
        HttpUtils.httpDownload(path, file0);
        FileUtils.copyFile(file0, file1);
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(path);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(tmp1);
            ffmpeg.addArgument("-filter_complex");
            String s = "[0:v]scale=-1:1280[bv0];[bv0]crop=720:1280:(iw-720)/2:0[bv1];[bv1]gblur=sigma=" + deg + "[bv2];[bv2]eq=contrast=1:brightness=-0.1[bv];[1:v]scale=720:-1[av];[bv][av]overlay=x=0:y=(1280-h)/2[out];[out]setsar=1";
            ffmpeg.addArgument(s);
            ffmpeg.addArgument("-r");
            ffmpeg.addArgument("25");
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("mp4");
            ffmpeg.addArgument("-an");
            ffmpeg.addArgument(out);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        } finally {
            if (file0 != null && file0.exists()) {
                file0.delete();
            }
            if (file1 != null && file1.exists()) {
                file1.delete();
            }
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }

    }
    

    /**
     * 给视频自定义背景
     */
    public static void customBack1(String path, String image, String out) throws Exception {
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(image);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(path);
            ffmpeg.addArgument("-filter_complex");
            String s = "[0:v]scale=720:1280[bv];[1:v]scale=720:-1[av];[bv][av]overlay=x=0:y=(1280-h)/2[out];[out]setsar=1";
            ffmpeg.addArgument(s);
            ffmpeg.addArgument("-r");
            ffmpeg.addArgument("25");
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("mp4");
            ffmpeg.addArgument("-an");
            ffmpeg.addArgument(out);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }

    //换行工具
    private static String lineFeed(String source, Integer i, int location) {
        //遍历每一行
        int flag = 0;
        StringBuilder res = new StringBuilder(source);
        for (int index = 1; index <= (source.length() / i); index++) {
            //存在下一行
            if (source.length() > (index * i)) {
                flag += i;
                res = res.insert(flag, '\n');
                flag++;
            }
        }
        return res.toString();
    }


    /**
     * 添加字幕
     */
    public static void addWords(List<String> words, Double first, String firstFont, Double second, String secondFont, List<Double> offset, String sourcePath, String targetPath, Integer firstSize, Integer secondSize, String firstColor, String secondColor, String firstBackColor, String secondBackColor, Integer firstAlign, Integer secondAlign) throws Exception {
        String s1 = "";
        String s2 = "";
        //不是默认文字背景(默认无背景)
        if (!"default".equals(firstBackColor)) {
            s1 = ":box=1:boxcolor=" + firstBackColor;
        }
        //不是默认文字背景(默认无背景)
        if (!"default".equals(secondBackColor)) {
            s2 = ":box=1:boxcolor=" + secondBackColor;
        }
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(sourcePath);
            ffmpeg.addArgument("-max_muxing_queue_size");
            ffmpeg.addArgument("2048");
            ffmpeg.addArgument("-vf");
            List<String> list = new ArrayList<>();
            Double flag = second;
            //700 (视频宽度720 左右宽度留了10 px)
            int i1 = 700 / firstSize;
            int i2 = 700 / secondSize;
            //每行不超过10个
            if (i1 > 10) {
                i1 = 10;
            }
            //每行不超过12个
            if (i2 > 12) {
                i2 = 12;
            }
            for (int i = 0; i < words.size(); i++) {
                //标题
                if (i == 0) {
                    String s = lineFeed(words.get(i), i1, 1);
                    //靠左
                    if (firstAlign == 1) {
                        String[] split = s.split("\n");
                        for (int k = 0; k < split.length; k++) {
                            list.add("drawtext=fontcolor=" + firstColor + ":fontsize=" + firstSize + ":fontfile='" + firstFont + "':line_spacing=7" + s1 + ":text='" + split[k] + "':x=10:y=(h-text_h)/6+" + (k * (firstSize + 7)));
                        }
//                        list.add("drawtext=fontcolor=" + firstColor + ":fontsize=" + firstSize + ":fontfile='" + firstFont + "':line_spacing=7" + s1 + ":text='" + s + "':x=10:y=(h-text_h)/6");
                    }
                    //居中
                    else if (firstAlign == 2) {
                        String[] split = s.split("\n");
                        for (int k = 0; k < split.length; k++) {
                            list.add("drawtext=fontcolor=" + firstColor + ":fontsize=" + firstSize + ":fontfile='" + firstFont + "':line_spacing=7" + s1 + ":text='" + split[k] + "':x=(w-text_w)/2:y=(h-text_h)/6+" + (k * (firstSize + 7)));
                        }
                    }
                    //靠右
                    else {
                        String[] split = s.split("\n");
                        for (int k = 0; k < split.length; k++) {
                            String s3 = split[k];
                            list.add("drawtext=fontcolor=" + firstColor + ":fontsize=" + firstSize + ":fontfile='" + firstFont + "':line_spacing=7" + s1 + ":text='" + s3 + "':x=w-text_w-10:y=(h-text_h)/6+" + (k * (firstSize + 7)));
                        }
                    }
                }
                //字幕
                else {
                    String s = lineFeed(words.get(i), i2, 1);
                    Double tmp = flag;
                    flag += offset.get(i - 1);
                    //靠左
                    if (secondAlign == 1) {
                        String[] split = s.split("\n");
                        for (int k = 0; k < split.length; k++) {
                            list.add("drawtext=fontcolor=" + secondColor + ":fontsize=" + secondSize + ":fontfile='" + secondFont + "':line_spacing=7" + s2 + ":text='" + split[k] + "':x=10:y=(h-" + (split.length * (secondSize + 7)) + ")*5/6+" + (k * (secondSize + 7)) + ":enable='between(t\\," + tmp + "\\," + flag + ")'");
                        }
//                        list.add("drawtext=fontcolor=" + secondColor + ":fontsize=" + secondSize + ":fontfile='" + secondFont + "':line_spacing=7" + s2 + ":text='" + s + "':x=10:y=(h-text_h)*5/6:enable='between(t\\," + tmp + "\\," + flag + ")'");
                    }
                    //居中
                    else if (secondAlign == 2) {
                        String[] split = s.split("\n");
                        for (int k = 0; k < split.length; k++) {
                            list.add("drawtext=fontcolor=" + secondColor + ":fontsize=" + secondSize + ":fontfile='" + secondFont + "':line_spacing=7" + s2 + ":text='" + split[k] + "':x=(w-text_w)/2:y=(h-" + (split.length * (secondSize + 7)) + ")*5/6+" + (k * (secondSize + 7)) + ":enable='between(t\\," + tmp + "\\," + flag + ")'");
                        }
                    }
                    //靠右
                    else {
                        String[] split = s.split("\n");
                        for (int k = 0; k < split.length; k++) {
                            String s3 = split[k];
                            list.add("drawtext=fontcolor=" + secondColor + ":fontsize=" + secondSize + ":fontfile='" + secondFont + "':line_spacing=7" + s2 + ":text='" + s3 + "':x=w-text_w-10:y=(h-" + (split.length * (secondSize + 7)) + ")*5/6+" + (k * (secondSize + 7)) + ":enable='between(t\\," + tmp + "\\," + flag + ")'");
                        }
                    }
                }
            }

            ffmpeg.addArgument(String.join(",", list));
            ffmpeg.addArgument("-y");
            ffmpeg.addArgument(targetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
//            log.debug("添加字幕成功={}", targetPath);
        } catch (IOException e) {
            throw new Exception("添加字幕失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }


    /**
     * 视频滤镜
     */
    public static void videoFilter(String path, String out, List<String> filter) throws Exception {
        Random random = new Random();
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(path);
            ffmpeg.addArgument("-vf");
            ffmpeg.addArgument(filter.get(random.nextInt(filter.size())));
            ffmpeg.addArgument("-y");
            ffmpeg.addArgument(out);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            throw new Exception("合并视频失败");
        }finally{
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }


    /**
     * 合并音频
     * 混音效果,长度以originAudioPath的音频为主
     *
     * @param originAudioPath 音频url或本地路径
     * @param magicAudioPath  音频url或本地路径
     * @param audioTargetPath 目标存储本地路径
     */
    public static void mixAudio(
            String pathHead, String originAudioPath, String magicAudioPath, String audioTargetPath) throws Exception {
        String tmp = pathHead + IdWorker.getId() + ".aac";
        ProcessWrapper ffmpeg =null;
        try {
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            //去除静默
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(originAudioPath);
            ffmpeg.addArgument("-c:v");
            ffmpeg.addArgument("copy");
            ffmpeg.addArgument("-ac");
            ffmpeg.addArgument("2");
            ffmpeg.addArgument(tmp);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
            ffmpeg.close();
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-protocol_whitelist");
            ffmpeg.addArgument("concat,file,http,https,tcp,tls,crypto");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(tmp);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(magicAudioPath);
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument("amix=inputs=2:duration=first:dropout_transition=2");

            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("mp3");
            ffmpeg.addArgument(audioTargetPath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
//            log.debug("合并音频={}", audioTargetPath);
        } catch (IOException e) {
            throw new Exception("合并音频失败");
        } finally {
            File file = new File(tmp);
            if (file.exists()) {
                file.delete();
            }
            if (null!=ffmpeg){
                ffmpeg.close();
            }
        }
    }
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值