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;}
}
相关文章:
Java 实现Rtsp 转rtmp,hls,flv
服务支撑:FFmpeg srs(流媒体服务器) 整个流程是 FFmpeg 收流转码 推 rtmp 到流媒体服务 流媒体服务再 分发流到公网 搭建流媒体服务: 1. SRS (Simple Realtime Server) | SRS (本例子使用的是SrS 安装使用docker ) 2.GitHub - ZLMedi…...
机器学习基础(三)
逻辑回归 场景 垃圾邮件分类 预测肿瘤是良性还是恶性 预测某人的信用是否良好 正确率与召回率 正确率与召回率(Precision & Recall)是广泛应用于信息检索和统计学分类领域的两个度量值,用来评价结果的质量。 一般来说,正确率就是检索出来的条目有多少是正确的,召回率就…...

Kubeadm安装K8s集群
一、硬件环境 准备3台Linux服务器,此处用Vmware虚拟机。 主机名CPU内存k8smaster2核4Gk8snode12核4Gk8snode22核4G 二、系统前置准备 配置三台主机的hosts文件 cat << EOF > /etc/hosts 192.168.240.130 k8smaster 192.168.240.132 k8snode1 192.168.…...

【C++】开源:spdlog跨平台日志库配置使用
😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍spdlog日志库配置使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下…...
[Azkaban] No active executors found
没有找到活动的executors,需在MySQL数据库里设置端口为12321的executors表的active为1: select * from executors;如果显示active0 则需要进行处理: update azkaban.executors set active1;当active0,更新为1时,用 n…...

无涯教程-Perl - recv函数
描述 This function receives a message on SOCKET attempting to read LENGTH bytes, placing the data read into variable SCALAR.The FLAGS argument takes the same values as the recvfrom( ) system function, on which the function is based. When communicating wit…...
算法练习-搜索 相关
文章目录 迷宫问题 迷宫问题 定义一个二维数组 m行 * n列 ,如 4 5 数组下所示: int arr[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, }; 它表示一个迷宫,1表示墙壁,0表示可以走的路,只…...

PyQt5控件布局管理
Qt Designer提供了四种窗口布局:Vertical Layout(垂直布局) ,Horizontal Layout(水平布局),Grid Layout(栅格布局),Form Layout(表单布局),以及一种隐藏的布局—绝对布局 一般进行布局有两种方式: 一是通…...
TypeScript 一分钟让你理解泛型是什么
TypeScript 一分钟让你理解 泛型是什么 TS的泛型是指在定义函数、接口或类型时,不预先指定具体的类型,而是在使用时指定类型限制的一种特性。 泛型和函数中的参数比较类似,我们定义一个函数的时候有时会给它留一个参数名,在使用这…...

PatchMatchNet 训练dtu数据集、训练曲线查看、实操教程图图文详解、
文章目录 1 查看要求 下载数据集2 训练2.1 路径配置2.2 训练2.3 模型输出 与 训练曲线查看2.4 输出训练 log文件1 查看要求 下载数据集 在代码文件加下打开 README.md文件找到训练说明,查看那要求、下载训练集、训练方法 ## Training Download pre-processed [DTUs trainin…...
怎样制定测试计划和设计测试用例?
测试工作贯穿于整个软件开发生命周期,是一项庞大而复杂的工作,需要制订一个完整且详细的测试计划作为指导。测试计划是整个测试工作的导航图,但它并不是一成不变的,随着项目推进或需求变更,测试计划也会不断发生改变&a…...

教你如何为博客网站申请阿里云的免费域名HTTPS证书
如何为博客网站申请阿里云的免费域名HTTPS证书 文章目录 如何为博客网站申请阿里云的免费域名HTTPS证书前置条件:步骤1 例如阿里云控制台,选择SSL证书步骤2 申请购买免费证书步骤3 创建证书步骤3.1 证书申请步骤3.2 DNS域名验证 步骤4 等待证书审核成功&…...

在线Word怎么转换成PDF?Word无法转换成PDF文档原因分析
不同的文件格式使用方法是不一样的,而且也需要使用不同的工具才可以打开编辑内容,针对不同的场合用户们难免会用到各种各样的文件格式,要想在不修改内容的前提下提高工作效率,那就需要用到文件格式转换,那么在线Word怎…...

计算机网络:网络通信相关概念入门
目录 一、网络发展背景二、理解网络通信三、理解IP地址1.简述IP地址2.IP地址的版本3.提高地址利用率的技术 四、理解端口1.简述端口2.使用端口的原因 五、理解网络通信协议 一、网络发展背景 网络发展背景: 最初的计算机是单机,那么单机是这样传输数据的…...

Spring-2-透彻理解Spring 注解方式创建Bean--IOC
今日目标 学习使用XML配置第三方Bean 掌握纯注解开发定义Bean对象 掌握纯注解开发IOC模式 1. 第三方资源配置管理 说明:以管理DataSource连接池对象为例讲解第三方资源配置管理 1.1 XML管理Druid连接池(第三方Bean)对象【重点】 数据库准备 -- 创建数据库 create …...

LeetCode150道面试经典题--单词规律(简单)
1.题目 给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 2.示例 pattern"abba" s "c…...

uniapp把城市换成26个字母和城市排序
后端返回的数据 我们要得效果 <template><view><view v-for"(value,key) in cities" :key"key"><view style"color: red;"> {{ key }} </view><view style"border: 1rpx solid black;"><tex…...

Flv格式视频怎么转MP4?视频格式转换方法分享
FLV格式的视频是一种早期的视频格式,不支持更高的分辨率和比特率,这意味着视频的清晰度和质量受限制,无法很好地保留细节和质量,这种格式的视频已经逐渐被更高质量的视频格式所替代,例如MP4格式,不仅具有很…...

Java类与对象详解(3)
目录 封装 封装的概念 访问限定符 封装扩展之包 包的概念 导入包中的类 自定义包 基本规则 包的访问权限控制举例 常见的包 static 成员 static 修饰成员变量 static修饰成员方法 static 成员变量的初始化 代码块 代码块的概念及其分类 普通代码块 构造代码块…...

PMP备考指南来啦!
第一步:通读教材,了解学习内容 在正式开始课程的学习前,可以先快速简单地阅览一遍教材(PMBOK),在较短的时间内知道自己将要学习的是什么内容;同时可以标记出难理解的知识点。这样做有以下两个好…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...