You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue.js中实现带环境变量的视频录制与回放?

实现带传感器数据同步的多摄像头视频录制与回放方案

针对你的需求,核心要解决视频与传感器数据的时间同步存储和Vue端的录制/回放联动两个问题,以下是具体实现方案:

一、数据与视频的同步存储设计

要实现类似CCTV的时间轴回放,关键是用精确时间戳作为视频片段和传感器数据的关联键:

  • 视频存储:将视频按固定时长(比如5分钟)分段,每个片段命名包含摄像头ID+起始时间戳(如cam_1_1699999200000.webm),视频文件存在对象存储或本地文件系统,同时在数据库中记录视频元数据:摄像头ID、起始/结束时间戳、文件路径。
  • 传感器数据存储:用时序数据库(如InfluxDB、TimescaleDB)按固定频率(比如1秒/条)存储温度、CO₂等数据,每条数据必须包含精确时间戳和对应的视频片段ID(或直接用时间戳关联)。

二、Vue端录制功能实现

利用浏览器的MediaRecorder API实现摄像头录制,同时定时采集传感器数据并关联到当前视频片段:

核心代码示例

<template>
  <div class="recording-container">
    <!-- 多摄像头切换可扩展为下拉选择器 -->
    <video ref="videoPlayer" autoplay width="640" height="480"></video>
    <button @click="toggleRecording" :disabled="isRecording">
      {{ isRecording ? '停止录制' : '开始录制' }}
    </button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const videoPlayer = ref(null)
const isRecording = ref(false)
let mediaRecorder = null
let sensorInterval = null
let currentSegmentStartTime = null
let currentCameraId = 'cam_1'

// 枚举可用摄像头设备
async function getCameraDevices() {
  const devices = await navigator.mediaDevices.enumerateDevices()
  return devices.filter(d => d.kind === 'videoinput')
}

// 切换录制状态
async function toggleRecording() {
  isRecording.value ? stopRecording() : await startRecording()
}

// 启动录制
async function startRecording() {
  const cameras = await getCameraDevices()
  // 选择第一个摄像头,可扩展为用户选择
  const stream = await navigator.mediaDevices.getUserMedia({
    video: { deviceId: cameras[0].deviceId, width: 640, height: 480 },
    audio: false // 花园场景无需音频
  })
  videoPlayer.value.srcObject = stream

  // 初始化MediaRecorder,选择webm格式(兼容性较好)
  mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm' })
  currentSegmentStartTime = Date.now()
  const segmentId = `${currentCameraId}_${currentSegmentStartTime}`

  // 定时采集传感器数据(每秒1次)
  sensorInterval = setInterval(async () => {
    const sensorData = await fetch('/api/sensors') // 后端接口获取实时数据
    // 保存数据到时序数据库,关联视频片段ID和当前时间戳
    await fetch('/api/sensors/save', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        ...sensorData,
        segmentId,
        timestamp: Date.now()
      })
    })
  }, 1000)

  // 每5分钟生成一个视频片段并上传后端
  mediaRecorder.start(5 * 60 * 1000)
  mediaRecorder.ondataavailable = async (e) => {
    if (e.data.size > 0) {
      const formData = new FormData()
      formData.append('video', e.data, `${segmentId}.webm`)
      formData.append('cameraId', currentCameraId)
      formData.append('startTime', currentSegmentStartTime)
      await fetch('/api/videos/save', { method: 'POST', body: formData })
    }
  }

  isRecording.value = true
}

// 停止录制
function stopRecording() {
  mediaRecorder.stop()
  clearInterval(sensorInterval)
  videoPlayer.value.srcObject.getTracks().forEach(track => track.stop())
  isRecording.value = false
}
</script>

三、回放与仪表盘联动实现

通过时间选择器加载对应视频片段,并在视频播放时同步更新传感器仪表盘:

核心代码示例

<template>
  <div class="playback-container">
    <video ref="playbackVideo" @timeupdate="syncSensorData" controls width="640" height="480"></video>
    <div class="dashboard">
      <div class="metric">温度: {{ currentData.temperature }}°C</div>
      <div class="metric">CO₂: {{ currentData.co2 }}ppm</div>
      <div class="metric">树木湿度: {{ currentData.humidity }}%</div>
      <div class="metric">水箱液位: {{ currentData.waterLevel }}%</div>
    </div>
    <input type="datetime-local" v-model="selectedTime" @change="loadPlaybackData">
  </div>
</template>

<script setup>
import { ref } from 'vue'

const playbackVideo = ref(null)
const currentData = ref({
  temperature: 0,
  co2: 0,
  humidity: 0,
  waterLevel: 0
})
const selectedTime = ref('')
let sensorDataCache = []

// 根据选择的时间加载视频和对应时段的传感器数据
async function loadPlaybackData() {
  const targetTs = new Date(selectedTime.value).getTime()
  // 后端接口:根据时间戳获取对应视频片段和传感器数据
  const res = await fetch(`/api/playback?timestamp=${targetTs}`)
  const data = await res.json()

  // 设置视频源
  playbackVideo.value.src = `/api/videos/${data.videoSegmentId}.webm`
  // 缓存传感器数据避免频繁请求
  sensorDataCache = data.sensorList
}

// 视频播放时同步更新传感器数据
function syncSensorData() {
  if (!sensorDataCache.length) return
  const playTimeMs = playbackVideo.value.currentTime * 1000
  const videoStartTs = new Date(selectedTime.value).getTime()
  const currentTs = videoStartTs + playTimeMs

  // 找到最接近当前播放时间的传感器数据
  const closestData = sensorDataCache.find(d => Math.abs(d.timestamp - currentTs) < 1000)
  if (closestData) {
    currentData.value = closestData
  }
}
</script>

<style scoped>
.dashboard {
  display: flex;
  gap: 2rem;
  margin: 1rem 0;
  padding: 1rem;
  background: #f5f5f5;
  border-radius: 8px;
}
.metric {
  font-size: 1.1rem;
  font-weight: 500;
}
</style>

四、关键注意事项

  1. 时间同步:所有时间戳必须用服务器时间,避免客户端本地时间偏差导致数据与视频错位。
  2. 性能优化:
    • 视频分段不要太长(5-10分钟最优),减少加载压力;
    • 回放时预加载相邻视频片段,避免切换卡顿;
    • 传感器数据可按10秒聚合存储,减少前端渲染的数据量。
  3. 存储选型:传感器数据用时序数据库查询效率更高,视频用对象存储更节省成本且易于扩展。

内容的提问来源于stack exchange,提问作者laser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:07:36