package com.afanticar.aliyun.fc.util;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.afanticar.aliyun.fc.HelloFC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author ：wuzhancai
 * @date ：2021-9-27 17:35
 * @description：ffmpeg工具集
 */
public class FFmpegUtil {

    private final static Integer SUCCESS = 0;

    private static final Logger log = LoggerFactory.getLogger(FFmpegUtil.class);



    //进行抽帧图片
    public static String getFramesByPic(String ffmpegPath, String proxyIp, String timeout, String liveUrl, String savePath, String fps, String startTime, String endTime) {
        //前10秒 500ms抽一帧 后剩下10s 2s抽1帧
//        Stopwatch stopwatch = Stopwatch.createStarted();
        List<String> command = new ArrayList<>();
        //获取操作系统名称
        String os = System.getProperty("os.name");
        command.add(ffmpegPath);
        if (StrUtil.isNotBlank(proxyIp)) {
            command.add("-http_proxy");
            command.add("http://" + proxyIp);
        }
        command.add("-i");
        command.add(liveUrl);
        if (StrUtil.isNotEmpty(startTime)) {
            command.add("-ss");
            command.add(startTime);
        }
        if (StrUtil.isNotEmpty(endTime)) {
            command.add("-t");
            command.add(endTime);
        }
        command.add("-q");
        command.add("30");
        command.add("-vf");
        command.add("fps=" + fps);
        command.add("-qscale:v");
        command.add("2");
        command.add(savePath + "/%05d.jpeg");
        String str = executeCommand(command);
        log.info("抽帧视频地址{}所用时长{}ffmpeg返回的字符串{}", liveUrl, null, str);
        return str;
    }


    /**
     * 抽帧视频-根据时间抽一张
     *
     * @param ffmpegPath
     * @param liveUrl
     * @param time
     * @param savePath
     * @param fileName
     * @return
     */
    public static String getOneFrame(String ffmpegPath, String liveUrl, String time, String savePath, String fileName) {
//        Stopwatch stopwatch = Stopwatch.createStarted();
        List<String> command = new ArrayList<>();

        command.add(ffmpegPath);
        command.add("-ss");
        command.add(time);
        command.add("-i");
        command.add(liveUrl);
        command.add("-vframes");
        command.add("1");
        command.add(savePath + fileName);
        String str = executeCommand(command);
        log.info("抽帧一张图片{}所用时长{}ffmpeg返回的字符串{}", liveUrl, null, str);
        return str;
    }

    /**
     * 注册ffmpeg权限
     * @param ffmpegPath
     * @return
     */
    public static String assignmentFfmpegAuthority(String ffmpegPath) {
        //前10秒 500ms抽一帧 后剩下10s 2s抽1帧
//        Stopwatch stopwatch = Stopwatch.createStarted();
        List<String> command = new ArrayList<>();
        String str = "";
        if(StrUtil.isNotBlank(ffmpegPath)){
            command.add("chmod");
            command.add("+x");
            command.add(ffmpegPath);
            str = executeCommand(command);
            log.info("ffmpeg赋值权限{},{}", ffmpegPath, str);
        }
        return str;
    }

    public static String live2Audio(String ffmpegPath, String liveUrl, String savePath, String startTime, String endTime) {
        createFolder(savePath);
        // 构建命令
        List<String> command = new ArrayList();
        if (StrUtil.isNotBlank(ffmpegPath)) {
            command.add(ffmpegPath);
        } else {
            command.add("ffmpeg");
        }
        command.add("-y");
        //时间
        command.add("-i");
        command.add(liveUrl);
        if (StrUtil.isNotBlank(startTime)) {
            command.add("-ss");
            command.add(startTime);
        }
        if (StrUtil.isNotBlank(endTime)) {
            command.add("-t");
            command.add(endTime);
        }
        command.add("-ar");
        command.add("16000");
        command.add("-ac");
        command.add("1");
        command.add("-ab");
        command.add("256K");
        command.add(savePath);
        String executeResult = executeCommand(command);
        return executeResult;
    }

    public static void createFolder(String filepath) {
        //如果文件夹不存在则创建
        File file = new File(filepath);
        File fileParent = file.getParentFile();
        if (!fileParent.exists()) {
            fileParent.mkdirs();
        }
    }

    private static int getTimelen(String timelen) {
        int min = 0;
        String strs[] = timelen.split(":");
        if (strs[0].compareTo("0") > 0) {
            // 秒
            min += Integer.valueOf(strs[0]) * 60 * 60;
        }
        if (strs[1].compareTo("0") > 0) {
            min += Integer.valueOf(strs[1]) * 60;
        }
        if (strs[2].compareTo("0") > 0) {
            min += Math.round(Float.valueOf(strs[2]));
        }
        return min;
    }

    /**
     * 执行FFmpeg命令
     *
     * @param commands 要执行的FFmpeg命令
     * @return FFmpeg程序在执行命令过程中产生的各信息，执行出错时返回null
     */
    public static String executeCommand(List<String> commands) {
        long beginDate = System.currentTimeMillis();
        if (CollUtil.isEmpty(commands)) {
            log.error("--- 指令执行失败，因为要执行的FFmpeg指令为空！ ---");
            return null;
        }
        LinkedList<String> ffmpegCmds = new LinkedList<>(commands);
        log.info("--- 待执行的FFmpeg指令为：--- {}" + ffmpegCmds);

        String cmdStr = Arrays.toString(ffmpegCmds.toArray()).replace(",", "");
        log.info("--- 正在执行的FFmpeg指令为：--- {}", cmdStr);

        Runtime runtime = Runtime.getRuntime();
        Process ffmpeg = null;
//        Stopwatch stopwatch = Stopwatch.createUnstarted();
        InputStream errorStream1 = null;
        InputStream inputStream1 = null;
        try {
            // 创建stopwatch并开始计时
//            stopwatch.start();
            // 执行ffmpeg指令
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(ffmpegCmds);
            builder.redirectErrorStream(false);
            ffmpeg = builder.start();
            log.info("--- 开始执行FFmpeg指令：--- 执行线程名：" + builder.toString());
            // 取出输出流和错误流的信息
            // 注意：必须要取出ffmpeg在执行命令过程中产生的输出信息，如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时，线程就回阻塞住
            errorStream1 = ffmpeg.getErrorStream();
            inputStream1 = ffmpeg.getInputStream();
            PrintStream errorStream = new PrintStream(errorStream1);
            PrintStream inputStream = new PrintStream(inputStream1);
            errorStream.start();
            inputStream.start();
            // 等待ffmpeg命令执行完
            int state = ffmpeg.waitFor();
            // 获取执行结果字符串
            String result = errorStream.stringBuffer.append(inputStream.stringBuffer).toString();
            if (state != SUCCESS || result.indexOf("nothing was encoded") != -1 || result.indexOf("Input/output error") != -1) {
                log.info("--- 已执行的FFmepg命令： ---" + cmdStr + " 已执行完毕,执行结果：【异常】, {}", result);
                return result;
            }
            log.info("--- FFmepg命令已执行完毕： ---" + cmdStr + " 已执行完毕,执行结果：{}", errorStream.stringBuffer.append(inputStream.stringBuffer).toString());
            return null;
        } catch (Exception e) {
            log.error("--- FFmpeg命令执行出错！ --- 出错信息： {}" + e);
            throw new RuntimeException(e.getMessage());
        } finally {
            if (null != ffmpeg && ffmpeg.isAlive()) {
                ffmpeg.destroy();
            }
            long endDate = System.currentTimeMillis();
//            stopwatch.stop();
            log.info("--- FFmepg命令执行时长： ---" + (endDate-beginDate) + "毫秒");
        }
    }

    /**
     * 用于取出ffmpeg线程执行过程中产生的各种输出和错误流的信息
     */
    static class PrintStream extends Thread {
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        StringBuffer stringBuffer = new StringBuffer();

        public PrintStream(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        public void run() {
            try {
                if (null == inputStream) {
                    log.error("--- 读取输出流出错！因为当前输出流为空！---");
                }
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                String line = null;
                while ((line = bufferedReader.readLine()) != null) {
                    log.debug(line);
                    stringBuffer.append(line + "*****");
                }
            } catch (Exception e) {
                log.error("--- 读取输入流出错了！--- 错误信息：" + e.getMessage());
            } finally {
                try {
                    if (null != bufferedReader) {
                        bufferedReader.close();
                    }
                    if (null != inputStream) {
                        inputStream.close();
                    }
                } catch (IOException e) {
                    log.error("--- 调用PrintStream读取输出流后，关闭流时出错！---");
                }
            }
        }
    }

    /**
     * 在程序退出前结束已有的FFmpeg进程
     */
    private static class ProcessKiller extends Thread {
        private Process process;

        public ProcessKiller(Process process) {
            this.process = process;
        }

        @Override
        public void run() {
            this.process.destroy();
            log.info("--- 已销毁FFmpeg进程 --- 进程名： " + process.toString());
        }
    }


    public static void main(String[] args) {

        //测试获取格式类型
//        String ffmpegUrl = "D:\\github\\ffmpeg-N-102781-g05f9b3a0a5-win64-gpl\\bin\\ffmpeg.exe";
//        String liveUrl = "http://pull-flv-l6.douyincdn.com/stage/stream-686841983849463839.flv";
//        String videoType = getVideoType(ffmpegUrl, liveUrl);
//        System.out.println("视频格式为->" + videoType);

//        String awemeUrl = "https://api-hl.amemv.com/aweme/v1/play/?video_id=v0200fg10000c7qvfr3c77u9gfo5fds0&line=1&file_id=2e39733bf21545fc80c8eea6d42c3add&sign=9cfdfd380af8105671a8ebfca654209e&is_play_url=1&source=PackSourceEnum_PUBLISH";
//        int videoTime = getVideoTime(ffmpegUrl, awemeUrl);
//        System.out.println("视频时长为->" + videoTime);

//        liveUrl = "http://tx.pull.yximgs.com/live/6000_l7abfpSdG4U.flv?txSecret=1621317c6ceba238af569b85ceccc4b6&txTime=617cded1&stat=WT%2BavlGMAdsjOUeSy7esaXb44bKwlLFe%2FYytqjx3K47iVB261DYdo7OK3aYXLoFE&fd=1&ss=s1";
//        videoType = getVideoType(ffmpegUrl, liveUrl);
//        System.out.println("视频格式为->" + videoType);
//
//        liveUrl = "http://ali-origin.pull.yximgs.com/gifshow/m5tJoLjvsmQ.flv?auth_key=1635573443-0-0-7d6e730acd6b8b0d59b75ac62bfe3f94&oidc=edge_hb&fd=1&ss=s19";
//        videoType = getVideoType(ffmpegUrl, liveUrl);
//        System.out.println("视频格式为->" + videoType);
//        String framesByPic = getFramesByPic(ffmpegUrl, awemeUrl, "d://test", "1/5", null, null);
        String str = "Output file is empty, nothInput/output errorng was encoded";
        System.out.println(str.indexOf("Input/output error"));

        System.out.println(System.getProperty("os.name"));
    }

}
