如何即时转换上传的文件并将其直接传输到帆中的亚马逊S3

时间:2014-02-21 16:43:05

标签: node.js amazon-s3 sails.js formidable

我正在开发一个将音频文件发送到由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);
});

},

2 个答案:

答案 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就是神奇的。谢谢大家!