Java 實現Rtsp 轉rtmp,hls,flv

服務支撐:FFmpeg? + srs(流媒體服務器)??

整個流程是 FFmpeg 收流轉碼 推 rtmp 到流媒體服務 流媒體服務再 分發流到公網

搭建流媒體服務:

1.??SRS (Simple Realtime Server) | SRS?(本例子使用的是SrS 安裝使用docker )

2.GitHub - ZLMediaKit/ZLMediaKit: WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181/SRT server and client framework based on C++11

3.nginx實現 (自己百度)

4. 其他的還有收費的那種?

2.服務器安裝FFmpeg? yum 可以安裝

java 服務實現調用ffmpeg

1.ProcessManager??用于執行指令以及 關閉這個流等操作

package io.renren.common.live;import cn.hutool.core.thread.ThreadUtil;
import org.springframework.beans.factory.DisposableBean;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;/*** @author chenkang* @date 2023年8月3日09:43:21*/
public class ProcessManager implements DisposableBean {private Map<String, WeakReference<Process>> processMap=new HashMap<>();/*** 啟動一個進程* @param processName 進程名稱key* @param command 執行指令*/public void startProcess(String processName, String command) {ThreadUtil.execAsync(() -> {try {ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));Process process = processBuilder.start();processMap.put(processName, new WeakReference<>(process));BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(processName + ": " + line);}int exitCode = process.waitFor();System.out.println(processName + ": Process execution completed with exit code: " + exitCode);} catch (IOException | InterruptedException e) {e.printStackTrace();}});}/***  銷毀* @param processName key*/public void terminateProcess(String processName) {WeakReference<Process> weakRef = processMap.get(processName);if (weakRef != null) {Process process = weakRef.get();if (process != null) {process.destroy();}processMap.remove(processName);}}private void terminateAllProcesses() {for (WeakReference<Process> weakRef : processMap.values()) {Process process = weakRef.get();if (process != null) {process.destroy();}}}@Overridepublic void destroy() throws Exception {this.terminateAllProcesses();this.processMap.clear();}
}

?對接的是大華的攝像頭

/**
? ? ?* 開始推流
? ? ?* 備注:現在客戶的設備是NVR NVR 下大概有54個攝像頭 ? 公網映射rtsp 554 端口 根據channel 開區分是那個攝像頭
? ? ?* 必須條件:1.服務端要安裝好 ffmpeg ? ?2.要搭建一個流媒體服務器 這個使用的是 srs
? ? ?* 流程:用戶端想要查看某個攝像頭->查詢到設備信息獲取到攝像頭的channel 這個是提前維護好的
? ? ?* ->拿到channel走如下方法 調用FFmpeg ?執行轉碼推流指令(客戶的攝像頭是h265)-》rtsp流會被轉碼 重新設定分辨率 碼率轉h264 并把轉碼流推向流媒體服務器 srs
? ? ?* ->客戶想看的時候就 拉取 流媒體服務端的rtmp流 完成播放
? ? ?*
? ? ?* 其他:
? ? ?* 1.用戶再播放的時候 要先確定這個攝像頭有沒有別的人在觀看 ?觀看了就不在執行了 (1.可以調用srs 接口查詢流是不是存在 這個比較穩妥 2.或者是 processManager 判斷是否在推了)
? ? ?* 2.有時候用戶強制關閉客戶端 無法感知用戶不在觀看了,這面還要 定時的去調用srs 接口查詢閑置的流及時的給關閉 同時也要 把服務的process 給主動關閉不然一直推
? ? ?* 這個要先去關閉process再調用接口關閉srs服務的流
? ? ?*
? ? ?*
? ? ?* http://127.0.0.1:1985/api/v1/streams 查詢服務端所有流
? ? ?*{
? ? ?* ? ? "code": 0,
? ? ?* ? ? "server": "vid-f1gt8j3",
? ? ?* ? ? "streams": [
? ? ?* ? ? ? ? {
? ? ?* ? ? ? ? ? ? "id": "vid-143p019",
? ? ?* ? ? ? ? ? ? //streamName
? ? ?* ? ? ? ? ? ? "name": "3",
? ? ?* ? ? ? ? ? ? "vhost": "vid-5847096",
? ? ?* ? ? ? ? ? ? "app": "live",
? ? ?* ? ? ? ? ? ? "live_ms": 1691039306435,
? ? ?* ? ? ? ? ? ? //客戶端數量 這個要注意 默認就有1 個客戶端是推流
? ? ?* ? ? ? ? ? ? "clients": 1,
? ? ?* ? ? ? ? ? ? "frames": 0,
? ? ?* ? ? ? ? ? ? "send_bytes": 0,
? ? ?* ? ? ? ? ? ? "recv_bytes": 1068,
? ? ?* ? ? ? ? ? ? "kbps": {
? ? ?* ? ? ? ? ? ? ? ? "recv_30s": 0,
? ? ?* ? ? ? ? ? ? ? ? "send_30s": 0
? ? ?* ? ? ? ? ? ? },
? ? ?* ? ? ? ? ? ? "publish": {
? ? ?* ? ? ? ? ? ? ? ? //是否正在推流 ?有時候服務端流停推了 但是還有客戶端在看 這個流還能查到 但是 ?active 為false
? ? ?* ? ? ? ? ? ? ? ? "active": false,
? ? ?* ? ? ? ? ? ? ? ? "cid": ""
? ? ?* ? ? ? ? ? ? },
? ? ?* ? ? ? ? ? ? "video": null,
? ? ?* ? ? ? ? ? ? "audio": null
? ? ?* ? ? ? ? }
? ? ?* ? ? ]
? ? ?* }
? ? ?*
? ? ?*
? ? ?*
? ? ?* http://127.0.0.1:1985/api/v1/clients
? ? ?*
? ? ?*{
? ? ?* ? ? "code": 0,
? ? ?* ? ? "server": "vid-f1gt8j3",
? ? ?* ? ? "clients": [
? ? ?* ? ? ? ? {
? ? ?* ? ? ? ? ? ? "id": "868249e9",
? ? ?* ? ? ? ? ? ? "vhost": "vid-5847096",
? ? ?* ? ? ? ? ? ? "stream": "vid-778ujy0",
? ? ?* ? ? ? ? ? ? "ip": "172.17.0.1",
? ? ?* ? ? ? ? ? ? "pageUrl": "",
? ? ?* ? ? ? ? ? ? "swfUrl": "",
? ? ?* ? ? ? ? ? ? "tcUrl": "rtmp://127.0.0.1:1935/live",
? ? ?* ? ? ? ? ? ? "url": "/live/9",
? ? ?* ? ? ? ? ? ? //類型是 fmle-publish 推流 ?刪除掉這個推流就會停止
? ? ?* ? ? ? ? ? ? //類型是 rtmp-play 拉流 刪除掉這個拉流就會停止
? ? ?* ? ? ? ? ? ? //剔除方法 Method DELETE ?api ? /api/v1/clients/{id} 停止推流/踢掉用戶端
? ? ?* ? ? ? ? ? ? "type": "fmle-publish",
? ? ?* ? ? ? ? ? ? "publish": true,
? ? ?* ? ? ? ? ? ? "alive": 16.18,
? ? ?* ? ? ? ? ? ? "kbps": {
? ? ?* ? ? ? ? ? ? ? ? "recv_30s": 0,
? ? ?* ? ? ? ? ? ? ? ? "send_30s": 0
? ? ?* ? ? ? ? ? ? }
? ? ?* ? ? ? ? }
? ? ?* ? ? ]
? ? ?* }
? ? ?*
? ? ?*
? ? ?* @param channel
? ? ?*/

@GetMapping("/start")@ResponseBodypublic void start(@RequestParam(defaultValue = "1") String channel){RtspUrlBuilder builder = new RtspUrlBuilder();RtmpUrlBuilder rtmpUrlBuilder = new RtmpUrlBuilder();//構建 rtsp 這個是客戶的nvr rtsp 地址 只有channel 是靈活的 他們是64路 現在接了50多攝像頭對應50 多路channelString rstp = builder.setUsername("admin").setPassword("xx").setIpAddress("xx").setChannel(channel).build();//這個是流媒體服務器的rtmp 推流地址String rtmp = rtmpUrlBuilder.setApplication("live").setStreamName(channel).build();final String vcodec="libx264";String camera1=String.format(RTSP_RTMP, rstp,vcodec,rtmp);//TODO 判斷是否已經再推了 推就直接返回拉流地址processManager.startProcess(channel,camera1);//拉流地址和推流地址是一至的 除非 java 服務和srs 在一臺服務器 那么  推流地址 rtmp ip為127.0.0.1 拉流 rtmp ip 為公網// 就是java通過ffmpeg 收流轉發到本地 rtmp srs分發流 到公網去System.out.println("拉流地址:"+rtmp);}@GetMapping("/end")@ResponseBodypublic void end(String channel){processManager.terminateProcess(channel);}

兩個輔助類:

package io.renren.common.live;/*** @author chenkang* @date 2023-8-3 12:27*/
public class RtspUrlBuilder {private String username;private String password;private String ipAddress;private int port;private String channel;private int subtype;public RtspUrlBuilder() {// 默認端口為554this.port = 554;// 默認子類型為0this.subtype = 0;}public RtspUrlBuilder setUsername(String username) {this.username = username;return this;}public RtspUrlBuilder setPassword(String password) {this.password = password;return this;}public RtspUrlBuilder setIpAddress(String ipAddress) {this.ipAddress = ipAddress;return this;}public RtspUrlBuilder setPort(int port) {this.port = port;return this;}public RtspUrlBuilder setChannel(String channel) {this.channel = channel;return this;}public RtspUrlBuilder setSubtype(int subtype) {this.subtype = subtype;return this;}public String build() {return "rtsp://" + username + ":" + password + "@" + ipAddress + ":" + port +"/cam/realmonitor?channel=" + channel + "&subtype=" + subtype;}
}
package io.renren.common.live;/*** @author chenkang* @date 2023-8-3 12:30*/
public class RtmpUrlBuilder {private String ipAddress;private int port;private String application;private String streamName;public RtmpUrlBuilder() {// 默認IP地址為127.0.0.1this.ipAddress = "127.0.0.1";// 默認端口為1935this.port = 1935;}public RtmpUrlBuilder setIpAddress(String ipAddress) {this.ipAddress = ipAddress;return this;}public RtmpUrlBuilder setPort(int port) {this.port = port;return this;}public RtmpUrlBuilder setApplication(String application) {this.application = application;return this;}public RtmpUrlBuilder setStreamName(String streamName) {this.streamName = streamName;return this;}public String build() {return  "rtmp://" + ipAddress + ":" + port + "/" + application + "/" + streamName;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36050.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36050.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36050.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python菱形問題

Python類分為兩種&#xff0c;一種叫經典類&#xff0c;一種叫新式類。都支持多繼承&#xff0c;但繼承順序不同。 新式類&#xff1a;從object繼承來的類。&#xff08;如:class A(object)&#xff09;&#xff0c;采用廣度優先搜索的方式繼承&#xff08;即先水平搜索&#…

【二分答案】CF803 D

感覺之前的*1900好簡單 Problem - D - Codeforces 題意&#xff1a; 思路&#xff1a; 注意到寬度具有單調性&#xff0c;考慮二分寬度 然后限制了最大寬度&#xff0c;要使行數 < k 那么在check里貪心&#xff0c;每行選的盡可能多 考慮雙指針&#xff0c;每次選長度…

Spring MVC相關知識點

1.Spring MVC的理解&#xff1f; 首先&#xff0c;MVC模型是模型&#xff0c;視圖&#xff0c;控制器的簡寫&#xff0c;其思想核心是通過將請求處理控制&#xff0c;業務邏輯&#xff0c;數據封裝&#xff0c;數據顯示等流程節點分離的思想來組織代碼。 所以&#xff0c;MVC…

SpringBoot復習:(47)ConfigFileApplicationListener

它監聽ApplicationEnvironmentPreparedEvent和ApplicationPreparedEvent。 它會把配置文件中配置的內容注入到環境中去&#xff0c;配置文件也就生效了

融云榮獲「2023 中國數字生態通信領軍企業」獎

融云北極星如何協助開發者排查問題和預警風險&#xff1f; 8月17日直播課&#xff0c;點擊上方報名~ 由 B.P 商業伙伴主辦的“2023 數字生態大會”于 8 月 4 日在京舉行&#xff0c;融云攜數智辦公解決方案受邀參展&#xff0c;并獲“2023 中國數字生態通信領軍企業”獎。關注【…

詳解VCC、VDD、VEE、VSS

VCC、 VDD、VEE、VSS 版本一&#xff1a; 簡單說來&#xff0c;可以這樣理解&#xff1a; 一、解釋 VCC&#xff1a;Ccircuit 表示電路的意思, 即接入電路的電壓&#xff1b; VDD&#xff1a;Ddevice 表示器件的意思, 即器件內部的工作電壓&#xff1b; VSS&#xff1a;Sser…

vue3+element-plus組件下拉列表,數組數據轉成樹形數據

引入組件 可以直接在項目中引入element-plus表格組件&#xff0c;如果需要變成下拉列表樣式需要添加以下屬性&#xff1a; row-key 必填 最好給數字或唯一屬性 &#xff0c; 給每個節點設置id 不填的話 沒有辦法實現展開效果 load 這個是動態添加數據的 前提&#xff08;開啟…

使用MyEclipse如何部署Descriptor (XML)編輯器?

Descriptor (XML) Editor編輯器包含了高級的XML編輯功能&#xff0c;在本文中您將了解到這些編輯功能、Web XML編輯等&#xff0c;此功能包含在MyEclipse中可用。 MyEclipse v2023.1.2離線版下載 1. Web XML 編輯器 MyEclipse Web XML編輯器包括高級XML編輯功能&#xff0c;…

最新AI創作系統ChatGPT程序源碼+詳細搭建部署教程+微信公眾號版+H5源碼/支持GPT4.0+GPT聯網提問/支持ai繪畫+MJ以圖生圖+思維導圖生成!

使用Nestjs和Vue3框架技術&#xff0c;持續集成AI能力到系統&#xff01; 新增 MJ 官方圖片重新生成指令功能同步官方 Vary 指令 單張圖片對比加強 Vary(Strong) | Vary(Subtle)同步官方 Zoom 指令 單張圖片無限縮放 Zoom out 2x | Zoom out 1.5x新增GPT聯網提問功能、手機號注…

深入了解 Postman Test 校驗的使用方法

Postman 是一個廣泛使用的 API 開發工具&#xff0c;它允許開發人員測試 API 的各個方面&#xff0c;包括請求、響應、身份驗證等等&#xff0c;其中最常用的功能之一就是 Test 校驗。那今天就一起來看看 Postman 的 Test 校驗該如何使用。 Test 校驗是什么&#xff1f; Test…

【Spring】淺談spring為什么推薦使用構造器注入

目錄 一、前言 二、常見的三種注入方式 2.1 field注入 2.2 構造器注入 2.3 setter注入 三、構造器注入的好處 四、答疑 五、總結 一、前言 ? Spring框架對Java開發的重要性不言而喻&#xff0c;其核心特性就是IOC&#xff08;Inversion of Control&#xff0c; 控制反轉&…

RunLoop

1.CFRunLoopModeRef特征代表RunLoop對象內的運行模式(每個RunLoop對象內存中存在很多種運行模式,每個Mode運行模式下必然包含若干個有效的Source0/Source1/Timer/Observer數據序組) 2.RunLoop對象活躍(操作)啟動時能且僅能選擇某個Mode匹配currentMode(暗示Loop對象的操作運行必…

分類預測 | MATLAB實現BO-BiGRU貝葉斯優化雙向門控循環單元多輸入分類預測

分類預測 | MATLAB實現BO-BiGRU貝葉斯優化雙向門控循環單元多輸入分類預測 目錄 分類預測 | MATLAB實現BO-BiGRU貝葉斯優化雙向門控循環單元多輸入分類預測預測效果基本介紹模型描述程序設計參考資料 預測效果 基本介紹 1.Matlab實現BO-BiGRU貝葉斯優化雙向門控循環單元多特征分…

2.1.2 VisionOS——VisionOS 中的窗口化應用程序

在visionOS中&#xff0c;用戶可以使用窗口來呈現2D或3D內容&#xff0c;或者使用體積來呈現3D內容和對象。Unity 將這些窗口中的應用程序描述為“窗口應用程序”。 默認情況下&#xff0c;如果您構建針對visionOS 平臺的Unity 應用程序而未通過XR 插件管理器啟用PolySpatial …

React - useEffect函數的理解和使用

文章目錄 一&#xff0c;useEffect描述二&#xff0c;它的執行時機三&#xff0c;useEffect分情況使用1&#xff0c;不寫第二個參數 說明監測所有state&#xff0c;其中一個變化就會觸發此函數2&#xff0c;第二個參數如果是[]空數組&#xff0c;說明誰也不監測3&#xff0c;第…

gRPC vs REST:創建API的方法比較

本文對gRPC和REST的特征和區別進行了介紹&#xff0c;這可能是當今創建API最常用的兩種方法。 文章目錄 一、gRPC的介紹 二、什么是REST&#xff1f; 三、什么是gRPC? 四、gRPC和REST的比較 &#xff08;1&#xff09;底層HTTP協議 &#xff08;2&#xff09;支持的數據…

平替 Docker - 玩轉容器新利器 Podman Desktop (視頻)

《OpenShift 4.x HOL教程匯總》 在 podman-desktop 1.2.1 podman 4.4 環境中驗證。 文章目錄 什么是 podman 和 podman-desktop安裝 podman 和 podman-desktop 基本環境Image、Container 和 Pod 的基本操作拉取 Image運行 Container 將 Pod 部署到 Kubernetes安裝 Kind 擴展插…

Python爬蟲——selenium_元素定位

元素定位&#xff1a;自動化要做的就是模擬鼠標和鍵盤來操作這些元素&#xff0c;點擊&#xff0c;輸入等等。操作這些元素前首先要找到它們&#xff0c;WebDriver提供很多定位元素的方法 from selenium import webdriver# 創建瀏覽器對象 path files/chromedriver.exe brows…

【安全】淺談信息安全

信息安全 理解信息安全&#xff0c;要從“信息”、“安全”兩個角度入手。 信息 信息是對客觀世界的反映&#xff0c;表現客觀事物的運動狀態和變化的實質內容。 信息具有可識別、可傳載、可共享、可度量的基本特征。 信息系統 信息系統是獲取&#xff08;收集&#xff0…

中心對稱鏈表

文章目錄 1 題目2 思路2.1 思路一2.2 思路二2.3 考點2.4 擴展 3 實現3.1 思路13.2 思路23.3 完整例子 1 題目 已知長度為n&#xff08;n>1&#xff09;的單鏈表&#xff0c;表頭指針為L&#xff0c;結點結構由data和next兩個域構成&#xff0c;其中data域為字符型&#xff…