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類(lèi)創(chuàng)建進(jìn)程的方式調(diào)用ffmpeg實(shí)現(xiàn)
ProcessBuilder 類(lèi)是JDK中java.lang包下提供的用于創(chuàng)建操作系統(tǒng)進(jìn)程的類(lèi), 可以通過(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-08java高級(jí)應(yīng)用:線程池的全面講解(干貨)
這篇文章主要介紹了java高級(jí)應(yīng)用:線程池的全面講解(干貨),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02SpringBoot中將@Bean方法解析為BeanDefinition詳解
這篇文章主要介紹了SpringBoot中將@Bean方法解析為BeanDefinition詳解,得到的BeanDefinition是ConfigurationClassBeanDefinition類(lèi)型,會(huì)為BeanDefinition設(shè)置factoryMethodName,這意味著當(dāng)實(shí)例化這個(gè)bean的時(shí)候?qū)⒉捎霉S方法,需要的朋友可以參考下2023-12-12Java基于JavaMail實(shí)現(xiàn)向QQ郵箱發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了Java基于JavaMail實(shí)現(xiàn)向QQ郵箱發(fā)送郵件的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01java開(kāi)發(fā)中嵌套類(lèi)的詳解及實(shí)例
這篇文章主要介紹了 java開(kāi)發(fā)中嵌套類(lèi)的詳解及實(shí)例的相關(guān)資料,一般把定義內(nèi)部類(lèi)的外圍類(lèi)成為包裝類(lèi)(enclosing class)或者外部類(lèi),需要的朋友可以參考下2017-07-07SpringBoot集成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-12ThreadLocal導(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