如何使用ffmpeg使用Node.js来流式传输MP4文件?

雷射耶稣

我已经尝试解决这一问题已有几天了,非常感谢您对此问题的任何帮助。

通过将文件的位置作为字符串传递并将其转码为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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何使用FFmpeg连接两个MP4文件?

Node.js:获取mp4文件的视频和音频格式信息

使用FFMPEG将可搜索的AAC音频流写入MP4文件

C ++ FFmpeg创建mp4文件

从mp4文件ffmpeg删除音频

使用Node JS将h264文件转换或包装为mp4

如何下载mp4文件并使用php隐藏URL路径

如何使用ffmpeg将自定义缩略图添加到.mp4文件?

如何使用ffmpeg将WebM音频(Opus)和MP4视频(H.264)合并为一个MP4文件

如何使用PHP令牌或会话保护mp4文件

无法使用ffmpeg从mp4文件创建音频文件

使用InputStreamReader从lz4文件流式传输内容-流损坏-Java

如何仅显示.mp4文件?

如何使用DXTory以MP4文件格式录制?

如何使用ffmpeg从.mp4文件中删除几秒钟?

使用FFMPEG来组合MP4和MP3文件?

如何在Java JMF中使用Socket编程流式传输Mp3文件

如何使用Flowplayer从子目录流式传输MP4文件?

如何将本地文件(例如.MP4文件)流式传输到Chrome Cast?

使用FFmpeg从WMV到MP4文件的转换失败

ffmpeg在命令行上使用ffmpeg加入两个mp4文件

使用ffmpeg分割mp4文件会导致黑色视频

如何在应用程序中快速流式传输mp3文件?

递归搜索.mp4文件并使用ffmpeg处理它们

如何使用ffmpeg从mp4文件中提取特定的音轨(音轨2)?

不使用ffmpeg将flv文件转换为mp4文件

从视频的特定时间开始,使用ffmpeg流mp4文件

使用ffmpeg将mp4文件夹转换为mp3?

如何使用ffmpeg更改mp4文件的h264属性、yuv、fps、tbr、tbn、tbc?