1.獲取直播流(本地文件、攝像頭、在線獲取的視頻鏈接)

2.將流推送到推流服務器(不建議使用穿透局域方式,網(wǎng)上有很多打開攝像頭獲取流,通過網(wǎng)頁顯示的,這" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運營 > 直播視頻網(wǎng)站設計到實現(xiàn)(例子-java版本)

直播視頻網(wǎng)站設計到實現(xiàn)(例子-java版本)

時間:2023-10-09 09:54:01 | 來源:網(wǎng)站運營

時間:2023-10-09 09:54:01 來源:網(wǎng)站運營

直播視頻網(wǎng)站設計到實現(xiàn)(例子-java版本):首先這里直播使用到的流程為:

1.獲取直播流(本地文件、攝像頭、在線獲取的視頻鏈接)

2.將流推送到推流服務器(不建議使用穿透局域方式,網(wǎng)上有很多打開攝像頭獲取流,通過網(wǎng)頁顯示的,這里要走公網(wǎng),而且是多人查看的,最好用成熟的推流服務器,我這里用的是SRS,還有很多這樣類似的服務器,比如EasyDarwin,因為SRS是企業(yè)級應用,可分布可擴展)

3.前端獲取播放地址,進行播放(具體視頻格式或者播放協(xié)議可以根據(jù)自己的需求來)

首先docker安裝這個服務器到公網(wǎng),這里用docker安裝方便一點

docker run -p 11935:1935 -p 1985:1985 -p 8080:8080 ossrs/srs:3第二步maven中添加依賴

<!-- javacv相關依賴,一個就夠了 --> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.8</version> </dependency>


第三步我們先編寫測試代碼(準備一個mp4文件-播放時間盡量長一點):

package com.netsdk.test;import org.bytedeco.ffmpeg.avcodec.AVCodecParameters;import org.bytedeco.ffmpeg.avformat.AVFormatContext;import org.bytedeco.ffmpeg.avformat.AVStream;import org.bytedeco.ffmpeg.global.avcodec;import org.bytedeco.ffmpeg.global.avutil;import org.bytedeco.javacv.*;import java.util.logging.Logger;public class Test1 { /** * 本地MP4文件的完整路徑 */ private static final String MP4_FILE_PATH = "E://data//testh264.mp4"; /** * SRS的推流地址這里要改 */ private static final String SRS_PUSH_ADDRESS = "rtmp://xxxxxx:11935/live/457578"; /** * 讀取指定的mp4文件,推送到SRS服務器 * @param sourceFilePath 視頻文件的絕對路徑 * @param PUSH_ADDRESS 推流地址 * @throws Exception */ private static void grabAndPush(String sourceFilePath, String PUSH_ADDRESS) throws Exception { // ffmepg日志級別 avutil.av_log_set_level(avutil.AV_LOG_INFO); FFmpegLogCallback.set(); // 實例化幀抓取器對象,將文件路徑傳入 FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(MP4_FILE_PATH); long startTime = System.currentTimeMillis(); System.out.println("開始初始化幀抓取器"); // 初始化幀抓取器,例如數(shù)據(jù)結(jié)構(gòu)(時間戳、編碼器上下文、幀對象等), // 如果入?yún)⒌扔趖rue,還會調(diào)用avformat_find_stream_info方法獲取流的信息,放入AVFormatContext類型的成員變量oc中 grabber.start(true); System.out.println("幀抓取器初始化完成,耗時[{}]毫秒:"); System.out.println(System.currentTimeMillis()-startTime); // grabber.start方法中,初始化的解碼器信息存在放在grabber的成員變量oc中 AVFormatContext avFormatContext = grabber.getFormatContext(); // 文件內(nèi)有幾個媒體流(一般是視頻流+音頻流) int streamNum = avFormatContext.nb_streams(); // 沒有媒體流就不用繼續(xù)了 if (streamNum<1) { System.out.println("文件內(nèi)不存在媒體流"); return; } // 取得視頻的幀率 int frameRate = (int)grabber.getVideoFrameRate(); System.out.println("視頻幀率[{}],視頻時長[{}]秒,媒體流數(shù)量[{}]"); System.out.println(frameRate); System.out.println(avFormatContext.duration()/1000000); System.out.println(avFormatContext.nb_streams()); // 遍歷每一個流,檢查其類型 for (int i=0; i< streamNum; i++) { AVStream avStream = avFormatContext.streams(i); AVCodecParameters avCodecParameters = avStream.codecpar(); System.out.println("流的索引[{}],編碼器類型[{}],編碼器ID[{}]"); System.out.println(i); System.out.println(avCodecParameters.codec_type()); System.out.println(avCodecParameters.codec_id()); } // 視頻寬度 int frameWidth = grabber.getImageWidth(); // 視頻高度 int frameHeight = grabber.getImageHeight(); // 音頻通道數(shù)量 int audioChannels = grabber.getAudioChannels(); System.out.println("視頻寬度[{}],視頻高度[{}],音頻通道數(shù)[{}]"); System.out.println(frameWidth); System.out.println(frameHeight); System.out.println(audioChannels); // 實例化FFmpegFrameRecorder,將SRS的推送地址傳入 FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(SRS_PUSH_ADDRESS, frameWidth, frameHeight, audioChannels); // 設置編碼格式 recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 設置封裝格式 recorder.setFormat("flv"); // 一秒內(nèi)的幀數(shù) recorder.setFrameRate(frameRate); // 兩個關鍵幀之間的幀數(shù) recorder.setGopSize(frameRate); // 設置音頻通道數(shù),與視頻源的通道數(shù)相等 recorder.setAudioChannels(grabber.getAudioChannels()); startTime = System.currentTimeMillis(); System.out.println("開始初始化幀抓取器"); // 初始化幀錄制器,例如數(shù)據(jù)結(jié)構(gòu)(音頻流、視頻流指針,編碼器), // 調(diào)用av_guess_format方法,確定視頻輸出時的封裝方式, // 媒體上下文對象的內(nèi)存分配, // 編碼器的各項參數(shù)設置 recorder.start(); System.out.println("幀錄制初始化完成,耗時[{}]毫秒"); System.out.println(System.currentTimeMillis()-startTime); Frame frame; startTime = System.currentTimeMillis(); System.out.println("開始推流"); long videoTS = 0; int videoFrameNum = 0; int audioFrameNum = 0; int dataFrameNum = 0; // 假設一秒鐘15幀,那么兩幀間隔就是(1000/15)毫秒 int interVal = 1000/frameRate; // 發(fā)送完一幀后sleep的時間,不能完全等于(1000/frameRate),不然會卡頓, // 要更小一些,這里取八分之一 interVal/=8; // 持續(xù)從視頻源取幀 while (null!=(frame=grabber.grab())) { videoTS = 1000 * (System.currentTimeMillis() - startTime); // 時間戳 recorder.setTimestamp(videoTS); // 有圖像,就把視頻幀加一 if (null!=frame.image) { videoFrameNum++; } // 有聲音,就把音頻幀加一 if (null!=frame.samples) { audioFrameNum++; } // 有數(shù)據(jù),就把數(shù)據(jù)幀加一 if (null!=frame.data) { dataFrameNum++; } // 取出的每一幀,都推送到SRS recorder.record(frame); // 停頓一下再推送 Thread.sleep(interVal); } System.out.println("推送完成,視頻幀[{}],音頻幀[{}],數(shù)據(jù)幀[{}],耗時[{}]秒"); System.out.println(videoFrameNum); System.out.println(audioFrameNum); System.out.println(dataFrameNum); System.out.println((System.currentTimeMillis()-startTime)/1000); // 關閉幀錄制器 recorder.close(); // 關閉幀抓取器 grabber.close(); } public static void main(String[] args) throws Exception { grabAndPush(MP4_FILE_PATH, SRS_PUSH_ADDRESS); }}


使用這個播放器,把自己代碼中設置推流到SRS中的地址拷貝進去




運行如下:

播放如下:

可以看到視頻被在公網(wǎng)上正確播放出來了。

現(xiàn)在我們不在使用文件形式,而是使用實時的預覽流:

1.第一步我們要建立管道流進行共享管理

// 創(chuàng)建管道輸出流 pipedOutputStream = new PipedOutputStream(); // 創(chuàng)建管道輸入流 pipedInputStream = new PipedInputStream(); try { // 將管道輸入流與輸出流連接 此過程也可通過重載的構(gòu)造函數(shù)來實現(xiàn) pipedOutputStream.connect(pipedInputStream); } catch (IOException e) { e.printStackTrace(); }2.第二步將我們?nèi)〉玫牧鲗懙焦艿乐校ū热绱笕A的sdk、海康的、或者其他從硬件設備中獲取的,如果是本機自帶的攝像頭可以直接用JavaCV提供的錄制功能,而不需要使用管道進行推送)

這里由于其他原因我這里截圖關鍵的寫入指令:

同樣可以使用上面的Test1的代碼,但是有個地方需要修改一下:

這個地方這樣設置一下,改成從管道中獲取流,就可以實時播放了。





關鍵詞:實現(xiàn),例子,版本,設計,視頻,直播

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點擊下載Chrome瀏覽器
關閉