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

如何使用three.js将IP摄像头视频流渲染为纹理?

解决IP摄像头MJPG流渲染到Three.js纹理的问题

你遇到的问题核心在于MJPG格式流的浏览器适配和跨域限制,再加上Three.js纹理更新的细节没处理到位。下面分步骤给你梳理解决思路:

一、先搞清楚为什么直接用video加载MJPG失败?

1. 跨域限制(最常见原因)

哪怕你设置了video.crossOrigin="anonymous",如果IP摄像头的服务器没配置CORS响应头(比如Access-Control-Allow-Origin),浏览器会直接阻止视频加载。你可以打开浏览器控制台,看看有没有No 'Access-Control-Allow-Origin' header is present的错误提示。

2. MJPG格式的video支持问题

MJPG本质是连续的JPEG帧流,部分浏览器(比如Chrome)对直接把MJPG作为video.src的支持并不理想——video更适配标准视频容器格式(如MP4、WebM),而非图片流。

二、可行的解决方案

方案1:用img元素加载MJPG流(最简便)

浏览器的img标签原生支持MJPG动态流,我们可以用它作为Three.js纹理的源,替代video:

// 创建img元素
const img = document.createElement('img');
img.crossOrigin = 'anonymous';
// 替换成你的IP摄像头MJPG地址
img.src = 'http://webcam01.bigskyresort.com/mjpg/video.mjpg';

// 等待img加载完成后创建纹理
img.onload = () => {
  // 创建Three.js纹理
  const texture = new THREE.Texture(img);
  
  // 关键:在动画循环中持续更新纹理(因为MJPG是动态流)
  function animate() {
    requestAnimationFrame(animate);
    
    if (texture) {
      texture.needsUpdate = true;
    }
    
    // 渲染你的场景
    renderer.render(scene, camera);
  }
  
  animate();
  
  // 把纹理应用到材质和网格(示例)
  const material = new THREE.MeshBasicMaterial({ map: texture });
  const plane = new THREE.Mesh(new THREE.PlaneGeometry(2, 1.5), material);
  scene.add(plane);
};

// 监听加载错误,方便排查问题
img.onerror = (err) => {
  console.error('摄像头流加载失败:', err);
};

方案2:解决跨域问题(如果方案1因跨域失败)

如果摄像头服务器无法配置CORS,你可以搭一个简单的代理服务器转发流,绕过跨域限制。用Node.js + Express就能快速实现:

// Node.js代理服务器代码
const express = require('express');
const request = require('request');
const app = express();

// 转发摄像头流的接口
app.get('/proxy-webcam', (req, res) => {
  const webcamUrl = 'http://webcam01.bigskyresort.com/mjpg/video.mjpg';
  // 设置CORS头,允许前端访问
  res.setHeader('Access-Control-Allow-Origin', '*');
  request(webcamUrl).pipe(res);
});

// 启动服务器,端口3000
app.listen(3000, () => {
  console.log('代理服务器运行在 http://localhost:3000');
});

之后前端把img的src改成代理地址即可:

img.src = 'http://localhost:3000/proxy-webcam';

方案3:如果一定要用video元素(针对支持MJPG的浏览器)

如果你的目标浏览器支持video播放MJPG,需要补充两个关键步骤:

  1. 监听video的canplay事件,确保视频加载完成后再创建纹理
  2. 在动画循环中更新纹理的needsUpdate属性

示例代码:

const video = document.createElement('video');
video.crossOrigin = 'anonymous';
video.width = 320;
video.height = 240;
video.autoplay = true;
video.muted = true; // 部分浏览器要求静音才能自动播放
video.src = 'http://webcam01.bigskyresort.com/mjpg/video.mjpg';

// 监听视频可播放事件
video.addEventListener('canplay', () => {
  const texture = new THREE.Texture(video);
  
  function animate() {
    requestAnimationFrame(animate);
    texture.needsUpdate = true; // 关键:每帧更新纹理
    renderer.render(scene, camera);
  }
  
  animate();
  
  // 应用纹理到材质
  const material = new THREE.MeshBasicMaterial({ map: texture });
  const plane = new THREE.Mesh(new THREE.PlaneGeometry(2, 1.5), material);
  scene.add(plane);
});

// 监听错误
video.addEventListener('error', (e) => {
  console.error('视频加载错误:', e.target.error);
});

三、排查小技巧

  • 直接在浏览器地址栏打开摄像头的MJPG URL,确认流本身能正常显示
  • 打开浏览器控制台,查看是否有跨域、格式不支持的错误提示
  • 测试不同浏览器(比如Firefox对MJPG的支持可能比Chrome好)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:49:12