从IP摄像机获取RTSP流并在Web浏览器中播放的最佳方法是什么?

32

是否有可能将RTSP流数据传输到网络浏览器中?

以下是我的一些发现,请纠正我如果我错了?

  1. 仅Mac OS和Safari支持RTSP实时流。

  2. HTML 5视频不支持RTSP。

  3. 我可以使用VLC插件,但我不想使用它。

ffmpeg和websocket混合的可能性?

假设我的IP摄像头连接到以太网。

在客户端计算机上:

  1. 我运行ffmpeg从服务器(即:IP)获取数据
  2. 客户端计算机运行websocket。
  3. 一旦ffmpeg从RTSP服务器获取数据,它会解码并生成任何格式的原始图像(例如:yuv)。
  4. 现在,我必须通过websocket将此图像发送到浏览器中。

问题:

  1. 这是正确的方法吗?
  2. 我如何将从ffmpeg解码的图像传输到浏览器中?

我可能在某些地方错了。请提供建议。

6个回答

29

这里是一篇博客文章,或者说是一个教程,它实现了非常相似的东西。

他们的设置略有不同,但这是摘要:

使用ffmpeg将您的输入转换为mpeg1video:

ffmpeg  -i rtsp://whatever -f mpeg1video -b 800k -r 30 http://localhost:8082/yourpassword/640/480/

使用jsmpeg中的stream-server.js脚本和WebSocket包ws来安装node.js

要查看流,请使用jsmpeg中的stream-example.htmljsmpg.js。将stream-example.html中的WebSocket URL更改为localhost,然后在您喜欢的浏览器中打开它。

更新:SO主题提供了另外两个使用<video>标记的解决方案:一个是使用Java服务器stream-m,另一个是使用ffserver


这个支持音频吗? - Lama
理论上可以。我会推荐使用<video>标签作为更好的解决方案 - Alex Cohn
我的意思是,它是否支持通过仅使用视频标签来流式传输视频的音频? :) - Lama
是的,<video>标签支持两种格式;但是准备相关流的责任在于您。 - Alex Cohn
我找不到stream-server.js脚本,你能进一步解释一下吗?目前我使用nodejs设置了一个本地http服务器并安装了jsmpeg,谢谢。 - utdev
显示剩余3条评论

9
如果您想将其流式传输到很少的客户端,那么可以使用一个cgi(或在nodejs中,一个child_process)直接运行ffmpeg:
NodeJS示例:
app.getExpressApp().get('/camera/feed', (req, res) => {
    // Thanks to https://dev59.com/9F4b5IYBdhLWcg3wlSdq
    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,因此它完全不具备可扩展性。这仅应用于非常私人的网站,其中连接受限(例如:仅限于您自己)。

附注:ffmpeg命令可能需要进行微调。


我认为现在最好的方法是使用WebRTC。我很惊讶这个六年前的问题仍然相关。我个人尝试过https://github.com/mpromonet/webrtc-streamer,并且感到相当满意。 - Alex Cohn
1
很抱歉,您可能打算将评论发布到另一个答案。 - Alex Cohn

2

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:password@192.168.0.1"
        """
        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:password@192.168.0.16",
            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)

1

scandir.php(由viewcamera.php中的JS使用)

<?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 循环,下面的循环会针对数据库中的所有摄像头重复执行。变量 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>

0

我需要在不同的平台和浏览器中显示流媒体。为了做到这一点而不使用任何插件(不确定它是否适用于智能手机和平板电脑),我采用了与您非常相似的方法。一个 ffmpeg crontab 任务每秒创建3个图像,并存储到一个目录中。使用 Jquery,一个 ajax 调用到一个 php 读取目录并获取文件名,以更改图像(只更改 <img> 的 'src' 属性),每330毫秒更改一次。为了解决存储问题,使用另一个 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 {} \;

希望能够帮到你!:)


0
多年来,浏览器已经不再支持RTSP流媒体。未来,浏览器很可能也不会支持RTSP流媒体。然而,近年来出现了许多新的发展,尤其是WebRTC的出现。
由于RTSP和WebRTC具有低延迟的特点,一个常见的需求和场景是使用WebRTC来查看RTSP流媒体或IP摄像头的流媒体。
简单来说,需要一个流媒体网关来将RTSP流媒体转换为WebRTC流媒体,以便在网页中进行查看。工作流程如下:
IP Camera --RTSP--> FFmpeg --RTMP--> Media Server --WebRTC--> Browser
                                    (SRS Gateway)

值得注意的是,IP摄像机通常提供RTSP拉流地址,不支持将RTSP流推送到流媒体网关。因此,我们需要主动拉取IP摄像机流并将其推送到流媒体网关,最后将其转换为WebRTC以在浏览器中播放。
这种解决方案的总延迟约为200毫秒至500毫秒,整体效果良好。要设置流媒体网关,您可以使用Docker进行一键部署。有关更多信息,请参考this post

RTSP to WebRTC

同一内部网络的端到端延迟为260毫秒,效果非常好!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接