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

如何在SvelteKit应用中基于WebSocket将rosbridge的JPEG字符串转为视频流?

解决ROSbridge WebSocket字符串JPEG转实时视频流问题

核心思路

从rosbridge接收的字符串形式JPEG本质是base64编码的图像数据,直接更新<img>标签会因重复加载导致闪烁。要实现类似Foxglove Studio的流畅效果,推荐用Canvas逐帧绘制,利用浏览器的重绘机制优化视觉体验;若追求更接近原生视频的性能,可尝试MediaSource API(需额外处理编码格式)。

具体实现步骤

1. 解析WebSocket接收的图像数据

首先从ROS消息中提取base64编码的JPEG数据,转换为Blob对象:

// 初始化WebSocket连接(示例)
const ws = new WebSocket('ws://your-rosbridge-ip:9090');

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  // 过滤目标摄像头话题
  if (msg.op === 'publish' && msg.topic === '/camera/image_raw') {
    const base64Data = msg.msg.data;
    // 移除base64前缀(若rosbridge自动添加)
    const pureBase64 = base64Data.startsWith('data:image') 
      ? base64Data.split(',')[1] 
      : base64Data;
    
    // 转Blob对象
    const byteChars = atob(pureBase64);
    const byteArray = new Uint8Array(byteChars.length);
    for (let i = 0; i < byteChars.length; i++) {
      byteArray[i] = byteChars.charCodeAt(i);
    }
    const jpegBlob = new Blob([byteArray], { type: 'image/jpeg' });
    
    // 传入绘制函数
    renderFrame(jpegBlob);
  }
};

2. 用Canvas实现流畅帧绘制

HTML中添加Canvas元素:

<canvas id="cameraCanvas" style="width: 100%; max-width: 1280px;"></canvas>

JavaScript编写绘制逻辑,利用requestAnimationFrame避免卡顿:

const canvas = document.getElementById('cameraCanvas');
const ctx = canvas.getContext('2d');
const tempImg = new Image();
let isRendering = false;

function renderFrame(blob) {
  // 节流:避免同一帧周期内重复绘制
  if (isRendering) return;
  isRendering = true;

  requestAnimationFrame(() => {
    tempImg.onload = () => {
      // 自动适配Canvas尺寸与图像分辨率
      if (canvas.width !== tempImg.width || canvas.height !== tempImg.height) {
        canvas.width = tempImg.width;
        canvas.height = tempImg.height;
      }
      // 绘制图像到画布
      ctx.drawImage(tempImg, 0, 0);
      // 释放Blob URL,避免内存泄漏
      URL.revokeObjectURL(tempImg.src);
      isRendering = false;
    };
    tempImg.src = URL.createObjectURL(blob);
  });
}

3. 优化技巧(接近Foxglove流畅度)

  • 帧率控制:若ROS端推送帧率过高(如>30fps),可添加时间戳判断,跳过间隔过短的帧:
    let lastRenderTime = 0;
    const minFrameInterval = 33; // 约30fps
    
    function renderFrame(blob) {
      const now = Date.now();
      if (now - lastRenderTime < minFrameInterval) return;
      lastRenderTime = now;
      // 后续绘制逻辑...
    }
    
  • 内存优化:务必调用URL.revokeObjectURL释放临时URL,防止浏览器内存溢出。
  • 样式适配:给Canvas添加object-fit: contain样式,确保图像在容器内按比例显示,避免拉伸变形。

关于MediaSource API的补充

如果想实现原生视频播放器的功能(如暂停、进度条),可尝试将JPEG序列封装为MP4流,但前端需要额外的编码处理(如用FFmpeg.wasm转码),复杂度较高。对于机器人控制面板场景,Canvas方案已足够满足流畅性需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:23:14