我正在开发一个将音频文件发送到由sails.js提供支持的服务器的应用程序。
我需要即时转换此音频文件,并使用节点流将转换后的数据发送到amazon S3。
我不想在服务器上存储数据,而是在转换后直接将上传文件流式传输到S3。
你知道这样做的方法吗?
我尝试使用强大的功能,但我无法使用它。有没有人成功实现这样的事情?
由于
修改
正如jibsales注意到的那样,如果我向你展示到目前为止我尝试过的一些内容可能会更好。所以基本上我的策略是使用强大的,流畅的ffmpeg和knox与流。
我计划接收带有强大的文件流,并在第一个流(流1)中写入接收数据的块,这将是使用fluent-ffmpeg进行转换的入口点。然后fluent-ffmpeg将输出流写入stream2,这是Knox的入口点。
我必须面对的第一个问题是强大的东西似乎不起作用。但是我不确定我的策略是好的......
到目前为止,代码如下所示:
upload : function(req,res){
//to streams to transfer file data
var stream1 = new stream.Stream(); //stream for the incoming file data
var stream2 = new stream.Stream(); //stream for the converted file data
var client = knox.createClient({
key: 'APIKEY'
, secret: 'SECRET'
, bucket: 'bucket'
});
//Using formidable to acces data chunks
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files){ //form.parse is not called
if(err){
return res.json(err);
}else{
return res.send('ok');
}
});
//overriding form.onPart to get the file data chunk
form.onPart = function(part) {
sails.log('getting part...');
if (!part.filename) {
form.handlePart(part);
return;
}
//we put the data chunk in stream1 to convert it
part.on('data', function(chunk) {
stream1.write(chunk[1]);
});
}
form.on('error',function(err){
return sails.log(err);
});
form.on('progress', function(bytesReceived, bytesExpected) {
sails.log(bytesReceived);
});
//conversion process
var proc = new ffmpeg({ source : stream1})
.withAudioCodec('libfdk_aac')
.toFormat('mp3')
.writeToStream(stream2, {end:true}, function(retcode, error){
console.log('file has been converted succesfully');
});
client.putStream(stream2, '/file.mp3', headers, function(err, response){
return res.send(response);
});
},
答案 0 :(得分:4)
强大的无法工作的原因是默认的Sails主体解析器在formidable可以到达之前解析请求。为了使其工作,你将不得不绕过Sails体解析器进行多部分表单上传。所以,在config/express.js
:
var express = require('sails/node_modules/express');
module.exports.express = {
bodyParser: function(options) {
return function (req, res, next) {
if (!req.headers['content-type'] || req.headers['content-type'].indexOf('multipart/form-data') === -1) {
return express.bodyParser()(req, res, next);
} else {
return next();
}
}
}
}
如果content-type
标题包含multipart/form-data
,则只会完全跳过正文解析器。否则,它执行默认的快速体解析器。请注意,默认的Sails正文解析器比Express附带的版本稍微好一些(如果它无法解析请求,它伪造application/json
标题并重试),所以如果你想要额外的好处,你将不得不将核心代码复制/粘贴到上面的bodyParser
函数中。但在大多数情况下,你不会错过它;-)
我们正在为Sails开发一个更好的文件解析器,希望能为你解决一些问题,但同时这也是你最好的选择!
答案 1 :(得分:1)
我已经找到了一种使用fluent-ffmpeg和formidable即时转换文件的方法。然而,目前似乎无法将转换后的块从ffmpeg转换为直接转换为亚马逊,因为您必须精确转换过程中未知的“Content-Length”标题...
对于第一部分(客户端上传),我首先必须在config / express.js文件中禁用上传路由上的express bodyParser:
var express = require('sails/node_modules/express');
module.exports.express = {
bodyParser: function() {
return function (req, res, next){
console.log(req.path);
if (!(req.path === '/upload' && req.method === 'POST')) {
return express.bodyParser()(req, res, next);
} else {
return next();
}
}
}
}
对于实现,我使用的转换流基本上什么也没做。它只是获取上传数据的正确部分(与文件数据相关的部分)。它将强大的解析器链接到fluent-ffmpeg。然后我只能将转换后的文件保存到磁盘上,然后再将其发送到亚马逊......
upload : function(req,res){
var Transform = Stream.Transform; //stream for the incoming file data
var client = knox.createClient({
key: 'KEY'
, secret: 'SECRET'
, bucket: 'BUCKET',
region : 'eu-west-1' //don't forget the region (My bucket is in Europe)
});
function InputStream(options)
{
if(!(this instanceof InputStream))
{
return new InputStream(options);
}
Transform.call(this,options);
return;
};
util.inherits(InputStream, Transform);
var inputDataStream = new InputStream;
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files)
{
if(err){
return res.send(err);
}else{
return;
}
});
form.onPart = function(part)
{
if (!part.filename)
{
form.handlePart(part);
return;
}
//we put the data chunk in stream1 to convert it
part.on('data', function (chunk)
{
if(!inputDataStream.write(chunk));
form.pause()
inputDataStream.once('drain', function(){form.resume()});
});
part.on('end', function (chunk){
inputDataStream.end(chunk);
});
}
InputStream.prototype._transform = function (chunk, enc, cb)
{
this.push(chunk);
cb();
}
var proc = new ffmpeg({ source : inputDataStream})
.withAudioBitrate('64k')
.withAudioCodec('libmp3lame')
.toFormat('mp3')
.saveToFile('file.mp3', function (retcode, error){
console.log('file has been converted successfully');
res.send('ok');
var upload = new MultiPartUpload(
{
client : client,
objectName: 'file.mp3',
file: 'file.mp3'
}, function(err,body){
if(err) {
console.log(err);
return;
}
console.log(body);
return;
});
});
},
修改强>
使用knox-mpu,您实际上可以直接将数据流式传输到亚马逊s3!你只需要创建另一个转换流,它将成为你上传的源头,而knox-mpu就是神奇的。谢谢大家!