JavaCV 拉流存儲(chǔ)到本地示例解析
拉流整體代碼
import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.javacv.*; public class LivePuller { public void pull(String rtmp, String outputVideoPath) { FFmpegFrameGrabber grabber = null; FFmpegFrameRecorder recorder = null; try { FFmpegLogCallback.set(); boolean hasStream = false; grabber = new FFmpegFrameGrabber(rtmp); grabber.setOption("nobuffer", "1"); // 采集流超時(shí)時(shí)間,停止推流后,grab() 大致會(huì)在 20 秒左右超時(shí)停止;值也不宜太小,否則可能有些音視頻幀采集不到影響推流 grabber.setOption("rw_timeout", "1000000"); grabber.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4); // setPixelFormat,可能會(huì)導(dǎo)致圖片幀保存的是黑白照 // grabber.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); grabber.setFormat("flv"); grabber.setAudioCodec(avcodec.AV_CODEC_ID_AAC); // 先執(zhí)行代碼后有直播流的情況下,grabber.start() 會(huì)拋出異常;因此循環(huán)start(),直到有流數(shù)據(jù)時(shí)成功 while (!hasStream) { try { grabber.start(); hasStream = true; } catch (Exception ignored) { } finally { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } } } // 重置分辨率 int imageWidth = grabber.getImageWidth(); int imageHeight = grabber.getImageHeight(); if (imageWidth > 1920 || imageHeight > 1080) { double wScale = imageWidth * 1.0 / 1920; double hScale = imageHeight * 1.0 / 1080; double scale = Math.max(wScale, hScale); grabber.setImageWidth((int) (imageWidth / scale)); grabber.setImageHeight((int) (imageHeight / scale)); } recorder = new FFmpegFrameRecorder(outputVideoPath, grabber.getImageWidth(), grabber.getImageHeight()); recorder.setOption("nobuffer", "1"); recorder.setAudioChannels(grabber.getAudioChannels()); recorder.setFrameRate(grabber.getFrameRate()); // 保持和采集一樣的幀率,避免音畫不同步; recorder.setVideoQuality(0); // 視頻質(zhì)量(清晰度) recorder.setAudioQuality(0); // 音頻質(zhì)量 // --------------------------- 非必須 ------------------------------ // 當(dāng)設(shè)置了下方的錄制器的視頻編碼,需要再加上 setVideoBitrate 保證視頻質(zhì)量 recorder.setVideoBitrate(grabber.getVideoBitrate()); recorder.setVideoCodec(grabber.getVideoCodec()); // 指定為 mp4 錄制時(shí)需要 avcodec.AV_CODEC_ID_MPEG4 // // 當(dāng)上面 grabber 沒(méi)有設(shè)置 setPixelFormat,recorder.setPixelFormat 最好不要使用 grabber.getPixelFormat();可能異常 // recorder.setPixelFormat(grabber.getPixelFormat()); // recorder.setFormat(grabber.getFormat()); // recorder.setAudioCodec(grabber.getAudioCodec()); // recorder.setSampleRate(grabber.getSampleRate()); recorder.start(); Frame frame; while ((frame = grabber.grab()) != null) { // 此處不能判斷 frame.streamIndex 為 avutil.AVMEDIA_TYPE_VIDEO 或 avutil.AVMEDIA_TYPE_DATA;遇到過(guò)采集流時(shí)兩個(gè)類型是反著的 if (frame.image != null || frame.samples != null) { // frame.image 是圖像數(shù)據(jù),frame.samples 是聲音數(shù)據(jù) recorder.record(frame); } } } catch (Exception e) { e.printStackTrace(); } finally { if (grabber != null) { try { grabber.close(); } catch (FrameGrabber.Exception e) { e.printStackTrace(); } } if (recorder != null) { try { recorder.close(); } catch (FrameRecorder.Exception e) { e.printStackTrace(); } } } } }
拉流整體代碼如上,基本該有的地方都有注釋;同 JavaCV 推流 也是改變分辨率等參數(shù)保證拉流速率,以及設(shè)置幀率保證音畫同步;
示例解析
另外上面提到 grabber.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
不要設(shè)置,避免后續(xù)的 JavaCV 保存視頻幀圖片 時(shí)保存的圖片是黑白的;另外上面的代碼經(jīng)過(guò)測(cè)試是可以將拉取的音視頻流保存成 mp4 格式,通過(guò)瀏覽器直接播放的
注意測(cè)試 mp4 文件保存的時(shí)候,盡量每次寫入一個(gè)新的文件;避免在調(diào)試過(guò)程中,出現(xiàn)因?yàn)g覽器緩存等問(wèn)題導(dǎo)致之前有問(wèn)題的 mp4 的文件,在參數(shù)調(diào)整好后依然不能正常播放等情況
以上就是JavaCV 拉流存儲(chǔ)到本地示例解析的詳細(xì)內(nèi)容,更多關(guān)于JavaCV 拉流存儲(chǔ)到本地的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Boot整合tk.mybatis代碼實(shí)例
這篇文章主要介紹了Spring Boot整合tk.mybatis代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11SpringBoot項(xiàng)目的漏洞修復(fù)經(jīng)驗(yàn)分享
在局域網(wǎng)環(huán)境下,由于無(wú)法連接外網(wǎng)下載Maven包,常見(jiàn)解決方案是在外網(wǎng)環(huán)境搭建相同的開(kāi)發(fā)環(huán)境以便更新Maven包,本次漏洞掃描包括Tomcat、jackson-databind、fastjson、logback等組件,通常解決方法是升級(jí)到更高版本2024-10-10設(shè)計(jì)模式之模版方法模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了設(shè)計(jì)模式之模版方法模式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08Java通過(guò)接口實(shí)現(xiàn)匿名類的實(shí)例代碼
這篇文章介紹了Java通過(guò)接口實(shí)現(xiàn)匿名類的實(shí)例代碼,有需要的朋友可以參考一下2013-10-10java運(yùn)行windows的cmd命令簡(jiǎn)單代碼
這篇文章主要介紹了java運(yùn)行windows的cmd命令簡(jiǎn)單代碼,有需要的朋友可以參考一下2013-12-12