【问题标题】:NodeJS - How to pipe same video stream to multiple clients?NodeJS - 如何将相同的视频流传输到多个客户端?
【发布时间】:2013-08-29 14:51:25
【问题描述】:

我们遇到了一个尝试提供视频流的情况。

由于 HTML5 视频标签不支持 udp 多播,我们正在尝试重新使用已转换的 ffmpeg 流并将其发送到多个响应。但这不起作用。

第一个响应使流正常,但第二个响应没有。 似乎该流无法通过管道输出到另一个响应,也无法克隆。

以前有人这样做过吗?有什么想法吗?

提前致谢!

代码如下:

var request = require('request');
var http = require('http');
var child_process = require("child_process");
var n = 1;
var stdouts = {};

http.createServer(function (req, resp) {

console.log("***** url ["+req.url+"], call "+n);

if (req.url != "/favicon.ico" && req.url != "/")
{
var params = req.url.substring(1).split("/");

switch (params[0])
{
  case "VIEW":
    if (params[1] == "C2FLOOR1" || params[1] == "C2FLOOR2" || params[1] == "C2PORFUN" || params[1] == "C2TESTCAM")
      var camera = "rtsp://192.168.16.19:554/Inter/Cameras/Stream?Camera="+params[1];
    else
      var camera = "http://192.168.16.19:8609/Inter/Cameras/GetStream?Camera="+params[1];

    // Write header
    resp.writeHead(200, {'Content-Type': 'video/ogg', 'Connection': 'keep-alive'});

    if (stdouts.hasOwnProperty(params[1]))
    {
      console.log("Getting stream already created for camera "+params[1]);

      var newStdout = Object.create(stdouts[params[1]]);

      newStdout.pipe(resp);
    }
    else
    {
        // Start ffmpeg
        var ffmpeg = child_process.spawn("ffmpeg",[
        "-i",camera,
        "-vcodec","libtheora",
        "-qscale:v","7",        // video quality
        "-f","ogg",             // File format
        "-g","1",               // GOP (Group Of Pictures) size
        "-"                     // Output to STDOUT
        ]);

        stdouts[params[1]] = ffmpeg.stdout;

        // Pipe the video output to the client response
        ffmpeg.stdout.pipe(resp);

    console.log("Initializing camera at "+camera);
    }

    // Kill the subprocesses when client disconnects
/*
    resp.on("close",function(){
      ffmpegs[params[1]].kill();
      console.log("FIM!");
    });
*/
    break;
}
}
else
{
resp.writeHeader(200, {"Content-Type": "text/html"});
resp.write("WRONG CALL");
resp.end();
}
n++;

}).listen(8088);

console.log('Server running at port 8088');

【问题讨论】:

    标签: html node.js video ffmpeg multicast


    【解决方案1】:

    Streams 可以被认为是固定大小的queues,因为它们在拒绝接受更多数据或数据开始从流;它们可以被视为队列,因为它们以“先进先出”(FIFO) 的顺序存储数据。

    写入流使数据可供流的所有当前读取器(已打开流进行读取的实体)使用。

    从流中读取会从流的一端移除固定数量的数据,从而释放另一端的空间以可能接受更多数据。

    一旦从流中读取数据并且更多数据被添加到流中以填充其缓冲区,那些已读取的数据就消失了。

    Node.js 流确实可以有多个阅读器同时,每个阅读器都有自己的指针,指向流的缓冲区,指示它消耗了多少数据,但如果你要添加一个新的在流已经将数据从其缓冲区中刷新后读取器,这些数据不再可用。

    我相信您在尝试从流中读取后续请求时看到的浏览器超时,因为流中的数据已用尽,并且进一步尝试从流中读取正在等待新数据可用。

    从本质上讲,您似乎在尝试使用流,就好像它们是长期存在的数据缓存一样,但事实并非如此。

    您可以尝试增加流的“高水位标记”,以便它们将整个视频流缓冲在内存中,这将允许后续阅读器从内存中读取整个数据流,而不会耗尽流的缓冲区。 (有关如何增加流的缓冲区大小,请参阅节点的 stream 文档。)

    但是,我怀疑通过增加操作系统的 I/O 缓冲区大小或从内存或固态硬盘驱动器读取数据,您是否会看到响应有很大改善。

    更新(每条评论)

    如果您需要随着时间的推移向多个观看者提供一个或多个连续(实时)视频源,您是否考虑过以“流动”模式创建和初始化视频数据流,并依靠它们发出的事件向您的用户提供数据?

    我会考虑

    • 在全局上下文(以确保流在请求之间持续存在)和“流动”(或事件驱动)模式下为每个实时源创建一个流
    • 将新流分配给全局feeds 的唯一feedName
    • 为其设置Stream.end 事件侦听器以在提要意外结束时重新初始化流

    然后在 HTTP 请求处理程序中

    • feeds feedName 中找到请求的提要
    • 在其上注册事件监听器
      1. Stream.readable - 确保有数据要读取
      2. Stream.data - 将数据传送到响应中
      3. Stream.endhttp.ServerResponse.close - 优雅地取消注册前两个处理程序

    我还会设置一个计时器来取消注册您的请求处理程序中设置的所有事件,并在合理的时间内未从流中发送数据时向客户端发送适当的错误。

    (“流动”模式在 node.js Stream 文档中有描述。)

    【讨论】:

    • 嗨 Rob,感谢您的回答,我们知道这一点,我们不需要缓存流以供其他人获取过去的数据,我们正在流式传输实时摄像头视频,因此新的浏览器将在他们当前的位置接收流;
      d
    • continuing...(在网上遇到了一些问题)我们不需要缓存流以供其他人获取过去的数据,我们正在流式传输实时摄像头视频,因此新的浏览器将获取当前点的流,这意味着与其他请求同时使用流数据。问题是,尝试保存流引用(如代码中所示)以使用相同的流来管道到另一个响应,似乎不起作用......为了简短起见,我们需要类似多播的东西,在 html5 上使用。谢谢!
    猜你喜欢
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-14
    • 2012-04-15
    相关资源
    最近更新 更多