package com.ruixuan.data.utils;

import com.ruixuan.jiaoyang.service.IJiaoYangReportService;
import com.tencent.SpeechClient;
import com.tencent.asr.model.Credential;
import com.tencent.asr.model.FlashRecognitionRequest;
import com.tencent.asr.model.FlashRecognitionResponse;
import com.tencent.asr.service.FlashRecognizer;
import com.tencent.core.utils.ByteUtils;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncoderException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.bytedeco.javacpp.Loader;
import org.mp4parser.IsoFile;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class VideoToPCMTool {
    @Autowired
    private IJiaoYangReportService jiaoYangReportService;

    public static void main(String[] args) {
        //        String filePath = "D:\\test\\d96843142a35726ab2e01197994e1bff.pcm";
//        File file = new File(filePath);

        String file = "D:\\test\\ff903858ab644495b920f89617916425.mp4";
        String pcmdir = "D:\\test";
        Path path = Paths.get(file);
        convertMP4toPCM(path, Paths.get(pcmdir));
    }

    /**
     * 将单个PM4文件，转换为PCM文件
     */
    public static Optional<String> convertMP4toPCM(Path mp4Path, Path pcmDir) {
        long seconds = readDuration(mp4Path);
        if (seconds == 0) {
            log.warn("文件总时长为0");
            return Optional.empty();
        }
        String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
        String endTime = String.valueOf(seconds);
        File src = mp4Path.toFile();
        //在当前源mp4文件目录下生成临时文件
        String mp4TempFile = src.getParent() + "\\" + System.currentTimeMillis() + ".mp4";
        //基于ffmpeg进行截取
        ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "0", "-i", mp4Path.toAbsolutePath().toString(),
                "-to", endTime, "-c", "copy", mp4TempFile);
        try {
            cutBuilder.inheritIO().start().waitFor();
        } catch (InterruptedException | IOException e) {
            log.error("ffmpeg截取MP4文件出错", e);
            return Optional.empty();
        }
        // 基于ffmpeg进行pcm转换
        // 基于输入路径的md5值来命名，也可以基于系统时间戳来命名
        String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
        ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
                "-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
        try {
            //inheritIO是指将 子流程的IO与当前java流程的IO设置为相同
            pcmBuilder.inheritIO().start().waitFor();
        } catch (InterruptedException | IOException e) {
            log.error("ffmpeg将mp4转换为pcm时出错", e);
            return Optional.empty();
        }
        // 删除MP4临时文件
        try {
            Files.deleteIfExists(Paths.get(mp4TempFile));
        } catch (IOException e) {
            log.error("删除mp4临时文件出错", e);
        }
        //返回pcm文件路径
        return Optional.of(pcmFile);
    }

    public static long readDuration(Path mp4Path) {

        if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
            log.warn("文件路径不存在或不可读 {}", mp4Path);
            return 0;
        }
        try {
            it.sauronsoftware.jave.MultimediaInfo m = null;
            File file = new File(mp4Path.toString());
            it.sauronsoftware.jave.Encoder encoder = new Encoder();
            m = encoder.getInfo(file);
            long duration = m.getDuration();
            long secondDuration = (long) Math.ceil(duration / 1000F);
            return secondDuration;
        } catch (Exception e) {
            log.error("读取MP4文件时长出错", e);
            return 0;
        }
    }

    /**
     * 批量将MP4文件转换为PCM文件
     *
     * @return 成功转换的PCM文件数
     */
    public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
        if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
            log.warn("mp4文件目录{}不存在", rootDir);
            return 0;
        }

        if (Files.notExists(pcmDir)) {
            //级联创建目录
            try {
                Files.createDirectories(pcmDir);
            } catch (IOException e) {
                log.error("创建文件夹出错", e);
            }
        }
        AtomicInteger pcmCount = new AtomicInteger(0);
        //遍历rootdir，获取所有目录下子目录和文件
        try {
            Files.list(rootDir).forEach(path -> {
                if (Files.isDirectory(path)) {
                    //递归遍历下级目录
                    pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
                }
                if (Files.isRegularFile(path) && Files.isReadable(path) && path.getFileName()
                        .toString()
                        .endsWith("mp4")) {
                    Optional<String> pcmFile = this.convertMP4toPCM(path, pcmDir);
                    if (pcmFile.isPresent()) {
                        pcmCount.getAndIncrement();
                    }
                }
            });
        } catch (IOException e) {
            log.error("批量将MP4文件转换为PCM文件出错", e);
        }
        return pcmCount.get();
    }


    //url转file
    private File getFileByUrl(String fileUrl, String suffix) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        BufferedOutputStream stream = null;
        InputStream inputStream = null;
        File file = null;
        try {
            URL imageUrl = new URL(fileUrl);
            HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            inputStream = conn.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            file = File.createTempFile("file", suffix);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            stream = new BufferedOutputStream(fileOutputStream);
            stream.write(outStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (stream != null) {
                    stream.close();
                }
                outStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return file;
    }
}
