2

我正在开发一个将音频文件发送到由sails.js 提供支持的服务器的应用程序。

我需要即时转换此音频文件并使用节点流将转换后的数据发送到亚马逊 S3。

我不想将数据存储在服务器上,而是在转换后直接将上传文件流式传输到 S3。

你知道这样做的方法吗?

我尝试使用强大的,但我无法让它工作。有没有人成功实施这样的事情?

谢谢

编辑

正如 jibsales 注意到的那样,如果我向您展示我迄今为止尝试过的部分内容可能会更好。所以基本上我的策略是使用强大的 fluent-ffmpeg 和 knox 与流。

我计划接收具有强大功能的文件流,并在第一个流(流 1)中写入接收到的数据块,这将是使用 fluent-ffmpeg 进行转换的入口点。然后 fluent-ffmpeg 将输出流写入到作为 Knox 的入口点的 stream2 中。

我必须面对的第一个问题是,强大的似乎不起作用。但是我不确定我的策略是否好...

到目前为止的代码如下所示:

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);
});

},
4

2 回答 2

4

强大不起作用的原因是默认的 Sails 正文解析器正在解析请求,然后强大的才能到达它。为了让它工作,您必须绕过 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 开发更好的文件解析器,希望能够为您解决其中的一些问题,但与此同时,这是您最好的选择!

于 2014-02-22T07:20:06.743 回答
1

我已经找到了一种使用 fluent-ffmpeg 和强大的即时转换文件的方法。但是,目前似乎不可能将来自 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,您实际上可以直接将数据流式传输到 amazon s3!您只需要创建另一个转换流,它将作为您上传的来源,并且 knox-mpu 会发挥作用。谢谢大家!

于 2014-02-24T14:42:56.843 回答