package com.sqx.ffmpeg;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RuntimeUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.sound.sampled.*;
import java.io.*;
import java.util.Collections;
import java.util.List;

@Component
@Slf4j
public class FFmpeg {

	@Value("${ffmpeg.core.executableFile}")
	public String ffmpegPath;

	@Value("${business.audio.uploadPath}")
	public String baseAudioUploadPath;


	public void montageAudio(String inFilePath, String inFilePath2,String outPath){
		//montageAudioByJavaIo(inFilePath, inFilePath2, outPath);
		montageAudioByFFmpeg(inFilePath, inFilePath2, outPath);
	}
	public void montageAudioByJavaIo(String inFilePath, String inFilePath2,String outPath){
		List<File> audioFiles = Lists.newArrayList();
		audioFiles.add(new File(inFilePath));
		audioFiles.add(new File(inFilePath2));
		mergeAudioFiles(audioFiles, new File(outPath));
	}

	public void mergeAudioFiles(List<File> audioFiles, File outputFile){
		if(audioFiles == null || audioFiles.isEmpty()){
			log.warn("待合并列表为空，不执行合并");
			return;
		}
		try {
			List<AudioInputStream> audioInputStreamList = Lists.newArrayList();
			AudioFormat audioFormat = null;
			AudioInputStream audioInputStream = null;

			//读取音频文件，读取格式和流
			for (File audioFile : audioFiles) {
				audioInputStream = AudioSystem.getAudioInputStream(audioFile);
				audioFormat = audioInputStream.getFormat();
				if (audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
					audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
							audioFormat.getSampleRate(),
							16,
							audioFormat.getChannels(),
							audioFormat.getChannels() * 2,
							audioFormat.getSampleRate(),
							false);
					audioInputStream = AudioSystem.getAudioInputStream(audioFormat, audioInputStream);
				}
				audioInputStreamList.add(audioInputStream);
			}
			AudioFormat newAudioFormat = new AudioFormat(
					audioFormat.getEncoding(),
					audioFormat.getSampleRate(),
					audioFormat.getSampleSizeInBits(),
					audioFormat.getChannels(),
					audioFormat.getFrameSize(),
					audioFormat.getFrameRate(),
					audioFormat.isBigEndian()
			);
//			AudioInputStream mergedAudioStream = new AudioInputStream(
//					new SequenceInputStream(Collections.enumeration(audioInputStreamList)),
//					newAudioFormat,
//					audioInputStream.getFrameLength()
//			);

			AudioInputStream mergedAudioStream = new AudioInputStream(
				new SequenceInputStream(Collections.enumeration(audioInputStreamList)),
				newAudioFormat,
				audioInputStream.getFrameLength()

			);

			//合并后扔到输出文件里
			AudioSystem.write(mergedAudioStream, AudioFileFormat.Type.WAVE, outputFile);
			//AudioSystem.write(mergedAudioStream, new AudioFileFormat.Type("MP3", "mp3"), outputFile);

			//Conv c = new Converter();
			//AudioFileWriter writer = (AudioFileWriter)

			//THeaderlessAudioFileWriter x = new THeaderlessAudioFileWriter();
			//MpegAudioFileWriter mpegAudioFileWriter = new MpegAudioFileWriter();
			//mpegAudioFileWriter.write(mergedAudioStream, MpegFileFormatType.MP3, outputFile);

			//new THeaderlessAudioFileWriter(null,null,null).write(null,null,null,null);

			//AudioSystem.write()


			//AudioSystem.write(mergedAudioStream, MpegFileFormatType.MP3, outputFile);
			//MpegFormatConversionProvider mpegFormatConversionProvider = new MpegFormatConversionProvider();
			//mpegFormatConversionProvider.
			for (AudioInputStream ais: audioInputStreamList){
				ais.close();
			}
			mergedAudioStream.close();
		} catch (IOException | UnsupportedAudioFileException e) {
			log.error(e.getMessage(),e);
		}
	}



	//合并音频
	public void montageAudioByFFmpeg(String inFilePath, String inFilePath2,String outPath){
//		//ffmpeg -i 1.mp3 -i 2.mp3 -filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[out]" -map "[out]" output.mp3
		List<String> command = Lists.newArrayList();
		command.add(ffmpegPath);
		command.add("-i");
		command.add(inFilePath);
		command.add("-i");
		command.add(inFilePath2);
		//command.add("-acodec copy");
		command.add("-filter_complex");
		command.add("[0:a][1:a]concat=n=2:v=0:a=1[out]");
		command.add("-map");
		command.add("[out]");
		command.add(outPath);
		command.add("-y");
//		String[] commands = command.toArray(new String[]{});
//
//		StringBuilder sb = new StringBuilder();
//		sb.append(ffmpegPath);
//		sb.append(" ");
//		sb.append("-i");
//		sb.append(" ");
//		sb.append(inFilePath);
//		sb.append(" ");
//		sb.append("-i");
//		sb.append(" ");
//		sb.append(inFilePath2);
//		sb.append(" ");
//		sb.append("-filter_complex");
//		sb.append(" ");
//		sb.append("\"[0:a][1:a]concat=n=2:v=0:a=1[out]\"");
//		sb.append(" ");
//		sb.append("-map");
//		sb.append(" ");
//		sb.append("\"[out]\"");
//		sb.append(" ");
//		sb.append(outPath);
//		sb.append(" -y");//强制覆盖
		log.info("执行此命令：{}",command);
		//String res = RuntimeUtil.execForStr(sb.toString());

		//手写吧。。。
		ProcessBuilder builder = new ProcessBuilder(command);


		try {
			Process process = builder.start();
//			int exitCode = process.exitValue();
			int exitCode = process.waitFor();
			if(exitCode == 0){
				log.info("正常退出！");
			}else{
				log.info("非正常退出！{}",exitCode);
			}
			InputStream is = process.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(is));
			String line;
			while ((line = reader.readLine()) != null){
				log.info(line);
			}
			InputStream eis = process.getErrorStream();
			BufferedReader ereader = new BufferedReader(new InputStreamReader(eis));
			String eline;
			while ((eline = ereader.readLine()) != null){
				log.info(eline);
			}
			process.destroy();
		} catch (IOException e) {
			log.error("IO错误！");
			log.error(e.getMessage(),e);
		} catch (InterruptedException e) {
			log.error("中断错误！");
			log.error(e.getMessage(),e);
		}

//		log.info("执行结果：{}",res);
	}

	public static String getOsName(){
		return System.getProperty("os.name").toLowerCase();
	}

	public void mergeAllAudio(List<String> inFilePathList,String outPath) {
		if (inFilePathList == null || inFilePathList.isEmpty()) return;
		if (StringUtils.isBlank(outPath)) return;
		//ffmpeg -i "concat:01.mp3|02.mp3|03.mp3" -acodec copy testAll.mp3
		List<String> command = Lists.newArrayList();
		command.add(ffmpegPath);
		//多个
		for (String path : inFilePathList) {
			command.add("-i");
			command.add(path);
		}
		command.add("-filter_complex");//过滤器
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < inFilePathList.size(); i++) {
			sb.append("[");sb.append(i);sb.append(":a]");
		}
		sb.append("concat=n=");
		sb.append(inFilePathList.size());
		sb.append(":v=0:a=1[out]");
		//[0:0] [1:0] [2:0] concat=n=3:v=0:a=1 [a]
		//[0:0] [1:0] concat=n=${}:v=0:a=1 [a]
		command.add(sb.toString());
		command.add("-map");
		command.add("[out]");
		command.add(outPath);
		command.add("-y");
		log.info("执行此命令：{}",command);
		//String res = RuntimeUtil.execForStr(sb.toString());

		//手写吧。。。
		ProcessBuilder builder = new ProcessBuilder(command);

		try {
			Process process = builder.start();
			int exitCode = process.waitFor();
			if(exitCode == 0){
				log.info("正常退出！");
			}else{
				log.info("非正常退出！{}",exitCode);
			}
			InputStream is = process.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(is));
			String line;
			while ((line = reader.readLine()) != null){
				log.info(line);
			}
			InputStream eis = process.getErrorStream();
			BufferedReader ereader = new BufferedReader(new InputStreamReader(eis));
			String eline;
			while ((eline = ereader.readLine()) != null){
				log.info(eline);
			}
			process.destroy();
		} catch (IOException e) {
			log.error("IO错误！");
			log.error(e.getMessage(),e);
		} catch (InterruptedException e) {
			log.error("中断错误！");
			log.error(e.getMessage(),e);
		}




	}


	//因为"字符无法在linux中使用，win下正常
	public void mergeAllAudio2(List<String> inFilePathList,String outPath) {
		log.info("系统名称：{}", getOsName());
		log.info("是win？：{}", StringUtils.contains(getOsName(), "win"));
		log.info("是linux？：{}", StringUtils.contains(getOsName(), "linux"));
		if (inFilePathList == null || inFilePathList.isEmpty()) return;
		if (StringUtils.isBlank(outPath)) return;
		//ffmpeg -i "concat:01.mp3|02.mp3|03.mp3" -acodec copy testAll.mp3
		List<String> command = Lists.newArrayList();
		command.add(ffmpegPath);
		command.add("-i");

		StringBuilder sb = new StringBuilder();
//		if(StringUtils.contains(getOsName(), "linux")){
//			sb.append("\\\"");
//		}else{
			sb.append("\"");
//		}
		sb.append("concat:");
//		if(StringUtils.contains(getOsName(), "linux")) {
//			for (String path : inFilePathList) {
//				sb.append(path);
//				sb.append("\\|");
//			}
//			//去除最后的|
//			sb.deleteCharAt(sb.length() - 1);
//			sb.deleteCharAt(sb.length() - 1);
//		}else{
			for (String path : inFilePathList) {
				sb.append(path);
				sb.append("|");
			}
			//去除最后的|
			sb.deleteCharAt(sb.length() - 1);
//		}
//		if(StringUtils.contains(getOsName(), "linux")){
//			sb.append("\\\"");
//		}else{
			sb.append("\"");
//		}
		command.add(sb.toString());
		command.add("-acodec");
		command.add("copy");
		command.add(outPath);
		command.add("-y");

//		if(StringUtils.contains(getOsName(), "linux")){
//			command.add("\"");
//		}

		log.info("执行此命令：{}",command);
		//手写吧。。。
		ProcessBuilder builder = new ProcessBuilder(command);

		try {
			Process process = null;
//			Process process = builder.start();
//			Process process = RuntimeUtil.exec(command.toArray(new String[]{}));
//			if(StringUtils.contains(getOsName(), "linux")){
//
//				//process = Runtime.getRuntime().exec("sh -c",command.toArray(new String[]{}));
//				process = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",ArrayUtil.join(command.toArray(new String[]{})," ")});

//				String commandBase64 = Base64.encode(ArrayUtil.join(command.toArray(new String[]{})," "));
//				process = Runtime.getRuntime().exec(new String[]{"bash","-c","{echo," + commandBase64 + "}|{base64,-d}|{bash,-i}"});
//
//
//				log.info("执行此命令：{}","bash -c {echo," + commandBase64 + "}|{base64,-d}|{bash,-i}");

//			}else{
				process = builder.start();
//				String commandBase64 = Base64.encode(ArrayUtil.join(command.toArray(new String[]{})," "));
//				process = Runtime.getRuntime().exec("bash -c {echo," + commandBase64 + "}|{base64,-d}|{bash,-i}");
//			}

//			process.createCommandLine
//			int exitCode = process.exitValue();
			int exitCode = process.waitFor();
			if(exitCode == 0){
				log.info("正常退出！");
			}else{
				log.info("非正常退出！{}",exitCode);
			}
			InputStream is = process.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(is));
			String line;
			while ((line = reader.readLine()) != null){
				log.info(line);
			}
			InputStream eis = process.getErrorStream();
			BufferedReader ereader = new BufferedReader(new InputStreamReader(eis));
			String eline;
			while ((eline = ereader.readLine()) != null){
				log.info(eline);
			}
			process.destroy();
		} catch (IOException e) {
			log.error("IO错误！");
			log.error(e.getMessage(),e);
		} catch (InterruptedException e) {
			log.error("中断错误！");
			log.error(e.getMessage(),e);
		}
	}

	public static void main(String[] args) {
//		for (int i = 0; i < 200; i++) {
//			//用原生合并的，，，只能合并出wav文件。文件特大。。。
//			new FFmpeg().montageAudioByJavaIo("F:\\temp\\000\\all.mp3","F:\\temp\\000\\01.mp3","F:\\temp\\000\\all.mp3");
//		}
		System.out.println(getOsName());
		FFmpeg fFmpeg = new FFmpeg();
		fFmpeg.ffmpegPath = "D:\\ProgramGreeFile\\ffmpeg\\bin\\ffmpeg.exe";

		List<String> audioList = Lists.newArrayList();
		audioList.add("F:\\temp\\000\\01.mp3");
		audioList.add("F:\\temp\\000\\02.mp3");
		audioList.add("F:\\temp\\000\\03.mp3");
		fFmpeg.mergeAllAudio(audioList,"F:\\temp\\000\\all250.mp3");
	}

}
