我想通过fs模块在node.js中流式传输视频,并且尝试了以下代码。
app.get('/video', function(req, res) {
const path = 'assets/sample.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)
}
})
我的视频“ sample.mp4”大小为:1055736字节,为1 MB。但是当我运行代码时,我发现在启动start
变量为0时,end
变量为1055735&chunksize
为1055736。如果您查看 Content-Range 标头,它等于开始时的以下值。
内容范围:'字节0-1055735 / 1055736'
我想逐个流式传输我的视频,而不是等待整个视频加载。但是我认为上面的代码不会做到这一点。
任何人都可以告诉我,此代码对视频流是否正确?
谢谢!
答案 0 :(得分:0)
您的代码没问题,除了以下几点:通常,浏览器会在视频请求中向您发送Range: bytes=0-
。在此标头中输入您的代码
const start = parseInt(parts[0],10);
const end = parts[1] ? parseInt(parts[1],10) : fileSize-1
为您提供start === 0
和end === fileSize-1
以及chunksize
的文件大小。因为parts[1]
总是虚假的。因此,决定是您发送文件的是一个很大的块,而不是浏览器。浏览器已准备好接收206 Partial Content
,但是您没有发送它。试试
const preferred_chunksize = 100000
let end = parts[1] ? parseInt(parts[1],10) : start + preferred_chunksize
if( end > fileSize-1 ) end = fileSize-1
const chunksize = end-start+1
preferred_chunksize
的范围可以是1到fileSize
,具体取决于您的网络状况。我尝试了preferred_chunksize = 1000
-很慢。我没有尝试preferred_chunksize = 1
-因为它会极其缓慢,并且会导致数百万个请求。 preferred_chunksize
介于10万和10000万之间是可以接受的。
但是,实际上,如果您在大文件上尝试使用代码,则不会发现过多的内存使用情况,并且浏览器将立即开始播放视频文件,而无需等待
要加载整个视频
即使您一起跳过end
部分(在您的代码版本中已经完成),也可以使用以下方法简化代码:
const end = fileSize-1
const chunksize = end-start+1
会的。
而且,正如我从问题的原始版本中所知道的那样,您正在编写教程,因此出于您的目的,就可以了。
PS。当然,在生产代码中,您最好检查Range
标头是否格式错误