java使用ffmpeg实现视频切割

因为公司项目的部分需求,需要将已经录制好的视频,从固定时间开始截取,到固定时间结束.并且将视频截取成相对平均的若干段视频.目前demo实现了,后续还会继续优化,在视频截取的时候,从关键帧开始或结束.

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;
        }
    }
  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
你可以使用Java调用FFmpeg切割视频。下面是一个简单的示例代码: ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class VideoCutter { public static void main(String[] args) { String inputVideo = "input.mp4"; // 输入视频文件路径 String outputVideo = "output.mp4"; // 输出视频文件路径 int startTime = 10; // 开始时间(以秒为单位) int duration = 5; // 持续时间(以秒为单位) try { // 构建FFmpeg命令 String command = "ffmpeg -i " + inputVideo + " -ss " + startTime + " -t " + duration + " -c:v copy -c:a copy " + outputVideo; // 执行命令 Process process = Runtime.getRuntime().exec(command); // 获取命令输出 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 等待命令执行完成 int exitCode = process.waitFor(); if (exitCode == 0) { System.out.println("视频切割成功!"); } else { System.out.println("视频切割失败!"); } } catch (Exception e) { e.printStackTrace(); } } } ``` 这段代码使用`Runtime.getRuntime().exec()`方法执行FFmpeg命令来切割视频。你需要将`input.mp4`替换为你的输入视频文件路径,`output.mp4`替换为你的输出视频文件路径,`startTime`替换为开始时间(以秒为单位),`duration`替换为持续时间(以秒为单位)。 请确保你已经正确安装了FFmpeg,并且FFmpeg可执行文件在系统路径中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值