package com.lansosdk.videoeditor;

import android.content.Context;
import android.graphics.Bitmap;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaMetadataRetriever;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.lansosdk.box.LSLog;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import static com.lansosdk.videoeditor.LanSongFileUtil.fileExist;

/**
 * 最简单的调用方法:
 *  //step1. 放在主线程中执行;
 * VideoEditor veditor=new VideoEditor();
 * veditor.setOnProgessListener(xxx)进度;
 *
 * //step2.
 * 然后在AsyncTask或Thread中执行如下;
 * veditor.executeXXXXX();
 *
 *
 * 杭州蓝松科技有限公司
 * www.lansongtech.com
 */
public class VideoEditor {

    private static final String TAG = LSLog.TAG;

    public static final String version="VideoEditor_20100101";
    /**
     * 使用软件编码的列表;
     */
    public static String[] qilinCpulist ={
            "EML-AL00",
            "EML-AL01",
            "LON-AL00",
            "MHA-AL00",
            "STF-AL00",
            "CLT-AL00",
            "ALP-AL00",
            "COL-AL10",
            "FRD-AL00",
            "EVR-AL00",
            "LYA-AL00",
            "PAR-AL00",
            "LON-AL00-PD",
            "VKY-AL00",
            "EDI-AL10",
            "DLI-AL10",
            "PRA-AL00X",
            "DUK-AL20",
            "DUK-AL20",
            "DUK-AL20",
            "WAS-AL00",
            "HUAWEI NXT-CL00",
            "RVL-AL09",
            "COR-AL00",
            "PAR-AL00",
            "INE-AL00",


            "EML-TL00",
            "EML-TL01",
            "LON-TL00",
            "MHA-TL00",
            "STF-TL00",
            "CLT-TL00",
            "ALP-TL00",
            "COL-TL10",
            "FRD-TL00",
            "EVR-TL00",
            "LYA-TL00"
    };

    public static String[] useSoftDecoderlist ={
            "SM919",
            "SM901"
    };
    /**
     * 是否强制使用硬件编码器;
     *
     * 全局变量
     *
     * 默认先硬件编码,如果无法完成则切换为软编码
     */
    public static boolean  isForceHWEncoder=false;
    /**
     * 强制使用软件编码器
     *
     * 全局变量
     * 默认先硬件编码,如果无法完成则切换为软编码
     */
    public static boolean  isForceSoftWareEncoder=false;


    /**
     * 强制使用软解码器
     *
     * 全局变量
     */
    public static boolean  isForceSoftWareDecoder=false;


    /**
     * 不检查是否是16的倍数.
     *
     */
    private static boolean noCheck16Multi=false;

    /**
     * 给当前方法指定码率.
     * 此静态变量, 在execute执行后, 默认恢复为0;
     */
    public int encodeBitRate=0;
    /**
     * 解析参数失败 返回1
     无输出文件 2；
     输入文件为空：3
     sdk未授权 -1；
     解码器错误：69
     收到线程的中断信号：255
     如硬件编码器错误，则返回：26625---26630
     */
    public static final int VIDEO_EDITOR_EXECUTE_SUCCESS1 = 0;
    public static final int VIDEO_EDITOR_EXECUTE_SUCCESS2 = 1;
    public static final int VIDEO_EDITOR_EXECUTE_FAILED = -101;  //文件不存在。


    private final int VIDEOEDITOR_HANDLER_PROGRESS = 203;
    private final int VIDEOEDITOR_HANDLER_COMPLETED = 204;
    private final int VIDEOEDITOR_HANDLER_ENCODERCHANGE = 205;


    private static LanSongLogCollector lanSongLogCollector =null;


    public void setEncodeBitRate(int bitRate){
        encodeBitRate=bitRate;
    }
    /**
     * 使能在ffmpeg执行的时候, 收集错误信息;
     *
     * @param ctx
     */
    public static void logEnable(Context ctx){

        if(ctx!=null){
            lanSongLogCollector =new LanSongLogCollector(ctx);
        }else{
            if(lanSongLogCollector !=null && lanSongLogCollector.isRunning()){
                lanSongLogCollector.stop();
                lanSongLogCollector =null;
            }
        }
    }
    /**
     * 当执行失败后,返回错误信息;
     * @return
     */
    public static String getErrorLog(){
        if(lanSongLogCollector !=null && lanSongLogCollector.isRunning()){
            return lanSongLogCollector.stop();
        }else{
            return null;
        }
    }
    /**
     * 构造方法.
     * 如果您想扩展ffmpeg的命令, 可以继承这个类,
     * 在其中像我们的各种executeXXX的举例一样来拼接ffmpeg的命令;
     *
     * 不要直接修改我们的这个文件, 以方便以后的sdk更新升级.
     */

    public VideoEditor() {
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
            Log.w(TAG, "cannot get Looper handler. may be cannot receive video editor progress!!");
        }
    }
    public onVideoEditorEncodeChangedListener mEncoderChangeListener=null;
    public void setOnEncodeChangedListener(onVideoEditorEncodeChangedListener listener) {
        mEncoderChangeListener = listener;
    }

    private void doEncoderChangedListener(boolean isSoft) {
        if (mEncoderChangeListener != null)
            mEncoderChangeListener.onChanged(this,isSoft);
    }



    public onVideoEditorProgressListener mProgressListener = null;

    public void setOnProgessListener(onVideoEditorProgressListener listener) {
        mProgressListener = listener;
    }

    private void doOnProgressListener(int timeMS) {
        if (mProgressListener != null)
            mProgressListener.onProgress(this, timeMS);
    }

    private EventHandler mEventHandler;

    private class EventHandler extends Handler {
        private final WeakReference<VideoEditor> mWeakExtract;

        public EventHandler(VideoEditor mp, Looper looper) {
            super(looper);
            mWeakExtract = new WeakReference<VideoEditor>(mp);
        }

        @Override
        public void handleMessage(Message msg) {
            VideoEditor videoextract = mWeakExtract.get();
            if (videoextract == null) {
                Log.e(TAG, "VideoEditor went away with unhandled events");
                return;
            }
            switch (msg.what) {
                case VIDEOEDITOR_HANDLER_PROGRESS:
                    videoextract.doOnProgressListener(msg.arg1);
                    break;
                case VIDEOEDITOR_HANDLER_ENCODERCHANGE:
                    videoextract.doEncoderChangedListener(true);  //暂停只要改变,就变成软编码;
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 异步线程执行的代码.
     */
    public int executeVideoEditor(String[] array) {
        return execute(array);
    }

    @SuppressWarnings("unused") /* Used from JNI */
    private void postEventFromNative(int what, int arg1, int arg2) {
        if (mEventHandler != null) {
            Message msg = mEventHandler.obtainMessage(VIDEOEDITOR_HANDLER_PROGRESS);
            msg.arg1 = what;
            mEventHandler.sendMessage(msg);
        }
    }
    protected void sendEncoderEnchange()
    {
        if (mEventHandler != null) {
            Message msg = mEventHandler.obtainMessage(VIDEOEDITOR_HANDLER_ENCODERCHANGE);
            mEventHandler.sendMessage(msg);
        }
    }

    public static native int getLimitYear();

    public static native int getLimitMonth();
    /**
     * 获取当前版本号
     * @return
     */
    public static native String getSDKVersion();


    /**
     * 执行成功,返回0, 失败返回错误码.
     *
     * 解析参数失败 返回1
     sdk未授权 -1；
     解码器错误：69
     收到线程的中断信号：255
     如硬件编码器错误，则返回：26625---26630

     * @param cmdArray ffmpeg命令的字符串数组, 可参考此文件中的各种方法举例来编写.
     * @return 执行成功, 返回0, 失败返回错误码.
     */
    private native int execute(Object cmdArray);
    private native int setForceColorFormat(int format);

    /**
     * 新增 在执行过程中取消的方法.
     * 如果在执行中调用了这个方法, 则会直接终止当前的操作.
     * 此方法仅仅是在ffmpeg线程中设置一个标志位,当前这一帧处理完毕后, 会检测到这个标志位,从而退出.
     * 因为execute是阻塞执行, 你可以判断execute有没有执行完,来判断是否完成.
     */
    public native void cancel();

    /**
     * @param filelength
     * @param channel
     * @param sampleRate
     * @param bitperSample
     * @param outData
     */
    public static native void createWavHeader(int filelength, int channel, int sampleRate, int bitperSample, byte[] outData);

    //-----------------
    public static String mergeAVDirectly(String audio, String video,boolean deleteVideo) {
        MediaInfo info=new MediaInfo(audio);
        if(info.prepare() && info.isHaveAudio()){
            String retPath= LanSongFileUtil.createMp4FileInBox();

            String inputAudio = audio;
            List<String> cmdList = new ArrayList<String>();

            cmdList.add("-i");
            cmdList.add(inputAudio);
            cmdList.add("-i");
            cmdList.add(video);

            cmdList.add("-map");
            cmdList.add("0:a");
            cmdList.add("-map");
            cmdList.add("1:v");

            cmdList.add("-acodec");
            cmdList.add("copy");
            cmdList.add("-vcodec");
            cmdList.add("copy");

            cmdList.add("-absf");
            cmdList.add("aac_adtstoasc");

            cmdList.add("-y");
            cmdList.add(retPath);
            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = (String) cmdList.get(i);
            }
            VideoEditor editor = new VideoEditor();
            int ret = editor.executeVideoEditor(command);
            if(ret==0){
                if(deleteVideo){
                    LanSongFileUtil.deleteFile(video);
                }
                return retPath;
            }else{
                return video;
            }
        }
        return video;
    }
    /**
     * 把一张图片变成视频
     *
     * @param srcPath
     * @param duration  形成视频的总时长;
     * @return  返回处理后的视频;
     */
    public String executePicture2Video(String srcPath, float duration) {
        if (fileExist(srcPath)) {
            List<String> cmdList = new ArrayList<String>();

            cmdList.add("-loop");
            cmdList.add("1");

            cmdList.add("-i");
            cmdList.add(srcPath);

            cmdList.add("-t");
            cmdList.add(String.valueOf(duration));

            return executeAutoSwitch(cmdList);
        }
        return null;
    }

    @Deprecated
    public String executePcmMix(String srcPach1, int samplerate, int channel, String srcPach2, int samplerate2, int
            channel2,float value1, float value2) {
        List<String> cmdList = new ArrayList<String>();

        String filter = String.format(Locale.getDefault(), "[0:a]volume=volume=%f[a1]; [1:a]volume=volume=%f[a2]; " +
                "[a1][a2]amix=inputs=2:duration=first:dropout_transition=2", value1, value2);

        String  dstPath= LanSongFileUtil.createFileInBox("pcm");

        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel));
        cmdList.add("-i");
        cmdList.add(srcPach1);

        cmdList.add("-f");
        ;
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate2));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel2));
        cmdList.add("-i");
        cmdList.add(srcPach2);

        cmdList.add("-y");
        cmdList.add("-filter_complex");
        cmdList.add(filter);
        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-acodec");
        cmdList.add("pcm_s16le");
        cmdList.add(dstPath);


        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = (String) cmdList.get(i);
        }
        int  ret= executeVideoEditor(command);
        if(ret==0){
            return dstPath;
        }else{
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }


    @Deprecated
    public String executePcmEncodeAac(String srcPach, int samplerate, int channel) {
        List<String> cmdList = new ArrayList<String>();

        String dstPath= LanSongFileUtil.createM4AFileInBox();
        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel));
        cmdList.add("-i");
        cmdList.add(srcPach);


        cmdList.add("-acodec");
        cmdList.add("libfaac");
        cmdList.add("-b:a");
        cmdList.add("64000");
        cmdList.add("-y");

        cmdList.add(dstPath);


        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = (String) cmdList.get(i);
        }
        int ret= executeVideoEditor(command);
        if(ret==0){
            return dstPath;
        }else{
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }

    /**
     * 把 pcm和视频文件合并在一起, pcm数据会编码成aac格式.
     * 注意:需要原视频文件里没有音频部分,
     * 如果有, 则需要先用 {@link #executeGetVideoTrack(String)} 拿到视频轨道, 在输入到这里.
     *
     * @param srcPcm     原pcm音频文件,
     * @param samplerate pcm的采样率
     * @param channel    pcm的通道数
     * @param srcVideo   原视频文件, 没有音频部分
     * @return  输出的视频文件路径, 需后缀是mp4格式.
     */
    public String executePcmComposeVideo(String srcPcm, int samplerate, int channel, String srcVideo) {
        List<String> cmdList = new ArrayList<String>();

        String dstPath= LanSongFileUtil.createMp4FileInBox();
        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel));
        cmdList.add("-i");
        cmdList.add(srcPcm);

        cmdList.add("-i");
        cmdList.add(srcVideo);

        cmdList.add("-acodec");
        cmdList.add("libfaac");
        cmdList.add("-b:a");
        cmdList.add("64000");
        cmdList.add("-y");

        cmdList.add("-vcodec");
        cmdList.add("copy");

        cmdList.add(dstPath);


        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = (String) cmdList.get(i);
        }
        int ret= executeVideoEditor(command);
        if(ret==0){
            return dstPath;
        }else{
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }
    /**
     * 两个音频文件延迟混合, 即把第二个音频延迟多长时间后, 与第一个音频混合.
     * 混合后的编码为aac格式的音频文件.
     * 注意,如果两个音频的时长不同, 以第一个音频的音频为准. 如需修改可联系我们或查询ffmpeg命令即可.
     *
     * @param audioPath1
     * @param audioPath2
     * @param leftDelayMS  第二个音频的左声道 相对 于第一个音频的延迟时间
     * @param rightDelayMS 第二个音频的右声道 相对 于第一个音频的延迟时间
     * @return
     */
    public String executeAudioDelayMix(String audioPath1, String audioPath2, int leftDelayMS, int rightDelayMS) {
        List<String> cmdList = new ArrayList<String>();
        String overlayXY = String.format(Locale.getDefault(), "[1:a]adelay=%d|%d[delaya1]; " +
                "[0:a][delaya1]amix=inputs=2:duration=first:dropout_transition=2", leftDelayMS, rightDelayMS);


        String dstPath= LanSongFileUtil.createM4AFileInBox();
        cmdList.add("-i");
        cmdList.add(audioPath1);

        cmdList.add("-i");
        cmdList.add(audioPath2);

        cmdList.add("-filter_complex");
        cmdList.add(overlayXY);

        cmdList.add("-acodec");
        cmdList.add("libfaac");

        cmdList.add("-y");
        cmdList.add(dstPath);
        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = (String) cmdList.get(i);
        }
        int ret= executeVideoEditor(command);
        if(ret==0){
            return dstPath;
        }else{
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }

    /**
     * 两个音频文件混合.
     * 混合后的文件压缩格式是aac格式, 故需要您dstPath的后缀是aac或m4a.
     *
     * @param audioPath1 主音频的完整路径
     * @param audioPath2 次音频的完整路径
     * @param value1     主音频的音量, 浮点类型, 大于1.0为放大音量, 小于1.0是减低音量.比如设置0.5则降低一倍.
     * @param value2     次音频的音量, 浮点类型.
     * @return 输出保存的完整路径. m4a格式.
     */
    public String executeAudioVolumeMix(String audioPath1, String audioPath2, float value1, float value2) {
        List<String> cmdList = new ArrayList<String>();

        String filter = String.format(Locale.getDefault(), "[0:a]volume=volume=%f[a1]; [1:a]volume=volume=%f[a2]; " +
                "[a1][a2]amix=inputs=2:duration=first:dropout_transition=2", value1, value2);

        String dstPath= LanSongFileUtil.createM4AFileInBox();
        cmdList.add("-i");
        cmdList.add(audioPath1);

        cmdList.add("-i");
        cmdList.add(audioPath2);

        cmdList.add("-filter_complex");
        cmdList.add(filter);

        cmdList.add("-acodec");
        cmdList.add("libfaac");

        cmdList.add("-b:a");
        cmdList.add("128000");

        cmdList.add("-ac");
        cmdList.add("2");

        //LSNEW 增加这行和上面的 码率, 通道数
        cmdList.add("-vn");

        cmdList.add("-y");
        cmdList.add(dstPath);

        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = (String) cmdList.get(i);
        }
        int ret= executeVideoEditor(command);
        if(ret==0){
            return dstPath;
        }else{
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }
    /**
     * 视频转码.
     * 通过调整视频的bitrate来对视频文件大小的压缩,降低视频文件的大小, 注意:压缩可能导致视频画质下降.
     *
     *
     * @param srcPath 源视频
     * @param percent 压缩百分比.值从0--1
     * @return
     */
    public String executeVideoCompress(String srcPath, float percent) {
        if (fileExist(srcPath)) {

            MediaInfo info = new MediaInfo(srcPath);
            if (info.prepare()) {

                setEncodeBitRate((int)(info.vBitRate *percent));


                List<String> cmdList = new ArrayList<String>();
                cmdList.add("-vcodec");
                cmdList.add("lansoh264_dec");

                cmdList.add("-i");
                cmdList.add(srcPath);
                cmdList.add("-acodec");
                cmdList.add("copy");

                return executeAutoSwitch(cmdList);
            }

        }
        return null;
    }

    /**
     * 分离mp4文件中的音频,并返回音频的路径,
     */
    public String executeGetAudioTrack(String srcMp4Path) {
        MediaInfo info = new MediaInfo(srcMp4Path);
        if(info.prepare()){
            String audioPath = null;
            if ("aac".equalsIgnoreCase(info.aCodecName)) {
                audioPath = LanSongFileUtil.createFileInBox(".m4a");
            } else if ("mp3".equalsIgnoreCase(info.aCodecName))
                audioPath = LanSongFileUtil.createFileInBox(".mp3");

            if (audioPath != null) {

                List<String> cmdList = new ArrayList<String>();
                cmdList.add("-i");
                cmdList.add(srcMp4Path);
                cmdList.add("-acodec");
                cmdList.add("copy");
                cmdList.add("-vn");
                cmdList.add("-y");
                cmdList.add(audioPath);
                String[] command = new String[cmdList.size()];
                for (int i = 0; i < cmdList.size(); i++) {
                    command[i] = (String) cmdList.get(i);
                }
                int ret= executeVideoEditor(command);
                if(ret==0){
                    return audioPath;
                }else{
                    LanSongFileUtil.deleteFile(audioPath);
                }
            }
        }
        return null;
    }

    /**
     *
     * 获取视频中的视频轨道.
     * (一个mp4文件, 里面可能有音频和视频, 这个是获取视频轨道, 获取后的视频里面将没有音频部分)
     * @param srcMp4Path
     * @return
     */
    public String executeGetVideoTrack(String srcMp4Path) {
        if(fileExist(srcMp4Path)){
            String videoPath  = LanSongFileUtil.createMp4FileInBox();
            List<String> cmdList = new ArrayList<String>();
            cmdList.add("-i");
            cmdList.add(srcMp4Path);
            cmdList.add("-vcodec");
            cmdList.add("copy");
            cmdList.add("-an");
            cmdList.add("-y");
            cmdList.add(videoPath);

            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = (String) cmdList.get(i);
            }
            int ret= executeVideoEditor(command);
            if(ret==0){
                return videoPath;
            }else{
                LanSongFileUtil.deleteFile(videoPath);
            }
        }
        Log.e(TAG,"执行获取视频轨道 错误, !!!!");
        return null;
    }

    public String executeVideoMergeAudio(String video, String audio) {

        MediaInfo vInfo=new MediaInfo(video);
        MediaInfo aInfo=new MediaInfo(audio);

        if(vInfo.prepare() && aInfo.prepare() && aInfo.isHaveAudio()){

            String retPath= LanSongFileUtil.createMp4FileInBox();
            boolean isAAC="aac".equals(aInfo.aCodecName);

            List<String> cmdList = new ArrayList<String>();
            cmdList.add("-i");
            cmdList.add(video);

            cmdList.add("-i");
            cmdList.add(audio);

            cmdList.add("-t");
            cmdList.add(String.valueOf(vInfo.vDuration));

            if(isAAC) {  //删去视频的原音,直接增加音频

                cmdList.add("-map");
                cmdList.add("0:v");

                cmdList.add("-map");
                cmdList.add("1:a");

                cmdList.add("-vcodec");
                cmdList.add("copy");

                cmdList.add("-acodec");
                cmdList.add("copy");

                cmdList.add("-absf");
                cmdList.add("aac_adtstoasc");

            }else { //删去视频的原音,并对音频编码
                cmdList.add("-map");
                cmdList.add("0:v");

                cmdList.add("-map");
                cmdList.add("1:a");

                cmdList.add("-vcodec");
                cmdList.add("copy");

                cmdList.add("-acodec");
                cmdList.add("libfaac");

                cmdList.add("-ac");
                cmdList.add("2");

                cmdList.add("-ar");
                cmdList.add("44100");

                cmdList.add("-b:a");
                cmdList.add("128000");
            }

            cmdList.add("-y");
            cmdList.add(retPath);
            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = (String) cmdList.get(i);
            }
            VideoEditor editor = new VideoEditor();
            int ret = editor.executeVideoEditor(command);
            if(ret==0){
                return retPath;
            }else{
                return video;
            }
        }
        return video;
    }
    /**
     * 建议用  AudioEditor中的executeVideoMergeAudio
     */
    @Deprecated
    public String executeVideoMergeAudio(String video, String audio,float audiostartS) {
        MediaInfo vInfo=new MediaInfo(video);
        MediaInfo aInfo=new MediaInfo(audio);

        if(vInfo.prepare() && aInfo.prepare() && aInfo.isHaveAudio()){

            String retPath= LanSongFileUtil.createMp4FileInBox();
            boolean isAAC="aac".equals(aInfo.aCodecName);

            List<String> cmdList = new ArrayList<String>();
            cmdList.add("-i");
            cmdList.add(video);

            cmdList.add("-ss");
            cmdList.add(String.valueOf(audiostartS));

            cmdList.add("-i");
            cmdList.add(audio);

            cmdList.add("-t");
            cmdList.add(String.valueOf(vInfo.vDuration));

            if(isAAC) {  //删去视频的原音,直接增加音频
                cmdList.add("-map");
                cmdList.add("0:v");

                cmdList.add("-map");
                cmdList.add("1:a");

                cmdList.add("-vcodec");
                cmdList.add("copy");

                cmdList.add("-acodec");
                cmdList.add("copy");

                cmdList.add("-absf");
                cmdList.add("aac_adtstoasc");

            }else { //删去视频的原音,并对音频编码
                cmdList.add("-map");
                cmdList.add("0:v");

                cmdList.add("-map");
                cmdList.add("1:a");

                cmdList.add("-vcodec");
                cmdList.add("copy");

                cmdList.add("-acodec");
                cmdList.add("libfaac");

                cmdList.add("-ac");
                cmdList.add("2");

                cmdList.add("-ar");
                cmdList.add("44100");

                cmdList.add("-b:a");
                cmdList.add("128000");
            }

            cmdList.add("-y");
            cmdList.add(retPath);
            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = (String) cmdList.get(i);
            }
            VideoEditor editor = new VideoEditor();
            int ret = editor.executeVideoEditor(command);
            if(ret==0){
                return retPath;
            }else{
                return video;
            }
        }
        return video;
    }


    /**
     * 用AudioEditor中的方法
     */
    @Deprecated
    public String executeCutAudio(String srcFile, float startS, float durationS) {
        if (fileExist(srcFile)) {

            List<String> cmdList = new ArrayList<String>();

            String dstFile= LanSongFileUtil.createFileInBox(LanSongFileUtil.getFileSuffix(srcFile));
            cmdList.add("-ss");
            cmdList.add(String.valueOf(startS));

            cmdList.add("-i");
            cmdList.add(srcFile);

            cmdList.add("-t");
            cmdList.add(String.valueOf(durationS));

            cmdList.add("-acodec");
            cmdList.add("copy");
            cmdList.add("-y");
            cmdList.add(dstFile);
            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = (String) cmdList.get(i);
            }
            int ret= executeVideoEditor(command);
            if(ret==0){
                return dstFile;
            }else{
                LanSongFileUtil.deleteFile(dstFile);
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 剪切mp4文件.
     * (包括视频文件中的音频部分和视频部分),即把mp4文件中的一段剪切成独立的一个视频文件, 比如把一个1分钟的视频,裁剪其中的10秒钟等.
     * <p>
     * 注意: 此方法裁剪不是精确裁剪,而是从视频的IDR帧开始裁剪的, 没有精确到您指定的那一帧的时间, 如果您指定的时间不是IDR帧上的时间,则退后到上一个IDR帧开始.
     *
     * @param videoFile 原视频文件 文件格式是mp4
     * @param startS    开始裁剪位置，单位是秒，
     * @param durationS 需要裁剪的时长，单位秒，比如您可以从原视频的8.9秒出开始裁剪，裁剪2分钟，则这里的参数是120
     * @return
     */
    public String executeCutVideo(String videoFile, float startS, float durationS) {
        if (fileExist(videoFile)) {

            String dstFile= LanSongFileUtil.createMp4FileInBox();

            List<String> cmdList = new ArrayList<String>();

            cmdList.add("-ss");
            cmdList.add(String.valueOf(startS));

            cmdList.add("-i");
            cmdList.add(videoFile);

            cmdList.add("-t");
            cmdList.add(String.valueOf(durationS));

            cmdList.add("-vcodec");
            cmdList.add("copy");
            cmdList.add("-acodec");
            cmdList.add("copy");
            cmdList.add("-y");
            cmdList.add(dstFile);
            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = (String) cmdList.get(i);
            }
            int ret= executeVideoEditor(command);
            if(ret==0){
                return dstFile;
            }else{
                LanSongFileUtil.deleteFile(dstFile);
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 精确裁剪
     * @param videoFile 输入源视频的完整路径
     * @param startS    开始裁剪时间点, 单位秒
     * @param durationS 要裁剪的总长度,单位秒
     * @return 裁剪后返回的目标视频
     */
    public String executeCutVideoExact(String videoFile, float startS, float durationS) {
        if (fileExist(videoFile)) {

            List<String> cmdList = new ArrayList<String>();

            cmdList.add("-vcodec");
            cmdList.add("lansoh264_dec");

            cmdList.add("-i");
            cmdList.add(videoFile);

            cmdList.add("-ss");
            cmdList.add(String.valueOf(startS));

            cmdList.add("-t");
            cmdList.add(String.valueOf(durationS));

            cmdList.add("-acodec");
            cmdList.add("copy");

            return executeAutoSwitch(cmdList);
        } else {
            return null;
        }
    }


    /**
     * 精确裁剪的同时,缩放到指定位置,不同于上面的命令,这个可以设置宽度和高度. 其中宽度和高度是采用缩放来完成.
     * <p>
     * <p>
     * 采用的是软缩放的形式.
     *
     * @param videoFile
     * @param startS
     * @param durationS
     * @param width     要缩放到的宽度 建议是16的倍数 ,
     * @param height    要缩放到的高度, 建议是16的倍数
     * @return
     */
    public String executeCutVideoExact(String videoFile, float startS, float durationS, int width, int height) {
        if (fileExist(videoFile)) {
            List<String> cmdList = new ArrayList<String>();

            String scalecmd = String.format(Locale.getDefault(), "scale=%d:%d", width, height);

            cmdList.add("-vcodec");
            cmdList.add("lansoh264_dec");

            cmdList.add("-i");
            cmdList.add(videoFile);

            cmdList.add("-ss");
            cmdList.add(String.valueOf(startS));

            cmdList.add("-t");
            cmdList.add(String.valueOf(durationS));

            cmdList.add("-vf");
            cmdList.add(scalecmd);

            cmdList.add("-acodec");
            cmdList.add("copy");

            return executeAutoSwitch(cmdList);
        } else {
            return null;
        }
    }
    /**
