是否可以将 RTSP 流数据输入到网络浏览器中?
以下是我的一些发现。如果我说错了请指正?
仅 Mac OS 和 Safari 支持 RTSP 直播。
HTML 5 视频不支持 RTSP。
我可以使用VLC插件,但我不想使用它。
混合 ffmpeg 和 websocket 的可能性吗?
假设我的网络摄像机已连接至以太网。
在客户端机器中:
问题:
我可能在不同的地方是错的。请提供意见。
这里是一篇博客文章,或者是教程,如果你愿意的话,它实现了非常相似的东西。
他们的设置略有不同,但总结如下:
使用
ffmpeg
将您的输入转换为 mpeg1video:
ffmpeg -i rtsp://whatever -f mpeg1video -b 800k -r 30 http://localhost:8082/yourpassword/640/480/
使用
jsmpeg和
node.js
ws WebSocket 包中的 stream-server.js
脚本安装 ws
。
要查看流,请使用
jsmpeg中的
stream-example.html
和 jsmpg.js
。将 stream-example.html
中的 WebSocket URL 更改为 localhost
并在您喜欢的浏览器中打开它。
更新一个SO主题建议另外两个工作解决方案,带有
ffserver
。
如果您只想将其流式传输到极少数客户端,那么您可以使用直接运行 ffmpeg 的 cgi(或在 Nodejs 中,子进程):
NodeJS 示例:
app.getExpressApp().get('/camera/feed', (req, res) => {
// Thanks to https://stackoverflow.com/q/28946904/1954789
const child_process = require('child_process');
res.header('content-type', 'video/webm');
const cmd = `ffmpeg -i rtsp://user:pwd@somewhere/videoSub -c:v copy -c:a copy -bsf:v h264_mp4toannexb -maxrate 500k -f matroska -`.split(' ');
var child = child_process.spawn(cmd[0], cmd.splice(1), {
stdio: ['ignore', 'pipe', process.stderr]
});
child.stdio[1].pipe(res);
res.on('close', () => {
// Kill ffmpeg if the flow is stopped by the browser
child.kill();
});
CGI 应该更容易。
在浏览器中,您可以
<video autoplay=1 poster="camera.png" ><source src="/camera/feed"></video>
(使用海报,因为视频可能需要几秒钟才能显示)。
注意事项: 这将为您的设置的每个连接启动一个 ffmpeg,因此它根本无法扩展。这应该仅用于连接有限的非常个人的网站(例如:仅限您自己)。
PS:ffmpeg 命令可能需要一些调整。
vlc解决方案:
cvlc -v rtsp://user:password@camera_ip_address --sout='#transcode{vcodec=theo,vb=800,acodec=vorb,ab=128,channels=2,samplerate=44100,scodedec=none}:http{dst=:8080/webcam.ogg}'
然后检查
http://localhost:8080/webcam.ogg
或者将此 url 集成到您想要运行的任何 Web 服务中
如果你对vlc的python api感兴趣,这里有一个例子:
import vlc
class WebcamStreamer:
def __init__(self, config):
"""
Expected rtsp url format:
"rtsp://user:[email protected]"
"""
self.instance = vlc.Instance()
self.stream_name = "webcam".encode()
self.rtsp_url = config["rtsp_url"].encode()
def launch_webcam_stream_converter(self):
"""
Basically here is what is done:
cmd= ["cvlc", "-v", f"rtsp://user:[email protected]",
f"--sout='#transcode{{vcodec=theo,vb=800,acodec=vorb,ab=128,channels=2,samplerate=44100,scodedec=none}}:http{{dst=:8080/webcam.ogg}}'"]
subprocess.run(cmd)
"""
ret = vlc.libvlc_vlm_add_broadcast(
p_instance=self.instance,
psz_name=self.stream_name,
psz_input=self.rtsp_url,
psz_output=f"#transcode{{vcodec=theo,vb=800,acodec=vorb,ab=128,channels=2,samplerate=44100,scodedec=none}}:http{{dst=:8080/webcam.ogg}}".encode(),
i_options=0,
ppsz_options=[],
b_enabled=True,
b_loop=False
)
assert (ret == 0)
vlc.libvlc_vlm_play_media(self.instance, self.stream_name)
scandir.php
(由JS在viewcamera.php
中使用)
<?php
$folder = $_GET['name'];
$dir = "../cache/".$folder;
// Sort in descending order
$b = scandir($dir,1);
$myJSON = json_encode($b);
echo $myJSON;
?>
streamcam.php
(跑进crontab
)
<?php
function live_view ($cameraip, $cameraname){
echo shell_exec("/usr/bin/ffmpeg -rtsp_transport tcp -i rtsp://root:pass@".$cameraip."/ufirststream -s 1920x1080 -f image2 -vf fps=fps=5 /var/www/html/occupancy/cache/".$cameraname."/frame%04d.jpg >/dev/null 2>/dev/null &");
}
viewcamera.php
- $camera_name
变量来自 SQL while 循环,其中以下内容对数据库中的所有摄像机重复。 var cameraName
如果来自下面的按钮数据属性...
<button
style="font-size: 24px"
class="btn2 fa fa-camera"
id="<?php echo $image_id;?>"
href="#<?php echo $camera_name_stripped;?>"
data-toggle="modal"
data-backdrop="false"
data-keyboard="false"
data-image-id="<?php echo $image_id;?>"
data-camera-ip="<?php echo $ip;?>"
data-camera-name="<?php echo $camera_name;?>"
data-camera-name-stripped="<?php echo $camera_name_stripped;?>"
>
<i style="font-size: 24px" title="Live View"></i>
</button>
<img width="100%" height="auto" id="img_cam<?php echo $camera_name_stripped;?>" src="">
<script>
var cameraName = $(e.relatedTarget).data('camera-name-stripped');
window.livetimer<?php echo $camera_name;?> = setInterval(function() {
<?php echo $camera_name_stripped;?> = $.ajax({
url: 'scandir.php?name='+cameraName,
type: "POST",
dataType: 'json'
}).done(function(result) {
$("#img_cam<?php echo $camera_name_stripped;?>").attr('src',"../cache/" + cameraName + "/" + result[0]);
});
}, 55);
});
</script>
我需要在不同的平台和浏览器中显示流。为了在不使用任何插件的情况下实现这一点(不确定它是否适用于智能手机和平板电脑),使用了与您非常相似的方法。 ffmpeg crontab 任务每秒创建 3 个图像,并存储到一个目录中。使用 Jquery,对 php 的 ajax 调用每 330 毫秒读取一次目录并获取文件名,以更改图像(仅更改
<img>
的“src”属性)。为了解决存储问题,使用了其他 crontab 任务来删除超过 1 分钟的文件。它不是真正的流媒体,而是跨浏览器的,并且很好地解决了问题。
ffmpeg 任务
ffmpeg -i "rtsp://path/to/cam" -s 320x240 -f image2 -vf fps=fps=3 cache/%04d.jpg
ajax 调用示例
$.ajax({
url: '_read_dir.php',
type: 'POST',
dataType: 'json'
})
.done(function(result) {
$("#img_cam").prop('src',"cache/" + result.img);
});
存储控制任务
find /var/www/path/to/dir -mmin +1 -exec rm -f {} \;
希望能帮到你! :)
多年来,浏览器已经不再支持 RTSP 流。未来浏览器不太可能支持RTSP流媒体。不过,也有很多新的发展,尤其是WebRTC的出现。
由于RTSP和WebRTC的低延迟,常见的需求和场景是使用WebRTC查看RTSP流或IP摄像头流。
简单来说,需要一个流媒体网关将RTSP流转换为WebRTC流,以便在网页中查看。工作流程如下:
IP Camera --RTSP--> FFmpeg --RTMP--> Media Server --WebRTC--> Browser
(SRS Gateway)
值得注意的是,网络摄像机一般都会提供RTSP拉流地址,不支持将RTSP流推送到流媒体网关。因此,我们需要主动拉取IP摄像头流并推送到流媒体网关,最后转换为WebRTC在浏览器中播放。
该方案整体延迟在200ms到500ms左右,整体效果不错。搭建流媒体网关,可以使用Docker进行一键部署。请参阅这篇文章了解更多信息。
同内网端到端延迟260ms,效果非常好!