如何将fluent-ffmpeg转换后的视频直接上传至S3而不存储在本地?
ffmpeg输出直接写入S3实现方案
完全可以实现ffmpeg转码结果直接存入S3,不需要生成本地临时文件,核心是利用ffmpeg的流输出能力对接S3的流式上传接口。
你现有代码的问题是先把转码结果写到本地磁盘,再读取文件上传,额外增加了磁盘IO开销,大文件场景下效率极低还容易占满本地存储空间,优化后的实现代码如下:
const AWS = require('aws-sdk'); const ffmpeg = require('fluent-ffmpeg'); const { PassThrough } = require('stream'); // S3实例初始化逻辑和你原有代码保持一致即可 const s3 = new AWS.S3({ endpoint: 's3-ap-south-1.amazonaws.com', accessKeyId: S3_ACCESS_KEY_ID, secretAccessKey: S3_ACCESS_SECRET_KEY, signatureVersion: 'v4', region: 'ap-south-1' }); const signedUrlExpireSeconds = 3600; // 替换为你自己的签名有效期 const S3_BUCKET_NAME = '你的存储桶名'; // 替换为实际值 const S3_STORE_PATH = '你的S3路径前缀'; // 替换为实际值 var params = { Bucket: S3_BUCKET_NAME, Delimiter: '', Prefix: S3_STORE_PATH }; s3.listObjects(params, function (err, data) { if (err) throw err; data.Contents.forEach(async function (obj, index) { const file_name = obj.Key; const type = "mp4"; const url = s3.getSignedUrl('getObject', { Bucket: S3_BUCKET_NAME, Key: obj.Key, Expires: signedUrlExpireSeconds }); const filename = file_name.split('.').slice(0, -1).join('.'); const outputKey = `${filename}.${type}`; // 创建中转流,对接ffmpeg输出和S3上传 const passThroughStream = new PassThrough(); // 启动S3上传,直接把流作为Body参数 const uploadPromise = s3.upload({ Bucket: S3_BUCKET_NAME, Key: outputKey, Body: passThroughStream, ContentType: 'video/mp4' }).promise(); // 执行ffmpeg转码,输出直接写入中转流,不生成本地文件 await new Promise((resolve, reject) => { ffmpeg() .input(url) .toFormat('mp4') // 输出到流,而不是本地文件 .output(passThroughStream, { end: true }) .on('end', () => { resolve(); }) .on('error', (err) => { reject(err); }) .run(); }); // 等待S3上传完成 await uploadPromise; console.log(`文件${outputKey}转码并上传成功`); }); });
注意事项
- 这里使用
s3.upload而非putObject,支持自动分块上传,大视频文件不会占用过高内存,上传稳定性更高 - 全程没有本地文件读写操作,转码后的数据流直接传递给S3上传接口,资源占用更低
- 生产环境建议补充异常捕获逻辑,处理转码失败、上传失败的场景,避免进程崩溃
- 可以根据业务需求添加ffmpeg的编码参数,比如分辨率、码率、帧率配置,不影响流输出逻辑
内容的提问来源于stack exchange,提问作者Parth Shah
相关产品推荐
相关产品推荐

