=======开头重要绿色链接,不看后悔,和下面关联==========
JAVA无需本地下载Ffmpeg,实现FfmpegCMD

本文不需要本地下载Ffmpeg,只需引入maven依赖即可

1、添加maven依赖

<!--m3u8视频转码需要FFmpeg依赖-->
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-all-deps</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-core</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-nativebin-win64</artifactId>
            <version>3.3.1</version>
        </dependency>

2、编写代码

package com.gxw.util;

import com.alibaba.fastjson.JSON;
import ws.schild.jave.MultimediaObject;
import ws.schild.jave.info.MultimediaInfo;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Description:(MP4 转码 HLS m3u8 AES128 加密)
 * @author: GuoXiangWen
 * @date:   2022年04月16日 上午08:08:08
 */
public class EncodeVideoUtils {
    private static String PREIX = "gxwAwdlpgyn";
    //加密文件路径,如:enc.key、enc.keyinfo、m3u8文件、ts文件等
    private static String ENC_DIRECTORY = "D:/test-ffmpeg/"+PREIX;

    //enc.key地址
    private static String ENC_KEY_FILE_PATH = null;

    //enc.keyinfo地址
    private static String ENC_KEY_INFO_FILE_PATH = null;

    //密钥http地址
    private static String ENC_HTTP_PATH = "http://127.0.0.1:8848/Student";

    //执行成功0,失败1
    private static int CODE_SUCCESS = 0;
    private static int CODE_FAIL = 1;

    //$encInfoPath、$encPath是需要替换的ENC_DIRECTORY文件路径
    private static String cmd_enc = " -y -i {videoPath} -hls_time 12 -hls_key_info_file $encInfoPath -hls_playlist_type vod -hls_segment_filename $encPath\\{tsName}_%3d.ts $encPath\\{saveM3u8Name} ";

    public static void main(String[] args) {
        //视频路径
        String videoPath = "D:/test-ffmpeg/test.mp4";
        System.out.println(JSON.toJSONString(encodeVideo(videoPath, "test", "1")));
    }

    /**
     * 第一步:创建enc.keyinfo文件
     *      * 第二步:HLS m3u8 AES128 加密
     * @param videoPath 视频路径
     * @param videoType 视频所属类型,
     * @param index 视频角标,传来递增的
     * @return
     */
    public synchronized static Map<String, String> encodeVideo(String videoPath, String videoType, String index) {
        String videoTypeBP = videoType;
        String mp4Name = videoPath.substring(videoPath.lastIndexOf('/') + 1, videoPath.lastIndexOf(".mp4"));
        String saveM3u8Name = PREIX + RandomUtils.generateRandomString(32);

        //设置tsName
        cmd_enc = cmd_enc.replace("{tsName}", saveM3u8Name);

        //设置视频地址
        cmd_enc = cmd_enc.replace("{videoPath}", videoPath);

        //设置视频保存名称地址

        cmd_enc = cmd_enc.replace("{saveM3u8Name}", saveM3u8Name + ".m3u8");
        if(videoType.equals("") || videoType == null){
            videoType = "";
        }else {
            videoType = "/" + Md5Utils.md5Password(videoType, 8);
        }
        ENC_DIRECTORY = ENC_DIRECTORY + videoType + "/" + index;

        ENC_KEY_FILE_PATH = ENC_DIRECTORY + "/" + saveM3u8Name + ".key";
        ENC_KEY_INFO_FILE_PATH = ENC_DIRECTORY + "/" + saveM3u8Name + ".keyinfo";

        ENC_HTTP_PATH = ENC_HTTP_PATH + "/" + PREIX + videoType + "/" + index + "/" + saveM3u8Name + ".key";

        // 先创建两个活动线程的线程池
        ExecutorService executor = Executors.newFixedThreadPool(10);

        //异步执行
        //第一步:创建enc.keyinfo文件等
        CompletableFuture<String> completableFutureTask = CompletableFuture.supplyAsync(() ->{

            //保存加密视频目录enc
            File encFilePathDir = new File(ENC_DIRECTORY);

            if (!encFilePathDir.exists()) {// 判断目录是否存在
                encFilePathDir.mkdirs();
            }

            //写入文件内容enc.key
            BufferedWriter bwkey = null;
            //写入文件内容enc.keyinfo
            BufferedWriter bwkeyInfo = null;

            try{//文件
                File fileKey = new File(ENC_KEY_FILE_PATH);
                File fileKeyInfo = new File(ENC_KEY_INFO_FILE_PATH);

                //初始化存在删除
                if(fileKey.exists()) {
                    fileKey.delete();
                }
                if(fileKeyInfo.exists()) {
                    fileKeyInfo.delete();
                }
                bwkey = new BufferedWriter(new FileWriter(fileKey));
                bwkeyInfo = new BufferedWriter(new FileWriter(fileKeyInfo));

                //写入key--自定义的AES128加密的密匙
                bwkey.write("********换成自己加密钥匙即可*******");
                //写入keyInfo
                //密匙URL地址,可以对该URL鉴权
                bwkeyInfo.write(ENC_HTTP_PATH);
                bwkeyInfo.newLine();
                //全路径,绝对路径
                bwkeyInfo.write(ENC_KEY_FILE_PATH);

                bwkey.flush();
                bwkeyInfo.flush();
            }catch(IOException e){
                e.printStackTrace();
                //恢复默认
                ENC_KEY_INFO_FILE_PATH = null;
            } finally{
                try {
                    //一定要关闭文件
                    bwkey.close();
                    bwkeyInfo.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return ENC_KEY_INFO_FILE_PATH;
        }, executor).exceptionally(e -> {
            System.out.println(e);
            return "false";
        });
        //异步执行
        //第二步:HLS m3u8 AES128 加密
        CompletableFuture<Integer> completableFutureTaskHls = completableFutureTask.thenApplyAsync((String encKeyInfoFilePath)->{
            if(encKeyInfoFilePath == null || encKeyInfoFilePath.length() == 0) {return CODE_FAIL;}
            Integer codeTmp =  cmdExecut(cmd_enc.replace("$encInfoPath", encKeyInfoFilePath).replace("$encPath", ENC_DIRECTORY));
            if(CODE_SUCCESS != codeTmp) {return CODE_FAIL;}
            System.out.println("类型:"+videoTypeBP+" 视频:" + mp4Name + " 加密,成功!");
            return codeTmp;
        }, executor).exceptionally(e -> {
            System.out.println(e);
            return null;
        });

        //获取执行结果
        //code=0表示正常
        try {
            System.out.println(String.format("获取最终执行结果:%s", completableFutureTaskHls.get() == CODE_SUCCESS ? "成功!" : "失败!"));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //返回结果
        Map<String, String> resultMap = new HashMap<>();
        //视频名称
        resultMap.put("videoName", mp4Name);
        //视频大小
        resultMap.put("videoSize", getVideoSize(new File(videoPath)));
        //视频时长
        resultMap.put("videoTime", getVideoTime(videoPath));
        //保存m3u8加密地址
        resultMap.put("saveM3u8Path", ENC_DIRECTORY + "/" + saveM3u8Name + ".m3u8");
        return resultMap;
    }

    /**
     *
     * @Description: (执行ffmpeg自定义命令)
     * @param: @param cmdStr
     * @param: @return
     * @return: Integer
     * @throws
     */
    public static Integer cmdExecut(String cmdStr) {
        //code=0表示正常
        Integer code  = null;
        FfmpegCmd ffmpegCmd = new FfmpegCmd();
        /**
         * 错误流
         */
        InputStream errorStream = null;
        try {
            ffmpegCmd.execute(false, true, cmdStr);
            errorStream = ffmpegCmd.getErrorStream();

            //打印过程
            int len = 0;
            while ((len=errorStream.read())!=-1){
                System.out.print((char)len);
            }

            //code=0表示正常
            code = ffmpegCmd.getProcessExitCode();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            ffmpegCmd.close();
        }
        //返回
        return code;
    }

    /**
     * 获取视频时长
     *
     * @param FileUrl
     * @return
     */
    public static String getVideoTime(String FileUrl) {
        File source = new File(FileUrl);
        String length = "";
        try {
            MultimediaObject instance = new MultimediaObject(source);
            MultimediaInfo result = instance.getInfo();
            long ls = result.getDuration() / 1000;
            Integer hour = (int) (ls / 3600);
            Integer minute = (int) (ls % 3600) / 60;
            Integer second = (int) (ls - hour * 3600 - minute * 60);
            String hr = hour.toString();
            String mi = minute.toString();
            String se = second.toString();
            if (hr.length() < 2) {
                hr = "0" + hr;
            }
            if (mi.length() < 2) {
                mi = "0" + mi;
            }
            if (se.length() < 2) {
                se = "0" + se;
            }
            length = hr + ":" + mi + ":" + se;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return length;
    }


    /**
     * 获取视频大小
     *
     * @param source
     * @return
     */
    public static String getVideoSize(File source) {
        FileChannel fc = null;
        String size = "";
        try {
            FileInputStream fis = new FileInputStream(source);
            fc = fis.getChannel();
            BigDecimal fileSize = new BigDecimal(fc.size());
            size = fileSize.divide(new BigDecimal(1024 * 1024), 2, RoundingMode.HALF_UP) + "MB";
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != fc) {
                try {
                    fc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return size;
    }


}

3、运行测试

获得以下结果,即成功:
image.png


稳之楠
130 声望25 粉丝

行之稳,为之楠!