zoukankan      html  css  js  c++  java
  • 【Java】java使用ffmpeg实现视频切割

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

    ffmpeg命令官方文档:http://ffmpeg.org/ffmpeg.html

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

    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

  • 相关阅读:
    Swift中的可选链与内存管理(干货系列)
    Swift中的类型转换
    Swift中类与结构的初始化
    Swift3中函数的使用
    Java常用的公共方法
    Eclipse中添加文档注释快捷键
    SVN服务器的搭建(三)
    SVN服务器的搭建(二)
    SVN服务器的搭建(一)
    多线程常见的例子
  • 原文地址:https://www.cnblogs.com/vickylinj/p/14976802.html
Copyright © 2011-2022 走看看