我已经试着解决这个问题好几天了,希望能在这个问题上提供任何帮助。
我能够使用fluent-ffmpeg成功地流存储在mp4服务器上的Node.js音频文件,方法是将文件的位置作为字符串传递并将其转换为mp3。如果我从同一个文件创建一个文件流并将其传递给fluent-ffmpeg,那么它可以用于mp3输入文件,而不是mp4文件。在mp4文件的情况下,没有抛出错误,它声称流已成功完成,但浏览器中没有播放任何内容。我猜想这与存储在mp4文件末尾的元数据有关,但我不知道如何编写代码。当它的位置被传递给ffmpeg,而不是流时,这就是正确工作的文件。当我尝试将一个流传递给mp4文件时,s3上同样不会抛出错误,但不会向浏览器抛出任何流。这并不奇怪,因为ffmpeg不会在本地作为流处理文件,因此期望它处理来自s3的流是一厢情愿的想法。
如何在不首先将mp4文件本地存储为文件的情况下,从s3中流该文件?我如何使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编写它,如下所示,但结果与上面相同。
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});=====================================
更新的
我将一个mp3文件放置在同一个s3桶中,我在这里工作过的代码能够将文件流到浏览器中,而无需存储本地副本。因此,我面临的流问题与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()=====================================
答案
上面标题为“再次更新”的代码将在不使用闪存的情况下将mp4文件从s3通过Node.js服务器流到浏览器。它确实要求将文件临时存储在Node.js服务器上,以便将文件中的元数据从文件的末尾移到前面。为了在不存储临时文件的情况下进行流,首先需要在S3上实际修改该文件,并对此元数据进行更改。如果您在S3上以这种方式更改了该文件,那么您可以在标题“updated”下修改代码,以便将来自S3的结果直接传输到ffmpeg构造函数中,而不是输入到Node.js服务器上的文件流中,然后像现在的代码那样将该文件位置提供给ffmepg。您可以将最后的“管道”命令更改为“save(Location)”,以在本地获得mp4文件的版本,并将元数据移到前面。然后,您可以将该文件的新版本上传到S3,并尝试端到端的流。就我个人而言,我现在要创建一个任务,以这种方式修改这些文件,因为它们首先被上传到s3。这允许我在mp4中记录和流,而无需在Node.js服务器上转码或存储临时文件。
发布于 2015-11-22 17:12:56
块引号--如何从mp4中流出s3文件,而不首先将其本地存储为一个文件?我如何使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:”标题中。我不知道,但我不认为这种类型的流需要它(原子解决这些问题)
发布于 2015-11-20 04:19:39
这里的主要问题之一是你不能在管道上寻找。所以你必须先存储文件。但是,如果您想从一开始就流,您可以使用稍微不同的结构和管道。这里是一个最直接的方法来做它的例子。
// can just create an in-memory read stream without saving
var stream = aws.s3(s3Bucket).getObject(s3Path).createReadStream();
// fluent-ffmpeg supports a readstream as an arg in constructor
var proc = new ffmpeg(stream)
.outputOptions(['-movflags isml+frag_keyframe'])
.toFormat('mp4')
.withAudioCodec('copy')
//.seekInput(offset) this is a problem with piping
.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});发布于 2016-11-02 03:22:17
我在缓冲来自S3文件对象的文件流时遇到了问题。s3 filestream没有设置正确的标头,而且它似乎没有正确地实现管道。
我认为更好的解决方案是使用这个名为s3-streams的nodejs模块。它设置正确的标头并缓冲输出,以便流可以正确地通过管道传输到输出响应套接字。它可以在重新流之前先从本地保存filestream。
https://stackoverflow.com/questions/33725893
复制相似问题