从 HTML5 视频中获取原始像素数据

Posted

技术标签:

【中文标题】从 HTML5 视频中获取原始像素数据【英文标题】:Get raw pixel data from HTML5 video 【发布时间】:2012-08-21 06:17:10 【问题描述】:

我想从视频元素中获取原始数据(TypedArray 之类的)并使用 javascript 对其进行操作。

目前我新建了一个画布,将视频绘制到画布中,然后获取图像数据。

ctx.drawImage(myVideo);
var data = ctx.getImageData(0, 0, w, h).data;

它工作正常,但它会消耗 CPU(将视频放到画布上并从画布复制回来)并且会产生大量垃圾(每秒大约 50 MB)。还有其他更简单的解决方案吗?如果我可以将自己的缓冲区传递给 getImageData(...),那就太好了。

顺便说一句。使用 WebGL 绘制视频并从 GPU 加载回来并不快 :( http://jsperf.com/getting-raw-data-from-video

【问题讨论】:

这是最简单的方法。您也许可以通过 WebGL 获得更多性能。您可以看到github.com/brianchirls/Seriously.js 是如何处理视频过滤器的。 嘿,谢谢你的链接。该库在片段着色器中编辑原始数据。但我需要从 JavaScript 编辑它:( 【参考方案1】:

请阅读

https://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript

因为您实际上并没有显示任何代码、提及浏览器或提供有关视频的信息(分辨率、FPS、编码),所以无法说明您的代码为何缓慢或为什么它创建显示很多垃圾。在某些分辨率限制下,可以使用 Javasrcipt 实现实时视频效果。

这是一个使用 Mozilla 进行实时视频过滤的示例。

https://developer.mozilla.org/samples/video/chroma-key/index.xhtml https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Manipulating_video_using_canvas

如果不首先在<canvas> 上传输视频帧,您将无法获得对视频数据的任何原始访问权限。但是,我相信这个操作应该是硬件加速的,因为它发生在 GPU 内存中。从 GPU 下载像素并在 Javascript 中对其进行操作,然后上传回显存可能是高分辨率的最慢步骤。

优化提示

考虑跳帧(较低 FPS 的处理效果)

服务器端HTML5视频渲染Rendering HTML5 animation server-side?

【讨论】:

我的问题不是关于 Bowser,而是关于 W3C 规范。我给你看了代码。问题是,HTML5 画布上下文函数 getImageData 生成一个新的 ArrayBufferView,每个像素有 4 个字节。这就是我寻找其他解决方案的原因。 嘿,我正在获取对视频数据的原始访问权限 - 我什至编写了我如何做到这一点的代码...... 顺便说一句。 Mozilla 示例读取原始数据的方式与我相同(getImageData(...))。那里没有改进。 Chrome 实现了增量垃圾收集器,有助于快速创建对象;您还可以调整其他浏览器上的垃圾收集器设置。您仍然没有提及使用哪种浏览器消耗 50 MB / sec 以及使用哪种帧。是的 我更新了问题。对于原始视频数据访问,我的意思是直接访问 video.getImageData() ,而不是先将其传送到画布上。如您所见, getImageData() 是当前操作数据的唯一方法。但是你是对的,API 没有让你能够回收你自己的缓冲区,但它也不应该创建一个新的缓冲区。您确定垃圾来自像素数据而不是来自您的其他代码吗?也许您在 Javascript 中保留了像素数据指针的副本(范围定义错误),并且像素数据引用永远不会被回收。【参考方案2】:

clearRect() 是我认为你正在寻找的。​​p>

据我所知,在画布上上传图像会占用空间,但 clearRect() 会删除画布上的所有内存。

我在 JS 代码上做了什么:

    在下面的代码中,我在视频标签上设置了一个流。有关更多网络摄像头信息,请参阅https://www.kirupa.com/html5/accessing_your_webcam_in_html5.htm。

    我设置一秒的时间间隔(每秒调用一次函数)来清除画布,然后在该帧上绘制流。

    现在轮到你了。最小化视频或画布应该对做什么没有影响。现在您可以随时抓取网络摄像头或视频上的像素颜色。

这是工作代码:

注意:我发现此示例不适用于内置 Web 查看器。这个例子需要它自己的网页。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="stuff, to, help, search, engines, not" name="keywords">
<meta content="What this page is about." name="description">
<meta content="Display Webcam Stream" name="title">
<title>Display Webcam Stream</title>
  
<style>
#container 
    margin: 0px auto;
    width: 500px;
    height: 375px;
    border: 10px #333 solid;

#videoElement 
    width: 500px;
    height: 375px;
    background-color: #666;

#canvas 
  background-color: #666;

</style>
</head>
  
<body>
    <video autoplay="true" id="videoElement"></video>
    <canvas id="canvas" onclick= canvasOnclick()></canvas>

<script>
var video = document.querySelector("#videoElement");
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
if (navigator.mediaDevices.getUserMedia)        
    navigator.mediaDevices.getUserMedia(video: true)
  .then(function(stream) 
    video.srcObject = stream;
  )
  .catch(function(err0r) 
    console.log("Something went wrong!");
  );




var myVar = setInterval(intervalTimer, 1000);

function intervalTimer() 
  ctx.clearRect(0,0,400,400);
  ctx.drawImage(video,0,0,400,400);



//var data = ctx.getImageData(0, 0, w, h).data;
</script>
</body>
</html>

【讨论】:

谢谢!但我不想在 Canvas 上绘制视频。我想获取像素数据(当前视频帧的每个像素的红色、绿色和蓝色的值),所以我可以用我的代码循环像素,计算平均颜色等。【参考方案3】:

canvasdisplay:none 可能有助于减少一些开销。 js 仍然可以访问 Canvas。

【讨论】:

谢谢!我用 JS 做画布,并没有将它们添加到文档中。

以上是关于从 HTML5 视频中获取原始像素数据的主要内容,如果未能解决你的问题,请参考以下文章

OSX 上的 AVFoundation:来自视频的 OpenGL 纹理,无需访问像素数据

从视频流中获取像素数据

从 CVPixelBufferRef 获取 RAW 拜耳像素数据

iOS:从相机获取逐像素数据

OpenGL获取像素的原始3d坐标

如何从 HTML5 中的视频中提取音频?