java使用ffmpeg实现视频切割

2023-11-07

因为公司项目的部分需求,需要将已经录制好的视频,从固定时间开始截取,到固定时间结束.并且将视频截取成相对平均的若干段视频.目前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;
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java使用ffmpeg实现视频切割 的相关文章

随机推荐

  • FPAG的上电配置的3种方法

    目前 大多数FPGA芯片是基于SRAM 的结构的 而 SRAM 单元中的数据掉电就会丢失 因此系统上电后 必须要由配置电路将正确的配置数据加载到 SRAM 中 此后 FPGA 才能够正常的运行 常见的配置芯片有EPCS 芯片 EPCS4 E
  • 【图解HTTP】(二)IP、TCP和DNS

    图解HTTP 二 IP TCP和DNS 一 负责传输的IP协议 二 确保可靠性的TCP协议 三 负责域名解析的DNS服务器 四 IP TCP和DNS三者与HTTP的关系 一 负责传输的IP协议 IP协议 即Internet Protocol
  • net6授权认证源码详解(三)

    授权 接下来跟着源码来一起学习授权相关知识 一般的service注入服务方式有如下 builder Services AddAuthorization option gt 增加授权策略 option AddPolicy Api1 build
  • 【spring】ApplicationContext详解

    ApplicationContext到底是什么 父类HierarchicalBeanFactory 拥有获取父BeanFactory的功能 父类ListableBeanFactory 拥有获取beanNames的功能 父类ResourceP
  • Redis离线安装

    Redis离线安装 目标 离线安装redis 设置redis访问权限 配置redis密码 离线安装redis 下载redis 地址 https redis io download redis downloads 下载完成后将redis拷贝到
  • 大数据项目实训总结_大数据分析必备知识点总结

    今天给大家分享一篇关于大数据分析必备知识点总结 下面我们一起来看一下吧 1 数据 信息和知识是广义数据表现的不同形式 2 主要知识模式类型有 广义知识 关联知识 类知识 预测型知识 特异型知识3 web挖掘研究的主要流派有 Web结构挖掘
  • 绝杀 GETPOST 嵌套的 JSON 参数

    JSON JavaScript Object Notation 是一种轻量级的数据交换格式 常用于Web应用程序中的数据传输 在HTTP数据包信息传递时 JSON扮演着非常正常的角色 因为它是一种通用的数据格式 可以被多种编程语言和应用程序
  • Python笔记_列表

    Python笔记 列表 列表的常用操作 任意定义两个列表 list one 1 2 3 14 python list two 1 10 55 20 6 计算序列的长度 print len list one 返回序列最小元素 注意 不同的类型
  • 液晶屏的接口信号RGB_TTL、LVDS、MIPI

    RGB TTL信号是TFT LCD能识别的标准信号 就算是以后用到的LVDS TMDS 都是在它的基础上编码得来的 RGB TTL信号可分为数据信号RGB 行同步信号HS 场同步信号VS 时钟信号CLK 使能信号DE 其中R G G三基色中
  • C# 线程暂停和恢复

    文章目录 前言 一 暂停与恢复 二 功能实现 1 按钮事件 播放和停止 2 线程和ManualResetEvent 总结 前言 因为需要一个自动播放和暂停图片的功能 所以就非常自然想到了创建一个线程 用点击事件控制线程的暂停和启动 一 暂停
  • [Windows驱动开发](四)内存管理

    一 内存管理概念 1 物理内存概念 Physical Memory Address PC上有三条总线 分别是数据总线 地址总线和控制总线 32位CPU的寻址能力为4GB 2的32次方 个字节 用户最多可以使用4GB的真实物理内存 PC中很多
  • PyTorch简介

    PyTorch是一个针对深度学习 并且使用GPU和CPU来优化的tensor library 张量库 最新发布的稳定版本为1 9 源码在https github com pytorch pytorch 它支持在Linux Mac和Windo
  • kafka启动失败,报错java.lang.NoSuchMethodError

    ERROR KafkaServer id 1 Fatal error during KafkaServer startup Prepare to shutdown kafka server KafkaServer java lang NoS
  • Java迭代器和Collection接口

    各位小伙伴们大家好 欢迎来到这个小扎扎的 Java核心技术 卷 笔记专栏 在这个系列专栏中我将记录浅学这本书所得收获 鉴于 看到就是学到 学到就是赚到 精神 这波简直就是血赚 涉及的知识点速通 关于迭代器你都知道什么 什么是迭代器 迭代器的
  • 机智云GoKit3点灯教程(基于正点原子的代码风格)

    首先的首先 吐槽一波机智云的教程 官方的教程总是让下它那个微信宠物屋的代码 一步看结果 拜托 就不能来个一步一步地教程吗 还有那个宠物屋的代码看得很头痛啊 总而言之 官方的教程给我的感觉就是很凌乱 按习惯 拿到板子先点个灯 下面就来一步一步
  • java tomcat get url地址长度如何设置_解决Springboot get请求是参数过长的情况

    问题原因 Springboot get请求是参数过长抛出异常 Request header is too large 的问题 错误描述 java lang IllegalArgumentException Request header is
  • sonarQube10.0代码审计软件安装(一)

    sonarQube10 0代码审计软件安装 一 下载地址 官网 可能需要科学上网一下 安装教程 选择Try out SonarQube 页面中即可发现Installing a local instance of SonarQube 下方即为
  • linux2——GDB调试,makefile规则(比之前的深一点点)

    一 常用gdb指令一览 二 makefile 1 超简单例子 2 基本规则 在替换之前 能看懂之前 3 经过替换开始一眼看不懂 4 但是即便经过3的变换也无法做到 自动化扩展 比如加一个乘法函数就需要再写一个乘法的规则 因此有模式规则 o
  • Spring Bean生命周期doCreateBean源码阅读

    bean的生命周期的几个后置接口都是在这个方法里面调用 所以单独开一篇该方法的源码阅读 下面从两个点来阅读 1 何时调用 只看容器启动 2 梳理这个方法的流程 跟上一节对应上 先贴上源码 protected Object doCreateB
  • java使用ffmpeg实现视频切割

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