JAVA代碼調(diào)用ffmpeg程序進(jìn)行視頻轉(zhuǎn)碼和推流方式
一、前言
FFmpeg是一款多媒體視頻處理工具,有非常強(qiáng)大的功能包括:視頻采集、視頻推流、視頻格式轉(zhuǎn)換、視頻抓圖、給視頻加水印等功能。
FFmpeg本身是一個(gè)命令行程序,需要通過(guò)執(zhí)行 ffmpeg命令來(lái)實(shí)現(xiàn)功能,如下:
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
在實(shí)際開(kāi)發(fā)工作中,會(huì)需要通過(guò)JAVA代碼去調(diào)用ffmpeg程序去完成功能,而不是手動(dòng)去執(zhí)行ffmpeg命令。本篇文章將介紹如何通過(guò)JAVA代碼去調(diào)用執(zhí)行ffmpeg程序。
二、JAVA代碼調(diào)用ffmpeg
本篇文章將介紹兩種方式實(shí)現(xiàn) JAVA代碼去調(diào)用ffmpeg程序。
方式一:采用第三方封裝調(diào)用ffmpeg接口的jar包實(shí)現(xiàn)
1. 在Maven項(xiàng)目pom.xml文件中引入jar包依賴
<dependency>
<groupId>net.bramp.ffmpeg</groupId>
<artifactId>ffmpeg</artifactId>
<version>0.6.2</version>
</dependency>2. 編寫(xiě)java代碼
//創(chuàng)建FFmpeg對(duì)象
FFmpeg ffmpeg = new FFmpeg("D:\\ffmpeg\\bin\\ffmpeg.exe"); //參數(shù)是:ffmpeg命令工具的安裝路徑
//創(chuàng)建FFmpegBuilder對(duì)象,設(shè)置推流/轉(zhuǎn)碼參數(shù)
FFmpegBuilder builder = new FFmpegBuilder()
.setInput("D:\\111.mp4") //輸入視頻源地址
.overrideOutputFiles(true) //設(shè)置是否覆蓋已存在的輸出文件
.addOutput("D:\\hls\\test.m3u8") //輸出流地址
.setFormat("hls") //輸出流格式 -f hls
.setAudioCodec("copy") //設(shè)置音頻轉(zhuǎn)碼 copy表示不轉(zhuǎn)碼
.setVideoCodec("libx264") //設(shè)置視頻轉(zhuǎn)碼 copy表示不轉(zhuǎn)碼
.setVideoQuality(1) //設(shè)置視頻質(zhì)量,一般為1到5(1代表質(zhì)量最高)
.setVideoFrameRate(25) //設(shè)置視頻幀率
.addExtraArgs("-t", "30") //設(shè)置推流持續(xù)時(shí)間
.addExtraArgs("-hls_list_size", "5") //設(shè)置輸出文件個(gè)數(shù)(hls輸出流特有的參數(shù))
.addExtraArgs("-hls_flags", "50") //設(shè)置輸出文件替換(hls輸出流特有的參數(shù))
.addExtraArgs("-hls_time", "6") //設(shè)置輸出文件每個(gè)時(shí)長(zhǎng)多少秒(hls輸出流特有的參數(shù))
.done(); //最后調(diào)用done()完成參數(shù)配置
//創(chuàng)建FFmpegExecutor對(duì)象,用于執(zhí)行ffpmeg轉(zhuǎn)流任務(wù)
FFmpegExecutor executor=new FFmpegExecutor(ffmpeg);
//執(zhí)行ffpmeg轉(zhuǎn)流任務(wù),并添加了監(jiān)聽(tīng)器ProgressListener,可以監(jiān)聽(tīng)ffpmeg運(yùn)行狀態(tài)情況
executor.createJob(builder, new ProgressListener() {
@Override
public void progress(Progress progress) {
System.out.println("-----------");
System.out.println(progress);
}
}).run();3. 第三方j(luò)ar包實(shí)現(xiàn)優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn):封裝好了ffmpeg調(diào)用功能,代碼實(shí)現(xiàn)簡(jiǎn)單易用
- 缺點(diǎn):沒(méi)有提供停止ffmpeg程序的方法,無(wú)法實(shí)現(xiàn)手動(dòng)終止任務(wù)。就算手動(dòng)殺死JAVA程序也無(wú)法終止ffmpeg程序的執(zhí)行,只有等f(wàn)fmpeg轉(zhuǎn)流任務(wù)完成了程序自行停止。
方式二:采用ProcessBuilder類創(chuàng)建進(jìn)程的方式調(diào)用ffmpeg實(shí)現(xiàn)
ProcessBuilder 類是JDK中java.lang包下提供的用于創(chuàng)建操作系統(tǒng)進(jìn)程的類, 可以通過(guò)JDK API 文檔查看其用法。

1. 編寫(xiě)java代碼
//創(chuàng)建一個(gè)命令List集合,用于存放ffmpeg執(zhí)行的命令參數(shù)
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"); //輸出流地址
//創(chuàng)建ProcessBuilder對(duì)象,傳入集合
ProcessBuilder builder = new ProcessBuilder(command);
//start()方法創(chuàng)建一個(gè)系統(tǒng)進(jìn)程,執(zhí)行ffmpeg命令工具
Process process = builder.start();
//注意:使用ProcessBuilder執(zhí)行任務(wù),必須要手動(dòng)接收正常輸出信息和錯(cuò)誤輸出信息,不然ProcessBuilder任務(wù)會(huì)阻塞卡住
//多線程讀取正常輸出信息 process.getInputStream()
new Thread(() -> {
try {
InputStream is = process.getInputStream();
//將正常輸出信息寫(xiě)入到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();
//多線程讀取錯(cuò)誤輸出信息 process.getErrorStream()
new Thread(() -> {
try {
InputStream is = process.getErrorStream();
//將錯(cuò)誤輸出信息寫(xiě)入到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()方法可以停止進(jìn)程,從而終止ffmpeg程序
//process.destroy();2. ProcessBuilder實(shí)現(xiàn)優(yōu)缺點(diǎn):
- 優(yōu)點(diǎn):可以手動(dòng)調(diào)用destory()方法隨時(shí)停止ffmpeg程序的執(zhí)行
- 缺點(diǎn):需要手動(dòng)寫(xiě)代碼去主動(dòng)接收任務(wù)進(jìn)程產(chǎn)生的正常輸出信息和錯(cuò)誤信息,不然進(jìn)程會(huì)被卡住。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpingMvc復(fù)雜參數(shù)傳收總結(jié)
這篇文章主要為大家介紹了SpingMvc復(fù)雜參數(shù)傳收總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
java高級(jí)應(yīng)用:線程池的全面講解(干貨)
這篇文章主要介紹了java高級(jí)應(yīng)用:線程池的全面講解(干貨),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
SpringBoot中將@Bean方法解析為BeanDefinition詳解
這篇文章主要介紹了SpringBoot中將@Bean方法解析為BeanDefinition詳解,得到的BeanDefinition是ConfigurationClassBeanDefinition類型,會(huì)為BeanDefinition設(shè)置factoryMethodName,這意味著當(dāng)實(shí)例化這個(gè)bean的時(shí)候?qū)⒉捎霉S方法,需要的朋友可以參考下2023-12-12
Java基于JavaMail實(shí)現(xiàn)向QQ郵箱發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了Java基于JavaMail實(shí)現(xiàn)向QQ郵箱發(fā)送郵件的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01
java開(kāi)發(fā)中嵌套類的詳解及實(shí)例
這篇文章主要介紹了 java開(kāi)發(fā)中嵌套類的詳解及實(shí)例的相關(guān)資料,一般把定義內(nèi)部類的外圍類成為包裝類(enclosing class)或者外部類,需要的朋友可以參考下2017-07-07
SpringBoot集成Tess4J實(shí)現(xiàn)OCR的示例代碼
Tess4J是一個(gè)基于Tesseract OCR引擎的Java接口,可以用來(lái)識(shí)別圖像中的文本,說(shuō)白了,就是封裝了它的API,讓Java可以直接調(diào)用,本文給大家介紹了SpringBoot集成Tess4J實(shí)現(xiàn)OCR的示例,需要的朋友可以參考下2024-12-12
ThreadLocal導(dǎo)致JVM內(nèi)存泄漏原因探究
ThreadLocal是JDK提供的線程本地變量機(jī)制,但若使用不當(dāng)可能導(dǎo)致內(nèi)存泄漏。正確的使用方式是在使用完后及時(shí)remove,或者使用弱引用等手段避免強(qiáng)引用導(dǎo)致的內(nèi)存泄漏。在多線程編程中,合理使用ThreadLocal可以提高并發(fā)性能,但也需要注意其潛在的內(nèi)存泄漏問(wèn)題2023-04-04

