当前位置: 首页 > 面试题库 >

使用Node.js将视频文件流式传输到html5视频播放器,以便视频控件可以继续工作吗?

东郭宏朗
2023-03-14
问题内容

Tl; Dr-问题:

用Node.js处理将视频文件流传输到html5视频播放器以 使视频控件继续工作 的正确方法是什么

认为 这与处理标头的方式有关。无论如何,这是背景信息。代码 有点 冗长,但是非常简单。

使用Node将小视频文件流化为HTML5视频很容易

我学习了如何非常轻松地将小型视频文件流式传输到HTML5视频播放器。使用此设置,控件可以正常工作,而我的视频也完美无缺。此处包含示例视频的完整工作代码的工作副本,可在Google文档中下载。

客户:

<html>
  <title>Welcome</title>
    <body>
      <video controls>
        <source src="movie.mp4" type="video/mp4"/>
        <source src="movie.webm" type="video/webm"/>
        <source src="movie.ogg" type="video/ogg"/>
        <!-- fallback -->
        Your browser does not support the <code>video</code> element.
    </video>
  </body>
</html>

服务器:

// Declare Vars & Read Files

var fs = require('fs'),
    http = require('http'),
    url = require('url'),
    path = require('path');
var movie_webm, movie_mp4, movie_ogg;
// ... [snip] ... (Read index page)
fs.readFile(path.resolve(__dirname,"movie.mp4"), function (err, data) {
    if (err) {
        throw err;
    }
    movie_mp4 = data;
});
// ... [snip] ... (Read two other formats for the video)

// Serve & Stream Video

http.createServer(function (req, res) {
    // ... [snip] ... (Serve client files)
    var total;
    if (reqResource == "/movie.mp4") {
        total = movie_mp4.length;
    }
    // ... [snip] ... handle two other formats for the video
    var range = req.headers.range;
    var positions = range.replace(/bytes=/, "").split("-");
    var start = parseInt(positions[0], 10);
    var end = positions[1] ? parseInt(positions[1], 10) : total - 1;
    var chunksize = (end - start) + 1;
    if (reqResource == "/movie.mp4") {
        res.writeHead(206, {
            "Content-Range": "bytes " + start + "-" + end + "/" + total,
                "Accept-Ranges": "bytes",
                "Content-Length": chunksize,
                "Content-Type": "video/mp4"
        });
        res.end(movie_mp4.slice(start, end + 1), "binary");
    }
    // ... [snip] ... handle two other formats for the video
}).listen(8888);

但是此方法仅限于大小小于1GB的文件。

流式传输(任何大小)视频文件 fs.createReadStream

通过利用fs.createReadStream(),服务器可以读取流中的文件,而不必一次将所有文件都读取到内存中。这听起来像做事的正确方法,语法非常简单:

服务器片段:

movieStream = fs.createReadStream(pathToFile);
movieStream.on('open', function () {
    res.writeHead(206, {
        "Content-Range": "bytes " + start + "-" + end + "/" + total,
            "Accept-Ranges": "bytes",
            "Content-Length": chunksize,
            "Content-Type": "video/mp4"
    });
    // This just pipes the read stream to the response object (which goes 
    //to the client)
    movieStream.pipe(res);
});

movieStream.on('error', function (err) {
    res.end(err);
});

这样就可以正常播放视频了!但是视频控件不再起作用。


问题答案:

Accept Ranges报头(在该位writeHead())所需的HTML5视频控制来工作。

我认为,不仅要盲目发送完整文件,还应首先检查Accept RangesREQUEST中的标头,然后读入并发送该位。fs.createReadStreamsupport startend选项。

所以我尝试了一个例子,它可以工作。该代码不是很漂亮,但是很容易理解。首先,我们处理范围标头以获取开始/结束位置。然后,我们用于fs.stat获取文件的大小,而无需将整个文件读入内存。最后,用于fs.createReadStream将请求的部分发送给客户端。

var fs = require("fs"),
    http = require("http"),
    url = require("url"),
    path = require("path");

http.createServer(function (req, res) {
  if (req.url != "/movie.mp4") {
    res.writeHead(200, { "Content-Type": "text/html" });
    res.end('<video src="http://localhost:8888/movie.mp4" controls></video>');
  } else {
    var file = path.resolve(__dirname,"movie.mp4");
    fs.stat(file, function(err, stats) {
      if (err) {
        if (err.code === 'ENOENT') {
          // 404 Error if file not found
          return res.sendStatus(404);
        }
      res.end(err);
      }
      var range = req.headers.range;
      if (!range) {
       // 416 Wrong range
       return res.sendStatus(416);
      }
      var positions = range.replace(/bytes=/, "").split("-");
      var start = parseInt(positions[0], 10);
      var total = stats.size;
      var end = positions[1] ? parseInt(positions[1], 10) : total - 1;
      var chunksize = (end - start) + 1;

      res.writeHead(206, {
        "Content-Range": "bytes " + start + "-" + end + "/" + total,
        "Accept-Ranges": "bytes",
        "Content-Length": chunksize,
        "Content-Type": "video/mp4"
      });

      var stream = fs.createReadStream(file, { start: start, end: end })
        .on("open", function() {
          stream.pipe(res);
        }).on("error", function(err) {
          res.end(err);
        });
    });
  }
}).listen(8888);


 类似资料:
  • 问题内容: Tl; Dr-问题: 用Node.js处理将视频文件流传输到html5视频播放器以 使视频控件继续工作 的正确方法是什么 ? 我 认为 这与处理标头的方式有关。无论如何,这是背景信息。代码 有点 冗长,但是非常简单。 客户: 服务器: 但是此方法仅限于大小小于1GB的文件。 流式传输(任何大小)视频文件 通过利用,服务器可以读取流中的文件,而不是一次将其全部读取到内存中。这听起来像做事

  • 用Node.js处理将视频文件流到html5视频播放器以使视频控件继续工作的正确方法是什么? 我认为这与头的处理方式有关。不管怎样,这是背景资料。代码有点长,但是,它非常简单。 我学会了如何将小视频文件流式传输到HTML5视频播放器。有了这个设置,控制工作没有任何工作,我的部分,视频流完美。这里有一个完整的工作代码和示例视频的工作副本,可以在Google Docs上下载。 客户: 服务器: 但此方

  • 我的应用程序中有一项服务。它发送和接收webservice请求和响应。当我收到来自web服务的特定响应时,我需要停止播放音频/视频文件(媒体文件正在从另一个应用程序播放)。当我完成某个过程时,我需要再次恢复。 注: 在andoid设备中,如果任何2G呼叫停止播放媒体文件,则音乐播放器播放任何音乐,然后当2G呼叫断开时,停止播放媒体文件。我只需要这样做。

  • 我有一个blob数组(实际上是二进制数据--我可以表达它是最有效的。我现在使用Blobs,但可能或其他更好的方法)。每个Blob包含1秒的音频/视频数据。每秒都会生成一个新的Blob并将其追加到我的数组中。因此代码大致如下所示: 我的目标是将此音频/视频数据流式传输到HTML5元素。我知道Blob URL可以像下面这样生成和播放:

  • 问题内容: 该标签属性的作品在Safari罚款。 在iPad上进行测试时,必须手动激活视频。 我认为这是一个加载问题,所以我循环检查了媒体的状态: 该状态仍在iPad上。在我的桌面野生动物园中,它会通过,最后。在iPad上,只有在我手动点击“播放”箭头时才能到达。 此外,通过点击呼叫也可以。 苹果在自动播放方面是否有任何限制?(顺便说一下,我正在运行iOS 5+)。 问题答案: iOS 10更新

  • 问题内容: 我要实现以下目标。 目的是使用户能够从他/她的硬盘驱动器中选择文件。 不上传的原因当然是传输成本和存储配额。没有理由保存文件。 可能吗? 问题答案: 可以播放本地视频文件。 通过元素选择文件时: “更改”事件被触发 从获取第一个File对象 制作指向File对象的对象URL 将对象URL设置为属性 靠后看