亚马逊 S3 服务器上的 Concat MP3/媒体音频文件

Posted

技术标签:

【中文标题】亚马逊 S3 服务器上的 Concat MP3/媒体音频文件【英文标题】:Concat MP3/media audio files on amazon S3 server 【发布时间】:2015-09-24 22:30:09 【问题描述】:

我想连接上传到 Amazon S3 服务器上的文件。 我该怎么做。

我可以使用以下代码在本地机器上进行连接。

var fs = require('fs'),
    files = fs.readdirSync('./files'),
    clips = [],
    stream,
    currentfile,
    dhh = fs.createWriteStream('./concatfile.mp3');

files.forEach(function (file) 
    clips.push(file.substring(0, 6));  
);


function main() 
    if (!clips.length) 
        dhh.end("Done");
        return;
    
    currentfile = './files/' + clips.shift() + '.mp3';
    stream = fs.createReadStream(currentfile);
    
    stream.pipe(dhh, end: false);
    stream.on("end", function() 
        main();        
    );



main();

【问题讨论】:

你不能,因为你不能在 S3 服务器上执行代码。您需要下载、连接、上传。 可以在 unix shell 中使用cat 管道| 和大于> 来完成连接文件。将两个 mp3 放在一起是一个不同的问题。请区分并更好地描述您的问题。 是的,连接 mp3 的内容是不同的业务,然后只是连接文件 连接文本文件是一回事......你只需下载 concat 然后上传。但是,二进制媒体文件(例如 MP3)不能只是串联,因为这实际上是一个相当复杂的过程。关于 MP3 或如何从 S3 连接通用文本文件的问题也是如此。请适当编辑您的问题。 您可以使用 audiosprite 节点模块将 mp3 文件与 ffmpeg 连接起来。 https://github.com/tonistiigi/audiosprite。正如其他人所提到的。您通常需要从 S3 下载 mp3 文件,然后加入它们。根据您的最终目标,可以加入并将加入的文件提供给您的用户,而无需下载到您的服务器,而是根据用户事件(例如join button)使用 AWS lambda 进行处理。 lambda 和 S3 靠得很近,因此不会增加双倍延迟或额外的服务器负载。如果这是您想知道的,请更新问题。 【参考方案1】:

你可以把它分成两个步骤来实现你想要的:

在 s3 上操作文件

由于 s3 是远程文件存储,因此您无法在 s3 服务器上运行代码以在本地执行操作(如 @Andrey 所述)。 您需要在代码中做的是获取每个输入文件,在本地处理它们并将结果上传回 s3。查看amazon的代码示例:

var s3 = new AWS.S3();
var params = Bucket: 'myBucket', Key: 'mp3-input1.mp3';
var file = require('fs').createWriteStream('/path/to/input.mp3');
s3.getObject(params).createReadStream().pipe(file);

在此阶段,您将运行连接代码,并将结果上传回来:

var fs = require('fs');
var zlib = require('zlib');

var body = fs.createReadStream('bigfile.mp3').pipe(zlib.createGzip());
var s3obj = new AWS.S3(params: Bucket: 'myBucket', Key: 'myKey');
s3obj.upload(Body: body).
   on('httpUploadProgress', function(evt)  console.log(evt); ).
   send(function(err, data)  console.log(err, data) );

合并两个(或更多)mp3 文件

由于 MP3 文件包含指定比特率等信息的标头,因此简单地将它们连接在一起可能会导致播放问题。 见:https://***.com/a/5364985/1265980

你想用什么工具来做。您可以采用一种方法将输入的 mp3 文件保存在 tmp 文件夹中,然后执行外部程序,例如更改比特率、连接文件和修复标题。 或者,您可以使用允许您使用的库 ffmpeg within node.js.

在他们展示的代码示例中,您可以看到他们如何在节点 api 中将两个文件合并在一起。

ffmpeg('/path/to/part1.avi')
  .input('/path/to/part2.avi')
  .input('/path/to/part2.avi')
  .on('error', function(err) 
    console.log('An error occurred: ' + err.message);
  )
  .on('end', function() 
    console.log('Merging finished !');
  )
  .mergeToFile('/path/to/merged.avi', '/path/to/tempDir'); 

【讨论】:

【参考方案2】:

这是我对下载和处理S3 objects 问题的快速看法。我的示例主要侧重于获取本地数据,然后在全部下载后对其进行处理。我建议你使用上面提到的ffmpeg 方法之一。

var RSVP = require('rsvp');

var s3 = new AWS.S3();
var bucket = '<your bucket name>';

var getFile = function(key, filePath) 
    return new RSVP.Promise(function(resolve, reject) 
        var file = require('fs').createWriteStream(filePath);
        if(!file) 
            reject('unable to open file');
        

        s3.getObject(
            Bucket: bucket,
            Key: key
        ).on('httpData', function(chunk) 
            file.write(chunk);
        ).on('httpDone', function() 
            file.end();
            resolve(filePath);
        );
    );
;

var tempFiles = ['<local temp filename 1>', '<local temp filename 2>'];
var keys = ['<s3 object key 1>', '<s3 object key 2>'];
var promises = [];

for(var i = 0; i < keys.length; ++i) 
    var promise = getFile(keys[i], tempFiles[i]);
    promises.push(promise);


RSVP.all(promises).then(function(data) 
    //do something with your files
).catch(function(error) 
    //handle errors
);

【讨论】:

以上是关于亚马逊 S3 服务器上的 Concat MP3/媒体音频文件的主要内容,如果未能解决你的问题,请参考以下文章

亚马逊s3上的zcat

强制从 s3 亚马逊服务器下载

为亚马逊 s3 上的每个视频商店创建缩略图的最佳方法是啥?

aws S3使用总结

由于 CORS 访问限制,MediaElementAudioSource 输出零

从 Amazon S3 流式传输 MP3