java中實(shí)現(xiàn)視頻處理以及播放功能代碼詳解
前言
我們知道,現(xiàn)在視頻可以說(shuō)是最火爆的多媒體手段了,所以順帶著視頻處理技術(shù)也就成了目前炙手可熱的技術(shù)之一了。我們作為一個(gè)Java程序員,又該怎么處理視頻呢?今天Java架構(gòu)棧就給大家講解一下,如何通過(guò)Java代碼來(lái)實(shí)現(xiàn)視頻處理及播放。
一. 需要了解的技術(shù)點(diǎn)
在具體實(shí)現(xiàn)之前,我們先來(lái)看看視頻處理需要了解的技術(shù)點(diǎn)都有哪些。
FFmpeg
FFmpeg是一套可以用來(lái)記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開(kāi)源計(jì)算機(jī)程序。采用LGPL或GPL許可證。它提供了錄制、轉(zhuǎn)換以及流化音視頻的完整解決方案。它包含了非常先進(jìn)的音頻/視頻編解碼庫(kù)libavcodec,為了保證高可移植性和編解碼質(zhì)量,libavcodec里很多code都是從頭開(kāi)發(fā)的。 FFmpeg在Linux平臺(tái)下開(kāi)發(fā),但它同樣也可以在其它操作系統(tǒng)環(huán)境中編譯運(yùn)行,包括Windows、Mac OS X等。這個(gè)項(xiàng)目最早由Fabrice Bellard發(fā)起,2004年至2015年間由Michael Niedermayer主要負(fù)責(zé)維護(hù)。許多FFmpeg的開(kāi)發(fā)人員都來(lái)自MPlayer項(xiàng)目,而且當(dāng)前FFmpeg也是放在MPlayer項(xiàng)目組的服務(wù)器上。項(xiàng)目的名稱(chēng)來(lái)自MPEG視頻編碼標(biāo)準(zhǔn),前面的"FF"代表"Fast Forward"。 [1] FFmpeg編碼庫(kù)可以使用GPU加速。
HLS
HLS(HTTP Live Streaming)是Apple的動(dòng)態(tài)碼率自適應(yīng)技術(shù)。主要用于PC和Apple終端的音視頻服務(wù)。包括一個(gè)m3u8的索引文件,TS媒體分片文件和key加密串文件。
HLS的工作原理:將視頻文件分成多個(gè)ts格式的小文件,通過(guò)m3u8格式的索引文件對(duì)這些ts小文件組織索引。播放器可以通過(guò)連接m3u8文件播放視頻,當(dāng)要快進(jìn)時(shí)可以通過(guò)m3u8這個(gè)索引文件找到對(duì)應(yīng)的小文件,并去下載對(duì)應(yīng)的ts文件,最終可以實(shí)現(xiàn)快進(jìn)、快退、實(shí)時(shí)播放等功能。
m3u8所以文件和ts小文件可以讓FFmpeg幫我們生成。
video.js 網(wǎng)絡(luò)播放器
Video.js是一個(gè)為HTML5世界從頭開(kāi)始構(gòu)建的網(wǎng)絡(luò)視頻播放器。它支持HTML5視頻和現(xiàn)代流媒體格式,它支持桌面和移動(dòng)設(shè)備上的視頻播放。該項(xiàng)目于2010年中期啟動(dòng),目前已有數(shù)百名撰稿人,在450000多個(gè)網(wǎng)站上使用。
官方地址:https://videojs.com/
二. 具體實(shí)現(xiàn)步驟
了解完上面的這些基本理論知識(shí)后,接下來(lái)咱們就來(lái)看看該如何進(jìn)行代碼實(shí)現(xiàn)吧。
使用ffmpeg將錄制的avi格式文件生成MP4文件
我們可以把a(bǔ)vi格式的文件轉(zhuǎn)為mp4格式的文件,實(shí)現(xiàn)代碼如下所示:
/** 生成avi文件生成mp4文件 @param ffmpeg_path ffmpeg的安裝路徑:C:\Program Files\ffmpeg-master-latest-win64-gpl-shared\bin\ffmpeg.exe @param video_path 要轉(zhuǎn)化的avi文件地址 @param mp4folder_path 生成的MP4存放路徑 @param mp4_name 生成的MP4文件名 @return 成功返回ok,失敗返回error */
public String makeMp4(String ffmpeg_path,String video_path,String mp4folder_path,String mp4_name){ //ffmpeg.exe -i qfedu.avi -c:v libx264 -s 1280x720 -pix_fmt yuv420p -b:a 63k -b:v 753k -r 18 .\qfedu.mp4 // 通過(guò) ProcessBuilder 執(zhí)行 ffmpeg.exe List cmd = new ArrayList(); cmd.add(ffmpeg_path); cmd.add("-i"); cmd.add(video_path); cmd.add("-c:v"); cmd.add("libx264"); cmd.add("-y"); cmd.add("-s"); cmd.add("1280x720"); cmd.add("-pix_fmt"); cmd.add("yuv420p"); cmd.add("-b:a"); cmd.add("63k"); cmd.add("-b:v"); cmd.add("753k"); cmd.add("-r"); cmd.add("18"); cmd.add(mp4folder_path + mp4_name ); String outstring = null; try { ProcessBuilder builder = new ProcessBuilder(); builder.command(cmd); builder.redirectErrorStream(true); Process process = builder.start(); outstring = getProcessResult(process); System.out.println(outstring); return "ok"; } catch (Exception ex) { ex.printStackTrace(); return "error"; } } /**
獲取進(jìn)程執(zhí)行結(jié)果
*/ public String getProcessResult(Process process) { String result = "error"; int exitValue = -1; InputStream inputStream = null; InputStream errorInputStream = null; StringBuffer outputString = new StringBuffer(); try { inputStream = process.getInputStream(); errorInputStream = process.getErrorStream(); boolean finished = false; int max = 300;//每次休眠1秒,最長(zhǎng)執(zhí)行時(shí)間5分種 int count = 0; while (!finished) { //超過(guò)5分鐘,默認(rèn)失敗 if (retry > max) { return "error"; }
try { while (inputStream.available() > 0) { Character c = new Character((char) inputStream.read()); outputString.append(c); System.out.print(c); } while (errorInputStream.available() > 0) { Character c = new Character((char) errorInputStream.read()); outputString.append(c); System.out.print(c); } exitValue = p.exitValue(); finished = true; } catch (IllegalThreadStateException e) { Thread.currentThread().sleep(1000);//休眠1秒 count++; } } } catch (Exception e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } return outputString.toString();
使用ffmpeg將MP4文件生成m3u8/ts文件
我們也可以把MP4格式的文件轉(zhuǎn)換為m3u8/ts格式的文件,實(shí)現(xiàn)代碼如下所示:
/** 生成m3u8文件 @param ffmpeg_path ffmpeg的安裝路徑:C:\Program Files\ffmpeg-master-latest-win64-gpl-shared\bin\ffmpeg.exe @param video_path 要轉(zhuǎn)化的mp4文件地址 @param m3u8folder_path 生成m3u8的存放路徑 @param m3u8_name 生成的m3u8文件名 @return 成功返回ok,失敗返回error @return 成功則返回success,失敗error / public String makeM3u8(String ffmpeg_path,String video_path,String m3u8folder_path,String m3u8_name) { / ffmpeg -i qfedu.mp4 -hls_time 10 -hls_list_size 0 -hls_segment_filename ./hls/qfedu_%05d.ts ./hls/qfedu.m3u8 */ List cmd = new ArrayList(); cmd.add(ffmpeg_path); cmd.add("-i"); cmd.add(video_path); cmd.add("-hls_time"); cmd.add("10"); cmd.add("-hls_list_size"); cmd.add("0"); cmd.add("-hls_segment_filename"); cmd.add(m3u8folder_path + m3u8_name.substring(0, m3u8_name.lastIndexOf(".")) + "_%05d.ts"); cmd.add(m3u8folder_path + m3u8_name); String out = null; try { ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.command(cmd); processBuilder.redirectErrorStream(true); Process process = processBuilder.start(); out = getProcessResult(process); System.out.println(out); } catch (Exception e) { e.printStackTrace(); } //通過(guò)檢查生成的m3u8的文件列表判斷是否成功 List tsList = getTsList(m3u8folder_path,m3u8_name); if (tsList == null) { return "error"; } return "success"; } /** 獲取ts列表 @return ts列表 */ public List getTsList(String m3u8folder_path,String m3u8_name ) { List fileList = new ArrayList(); List tsList = new ArrayList(); String m3u8file_path = m3u8folder_path + m3u8_name; BufferedReader reader = null; String str = null; String line = ""; try { reader = new BufferedReader(new FileReader(m3u8file_path)); while ((str = reader.readLine()) != null) { line = str; if (line.endsWith(".ts")) { tsList.add(line); } } } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } if (line.contains("#EXT-X-ENDLIST")) { fileList.addAll(tsList); return fileList; } return null; }
使用基于html5支持Video.js網(wǎng)絡(luò)視頻播放器播放視頻
我們也可以在html頁(yè)面中,把處理好的視頻嵌入進(jìn)來(lái),供用戶流量播放。
總結(jié)
到此這篇關(guān)于java中實(shí)現(xiàn)視頻處理以及播放功能的文章就介紹到這了,更多相關(guān)java視頻處理及播放內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java集合PriorityQueue優(yōu)先級(jí)隊(duì)列方法實(shí)例
這篇文章主要為大家介紹了java集合PriorityQueue優(yōu)先級(jí)隊(duì)列方法實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12java javax.annotation.Resource注解的詳解
這篇文章主要介紹了javax.annotation.Resource注解的詳解的相關(guān)資料,需要的朋友可以參考下2016-10-10SpringBoot事務(wù)異步調(diào)用引發(fā)的bug解決
本文主要介紹了SpringBoot事務(wù)異步調(diào)用引發(fā)的bug解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06如何使用Java實(shí)現(xiàn)請(qǐng)求deepseek
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)請(qǐng)求deepseek功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02Java設(shè)計(jì)模式中單一職責(zé)原則詳解
這篇文章主要介紹了Java設(shè)計(jì)模式中單一職責(zé)原則詳解,單一職責(zé)原則 (SRP) 是軟件設(shè)計(jì)中的一個(gè)重要原則,它要求每個(gè)類(lèi)只負(fù)責(zé)一個(gè)職責(zé),需要的朋友可以參考下2023-05-05在springboot中添加mvc功能的正確姿勢(shì)講解
這篇文章主要介紹了在springboot中添加mvc功能的正確姿勢(shì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08