1. 为什么需要WebRTC-Streamer

在开发监控系统前端界面时,很多开发者都会遇到一个头疼的问题:浏览器无法直接播放摄像头的RTSP流。传统的监控摄像头(如海康威视、大华等品牌)输出的都是RTSP协议的视频流,而现代浏览器中的video标签仅支持MP4、WebM这类封装格式。这就导致了一个尴尬的局面——明明摄像头就在那里,却无法在网页上直接观看。

我曾经接手过一个仓库监控系统的改造项目,客户要求在原有Vue管理后台中增加实时监控功能。最初尝试用vue-video-player这类现成组件,结果发现它们本质上还是在调用浏览器的video标签,对RTSP流束手无策。也试过FFmpeg转码方案,但转码带来的延迟和服务器负载让人难以接受。

WebRTC-Streamer的出现完美解决了这个痛点。它相当于一个轻量级的"翻译官",把摄像头的RTSP流实时转换成浏览器原生支持的WebRTC协议。最让我惊喜的是,整个过程中视频数据始终保持着200-500ms的超低延迟,这对于需要实时响应的安防场景至关重要。

2. 环境准备与基础配置

2.1 获取WebRTC-Streamer

首先需要下载WebRTC-Streamer的可执行文件。官方GitHub仓库提供了各平台的编译版本,建议下载最新稳定版。这里有个小技巧:如果GitHub下载速度慢,可以尝试在Releases页面右键复制下载链接,然后通过国内镜像站点加速下载。

下载完成后解压压缩包,你会看到如下目录结构:

webrtc-streamer/
├── html/
│   ├── webrtcstreamer.js
│   └── libs/
│       └── adapter.min.js
├── webrtc-streamer.exe
└── LICENSE

2.2 启动服务的最佳实践

很多教程会告诉你直接双击exe文件运行,但这样会占用较高的CPU资源。经过多次测试,我推荐用命令行方式启动:

webrtc-streamer.exe -H 0.0.0.0 -p 8000 -o

参数说明:

  • -H 0.0.0.0 允许所有IP访问
  • -p 8000 指定服务端口
  • -o 启用硬件加速(如果设备支持)

启动成功后,访问http://localhost:8000 应该能看到测试页面。如果需要在其他设备访问,记得关闭防火墙或添加入站规则。

3. Vue项目集成实战

3.1 前端资源引入

将解压目录中的两个关键JS文件复制到Vue项目的public目录:

  • html/webrtcstreamer.js
  • html/libs/adapter.min.js

然后在public/index.html中添加引用:

<head>
  <!-- 其他meta标签 -->
  <script src="<%= BASE_URL %>adapter.min.js"></script>
  <script src="<%= BASE_URL %>webrtcstreamer.js"></script>
</head>

这里有个坑要注意:adapter.min.js必须放在webrtcstreamer.js之前加载,否则会报错。我曾经因为这个问题调试了整整一个下午。

3.2 视频组件封装

创建一个可复用的监控组件Monitor.vue:

<template>
  <div class="monitor-container">
    <video 
      ref="videoPlayer"
      controls
      autoplay
      muted
      :style="videoStyle"
    ></video>
    <div v-if="!isConnected" class="status-overlay">
      连接中...
    </div>
  </div>
</template>

<script>
export default {
  props: {
    rtspUrl: {
      type: String,
      required: true
    },
    serverUrl: {
      type: String,
      default: 'http://127.0.0.1:8000'
    },
    videoStyle: {
      type: Object,
      default: () => ({
        width: '100%',
        height: '100%',
        'object-fit': 'cover'
      })
    }
  },
  data() {
    return {
      streamer: null,
      isConnected: false
    }
  },
  mounted() {
    this.initStreamer()
  },
  methods: {
    initStreamer() {
      this.streamer = new WebRtcStreamer(
        this.$refs.videoPlayer,
        this.serverUrl
      )
      
      this.streamer.onstatus = (status) => {
        this.isConnected = status === 'connected'
      }
      
      this.streamer.connect(this.rtspUrl)
    },
    reconnect() {
      if (this.streamer) {
        this.streamer.disconnect()
        this.streamer.connect(this.rtspUrl)
      }
    }
  },
  beforeDestroy() {
    if (this.streamer) {
      this.streamer.disconnect()
      this.streamer = null
    }
  }
}
</script>

<style scoped>
.monitor-container {
  position: relative;
  width: 100%;
  height: 100%;
}
.status-overlay {
  position: absolute;
  top: 10px;
  left: 10px;
  background: rgba(0,0,0,0.5);
  color: white;
  padding: 5px 10px;
  border-radius: 4px;
}
</style>

这个组件做了几项重要改进:

  1. 增加了连接状态提示
  2. 支持自定义视频样式
  3. 封装了重连方法
  4. 完善的资源清理机制

4. 高级配置与优化

4.1 跨设备访问方案

要让其他设备访问,需要修改两处配置:

  1. 服务端启动时指定可访问IP:
webrtc-streamer.exe -H 0.0.0.0 -p 8000
  1. Vue组件中修改serverUrl为服务端实际IP:
<Monitor 
  rtsp-url="rtsp://admin:password@192.168.1.100:554/stream"
  server-url="http://192.168.1.50:8000"
/>

我曾经遇到一个典型问题:服务启动后本机可以访问,但手机无法连接。后来发现是Windows防火墙阻止了入站连接。解决方法是在防火墙高级设置中添加8000端口的入站规则。

4.2 多摄像头管理

实际项目中经常需要同时展示多个摄像头。这里分享一个多视图解决方案:

<template>
  <div class="multi-view">
    <Monitor
      v-for="(camera, index) in cameras"
      :key="index"
      :rtsp-url="camera.url"
      :server-url="serverUrl"
      :style="{
        width: `calc(100% / ${columns} - 10px)`,
        height: `calc(100% / ${rows} - 10px)`
      }"
    />
  </div>
</template>

<script>
import Monitor from './Monitor.vue'

export default {
  components: { Monitor },
  props: {
    cameras: {
      type: Array,
      required: true,
      validator: value => value.every(cam => cam.url)
    },
    serverUrl: {
      type: String,
      default: 'http://127.0.0.1:8000'
    },
    columns: {
      type: Number,
      default: 2
    }
  },
  computed: {
    rows() {
      return Math.ceil(this.cameras.length / this.columns)
    }
  }
}
</script>

<style scoped>
.multi-view {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  width: 100%;
  height: 100%;
}
</style>

使用时只需传入摄像头数组:

<MultiView
  :cameras="[
    { url: 'rtsp://cam1' },
    { url: 'rtsp://cam2' },
    { url: 'rtsp://cam3' }
  ]"
  :columns="3"
/>

5. 常见问题排查

5.1 视频无法播放的排查步骤

  1. 检查服务是否正常运行:访问http://server-ip:8000 应该能看到WebRTC-Streamer的测试页面

  2. 验证RTSP地址有效性:使用VLC播放器测试RTSP流是否能正常播放

  3. 查看编码格式:WebRTC-Streamer只支持H.264编码,可以在摄像头后台修改编码设置

  4. 检查控制台错误:F12打开开发者工具,查看Network和Console面板的错误信息

  5. 测试网络连通性:确保Vue应用所在设备能ping通WebRTC-Streamer服务

5.2 性能优化建议

  1. 启用硬件加速:启动参数添加-o选项(需要显卡支持)

  2. 限制视频分辨率:在摄像头设置中将分辨率调整为1080p或更低

  3. 调整帧率:将帧率降至15-20fps可以显著降低带宽占用

  4. 使用TCP传输:在RTSP地址后添加?tcp参数,如rtsp://...?tcp(牺牲少量延迟换取稳定性)

  5. 服务端负载均衡:对于大规模部署,可以在不同服务器上运行多个WebRTC-Streamer实例

6. 实际项目经验分享

在最近一个智慧园区项目中,我们需要在管理后台集成30多个监控点。最初尝试直接使用WebRTC-Streamer的方案,发现当同时播放超过8路视频时,服务端CPU占用会飙升到90%以上。

经过反复测试,最终采用了分级加载策略:

  1. 默认只加载当前可视区域内的4路视频
  2. 当用户滚动或切换标签时,动态加载新视频
  3. 离开视口的视频自动断开连接

实现代码片段:

<template>
  <div @scroll="handleScroll">
    <Monitor
      v-for="camera in visibleCameras"
      :key="camera.id"
      :rtsp-url="camera.url"
      :server-url="serverUrl"
    />
  </div>
</template>

<script>
import { throttle } from 'lodash'

export default {
  data() {
    return {
      viewport: {
        top: 0,
        bottom: window.innerHeight
      }
    }
  },
  computed: {
    visibleCameras() {
      return this.cameras.filter(cam => 
        cam.position >= this.viewport.top && 
        cam.position <= this.viewport.bottom
      )
    }
  },
  mounted() {
    window.addEventListener('resize', this.updateViewport)
    this.updateViewport()
  },
  methods: {
    updateViewport: throttle(function() {
      const rect = this.$el.getBoundingClientRect()
      this.viewport = {
        top: -rect.top,
        bottom: window.innerHeight - rect.top
      }
    }, 200),
    handleScroll() {
      this.updateViewport()
    }
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.updateViewport)
  }
}
</script>

这个优化使CPU占用率降低了70%,同时保证了用户体验不受影响。

Logo

邀请您加入社区

更多推荐