【Java】]java使用ffmpeg实现视频切割

转自:https://blog.csdn.net/qq_34445142/article/details/106570745

需求:将已经录制好的视频,从固定时间开始截取,到固定时间结束.并且将视频截取成相对平均的若干段视频

1.首先需要安装FFmpeg.

2.代码

 //分割视频的大小
    private long blockSize = 1 * 1024 * 1024;
    
    @Test
    public void Test1() throws Exception {
       List<String> lists = cutVideo("/Users/wangge/Desktop/erge.mp4");
        System.out.println(lists);
    }

视频切割规则计算,切割命令组装

/**
     * @param filePath 要处理的文件路径
     * @return 分割后的文件路径
     * @throws Exception 文件
     */
    List<String> cutVideo(String filePath) throws Exception {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath + "文件不存在");
        }
        if (!filePath.endsWith(".mp4")) {
            throw new Exception("文件格式错误");
        }
        //从ffmpeg获得的时间长度00:00:00格式
        String videoTimeString = getVideoTime(file);
        log.info("从ffmpeg获得的时间长度00:00:00格式:{}",videoTimeString);
        //将时长转换为秒数
        int videoSecond = parseTimeToSecond(videoTimeString);
        log.info("将时长转换为秒数:{}",videoSecond);
        //视频文件的大小
        long fileLength = getVideoFileLength(file);
        log.info("视频文件的大小:{}",fileLength);
        List<String> cutedVideoPaths = new ArrayList<String>();
        if (fileLength <= blockSize) {
            log.info("如果视频文件大小不大于预设值,则直接返回原视频文件");
            cutedVideoPaths.add(filePath);
        } else {
            log.info("超过预设大小,需要切割");
            int partNum = (int) (fileLength / blockSize);
            log.info("文件大小除以分块大小的商:{}",partNum);
            long remainSize = fileLength % blockSize;
            log.info("余数:{}",remainSize);
            int cutNum;
            if (remainSize > 0) {
                cutNum = partNum + 1;
            } else {
                cutNum = partNum;
            }
            log.info("cutNum:{}",cutNum);
            int eachPartTime = videoSecond / cutNum;
            log.info("eachPartTime:{}",eachPartTime);
            String fileFolder = file.getParentFile().getAbsolutePath();
            log.info("fileFolder:{}",fileFolder);
            String fileName[] = file.getName().split("\\.");
            log.info("fileName[]:{}",fileName);

            for (int i = 0; i < cutNum; i++) {
                List<String> commands = Lists.newArrayList();
                commands.add("ffmpeg");
                commands.add("-ss");
                commands.add(parseTimeToString(eachPartTime * i));
                if (i != cutNum - 1) {
                    commands.add("-t");
                    commands.add(parseTimeToString(eachPartTime));
                }
                commands.add("-i");
                commands.add(filePath);
                commands.add("-codec");
                commands.add("copy");
                commands.add(fileFolder + File.separator + fileName[0] + "_part" + i + "." + fileName[1]);
                cutedVideoPaths.add(fileFolder + File.separator + fileName[0] + "_part" + i + "." + fileName[1]);
                newRunCommand(commands);
            }
        }
        return cutedVideoPaths;
    }

开始逐条执行命令

private Result newRunCommand(List<String> command) {
        log.info("相关命令 command:{}",command);
        Result result = new Result(false, "");
        ProcessBuilder builder = new ProcessBuilder(command);
        builder.redirectErrorStream(true);
        try {
            Process process = builder.start();
            final StringBuilder stringBuilder = new StringBuilder();
            final InputStream inputStream = process.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String line;
                 while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }

            while ((line = reader.readLine()) != null){

            }
            if (reader != null) {
                reader.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (Exception e) {
            throw new RuntimeException("ffmpeg执行异常" + e.getMessage());
        }
        return result;
    }

工具类相关:

/**
     * 获取视频文件时长
     *
     * @param file 文件
     * @return 时长 格式hh:MM:ss
     * @throws FileNotFoundException 视频不存在抛出此异常
     */
    private String getVideoTime(File file) throws FileNotFoundException {
        if (!file.exists()) {
            throw new FileNotFoundException(file.getAbsolutePath() + "不存在");
        }
        List<String> commands = new ArrayList<String>();
        commands.add("ffmpeg");
        commands.add("-i");
        commands.add(file.getAbsolutePath());
        Result result = runCommand(commands);
        String msg = result.getMsg();
        if (result.isSuccess()) {
            Pattern pattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}");
            Matcher matcher = pattern.matcher(msg);
            String time = "";
            while (matcher.find()) {
                time = matcher.group();
            }
            return time;
        } else {
            return "";
        }
    }
 /**
     * 获取文件大小
     *
     * @param file 去的文件长度,单位为字节b
     * @return 文件长度的字节数
     * @throws FileNotFoundException 文件未找到异常
     */
    private long getVideoFileLength(File file) throws FileNotFoundException {
        if (!file.exists()) {
            throw new FileNotFoundException(file.getAbsolutePath() + "不存在");
        }
        return file.length();
    }
/**
     * 将字符串时间格式转换为整型,以秒为单位
     *
     * @param timeString 字符串时间时长
     * @return 时间所对应的秒数
     */
    private int parseTimeToSecond(String timeString) {
        Pattern pattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}");
        Matcher matcher = pattern.matcher(timeString);
        if (!matcher.matches()) {
            try {
                throw new Exception("时间格式不正确");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String[] time = timeString.split(":");
        return Integer.parseInt(time[0]) * 3600 + Integer.parseInt(time[1]) * 60 + Integer.parseInt(time[2]);
    }

    /**
     * 将秒表示时长转为00:00:00格式
     *
     * @param second 秒数时长
     * @return 字符串格式时长
     */
    private String parseTimeToString(int second) {
        int end = second % 60;
        int mid = second / 60;
        if (mid < 60) {
            return mid + ":" + end;
        } else if (mid == 60) {
            return "1:00:" + end;
        } else {
            int first = mid / 60;
            mid = mid % 60;
            return first + ":" + mid + ":" + end;
        }

    }
public class Result {
        private boolean success;
        private String msg;

        public Result(boolean success, String msg) {
            this.success = success;
            this.msg = msg;
        }

        public Result() {

        }

        public boolean isSuccess() {
            return success;
        }

        public void setSuccess(boolean success) {
            this.success = success;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }
    }

processBuiler教程:https://geek-docs.com/java/java-tutorial/processbuilder.html#ProcessBuilder-7

上一篇:GDB ------ 为断点设置命令列表


下一篇:Cypress系列(63)- 使用 Cypress.Commands 完成 Custom Commands 自定义命令