4

我正在编写一个代理 mjpeg 视频流的应用程序。我认为从 mjpeg 服务器(我从中代理的那个服务器)推送的 mjpeg 中提取每一帧,base64 对其进行编码并通过 websockets 发布帧以作为 data-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,该请求以一系列块响应,直到流结束(大约一分钟后)。

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 编码字符串以及缓冲区的剩余块(包含下一个图像头的位)返回, 上)。

4

1 回答 1

0

所以不知何故,我错过了 Paparazzo.js——这太棒了,为我节省了大量时间。基本上,在解析标头时需要了解两件重要的事情。

首先,您需要知道最后一个标题行将是什么(我的是“X-Resource-Status:active”)。让我绊倒的是你需要使用 \s 而不是 \r\n 作为标题的结尾。所以你应该匹配这样的东西:

var headerEnd = remaining.match(/X-Resource-Status: active\s+/);

您基本上遍历从流中接收的块并找到最后一个标头末尾的索引。您从最后一个标头的端点开始获取一个子字符串,然后等到再次调用处理程序以查找下一个标头的开头。

下一个棘手的问题是您必须使用缓冲区将图像转换为 base64(或任何其他格式)。因此,您不必获取刚刚解析出来的帧并在其上调用 .toString('base64'),而是必须执行 new Buffer(image).toString('base64')。

这是狗仔队源代码的链接,因此您可以更好地了解我在说什么:https ://github.com/wilhelmbot/Paparazzo.js/blob/master/src/paparazzo.js

于 2013-11-04T19:17:32.143 回答