首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Node.js来使用ffmpeg来流MP4文件?

如何使用Node.js来使用ffmpeg来流MP4文件?
EN

Stack Overflow用户
提问于 2015-11-15 22:32:13
回答 3查看 21.6K关注 0票数 17

我已经试着解决这个问题好几天了,希望能在这个问题上提供任何帮助。

我能够使用fluent-ffmpeg成功地流存储在mp4服务器上的Node.js音频文件,方法是将文件的位置作为字符串传递并将其转换为mp3。如果我从同一个文件创建一个文件流并将其传递给fluent-ffmpeg,那么它可以用于mp3输入文件,而不是mp4文件。在mp4文件的情况下,没有抛出错误,它声称流已成功完成,但浏览器中没有播放任何内容。我猜想这与存储在mp4文件末尾的元数据有关,但我不知道如何编写代码。当它的位置被传递给ffmpeg,而不是流时,这就是正确工作的文件。当我尝试将一个流传递给mp4文件时,s3上同样不会抛出错误,但不会向浏览器抛出任何流。这并不奇怪,因为ffmpeg不会在本地作为流处理文件,因此期望它处理来自s3的流是一厢情愿的想法。

如何在不首先将mp4文件本地存储为文件的情况下,从s3中流该文件?我如何使ffmpeg做到这一点,而不转码文件也?下面是我目前的代码,它不起作用。请注意,它尝试将s3文件作为流传递给ffmpeg,它还将其转换为mp3,这是我不想做的。

代码语言:javascript
复制
.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编写它,如下所示,但结果与上面相同。

代码语言:javascript
复制
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中流的方法。

代码语言:javascript
复制
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:

代码语言: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服务器上转码或存储临时文件。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-11-22 17:12:56

块引号--如何从mp4中流出s3文件,而不首先将其本地存储为一个文件?我如何使ffmpeg做到这一点,而不转码文件也?下面是我目前的代码,它不起作用。请注意,它尝试将s3文件作为流传递给ffmpeg,它还将其转换为mp3,这是我不想做的。

AFAIK -如果moov原子位于媒体文件中的正确位置,对于S3托管的mp4,对于流没有什么特殊要求,因为您可以依赖http。如果客户端请求“分块”编码,它将得到这样的结果,一个块流以下面所示的"END-OF“标记终止。

代码语言:javascript
复制
0\r\n
\r\n 

通过包含块头,客户端正在说“我想要一个流”。在幕后,S3只是nginx或apache,不是吗?他们都尊重头像。

以curl CLI作为你的客户..。

代码语言:javascript
复制
> User-Agent: curl/7.28.1-DEV
> Host: S3.domain
> Accept: */*
> Transfer-Encoding: chunked
> Content-Type: video/mp4
> Expect: 100-continue

可能想尝试将编解码器添加到“Content:”标题中。我不知道,但我不认为这种类型的流需要它(原子解决这些问题)

票数 3
EN

Stack Overflow用户

发布于 2015-11-20 04:19:39

这里的主要问题之一是你不能在管道上寻找。所以你必须先存储文件。但是,如果您想从一开始就流,您可以使用稍微不同的结构和管道。这里是一个最直接的方法来做它的例子。

代码语言:javascript
复制
// 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});
票数 7
EN

Stack Overflow用户

发布于 2016-11-02 03:22:17

我在缓冲来自S3文件对象的文件流时遇到了问题。s3 filestream没有设置正确的标头,而且它似乎没有正确地实现管道。

我认为更好的解决方案是使用这个名为s3-streams的nodejs模块。它设置正确的标头并缓冲输出,以便流可以正确地通过管道传输到输出响应套接字。它可以在重新流之前先从本地保存filestream。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33725893

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档