NodeJS - 如何将同一个视频流传输到多个客户端?

4
我们有一个问题,正在尝试提供视频流服务。
由于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');
1个回答

2
可以被视为固定大小的队列,因为它们在接受更多数据之前会“缓冲”或存储一定预定义量的数据,或者数据开始从流的读取端掉落;它们可以被认为是队列,因为它们按照“先进先出”(FIFO)的顺序存储数据。
向流中写入数据会使所有当前读取该流的读取器(已打开该流进行读取的实体)能够使用该数据。
从流中读取数据会从流的一端移除固定数量的数据,从而释放另一端的空间以潜在地接受更多数据。
一旦从流中读取了数据并且已经添加了更多数据以填充其缓冲区,那些已读取的数据就消失了。
Node.js流确实可以同时具有多个读取器,每个读取器都有自己的指针指向流缓冲区,指示它已经消耗了多少数据,但如果在流已经将数据刷新出其缓冲区后添加新的读取器,则这些数据将不再可用。
我认为您在尝试从流中读取数据时看到的浏览器超时是因为流已经没有数据可用,进一步尝试从流中读取数据需要等待新数据变为可用。
实际上,您似乎正在尝试将流用作长期存在的数据缓存,而它们并不是。
您可以尝试增加流的“高水位标记”,以便它们在内存中缓冲整个视频流,这将允许后续读取器从内存中读取整个数据流,而不会耗尽流的缓冲区。(请参阅Node的stream文档,了解如何增加流的缓冲区大小。)
然而,我怀疑通过这样做来改善响应速度,与增加操作系统的I/O缓冲区大小或从内存或固态硬盘中读取数据相比,效果不大。
更新(根据评论)
如果您需要向多个观众提供一个或多个连续的(实时)视频流,您是否考虑过创建和初始化您的视频数据流为“流动”模式,并依赖它们发出的事件来向用户传递数据?
我会考虑以下内容:
  • 在全局上下文中为每个实时流创建一个流(以确保流在请求之间持续存在),并以“流动”(或事件驱动)模式运行
  • 将新的流分配给唯一的feedName全局feeds
  • 为其设置一个Stream.end事件监听器,以重新初始化流,以防意外终止源
然后,在HTTP请求处理程序中:
  • feeds中查找所请求的feedName的流
  • 为其注册事件监听器,包括:
    1. Stream.readable - 确保有数据可读
    2. Stream.data - 将数据传输到响应中
    3. Stream.endhttp.ServerResponse.close - 优雅地注销前两个处理程序
我还会设置一个定时器,在您的请求处理程序中取消所有设置的事件,并在一定时间内没有从流中获取到数据时向客户端发送适当的错误信息。
(“流动”模式在node.js的Stream文档中有描述。)

嗨,Rob,感谢你的回答,我们已经知道了这一点,我们不需要缓存流以供其他人获取过去的数据,我们正在实时传输摄像头视频,因此新的浏览器将在它们当前的位置接收到流;<br> d - SergioBR
1
我们不需要缓存流以供其他人获取过去的数据,我们正在实时传输摄像头视频,因此新浏览器将在其当前点拾取流,这意味着与其他请求同时消耗流数据。问题是,尝试保存流引用(如代码所示)以使用相同的流管道到另一个响应似乎不起作用...简而言之,我们需要类似于html5上使用的多播功能。谢谢! - SergioBR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接