我正在编写一个代理 mjpeg 视频流的应用程序。我认为从 mjpeg 服务器(我正在代理的服务器)推送的 mjpeg 中提取每一帧会很酷,对其进行 base64 编码并通过 websockets 发布帧以作为数据 uri 图像呈现前端。这样,不支持 mjpeg 的客户端将能够以图像序列的形式查看实时视频。
问题是我不知道如何从 MJPEG 边界之间提取 jpeg 数据。这是边界(连同标题)的样子:
--------JPEG_FRAME_BOUNDARY
Content-Type: image/jpeg
Content-Length: 33377
X-Frame-Epoc-HiRes: 1383166748.031929
X-Frame-Timestamp: 2013-10-30T20:59:08.031929Z
X-Resource-Status: active
在这些边界和标题的两边是一堆乱码数据,我认为它们是原始 jpeg 图像。
我正在使用一个 http 请求获取 mjpeg,该请求以一系列 block 响应,直到流结束(大约一分钟后)。
var boundary = extractBoundary(response.headers['content-type'])
, buffer = [];
response.on('data', function(chunk) {
buffer.push(chunk);
var frames = getFrames(buffer, boundary);
if(frames[0]) {
camera.set('data', "data:image/jpeg;base64," + frames[0]);
}
if(frames[1]) {
buffer = [new Buffer(frames[1])];
}
});
response.on('end', function() {
console.log('done');
});
现在我只需要弄清楚“getFrames”必须做什么来检查缓冲区是否包含完整的图像,然后将该图像作为 base64 编码的字符串与缓冲区的剩余 block (包含下一个图像标题,打开)。
最佳答案
不知何故,我错过了 Paparazzo.js——它很棒,为我节省了大量时间。基本上,在解析 header 时需要了解两件重要的事情。
首先,您需要知道最后一个标题行是什么(我的是“X-Resource-Status:active”)。让我绊倒的是你需要使用\s 而不是\r\n 作为标题的结尾。所以你应该匹配这样的东西:
var headerEnd = remaining.match(/X-Resource-Status: active\s+/);
您基本上循环遍历从流接收的 block 并找到最后一个 header 末尾的索引。您获取从最后一个 header 的端点开始的子字符串,然后等待再次调用处理程序以查找下一个 header 的开头。
下一个棘手的问题是您必须使用缓冲区将图像转换为 base64(或任何其他格式)。因此,与其获取刚刚解析出的帧并在其上调用 .toString('base64'),不如执行 new Buffer(image).toString('base64')。
这是 Paparazzo 来源的链接,因此您可以更好地了解我在说什么:https://github.com/wilhelmbot/Paparazzo.js/blob/master/src/paparazzo.js
关于node.js - 从 MJPEG 流中提取 JPEG 并通过 websocket 发布 base64 编码图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19696549/