关于rtsp转码rtmp播放的两种方式,客户端直接转,远程服务器转
需求
一、场景
用户多家门店有监控探头,设备是海康的和大华的。用户总部和门店不在一个网络下,并且总部要能实时调用查看门店监控,和门店回放画面。我们知道监控摄像机获取的视频是 rtsp 流的格式。 只能在特用的软件中播放,并且只能在相同的网络下播放。用户要求开发一个管理软件根据业务需要来播放视频。最终的目地是要把rtsp 流视频 转换为能在浏览器,手机等主流的播放渠道上能播放的视频(rtmp,mp4,flv,m3u8等格式);
解决办法
(1)、客户端转码
我们用electron 来打包客户端,客户端中安装一个在线转码ffmpeg 模块,这个模块中有功能接口能直接对rtsp 进行转码(这种场景主要给 播放软件和门店在一个网络下能直接连接的场景);
用到两个模块 “fluent-ffmpeg” “node-media-server”
fluent-ffmpeg 转码模块
我们用这个模块转码为rtmp 直播流,转码后推送到一个我们在软件内部搭建的一个rtmp 直播流服务器地址
“rtmp://localhost:1938/live/livestream”
node-media-server 模块做rtmp直播流服务器
上面的fluent-ffmpeg 模块转码推送rtmp 流到这个服务器rtmp://localhost:1938/live/livestream,
到此rtsp被本地转换为了 rtmp流了。 由于rtmp流可以在浏览器中播放, 我们找一个播放器播放这个地址即可。 能播放rtmp流的播放器很多。 我用了一个阿里的flash 播放器来播放可行。
# electron main.js 部分功能代码
const ffmpeg = require('fluent-ffmpeg');
const { NodeMediaServer } = require('node-media-server');
// rtmp 播放 服务器
const config = {
rtmp: {
port: 1938,
chunk_size: 60000,
gop_cache: true,
ping: 60,
ping_timeout: 30
},
http: {
port: 8000,
allow_origin: '*'
}
};
var nms = new NodeMediaServer(config)
nms.run();
// 转码指令
var command = ffmpeg(uri)
.outputOptions([
'-fflags',
'nobuffer',
'-vcodec',
'libx264',
'-preset',
'superfast',
'-rtsp_transport',
'tcp',
'-threads',
'2',
// '-f',
// 'flv',
'-r',
'25',
// '-s',
// '640x480',
//'1280x720',
'-an'
])
.inputFPS(25)
.noAudio()
.size('640x?')
.aspect('4:3')
.format('flv')
// 此处的 /live/camera, camera类似于一个房间的概念, 你可以设置为你想要的名字
.save(`rtmp://localhost:1938/live/livestream`)
.on('start', function (e) {
running = true
console.log('stream is start: ' + e)
})
.on('end', function () {
running = false
console.log('ffmpeg is end')
})
.on('error', function (err) {
running = true
console.log('ffmpeg is error! ' + err)
//command.kill()
//reloadStream(uri)
})
(2)、服务器端转码
另一种转码是在外部服务器端安装一套转码服务器,业务中发送接口到远程服务器,服务器收到指令后“主动去拉取rtmp流进行转码”,转码后 再 推送到 服务器上的另外一个 rtmp 服务器上进行分发 rtmp 流;
1.转码服务器
我们用一个docker 容器来跑转码服务;
docker pull ranmufei/srs-php5-transcode-server:v1.18
容器中封装了一个FFmpeg + web服务器 http://127.0.0.1//runffmpeg.php?type=run; post 提交参数
rtsp地址
curl -X POST \
http://xxxx.cn/admin/Index/testrunffmpeg \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded' \
-H 'postman-token: 148e4b67-1e03-f854-5c71-b1fc6502210c' \
-H 'token: 667778c46b900c9768c65ac7ce8102d9' \
-d rtsp=rtsp%3A%2F%2Fadmin%3Aadmin123%4010.31.37.50%3A554%2Fcam%2Frealmonitor%3Fchannel%3D1%26subtype%3D1
转码服务器放回 播rtmp 播放地址
放回格式json
{
"response": {
"ipinfo": {
"pid": null,
"ipinfo": null,
"command": null
},
"pid": "31199",
"playurl": "rtmp://srs-docker-rmf.bubugao:1935/live/livestream_1547693691",
"str": "/srs/objs/ffmpeg/bin/ffmpeg -rtsp_transport tcp -re -i 'rtsp://admin:xxxxx@10.31.37.50:554/cam/realmonitor?channel=1&subtype=1' -c:a copy -c:v libx264 -preset ultrafast -b:v 200k -r 8 -s 640x480 -f flv rtmp://srs-docker-rmf.bubugao:1935/live/livestream_1547693691 > /dev/null 2>&1 & echo $!;",
"rtsp": "rtsp://admin:xxxx@10.31.37.50:554/cam/realmonitor?channel=1&subtype=1",
"playpath": "rtmp://transcode.xxxxxx.cn:1935/live/livestream_1547693691",
"datainfo": {
"type": "run",
"rtsp": "rtsp://admin:xxxxx@10.31.37.50:554/cam/realmonitor?channel=1&subtype=1"
}
},
"status": 200,
"API_debug": {
"url": "transcode.video//runffmpeg.php?type=run",
"data": {
"type": "run",
"rtsp": "rtsp://admin:xxxx@10.31.37.50:554/cam/realmonitor?channel=1&subtype=1"
}
}
}
2.rtmp 分发流服务器
和第一中方式类似,也是拉取rtsp 地址 进行转码 ,这是转码后推送到了云上的这台rtmp 流分发服务器上来了;
docker pull ossrs/srs:3.0.42-ffmpeg
配置服务器作为 rtmp 服务器; srs 的功能很强大,目前我们只用到了它的分发rtmp 流功能;
配置参考 https://github.com/ossrs/srs/wiki/v2_CN_Home
分发为m3u8 格式 供移动端播放
# srs 的docker.conf 配置中添加hls 配置 会生成 m3u8 的文件,当有流推送到 srs 服务器的时候 会自动高转换为 m3u8 格式文件。
vhost __defaultVhost__ {
hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 60;
}
}
参考资料
关于rtsp转码rtmp播放的两种方式,客户端直接转,远程服务器转的更多相关文章
- ASP.NET 生成二维码(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
最近做项目遇到生成二维码的问题,发现网上用的最多的是ThoughtWorks.QRCode和QrCode.Net两种方式.访问官网看着例子写了两个Demo,使用过程中发现两个都挺好用的,Thought ...
- Cocos2d-x学习笔记(五岁以下儿童) 精灵两种方式播放动画
这几天在看控件类,临时没有想好实际运用的方向.单纯的创建网上已经有非常多这方面的样例,我就不写了.接下来是学习精灵类.精灵类若是单独学习也是非常easy.于是我加了一些有关动画方面的知识点与精灵 ...
- Python 实现接口类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)
实现接口类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=AB ...
- 自学Linux Shell9.4-基于Red Hat系统工具包存在两种方式之二:源码包
点击返回 自学Linux命令行与Shell脚本之路 9.4-基于Red Hat系统工具包存在两种方式之二:源码包 本节主要介绍基于Red Had的系统(测试系统centos) 1. 工具包存在两种方式 ...
- Python 实现抽象类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)
实现抽象类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=AB ...
- 【转】Unity3D研究院之两种方式播放游戏视频
http://www.xuanyusong.com/archives/1019 Unity3D中播放游戏视频的方式有两种,第一种是在游戏对象中播放,就好比在游戏世界中创建一个Plane面对象,摄像 ...
- java创建线程的两种方式及源码解析
创建线程的方式有很多种,下面我们就最基本的两种方式进行说明.主要先介绍使用方式,再从源码角度进行解析. 继承Thread类的方式 实现Runnable接口的方式 这两种方式是最基本的创建线程的方式,其 ...
- 两种方式实现java生成Excel
Web应用中难免会遇到需要将数据导出并生成excel文件的需求.同样,对于本博客中的总结,也是建立在为了完成这样的一个需求,才开始去了解其实现形式,并且顺利完成需求的开发,先将实现过程总结于此.本博文 ...
- 【java并发】传统线程技术中创建线程的两种方式
传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法:二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread.这两种方式 ...
随机推荐
- var和function定义方法的区别
在JS中有两种定义函数的方式,1是var aaa=function(){...}2是function aaa(){...}var 方式定义的函数,不能先调用函数,后声明,只能先声明函数,然后调用.fu ...
- firewalld的防火墙
firewalld的介绍与简单应用 CentOS7的默认防火墙是firewalld,在之前使用iptables时,关闭了firewalld服务,现在反过来关闭iptables服务,打开firewall ...
- Android EditText默认不弹出输入法,以及获取光标,修改输入法Enter键的方法
一.Android EditText默认不弹出输入法的办法:1. 在AndroidManifest.xml中将需要默认隐藏键盘的Activity中添加属性即可(常用此方法) android:windo ...
- Python的生成器Generator小结
一. 生成器的介绍 在介绍生成器(Generator)之前,我们首先需要熟悉列表生成式,列表生成式是Python内置的简单又强大的用来创建列表的生成式. 举个例子, 如果我们想生成[1*1,2*2,3 ...
- [luogu1357] 花园 [dp+矩阵快速幂]
题面: 传送门 思路: 把P形花圃记录为0,C形记录为1,那么一段花圃就可以状态压缩成一个整数 那么,我们可以有这样的状压dp: dp[i][S]表示前i个花圃,最后m个的状态为S的情况 如果这是一条 ...
- [URAL1519] Formula 1 [插头dp入门]
题面: 传送门 思路: 插头dp基础教程 先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走 看到这个数据范围,还有回路处理,就想到使用插头dp来做了 观察一下发现,这道题因为都是 ...
- Posix线程编程指南
Posix线程编程指南 Posix线程编程指南... 1 一线程创建与取消... 2 线程创建... 2 1.线程与进程... 2 2. 创建线程... 2 3. 线程创建属性... 2 4. 创建的 ...
- spring项目启动报错BeanFactory not initialized or already closed
spring项目启动的时候报如下错误: java.lang.IllegalStateException: BeanFactory not initialized or already closed - ...
- 问题:viewController不会调用dealloc()不会销毁
问题 在调试程序时,我从ViewController A push进 ViewController B,在从B back时发现程序不会执行B里面的dealloc(),很诡异的问题,因为按理说此时点击b ...
- HAOI2008题解
又来写题解辣-然而并不太清楚题目排列情况...不管辣先写起来- T1:[bzoj1041] 题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1 ...