最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA使用ffmepg處理視頻的方法(壓縮,分片,合并)

 更新時(shí)間:2021年05月14日 14:07:03   作者:HikL[愛心]  
這篇文章主要介紹了JAVA使用ffmepg處理視頻的方法,包括視頻壓縮分片合并功能,通過實(shí)例代碼講解的很詳細(xì),對java ffmepg處理視頻相關(guān)知識感興趣的朋友一起看看吧

FFmepg安裝

路徑:
然后在使用的類中生命一個(gè)全局變量就好

 private static String ffmpegPath  = "C:\\hk\\ffmpeg\\bin\\ffmpeg.exe";  //ffmepg的絕對路徑

視頻壓縮

注意:此壓縮視頻涉及轉(zhuǎn)碼,對cpu的占用比較大(能不壓縮盡量不壓縮)

/**
     * 壓縮視頻
     * @param convertFile  待轉(zhuǎn)換的文件
     * @param targetFile  轉(zhuǎn)換后的目標(biāo)文件
     */
    public static void toCompressFile(String convertFile,String targetFile) throws IOException {
        List<String> command = new ArrayList<String>();
        /**將視頻壓縮為 每秒15幀 平均碼率600k 畫面的寬與高 為1280*720*/
        command.add(ffmpegPath);
        command.add("-i");
        command.add(convertFile);
        command.add("-r");
        command.add("15");
        command.add("-b:v");
        command.add("600k");
        command.add("-s");
        command.add("1280x720");
        command.add(targetFile);
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 使用這種方式會在瞬間大量消耗CPU和內(nèi)存等系統(tǒng)資源,所以這里我們需要對流進(jìn)行處理

        InputStream errorStream = process.getErrorStream();
        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(inputStreamReader);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        if (br != null) {
            br.close();
        }
        if (inputStreamReader != null) {
            inputStreamReader.close();
        }
        if (errorStream != null) {
            errorStream.close();
        }
        logger.info("-------------------壓縮完成---轉(zhuǎn)存文件--"+targetFile+"-------------");
    }

獲取視頻合并

/**
     * ffmpeg合并多個(gè)視頻文件
     *
     * @param list       需要合并的多視頻url地址以List存放
     * @param outputDir  此處是ffmpeg 配置地址,可寫死如“E:/ffmpeg/bin/ffmpeg.exe”
     * @param outputFile 合并后的視頻存放地址,如:E:/mergevideo.mp4
     * @date: 2021/4/17 9:31
     * @return: void
     */
    public static String mergeVideo(List<String> list, String outputDir, String outputFile) {

        try {
            String format1 = "%s -i %s -c copy -bsf:v h264_mp4toannexb -f mpegts %s";
            List<String> commandList = new ArrayList<>(6);
            List<String> inputList = new ArrayList<>(6);
            for (int i = 0; i < list.size(); i++) {
                String input = String.format("input%d.ts", i + 1);
                String command = String.format(format1, ffmpegPath, list.get(i), outputDir + input);
                commandList.add(command);
                inputList.add(input);
            }
            String command = getCommand(outputDir,outputFile, inputList);
            commandList.add(command);
            Boolean falg = Boolean.FALSE;
            for (int i = 0; i < commandList.size(); i++) {
                if (execCommand(commandList.get(i)) > 0) falg = true;
            }
            if (falg) {
                for (int i = 0; i < inputList.size(); i++) {
                    if (i != commandList.size() - 1) {
                        File file = new File(outputDir + inputList.get(i));
                        file.delete();
                    }
                }
//                //刪除壓縮的文件
//                for (String s:list
//                     ) {
//                    new File(s).delete();
//                }
                return outputFile;
            } else {
                return "fail";
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("-----合并失敗!!!!!!" + outputFile);
            return "fail";
        }

    }
    private static Integer execCommand(String command) {

        logger.info("execCommand.exec command={}",command);
        try {
            Process process = Runtime.getRuntime().exec(command);
            //獲取進(jìn)程的標(biāo)準(zhǔn)輸入流
            final InputStream is1 = process.getInputStream();
            //獲取進(jìn)城的錯誤流
            final InputStream is2 = process.getErrorStream();
            //啟動兩個(gè)線程,一個(gè)線程負(fù)責(zé)讀標(biāo)準(zhǔn)輸出流,另一個(gè)負(fù)責(zé)讀標(biāo)準(zhǔn)錯誤流
            readInputStream(is1);
            readInputStream(is2);
            process.waitFor();
            process.destroy();
            logger.info("-----操作成功" + command + " " + sdf.format(new Date()));
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("-----操作失敗" + command);
            return -1;
        }
    }

    private static void readInputStream(InputStream inputStream) {
        new Thread(() -> {
            BufferedReader br1 = new BufferedReader(new InputStreamReader(inputStream));
            try {
                String line1;
                while ((line1 = br1.readLine()) != null) {
                    if (line1 != null) {
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

視頻分片(分割)

/**
     * 將視頻分割為小段
     *
     * @param fileName    源文件名字(帶路徑)
     * @param outputPath  輸出文件路徑,會在該路徑下根據(jù)系統(tǒng)時(shí)間創(chuàng)建目錄,并在此目錄下輸出段視頻
     * @param videoTime   總時(shí)間,單位 分鐘
     * @param periodTime  小段視頻時(shí)長 單位 分鐘
     * @param merge       true合并,false單獨(dú)分割 說明:是否將整個(gè)視頻結(jié)尾部分不足一次分割時(shí)間的部分,合并到最后一次分割的視頻中,即false會比true多生成一段視頻
     */
    public static List<Map<String,Object>>  splitVideoFile(String fileName, String outputPath, float videoTime, int periodTime,  boolean merge) {
        final String TAG = "----------------------------";

        // 在outputPath路徑下根據(jù)系統(tǒng)時(shí)間創(chuàng)建目錄
        File file = createFileBySysTime(outputPath);
        if (file == null) {
            System.out.println("分割視頻失敗,創(chuàng)建目錄失敗");
            return null;
        }
        outputPath = file.getPath() + File.separator; // 更新視頻輸出目錄


        // 計(jì)算視頻分割的個(gè)數(shù)
        int count;// 分割為幾段
        float remain = 0; // 不足一次剪輯的剩余時(shí)間
        if (merge) {
            count = (int) (videoTime / periodTime);
            remain = videoTime % periodTime; // 不足一次剪輯的剩余時(shí)間
        } else {
            count = (int) (videoTime / periodTime) + 1;
        }
        System.out.println("將視頻分割為" + count + "段,每段約" + periodTime + "分鐘");

        String indexName; // 第 i 個(gè)視頻,打印日志用
        final String FFMPEG = ffmpegPath;
        String startTime; // 每段視頻的開始時(shí)間
        String periodVideoName; // 每段視頻的名字,名字規(guī)則:視頻i_時(shí)間段xx_yy
        float duration; // 每次分割的時(shí)長
        String command;// 執(zhí)行的命令
        // 得到視頻后綴 如.mp4
        String videoSuffix = fileName.substring(fileName.lastIndexOf("."));//得到點(diǎn)后面的后綴,包括點(diǎn)
        Runtime runtime = Runtime.getRuntime(); // 執(zhí)行命令者

        List<Map<String,Object>> list =new ArrayList<>();

        // 將視頻分割為count段
        for (int i = 0; i < count; i++) {
            Map<String,Object> map =new HashMap<>();
            indexName = "第" + (i+1) + "個(gè)視頻";

            // 決定是否將整個(gè)視頻結(jié)尾部分不足一次的時(shí)間,合并到最后一次分割的視頻中
            if (merge) {
                if (i == count - 1) {
                    duration = periodTime * 60 + remain * 60;// 將整個(gè)視頻不足一次剪輯的時(shí)間,拼接在最后一次剪裁中
                    if(periodTime * i /60 >= 1){
                        startTime = "0"+periodTime * i /60+ ":00:00";
                    }else{
                        startTime = periodTime * i + ":00";
                    }
                    periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_end" + videoSuffix;
                } else {
                    duration = periodTime * 60;
                    if(periodTime * i /60 >= 1){
                        startTime = "0"+periodTime * i /60+ ":00:00";
                    }else{
                        startTime = periodTime * i + ":00";
                    }
                    periodVideoName = "video" +(i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix;
                }
            } else {
                duration = periodTime * 60;
                if(periodTime * i /60 >= 1){
                    startTime = "0"+periodTime * i /60+ ":00:00";
                }else{
                    startTime = periodTime * i + ":00";
                }
                periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix;
            }

            // 執(zhí)行分割命令
            try {
                // 創(chuàng)建命令
                command = FFMPEG + " -ss " + startTime +" -accurate_seek "+ " -i " + fileName + " -c copy -t " + duration + " " + outputPath + periodVideoName;

                System.out.println(TAG);
                System.out.println(indexName);
                System.out.println("執(zhí)行命令:" + command);
                runtime.exec(command);
                System.out.println(indexName + "分割成功");

                map.put("videoPath",(outputPath + periodVideoName).replace("\\","/"));
                map.put("count",i);
                list.add(map);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(indexName + "分割失敗!!!!!!");
            }
        }
        //刪除原來的大視頻
        new File(fileName).delete();

        return list;
    }
/**
     * 在指定目錄下根據(jù)系統(tǒng)時(shí)間創(chuàng)建文件夾
     * 文件名字eg:2019-07-02-23-56-31
     *
     * @param path 路徑:eg: "/Users/amarao/業(yè)余/剪輯/output/";
     *             結(jié)果:創(chuàng)建成功/Users/amarao/業(yè)余/剪輯/output/2019-07-03-10-28-05
     *             <p>
     *             步驟:
     *             1. 讀取系統(tǒng)時(shí)間
     *             2. 格式化系統(tǒng)時(shí)間
     *             3. 創(chuàng)建文件夾
     *             <p>
     *             參考:http://www.bubuko.com/infodetail-1685972.html
     */
    public static File createFileBySysTime(String path) {

        // 1. 讀取系統(tǒng)時(shí)間
        Calendar calendar = Calendar.getInstance();
        Date time = calendar.getTime();

        // 2. 格式化系統(tǒng)時(shí)間
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        String fileName = format.format(time); //獲取系統(tǒng)當(dāng)前時(shí)間并將其轉(zhuǎn)換為string類型,fileName即文件名

        // 3. 創(chuàng)建文件夾
        String newPath = path + fileName;
        File file = new File(newPath);
        //如果文件目錄不存在則創(chuàng)建目錄
        if (!file.exists()) {
            if (!file.mkdir()) {
                System.out.println("當(dāng)前路徑不存在,創(chuàng)建失敗");
                return null;
            }
        }
        System.out.println("創(chuàng)建成功" + newPath);
        return file;
    }

獲取視頻的時(shí)長

/**
     * 獲取視頻時(shí)長 單位/秒
     * @param video
     * @return
     */
    public static long getVideoDuration(File video) {
        long duration = 0L;
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
        try {
            ff.start();
            duration = ff.getLengthInTime() / (1000 * 1000 * 60);
            ff.stop();
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
        return duration;
    }

視頻剪切

 /**
     *
     *剪切視頻
     videoInputPath 需要處理的視頻路徑
     startTime: 截取的開始時(shí)間 格式為 00:00:00(時(shí)分秒)
     endTime: 截取的結(jié)束時(shí)間 格式為00:03:00(時(shí)分秒) 
     devIp: 通道號  業(yè)務(wù)存在 ,可自行刪除
          * */

    public static String videoClip(String videoInputPath,String startTime,String endTime,String devIp) throws IOException {


        SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat dtf=new SimpleDateFormat("yyyyMMddHHmmss");

        //判斷轉(zhuǎn)碼文件是否存在
        if(!new File(videoInputPath).exists()){
            System.out.println("需要處理的視頻不存在");
            return null;
        }
        StringBuffer videoOutPath = new StringBuffer();
        videoOutPath.append("C:/video/playBack/"+devIp+"/"+sdf1.format(new Date())+"/clip/");
        File file = new File(videoOutPath.toString());
        if (!file.exists()){
            file.mkdirs();
        }
        videoOutPath.append(dtf.format(new Date())+".mp4");
        List<String> command = new ArrayList<String>();
        command.add(ffmpegPath);
        command.add("-ss");
        command.add(startTime);
        command.add("-t");
        command.add(endTime);
        command.add("-i");
        command.add(videoInputPath);
        command.add("-c");
        command.add("copy");
        command.add(videoOutPath.toString());
        command.add("-y");
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        InputStream errorStream = process.getErrorStream();
        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(inputStreamReader);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        if (br != null) {
            br.close();
        }
        if (inputStreamReader != null) {
            inputStreamReader.close();
        }
        if (errorStream != null) {
            errorStream.close();
        }

        return videoOutPath.toString();
    }

視頻轉(zhuǎn)GIF(MP4)

/*
     * 視頻轉(zhuǎn)gif
     *inputVideoPath   需要轉(zhuǎn)換的視頻
     * createGif  gif保存的位置
     * */
    public static String mp4ToGif(String inputVideoPath,String createGif) {
        String name = UUID.randomUUID().toString().replaceAll("-", "");
        String paletteFile = createGif +name + ".png";
        String gifFile = createGif+name + ".gif";
        boolean isComplete = false;
        //操作ffmpeg生成gif圖片
        for (int i = 0; i < 5; i++) {
            try {
                //生成調(diào)色板
                Process p = new ProcessBuilder()
                        .command(ffmpegPath,
                                "-v", "warning",
                                "-ss", "2",
                                "-t", "10",
                                "-i", inputVideoPath,
                                "-vf", "fps=5,scale=400:-1:flags=lanczos,palettegen",
                                "-y", paletteFile, "-vn")
                        .redirectError(new File("stderr.txt"))
                        .start();
                isComplete = p.waitFor(10, TimeUnit.SECONDS);

                if (!isComplete) {
                    System.out.println("生成調(diào)色板出錯");
                } else {
                    List<String> command = new ArrayList<String>();
                    /**將視頻壓縮為 每秒15幀 平均碼率600k 畫面的寬與高 為1280*720*/
                    command.add(ffmpegPath);
                    command.add("-v");
                    command.add("warning");
                    command.add("-ss");
                    command.add("2");
                    command.add("-t");
                    command.add("10");
                    command.add("-i");
                    command.add(inputVideoPath);
                    command.add("-i");
                    command.add(paletteFile);
                    command.add("-lavfi");
                    command.add("fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse");
                    command.add("-y");
                    command.add(gifFile);
                    command.add("-vn");
                    ProcessBuilder builder = new ProcessBuilder(command);
                    Process process = null;
                    try {
                        process = builder.start();
                        isComplete = process.waitFor(10, TimeUnit.SECONDS);
                        if (isComplete) {
                            new File(paletteFile).delete();
                            System.out.println("生成gif成功");
                            break;
                        } else {
                            System.out.println("生成gif出錯");
                        }
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
//                process = new ProcessBuilder()
//                            .command(ffmpegPath,
//                                    "-v", "warning",
//                                    "-ss", "2",
//                                    "-t", "10",
//                                    "-i", "E:\\Video_2021-05-14_113013.mp4",
//                                    "-i", paletteFile,
//                                    "-lavfi", "fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse",
//                                    "-y", gifFile, "-vn")
//                            .redirectError(new File("stderr.txt"))
//                            .start();
//                    isComplete = process.waitFor(10, TimeUnit.SECONDS);
//                    if (isComplete) {
//                        System.out.println("生成gif成功");
//                        break;
//                    } else {
//                        System.out.println("生成gif出錯");
//                    }
                }
            } catch (Exception e) {
                System.out.println("生成gif出錯");
            }
        }

        return gifFile;
    }

以上就是JAVA使用ffmepg處理視頻的方法(壓縮,分片,合并)的詳細(xì)內(nèi)容,更多關(guān)于java ffmepg處理視頻的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringMVC找不到Controller路徑的解決方案

    SpringMVC找不到Controller路徑的解決方案

    這篇文章主要介紹了SpringMVC找不到Controller路徑的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java中的Native方法

    Java中的Native方法

    這篇文章主要介紹了Java中的Native方法,在本文中,我們將看到j(luò)ava中本機(jī)native方法的介紹。我們將看到它的基本語法及其工作原理。將有java代碼示例展示native本機(jī)方法的使用,下面來看看文章的具體介紹
    2021-12-12
  • 基數(shù)排序簡介及Java語言實(shí)現(xiàn)

    基數(shù)排序簡介及Java語言實(shí)現(xiàn)

    這篇文章主要介紹了基數(shù)排序簡介及Java語言實(shí)現(xiàn),涉及基數(shù)排序的基本思想簡單介紹和桶排序的分析,以及基數(shù)排序的Java實(shí)現(xiàn),具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-11-11
  • Java SpringBoot實(shí)現(xiàn)AOP

    Java SpringBoot實(shí)現(xiàn)AOP

    AOP包括連接點(diǎn)(JoinPoint)、切入點(diǎn)(Pointcut)、增強(qiáng)(Advisor)、切面(Aspect)、AOP代理(AOP Proxy),具體的方法和類型下面文章會舉例說明,感興趣的小伙伴和小編一起閱讀全文吧
    2021-09-09
  • 使用Java將DOCX文檔解析為Markdown文檔的代碼實(shí)現(xiàn)

    使用Java將DOCX文檔解析為Markdown文檔的代碼實(shí)現(xiàn)

    在現(xiàn)代文檔處理中,Markdown(MD)因其簡潔的語法和良好的可讀性,逐漸成為開發(fā)者、技術(shù)寫作者和內(nèi)容創(chuàng)作者的首選格式,然而,許多文檔仍然以Microsoft Word的DOCX格式保存,本文將介紹如何使用Java和相關(guān)庫將DOCX文檔解析為Markdown文檔,需要的朋友可以參考下
    2025-04-04
  • 解決使用gateway后靜態(tài)資源失效的問題

    解決使用gateway后靜態(tài)資源失效的問題

    這篇文章主要介紹了解決使用gateway后靜態(tài)資源失效的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說明

    feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說明

    這篇文章主要介紹了feign的ribbon超時(shí)配置和hystrix的超時(shí)配置說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 使用dom4j解析xml文件問題

    使用dom4j解析xml文件問題

    這篇文章主要介紹了使用dom4j解析xml文件問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java annotation元注解原理實(shí)例解析

    Java annotation元注解原理實(shí)例解析

    這篇文章主要介紹了Java annotation元注解原理實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Java基礎(chǔ)之ArrayList的擴(kuò)容機(jī)制

    Java基礎(chǔ)之ArrayList的擴(kuò)容機(jī)制

    這篇文章主要介紹了Java基礎(chǔ)之ArrayList的擴(kuò)容機(jī)制,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05

最新評論

兰西县| 绥阳县| 绿春县| 枣阳市| 漯河市| 门源| 西昌市| 临安市| 铜山县| 新龙县| 呈贡县| 伊通| 漳平市| 廉江市| 贵州省| 宜城市| 双峰县| 西华县| 钟祥市| 巴林右旗| 莱阳市| 繁峙县| 横山县| 织金县| 安阳市| 综艺| 长宁县| 滁州市| 华亭县| 旬邑县| 依安县| 河东区| 龙口市| 阿拉善右旗| 中山市| 梅河口市| 乌什县| 赣州市| 仪征市| 辰溪县| 会宁县|