JAVA代码调用ffmpeg程序进行视频转码和推流方式

 更新时间:2025年02月07日 09:29:29   作者:F0urtEEn  
本文介绍了如何通过Java代码调用FFmpeg进行多媒体视频处理,包括两种方式:使用第三方封装的jar包和使用ProcessBuilder类创建进程,两种方式各有优缺点,选择时需根据具体需求和场景

一、前言

FFmpeg是一款多媒体视频处理工具,有非常强大的功能包括:视频采集、视频推流、视频格式转换、视频抓图、给视频加水印等功能。

FFmpeg本身是一个命令行程序,需要通过执行 ffmpeg命令来实现功能,如下:

ffmpeg -i 123.mp4 -c:a copy -c:v libx264 -f flv rtmp://127.0.0.1:1935/live/test
ffmpeg -i 123.mp4 -c copy -f hls -hls_list_size 5 -hls_flags 50 -hls_time 10 D:\hls\test.m3u8

在实际开发工作中,会需要通过JAVA代码去调用ffmpeg程序去完成功能,而不是手动去执行ffmpeg命令。本篇文章将介绍如何通过JAVA代码去调用执行ffmpeg程序。

二、JAVA代码调用ffmpeg

本篇文章将介绍两种方式实现 JAVA代码去调用ffmpeg程序。

方式一:采用第三方封装调用ffmpeg接口的jar包实现

1. 在Maven项目pom.xml文件中引入jar包依赖

<dependency>
    <groupId>net.bramp.ffmpeg</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>0.6.2</version>
</dependency>

2. 编写java代码

//创建FFmpeg对象
FFmpeg ffmpeg = new FFmpeg("D:\\ffmpeg\\bin\\ffmpeg.exe");     //参数是:ffmpeg命令工具的安装路径
        
//创建FFmpegBuilder对象,设置推流/转码参数
FFmpegBuilder builder = new FFmpegBuilder()
        .setInput("D:\\111.mp4")                                   //输入视频源地址
        .overrideOutputFiles(true)                                //设置是否覆盖已存在的输出文件
        .addOutput("D:\\hls\\test.m3u8")                         //输出流地址
        .setFormat("hls")                                       //输出流格式 -f hls
        .setAudioCodec("copy")                                  //设置音频转码  copy表示不转码
        .setVideoCodec("libx264")                               //设置视频转码  copy表示不转码
        .setVideoQuality(1)                                     //设置视频质量,一般为1到5(1代表质量最高)
        .setVideoFrameRate(25)                                  //设置视频帧率
        .addExtraArgs("-t", "30")                               //设置推流持续时间
        .addExtraArgs("-hls_list_size", "5")                    //设置输出文件个数(hls输出流特有的参数)
        .addExtraArgs("-hls_flags", "50")                       //设置输出文件替换(hls输出流特有的参数)
        .addExtraArgs("-hls_time", "6")                        //设置输出文件每个时长多少秒(hls输出流特有的参数)
        .done();                                               //最后调用done()完成参数配置


//创建FFmpegExecutor对象,用于执行ffpmeg转流任务
FFmpegExecutor executor=new FFmpegExecutor(ffmpeg);

//执行ffpmeg转流任务,并添加了监听器ProgressListener,可以监听ffpmeg运行状态情况
executor.createJob(builder, new ProgressListener() {     
    @Override
    public void progress(Progress progress) {
        System.out.println("-----------");
        System.out.println(progress);
    }
}).run();

3. 第三方jar包实现优缺点:

  • 优点:封装好了ffmpeg调用功能,代码实现简单易用
  • 缺点:没有提供停止ffmpeg程序的方法,无法实现手动终止任务。就算手动杀死JAVA程序也无法终止ffmpeg程序的执行,只有等ffmpeg转流任务完成了程序自行停止。

方式二:采用ProcessBuilder类创建进程的方式调用ffmpeg实现

ProcessBuilder 类是JDK中java.lang包下提供的用于创建操作系统进程的类, 可以通过JDK API 文档查看其用法。

1. 编写java代码

//创建一个命令List集合,用于存放ffmpeg执行的命令参数
List<String> command = new ArrayList<>();
command.add("D:\\ffmpeg\\bin\\ffmpeg.exe");
command.add("-i");
command.add("D:\\123.mp4");         //输入视频源或者流地址
command.add("-c");
command.add("copy");
command.add("-f");
command.add("hls");
command.add("-hls_time");
command.add("10");
command.add("-hls_list_size");
command.add("5");
command.add("-hls_flags");
command.add("50");
command.add("D:\\hls\\test.m3u8");   //输出流地址

//创建ProcessBuilder对象,传入集合
ProcessBuilder builder = new ProcessBuilder(command);
//start()方法创建一个系统进程,执行ffmpeg命令工具
Process process = builder.start();


//注意:使用ProcessBuilder执行任务,必须要手动接收正常输出信息和错误输出信息,不然ProcessBuilder任务会阻塞卡住

//多线程读取正常输出信息 process.getInputStream()
new Thread(() -> {
    try {
        InputStream is = process.getInputStream();
		//将正常输出信息写入到normal.txt文件中
		RandomAccessFile raf = new RandomAccessFile("D:\\normal.txt", "rw");
		
        byte[] data = new byte[128];
        int len = -1;
        while((len = is.read(data)) != -1) {
            raf.write(data, 0, len);
        }
        raf.close();
    } catch (IOException e) {
       e.printStackTrace();
    }
}, "Thread-Normal").start();


//多线程读取错误输出信息 process.getErrorStream()
new Thread(() -> {
    try {
        InputStream is = process.getErrorStream();
		//将错误输出信息写入到error.txt文件中
		RandomAccessFile raf = new RandomAccessFile("D:\\error.txt", "rw");
		
        byte[] data = new byte[128];
        int len = -1;
        while((len = is.read(data)) != -1) {
            raf.write(data, 0, len);
        }
        raf.close();
    } catch (IOException e) {
       e.printStackTrace();
    }
}, "Thread-Error").start();



//destroy()方法可以停止进程,从而终止ffmpeg程序
//process.destroy();

2. ProcessBuilder实现优缺点:

  • 优点:可以手动调用destory()方法随时停止ffmpeg程序的执行
  • 缺点:需要手动写代码去主动接收任务进程产生的正常输出信息和错误信息,不然进程会被卡住。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 详解如何修改idea配置文件位置从C盘更改到D盘

    详解如何修改idea配置文件位置从C盘更改到D盘

    这篇文章主要给大家介绍了关于如何将idea的配置文件从默认的C盘调整到D盘,从而节省C盘使用空间,具有很好的参考价值,希望对大家有所帮助,需要的朋友可以参考下
    2023-10-10
  • Java排序算法总结之堆排序

    Java排序算法总结之堆排序

    这篇文章主要介绍了Java排序算法总结之堆排序,详细分析了堆排序的原理与java实现技巧,需要的朋友可以参考下
    2015-05-05
  • Java异常 Exception类及其子类(实例讲解)

    Java异常 Exception类及其子类(实例讲解)

    下面小编就为大家带来一篇Java异常 Exception类及其子类(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Spring启动后获取所有拥有特定注解的Bean实例代码

    Spring启动后获取所有拥有特定注解的Bean实例代码

    这篇文章主要介绍了Spring启动后获取所有拥有特定注解的Bean实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-02-02
  • springboot静态资源的配置方式

    springboot静态资源的配置方式

    这篇文章主要介绍了springboot静态资源的配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java 坐标系相互转换方式

    Java 坐标系相互转换方式

    这篇文章主要介绍了Java中的坐标系相互转换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • 详解Springboot整合Dubbo之代码集成和发布

    详解Springboot整合Dubbo之代码集成和发布

    本篇文章主要介绍了Springboot整合Dubbo之代码集成和发布,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • 关于Spring MVC同名参数绑定问题的解决方法

    关于Spring MVC同名参数绑定问题的解决方法

    Spring MVC中的参数绑定还是蛮重要的,最近在使用中遇到了同名参数绑定的问题,想着总结分享出来,下面这篇文章主要给大家介绍了关于Spring MVC同名参数绑定问题的解决方法,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-08-08
  • 解读HttpServletRequestWrapper处理request数据流多次读取问题

    解读HttpServletRequestWrapper处理request数据流多次读取问题

    在Java Web开发中,获取HTTP请求参数是常见需求,本文详细讨论了通过POST方式获取参数的两种主要方法:使用request.getParameter()适用于application/x-www-form-urlencoded和multipart/form-data内容类型;而对于application/json类型的数据
    2024-10-10
  • java反射_改变private中的变量及方法的简单实例

    java反射_改变private中的变量及方法的简单实例

    下面小编就为大家带来一篇java反射_改变private中的变量及方法的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06

最新评论