我正在使用node.js中的web应用程序。应用程序的某些部分允许用户上载/检索文件。我使用' SoftLayer对象存储' -service来托管这些文件。但是,在投放视频时,它可以在Chrome / Firefox / Android上的HTML5-video元素中正常播放,但在Safari / iOS上却没有。
为了解决这个问题的根源,我在另一个Stackoverflow帖子上遇到了这个解释:
iOS设备希望视频以小块的形式到达。例如,流媒体服务器能够做到这一点。但是,blob服务器只是将视频作为blob传递,这不是iOS设备所期望的。有些浏览器足够聪明,可以处理这个,但其他浏览器则没有。
为了检查这个解释是否有意义,我尝试流式传输相同的mp4文件。为了做到这一点,我基于this stackoverflow-post上接受的答案,这实际上适用于所有浏览器和平台,这使我相信我上面引用的解释实际上是正确的。
不幸的是,这个流代码在我的情况下不起作用,因为该文件托管在SoftLayer上,而接受的假定该文件存在于服务器的文件系统上。我与" Softlayer Object Store"通过this API。我现在的代码看起来像这样:
router.get('/testFile', function (req, res) {
res.writeHead(200, {'Content-Type' : 'video/mp4','Accept-Ranges': 'bytes'});
request.get({url: authEndpoint, headers: {"X-Auth-Key": apiKey, "X-Auth-User": user}}, function (err, res1) {
var data = JSON.parse(res1.body);
var objectPath = data.storage.public + '/' + container + '/' + filename;
request.get({
url: objectPath,
headers: {"X-Auth-Token": res1.headers['x-auth-token']}
}, function (err) {
if (err) {
console.log('error', err);
}
}).pipe(res);
});
});
显然,这段代码没有"流"视频并立即将整个视频发送给客户端。使用此代码,视频无法在Safari中使用。
我想以某种方式按块发送视频块(如上面讨论的stackoverflow-answer中的情况),而不是一次完全发送,但我不知道如何通过REST检索视频时如何执行此操作请求。我注意到API允许在执行GET请求时提供可选的"范围" - 参数但我不确定如何将此用于我的优势。
最后,我还想提一下,我不相信视频的编码就是问题所在。我正在使用此视频http://www.w3schools.com/html/mov_bbb.mp4,当我在iOS / Safari上输入该链接时,它的工作正常。
答案 0 :(得分:1)
问题在于您尝试pipe
来自API的整个响应,包括状态和标题等。
相反,您需要将响应主体转换为可读流并将其传递给响应。要将Buffer
转换为ReadableStream
,您可以使用stream-buffers
所以,你的代码应该看起来像这样:
router.get('/testFile', function (req, res) {
res.writeHead(200, {'Content-Type' : 'video/mp4','Accept-Ranges': 'bytes'});
request.get({url: authEndpoint, headers: {"X-Auth-Key": apiKey, "X-Auth-User": user}}, function (err, res1) {
var data = JSON.parse(res1.body);
var objectPath = data.storage.public + '/' + container + '/' + filename;
request.get({
url: objectPath,
headers: {
"X-Auth-Token": res1.headers['x-auth-token']
}
}, function (err, data) {
if (err) {
console.log('error', err);
} else {
var bodyStream = new streamBuffers.ReadableStreamBuffer({
frequency: 10, // in milliseconds.
chunkSize: 2048 // in bytes.
});
bodyStream.pipe(res);
bodyStream.put(data.body);
}
});
});
});