【发布时间】:2020-05-16 10:32:08
【问题描述】:
我尝试将视频文件发送到 HTML5 <video>-tag。
我发现了一个可以追溯到 2010 年(如果不是更早的话)的 sn-p。
它在整个 Internet 上被复制并且仍在流传,但在代码风格、名称、使用的 Node.js API 版本或库方面存在一些细微差别。
我有一些问题。
这是sn-p:
app.get('/video', function(req, res) {
const path = 'some_path/video.mp4'
const stat = fs.statSync(path)
const fileSize = stat.size
const range = req.headers.range
if( range ) {
const parts = range.replace(/bytes=/, "").split("-")
const start = parseInt(parts[0],10);
const end = parts[1] ? parseInt(parts[1],10) : fileSize-1
const chunksize = (end-start)+1
const file = fs.createReadStream(path, {start, end})
const head = {
'Content-Range' : `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges' : 'bytes',
'Content-Length': chunksize,
'Content-Type' : 'video/mp4',
}
res.writeHead(206, head)
file.pipe(res)
} else {
const head = {
'Content-Length': fileSize,
'Content-Type' : 'video/mp4',
}
res.writeHead(200, head)
fs.createReadStream(path).pipe(res)
}
})
这里只是它的几个来源:
- Video streaming with HTML 5 via node.js
- video streaming in nodejs through fs module
- https://github.com/davidgatti/How-to-Stream-Movies-using-NodeJS/blob/master/routes/video.js
- https://github.com/tsukhu/rwd-spa-alljs-app/blob/master/routes/video_streamer.js
- https://tewarid.github.io/2011/04/25/stream-webm-file-to-chrome-using-node.js.html
很明显,这个 sn-p 还没有准备好生产:
- 它使用同步
statSync()而不是异步版本, - 不解析
Range头部的完整语法,也没有错误处理, - 它是硬编码的,
-
elsebrunch 可能是多余的, - 等
我对此没有意见。这是一个“入门级”代码。没关系。
但最重要的是,它没有按预期工作......但仍然有效。
据我所知,浏览器以Range标头的形式发送对<video>-tag来源的请求
Range: bytes=12345-
并且,如果是初始请求,它将是
Range: bytes=0-
所以,这条线
const end = parts[1] ? parseInt(parts[1],10) : fileSize-1
等同于
const end = fileSize-1
而且,在初始请求中,服务器将发送的不是一小段视频,而是整个文件。并且在视频倒带的情况下 - 从请求的位置到结束的一个非常大的块。
如果您通过 Javascript 请求文件,这肯定不会按预期工作。您将等待文件完全加载,或者您需要以某种方式处理跟踪请求进度,这将导致相当复杂的客户端代码。
但它对<video>-tag 来说就像一个魅力,因为浏览器会代表你处理这个问题。
我们可以通过计算end 来解决这个问题:
const preferred_chunksize = 10000000 // arbitrary selected value
let end = parts[1] ? parseInt(parts[1],10) : start + preferred_chunksize
if( end > fileSize-1 ) end = fileSize-1
或者,考虑到用于<video>-tag 的Range 标头的形式,即使这样:
const preferred_chunksize = 10000000 // arbitrary selected value
let end = start + preferred_chunksize
if( end > fileSize-1 ) end = fileSize-1
好的,现在它确实发送了预期大小的部分响应。 但是
- 这些行比
const end = fileSize-1 - 我们需要明智地选择
preferred_chunksize。例如,像preferred_chunksize=1000这样的小块大小会发出大量请求,并且工作速度会明显变慢。
虽然,至少在 Chrome 和 Firefox 中,原始版本的代码流视频文件非常好:我没有看到过多的缓存或内存使用,或速度问题。而且我无需担心preferred_chunksize的价值。
所以我的问题是:我是否应该费心发送正确大小的块(如果我只需要将视频发送到<video>-tag),是否有任何流行的浏览器/客户端 js 库无法播放使用原始 sn-p 提供的视频文件?或者这个 sn-p 的方法是否有任何隐藏的问题?
【问题讨论】:
标签: javascript node.js http-headers video-streaming html5-video