我已经尝试解决这一问题已有几天了,非常感谢您对此问题的任何帮助。
通过将文件的位置作为字符串传递并将其转码为mp3,我可以使用fluent-ffmpeg成功流式传输存储在Node.js服务器上的mp4音频文件。如果我从同一文件创建文件流,并将其传递给fluent-ffmpeg,则它适用于mp3输入文件,但不适用于mp4文件。对于mp4文件,不会引发任何错误,它声称流已成功完成,但是浏览器中没有播放任何内容。我猜想这与存储在mp4文件末尾的元数据有关,但是我不知道该如何编码。当它的位置传递到ffmpeg而不是流时,这是完全相同的文件,可以正常工作。当我尝试将流传递到s3上的mp4文件时,再次没有引发错误,但没有流向浏览器。这并不奇怪,因为ffmpeg会赢
如何从s3流式传输mp4文件,而无需先将其本地存储为文件?如何在不转码文件的情况下让ffmpeg执行此操作?以下是我目前无法使用的代码。请注意,它尝试将s3文件作为流传递给ffmpeg,并且还将其代码转换为mp3,我不希望这样做。
.get(function(req,res) {
aws.s3(s3Bucket).getFile(s3Path, function (err, result) {
if (err) {
return next(err);
}
var proc = new ffmpeg(result)
.withAudioCodec('libmp3lame')
.format('mp3')
.on('error', function (err, stdout, stderr) {
console.log('an error happened: ' + err.message);
console.log('ffmpeg stdout: ' + stdout);
console.log('ffmpeg stderr: ' + stderr);
})
.on('end', function () {
console.log('Processing finished !');
})
.on('progress', function (progress) {
console.log('Processing: ' + progress.percent + '% done');
})
.pipe(res, {end: true});
});
});
这在调用aws.s3时正在使用knox库...我也尝试过使用针对Node.js的标准aws sdk编写它,如下所示,但结果与上面相同。
var AWS = require('aws-sdk');
var s3 = new AWS.S3({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_KEY,
region: process.env.AWS_REGION_ID
});
var fileStream = s3.getObject({
Bucket: s3Bucket,
Key: s3Key
}).createReadStream();
var proc = new ffmpeg(fileStream)
.withAudioCodec('libmp3lame')
.format('mp3')
.on('error', function (err, stdout, stderr) {
console.log('an error happened: ' + err.message);
console.log('ffmpeg stdout: ' + stdout);
console.log('ffmpeg stderr: ' + stderr);
})
.on('end', function () {
console.log('Processing finished !');
})
.on('progress', function (progress) {
console.log('Processing: ' + progress.percent + '% done');
})
.pipe(res, {end: true});
====================================
更新
我在同一个s3存储桶中放置了一个mp3文件,我在这里工作的代码可以将文件流传输到浏览器,而无需存储本地副本。因此,我面临的流媒体问题与mp4 / aac容器/编码器格式有关。
我仍然对将m4a文件从s3完全传送到Node.js服务器,然后将其传递给ffmpeg进行流传输而不实际将文件存储在本地文件系统中的方法仍然感兴趣。
====================================
再次更新
我设法使服务器将文件mp4直接流向浏览器。这一半回答了我原来的问题。我现在唯一的问题是,必须先将文件下载到本地存储,然后再进行流传输。我仍然想找到一种无需临时文件即可从s3流式传输的方法。
aws.s3(s3Bucket).getFile(s3Path, function(err, result){
result.pipe(fs.createWriteStream(file_location));
result.on('end', function() {
console.log('File Downloaded!');
var proc = new ffmpeg(file_location)
.outputOptions(['-movflags isml+frag_keyframe'])
.toFormat('mp4')
.withAudioCodec('copy')
.seekInput(offset)
.on('error', function(err,stdout,stderr) {
console.log('an error happened: ' + err.message);
console.log('ffmpeg stdout: ' + stdout);
console.log('ffmpeg stderr: ' + stderr);
})
.on('end', function() {
console.log('Processing finished !');
})
.on('progress', function(progress) {
console.log('Processing: ' + progress.percent + '% done');
})
.pipe(res, {end: true});
});
});
在接收方,我只是在一个空的html页面中包含以下javascript:
window.AudioContext = window.AudioContext || window.webkitAudioContext;
context = new AudioContext();
function process(Data) {
source = context.createBufferSource(); // Create Sound Source
context.decodeAudioData(Data, function(buffer){
source.buffer = buffer;
source.connect(context.destination);
source.start(context.currentTime);
});
};
function loadSound() {
var request = new XMLHttpRequest();
request.open("GET", "/stream/<audio_identifier>", true);
request.responseType = "arraybuffer";
request.onload = function() {
var Data = request.response;
process(Data);
};
request.send();
};
loadSound()
====================================
答案
上面标题为“再次更新”下的代码将通过Node.js服务器将s3中的mp4文件流传输到浏览器,而无需使用Flash。它确实需要将文件临时存储在Node.js服务器上,以便将文件中的元数据从文件末尾移到前面。为了在不存储临时文件的情况下进行流传输,您需要首先在S3上实际修改文件并进行此元数据更改。如果您已在S3上以这种方式更改了文件,则可以修改“再次更新”标题下的代码,以便将S3的结果直接传递到ffmpeg构造函数中,而不是通过Node.js服务器上的文件流进行传递,然后将该代码位置提供给ffmepg,就像现在的代码一样。您可以将最终的“管道”命令更改为“保存(位置)” 在本地获取mp4文件的版本,并将元数据移到最前面。然后,您可以将该文件的新版本上传到S3,并尝试端到端流式传输。我个人现在要创建一个任务,以首先将文件上传到s3的方式来修改文件。这使我可以在mp4中记录和流式传输,而无需在Node.js服务器上进行转码或存储临时文件。
Blockquote如何从s3流mp4文件,而不先将其本地存储为文件?如何在不转码文件的情况下让ffmpeg执行此操作?以下是我目前无法使用的代码。请注意,它尝试将s3文件作为流传递给ffmpeg,并且还将其代码转换为mp3,我不希望这样做。
AFAIK-如果moov原子位于媒体文件中的正确位置,则对于S3托管的mp4,流式传输不需要任何特殊要求,因为您可以依靠http来实现。如果客户端请求“分块”编码,它将得到如下所示的分块流,该分块流以“ END-OF”标记终止。
0\r\n
\r\n
通过包含分块标题,客户端可以说“我想要一个流”。在幕后,S3只是nginx或apache,不是吗?他们都尊重标题。
使用curl CLI作为客户端对其进行测试...
> User-Agent: curl/7.28.1-DEV
> Host: S3.domain
> Accept: */*
> Transfer-Encoding: chunked
> Content-Type: video/mp4
> Expect: 100-continue
可能想尝试将编解码器添加到“ Content-Type:”标题中。我不知道,但不认为这种类型的流媒体会需要它(原子解决了该问题)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句