JAVA使用ffmepg处理视频的方法(压缩,分片,合并)

FFmepg安装

路径:
然后在使用的类中生命一个全局变量就好

 private static String ffmpegPath  = "C:\\hk\\ffmpeg\\bin\\ffmpeg.exe";  //ffmepg的绝对路径

视频压缩

注意:此压缩视频涉及转码,对cpu的占用比较大(能不压缩尽量不压缩)

/**
     * 压缩视频
     * @param convertFile  待转换的文件
     * @param targetFile  转换后的目标文件
     */
    public static void toCompressFile(String convertFile,String targetFile) throws IOException {
        List<String> command = new ArrayList<String>();
        /**将视频压缩为 每秒15帧 平均码率600k 画面的宽与高 为1280*720*/
        command.add(ffmpegPath);
        command.add("-i");
        command.add(convertFile);
        command.add("-r");
        command.add("15");
        command.add("-b:v");
        command.add("600k");
        command.add("-s");
        command.add("1280x720");
        command.add(targetFile);
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理

        InputStream errorStream = process.getErrorStream();
        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(inputStreamReader);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        if (br != null) {
            br.close();
        }
        if (inputStreamReader != null) {
            inputStreamReader.close();
        }
        if (errorStream != null) {
            errorStream.close();
        }
        logger.info("-------------------压缩完成---转存文件--"+targetFile+"-------------");
    }

获取视频合并

/**
     * ffmpeg合并多个视频文件
     *
     * @param list       需要合并的多视频url地址以List存放
     * @param outputDir  此处是ffmpeg 配置地址,可写死如“E:/ffmpeg/bin/ffmpeg.exe”
     * @param outputFile 合并后的视频存放地址,如:E:/mergevideo.mp4
     * @date: 2021/4/17 9:31
     * @return: void
     */
    public static String mergeVideo(List<String> list, String outputDir, String outputFile) {

        try {
            String format1 = "%s -i %s -c copy -bsf:v h264_mp4toannexb -f mpegts %s";
            List<String> commandList = new ArrayList<>(6);
            List<String> inputList = new ArrayList<>(6);
            for (int i = 0; i < list.size(); i++) {
                String input = String.format("input%d.ts", i + 1);
                String command = String.format(format1, ffmpegPath, list.get(i), outputDir + input);
                commandList.add(command);
                inputList.add(input);
            }
            String command = getCommand(outputDir,outputFile, inputList);
            commandList.add(command);
            Boolean falg = Boolean.FALSE;
            for (int i = 0; i < commandList.size(); i++) {
                if (execCommand(commandList.get(i)) > 0) falg = true;
            }
            if (falg) {
                for (int i = 0; i < inputList.size(); i++) {
                    if (i != commandList.size() - 1) {
                        File file = new File(outputDir + inputList.get(i));
                        file.delete();
                    }
                }
//                //删除压缩的文件
//                for (String s:list
//                     ) {
//                    new File(s).delete();
//                }
                return outputFile;
            } else {
                return "fail";
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("-----合并失败!!!!!!" + outputFile);
            return "fail";
        }

    }
    private static Integer execCommand(String command) {

        logger.info("execCommand.exec command={}",command);
        try {
            Process process = Runtime.getRuntime().exec(command);
            //获取进程的标准输入流
            final InputStream is1 = process.getInputStream();
            //获取进城的错误流
            final InputStream is2 = process.getErrorStream();
            //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
            readInputStream(is1);
            readInputStream(is2);
            process.waitFor();
            process.destroy();
            logger.info("-----操作成功" + command + " " + sdf.format(new Date()));
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("-----操作失败" + command);
            return -1;
        }
    }

    private static void readInputStream(InputStream inputStream) {
        new Thread(() -> {
            BufferedReader br1 = new BufferedReader(new InputStreamReader(inputStream));
            try {
                String line1;
                while ((line1 = br1.readLine()) != null) {
                    if (line1 != null) {
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

视频分片(分割)

/**
     * 将视频分割为小段
     *
     * @param fileName    源文件名字(带路径)
     * @param outputPath  输出文件路径,会在该路径下根据系统时间创建目录,并在此目录下输出段视频
     * @param videoTime   总时间,单位 分钟
     * @param periodTime  小段视频时长 单位 分钟
     * @param merge       true合并,false单独分割 说明:是否将整个视频结尾部分不足一次分割时间的部分,合并到最后一次分割的视频中,即false会比true多生成一段视频
     */
    public static List<Map<String,Object>>  splitVideoFile(String fileName, String outputPath, float videoTime, int periodTime,  boolean merge) {
        final String TAG = "----------------------------";

        // 在outputPath路径下根据系统时间创建目录
        File file = createFileBySysTime(outputPath);
        if (file == null) {
            System.out.println("分割视频失败,创建目录失败");
            return null;
        }
        outputPath = file.getPath() + File.separator; // 更新视频输出目录

        // 计算视频分割的个数
        int count;// 分割为几段
        float remain = 0; // 不足一次剪辑的剩余时间
        if (merge) {
            count = (int) (videoTime / periodTime);
            remain = videoTime % periodTime; // 不足一次剪辑的剩余时间
        } else {
            count = (int) (videoTime / periodTime) + 1;
        }
        System.out.println("将视频分割为" + count + "段,每段约" + periodTime + "分钟");

        String indexName; // 第 i 个视频,打印日志用
        final String FFMPEG = ffmpegPath;
        String startTime; // 每段视频的开始时间
        String periodVideoName; // 每段视频的名字,名字规则:视频i_时间段xx_yy
        float duration; // 每次分割的时长
        String command;// 执行的命令
        // 得到视频后缀 如.mp4
        String videoSuffix = fileName.substring(fileName.lastIndexOf("."));//得到点后面的后缀,包括点
        Runtime runtime = Runtime.getRuntime(); // 执行命令者

        List<Map<String,Object>> list =new ArrayList<>();

        // 将视频分割为count段
        for (int i = 0; i < count; i++) {
            Map<String,Object> map =new HashMap<>();
            indexName = "第" + (i+1) + "个视频";

            // 决定是否将整个视频结尾部分不足一次的时间,合并到最后一次分割的视频中
            if (merge) {
                if (i == count - 1) {
                    duration = periodTime * 60 + remain * 60;// 将整个视频不足一次剪辑的时间,拼接在最后一次剪裁中
                    if(periodTime * i /60 >= 1){
                        startTime = "0"+periodTime * i /60+ ":00:00";
                    }else{
                        startTime = periodTime * i + ":00";
                    }
                    periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_end" + videoSuffix;
                } else {
                    duration = periodTime * 60;
                    if(periodTime * i /60 >= 1){
                        startTime = "0"+periodTime * i /60+ ":00:00";
                    }else{
                        startTime = periodTime * i + ":00";
                    }
                    periodVideoName = "video" +(i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix;
                }
            } else {
                duration = periodTime * 60;
                if(periodTime * i /60 >= 1){
                    startTime = "0"+periodTime * i /60+ ":00:00";
                }else{
                    startTime = periodTime * i + ":00";
                }
                periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix;
            }

            // 执行分割命令
            try {
                // 创建命令
                command = FFMPEG + " -ss " + startTime +" -accurate_seek "+ " -i " + fileName + " -c copy -t " + duration + " " + outputPath + periodVideoName;

                System.out.println(TAG);
                System.out.println(indexName);
                System.out.println("执行命令:" + command);
                runtime.exec(command);
                System.out.println(indexName + "分割成功");

                map.put("videoPath",(outputPath + periodVideoName).replace("\\","/"));
                map.put("count",i);
                list.add(map);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(indexName + "分割失败!!!!!!");
            }
        }
        //删除原来的大视频
        new File(fileName).delete();

        return list;
    }
/**
     * 在指定目录下根据系统时间创建文件夹
     * 文件名字eg:2019-07-02-23-56-31
     *
     * @param path 路径:eg: "/Users/amarao/业余/剪辑/output/";
     *             结果:创建成功/Users/amarao/业余/剪辑/output/2019-07-03-10-28-05
     *             <p>
     *             步骤:
     *             1. 读取系统时间
     *             2. 格式化系统时间
     *             3. 创建文件夹
     *             <p>
     *             参考:http://www.bubuko.com/infodetail-1685972.html
     */
    public static File createFileBySysTime(String path) {

        // 1. 读取系统时间
        Calendar calendar = Calendar.getInstance();
        Date time = calendar.getTime();

        // 2. 格式化系统时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        String fileName = format.format(time); //获取系统当前时间并将其转换为string类型,fileName即文件名

        // 3. 创建文件夹
        String newPath = path + fileName;
        File file = new File(newPath);
        //如果文件目录不存在则创建目录
        if (!file.exists()) {
            if (!file.mkdir()) {
                System.out.println("当前路径不存在,创建失败");
                return null;
            }
        }
        System.out.println("创建成功" + newPath);
        return file;
    }

获取视频的时长

/**
     * 获取视频时长 单位/秒
     * @param video
     * @return
     */
    public static long getVideoDuration(File video) {
        long duration = 0L;
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
        try {
            ff.start();
            duration = ff.getLengthInTime() / (1000 * 1000 * 60);
            ff.stop();
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
        return duration;
    }

视频剪切

 /**
     *
     *剪切视频
     videoInputPath 需要处理的视频路径
     startTime: 截取的开始时间 格式为 00:00:00(时分秒)
     endTime: 截取的结束时间 格式为00:03:00(时分秒)
     devIp: 通道号  业务存在 ,可自行删除
          * */

    public static String videoClip(String videoInputPath,String startTime,String endTime,String devIp) throws IOException {

        SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat dtf=new SimpleDateFormat("yyyyMMddHHmmss");

        //判断转码文件是否存在
        if(!new File(videoInputPath).exists()){
            System.out.println("需要处理的视频不存在");
            return null;
        }
        StringBuffer videoOutPath = new StringBuffer();
        videoOutPath.append("C:/video/playBack/"+devIp+"/"+sdf1.format(new Date())+"/clip/");
        File file = new File(videoOutPath.toString());
        if (!file.exists()){
            file.mkdirs();
        }
        videoOutPath.append(dtf.format(new Date())+".mp4");
        List<String> command = new ArrayList<String>();
        command.add(ffmpegPath);
        command.add("-ss");
        command.add(startTime);
        command.add("-t");
        command.add(endTime);
        command.add("-i");
        command.add(videoInputPath);
        command.add("-c");
        command.add("copy");
        command.add(videoOutPath.toString());
        command.add("-y");
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        InputStream errorStream = process.getErrorStream();
        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(inputStreamReader);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        if (br != null) {
            br.close();
        }
        if (inputStreamReader != null) {
            inputStreamReader.close();
        }
        if (errorStream != null) {
            errorStream.close();
        }

        return videoOutPath.toString();
    }

视频转GIF(MP4)

/*
     * 视频转gif
     *inputVideoPath   需要转换的视频
     * createGif  gif保存的位置
     * */
    public static String mp4ToGif(String inputVideoPath,String createGif) {
        String name = UUID.randomUUID().toString().replaceAll("-", "");
        String paletteFile = createGif +name + ".png";
        String gifFile = createGif+name + ".gif";
        boolean isComplete = false;
        //操作ffmpeg生成gif图片
        for (int i = 0; i < 5; i++) {
            try {
                //生成调色板
                Process p = new ProcessBuilder()
                        .command(ffmpegPath,
                                "-v", "warning",
                                "-ss", "2",
                                "-t", "10",
                                "-i", inputVideoPath,
                                "-vf", "fps=5,scale=400:-1:flags=lanczos,palettegen",
                                "-y", paletteFile, "-vn")
                        .redirectError(new File("stderr.txt"))
                        .start();
                isComplete = p.waitFor(10, TimeUnit.SECONDS);

                if (!isComplete) {
                    System.out.println("生成调色板出错");
                } else {
                    List<String> command = new ArrayList<String>();
                    /**将视频压缩为 每秒15帧 平均码率600k 画面的宽与高 为1280*720*/
                    command.add(ffmpegPath);
                    command.add("-v");
                    command.add("warning");
                    command.add("-ss");
                    command.add("2");
                    command.add("-t");
                    command.add("10");
                    command.add("-i");
                    command.add(inputVideoPath);
                    command.add("-i");
                    command.add(paletteFile);
                    command.add("-lavfi");
                    command.add("fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse");
                    command.add("-y");
                    command.add(gifFile);
                    command.add("-vn");
                    ProcessBuilder builder = new ProcessBuilder(command);
                    Process process = null;
                    try {
                        process = builder.start();
                        isComplete = process.waitFor(10, TimeUnit.SECONDS);
                        if (isComplete) {
                            new File(paletteFile).delete();
                            System.out.println("生成gif成功");
                            break;
                        } else {
                            System.out.println("生成gif出错");
                        }
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
//                process = new ProcessBuilder()
//                            .command(ffmpegPath,
//                                    "-v", "warning",
//                                    "-ss", "2",
//                                    "-t", "10",
//                                    "-i", "E:\\Video_2021-05-14_113013.mp4",
//                                    "-i", paletteFile,
//                                    "-lavfi", "fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse",
//                                    "-y", gifFile, "-vn")
//                            .redirectError(new File("stderr.txt"))
//                            .start();
//                    isComplete = process.waitFor(10, TimeUnit.SECONDS);
//                    if (isComplete) {
//                        System.out.println("生成gif成功");
//                        break;
//                    } else {
//                        System.out.println("生成gif出错");
//                    }
                }
            } catch (Exception e) {
                System.out.println("生成gif出错");
            }
        }

        return gifFile;
    }

以上就是JAVA使用ffmepg处理视频的方法(压缩,分片,合并)的详细内容,更多关于java ffmepg处理视频的资料请关注我们其它相关文章!

(0)

相关推荐

  • 教你轻松制作java视频播放器

    前言 跳过废话,直接看正文 当年入坑Java是因为它的跨平台优势.那时我认为,"编写一次,处处运行."这听上去多么牛逼,应该是所有语言发展的终极之道,java势必会一统天下. 然而事实证明,那时的我还是太年轻. 正所谓鱼和熊掌不可兼得,若要享受跨平台带来的方便,便不可避免地要接受性能上的不足.事实上,java一直在致力于提高虚拟机的性能(JIT等技术),但面对对实时计算性能要求很高或涉及到用硬件优化的任务(视频的硬件编码.解码)时,仍远远比不上c或c++.因此,很少能够看到有人用jav

  • Java上传视频实例代码

    页面: 上传文件时的关键词:enctype="multipart/form-data" <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://&qu

  • Java 使用 FFmpeg 处理视频文件示例代码详解

    目前在公司做一个小东西,里面用到了 FFmpeg 简单处理音视频,感觉功能特别强大,在做之前我写了一个小例子,现在记录一下分享给大家,希望大家遇到这个问题知道解决方案. FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以及流化音视频的完整解决方案.它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的. FFmpeg在Linux平

  • Java刷视频浏览量点赞量的实现代码

    说明 这几天班主任一直让我们访问一个网页来观察看视频,增加访问次数.每个班级还有指定的名额...而且经过我的测试,点赞次数是在观看视频一会才出现的.. 可是身为计算机专业的 肯定不想一直点啊 点啊 于是我就有了一个大胆的想法 分析 于是我就查看网页的源代码 这行代码是弹出点赞的时间为18s. 18秒后发生了什么呢 ?继续看 可以看到这个弹出点赞的父div为class="video_mask" 而且默认的显示框类型为none,即不显示. 好吧 废话不多说. 主要看下面的 如果我们点击了t

  • Java爬虫抓取视频网站下载链接

    本篇文章抓取目标网站的链接的基础上,进一步提高难度,抓取目标页面上我们所需要的内容并保存在数据库中.这里的测试案例选用了一个我常用的电影下载网站(http://www.80s.la/).本来是想抓取网站上的所有电影的下载链接,后来感觉需要的时间太长,因此改成了抓取2015年电影的下载链接. 一 原理简介 其实原理都跟第一篇文章差不多,不同的是鉴于这个网站的分类列表实在太多,如果不对这些标签加以取舍的话,需要花费的时间难以想象. 分类链接和标签链接都不要,不通过这些链接去爬取其他页面,只通过页底的

  • java使用ffmpeg处理视频的方法

    FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以及流化音视频的完整解决方案. 官网链接http://ffmpeg.org/ 1.下载并解压windows版本安装包 2.windows本地使用命令行测试 1.修改格式测试(转码) 将需要修改的视频A.avi 提前放在bin目录下 在bin目录下cmd进入命令行 输入命令完成转码成B.mp4 ffmpeg.exe -i A.avi -y B.mp4 2.视频音频结合

  • Java使用FFmpeg处理视频文件的方法教程

    前言 本文主要讲述如何使用Java + FFmpeg实现对视频文件的信息提取.码率压缩.分辨率转换等功能: 之前在网上浏览了一大圈Java使用FFmpeg处理音视频的文章,大多都讲的比较简单,楼主在实操过程中踩了很多坑也填了很多坑,希望这份详细的踩坑&填坑指南能帮助到大家: 1. 什么是FFmpeg 点我了解 2. 开发前准备 在使用Java调用FFmpeg处理音视频之前,需要先安装FFmpeg,安装方法分为两种: 引入封装了FFmpeg的开源框架 在系统中手动安装FFmpeg 2.1 引入封装

  • JAVA使用ffmepg处理视频的方法(压缩,分片,合并)

    FFmepg安装 路径: 然后在使用的类中生命一个全局变量就好 private static String ffmpegPath = "C:\\hk\\ffmpeg\\bin\\ffmpeg.exe"; //ffmepg的绝对路径 视频压缩 注意:此压缩视频涉及转码,对cpu的占用比较大(能不压缩尽量不压缩) /** * 压缩视频 * @param convertFile 待转换的文件 * @param targetFile 转换后的目标文件 */ public static void

  • java调用ffmpeg实现视频转换的方法

    本文实例讲述了java调用ffmpeg实现视频转换的方法.分享给大家供大家参考.具体分析如下: 这里环境我是在windows平台下测试的... 需要在e:\下有ffmpeg.exe;mencoder.exe;drv43260.dll;pncrt.dll共4个文件.   还要在e:\input下放各种文件名为a的以下各种视频文件:还要e:\output:java程序执行后能得到一个a.flv的已转换的文件. ffmpeg.exe能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov

  • java批量修改文件名的实现方法

     java批量修改文件名的实现方法 初次学习java,被java的灵活性和简洁的思路所吸引 需求: 看到java视频在播放器列表中的文件名很长,每次都需要拉长列表才能看清全名,故写此代码批量修改该文件夹下所有文件名 实现代码: import java.io.*; class filesRename { public static void main(String[] args) throws IOException { String str1 = new String("这里是需要删除的文件名前

  • 在Java下利用log4j记录日志的方法

    1.前言 log4j是一个用Java编写的可靠,快速和灵活的日志框架(API),它在Apache软件许可下发布. Log4j已经被移植到了C,C++,C#,Perl,Python和Ruby等语言中. Log4j是高度可配置的,并可通过在运行时的外部文件配置.它根据记录的优先级别,并提供机制,以指示记录信息到许多的目的地,例如:数据库,文件,控制台,UNIX系统日志等. Log4j中有三个主要组成部分: loggers: 负责捕获记录信息. appenders : 负责发布日志信息,以不同的首选目

  • java实现文件重命名的方法

    本文实例讲述了java实现文件重命名的方法.分享给大家供大家参考.具体如下: 下载的电影总是有一些存在网站名称等没用的信息 作为一个强迫症患者 一定要删除他们 package sys.file; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.io.*; public class ZReName { public static void main(Str

  • Java实现把文件及文件夹压缩成zip

    最近碰到个需要下载zip压缩包的需求,于是我在网上找了下别人写好的zip工具类.但找了好多篇博客,总是发现有bug.因此就自己来写了个工具类. 这个工具类的功能为: (1)可以压缩文件,也可以压缩文件夹 (2)同时支持压缩多级文件夹,工具内部做了递归处理 (3)碰到空的文件夹,也可以压缩 (4)可以选择是否保留原来的目录结构,如果不保留,所有文件跑压缩包根目录去了,且空文件夹直接舍弃.注意:如果不保留文件原来目录结构,在碰到文件名相同的文件时,会压缩失败. (5)代码中提供了2个压缩文件的方法,

  • Java实现导出ZIP压缩包的方法

    最近接触到一个需求要求压缩导出文件,于是乎便要致力于研究一下工具类啦,故也诞生了此篇文章. 下面代码中,溪源也将import导入的依赖也贴出来了,避免大家引入错误. import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.text.SimpleD

  • Java实现将文件或者文件夹压缩成zip的详细代码

    最近碰到个需要下载zip压缩包的需求,于是我在网上找了下别人写好的zip工具类.但找了好多篇博客,总是发现有bug.因此就自己来写了个工具类.         这个工具类的功能为: (1)可以压缩文件,也可以压缩文件夹 (2)同时支持压缩多级文件夹,工具内部做了递归处理 (3)碰到空的文件夹,也可以压缩 (4)可以选择是否保留原来的目录结构,如果不保留,所有文件跑压缩包根目录去了,且空文件夹直接舍弃.注意:如果不保留文件原来目录结构,在碰到文件名相同的文件时,会压缩失败. (5)代码中提供了2个

随机推荐