您可以在 Firebase 云功能中调用 FFMPEG吗

问题描述 投票:0回答:7

根据 Firebase Cloud Functions 文档,您可以在云函数中利用 ImageMagick:https://firebase.google.com/docs/functions/use-cases

是否可以做类似的事情,但调用 FFMPEG 而不是 ImageMagick? 虽然缩略图图像很棒,但我还希望能够将传入图像附加到存储在 Firebase 存储上的视频文件中。

firebase ffmpeg google-cloud-functions
7个回答
78
投票

更新:

ffmpeg
现已预安装在 Cloud Functions 环境中。有关预安装软件包的完整列表,请查看 https://cloud.google.com/functions/docs/reference/system-packages

注意 截至 2023 年 4 月,Google 不再提供 ffmpeg 作为最新版本 Ubuntu(v22.04)的云功能预装包。因此,确保选择使用 Ubuntu (v18.04) 的运行时环境,以便在云功能上预安装 ffmpeg。您可以在此处找到使用 Ubuntu (v18.04) 的完整运行时环境列表

注意: 您只有在 /tmp/ 处具有磁盘

 访问权限。

选项 1:使用 ffmpeg- Fluent npm 模块

该模块通过易于使用的 Node.js 模块抽象了 ffmpeg 命令行选项。

const ffmpeg = require('fluent-ffmpeg'); let cmd = ffmpeg('example.mp4') .clone() .size('300x300') .save('/tmp/smaller-file.mp4') .on('end', () => { // Finished processing the video. console.log('Done'); // E.g. return the resized video: res.sendFile('/tmp/smaller-file.mp4'); });

GitHub 上的完整代码

选项 2:直接调用 ffmpeg 二进制文件

因为

ffmpeg

 已经安装,您可以通过 shell 进程调用二进制文件及其命令行选项。

const { exec } = require("child_process"); exec("ffmpeg -i example.mp4", (error, stdout, stderr) => { //ffmpeg logs to stderr, but typically output is in stdout. console.log(stderr); });

GitHub 上的完整代码

选项 3:上传您自己的二进制文件

如果您需要特定版本的 ffmpeg,您可以在上传过程中包含 ffmpeg 二进制文件,然后使用

child_process.exec

 等命令运行 shell 命令。您需要一个为目标平台 (Ubuntu) 编译的 ffmpeg 二进制文件。

预编译的 ffmpeg 二进制文件列表

./ ../ index.js ffmpeg
index.js

const { exec } = require("child_process"); exec("ffmpeg -i example.mp4", (error, stdout, stderr) => { //ffmpeg logs to stderr, but typically output is in stdout. console.log(stderr); });
我在 GitHub 上提供了

两个完整的工作示例。这些示例适用于 Google Cloud Functions(并非专门针对 Firebase 的 Cloud Functions)。



13
投票

ffmpeg

现已包含在 Cloud Functions 环境中,因此可以直接使用:

spawn( 'ffmpeg', ['-i', 'video.mp4'] )
已安装软件包的完整列表:

https://cloud.google.com/functions/docs/reference/nodejs-system-packages


9
投票
使用库

https://github.com/eugeneware/ffmpeg-static

const ffmpeg = require('fluent-ffmpeg'); const ffmpeg_static = require('ffmpeg-static'); let cmd = ffmpeg.('filePath.mp4') .setFfmpegPath(ffmpeg_static.path) .setInputFormat('mp4') .output('outputPath.mp4') ... ... .run()
    

2
投票
/** * Copyright 2017 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for t`he specific language governing permissions and * limitations under the License. */ 'use strict'; const functions = require('firebase-functions'); const gcs = require('@google-cloud/storage')(); const path = require('path'); const os = require('os'); const fs = require('fs'); const ffmpeg = require('fluent-ffmpeg'); const ffmpeg_static = require('ffmpeg-static'); /** * When an audio is uploaded in the Storage bucket We generate a mono channel audio automatically using * node-fluent-ffmpeg. */ exports.generateMonoAudio = functions.storage.object().onChange(event => { const object = event.data; // The Storage object. const fileBucket = object.bucket; // The Storage bucket that contains the file. const filePath = object.name; // File path in the bucket. const contentType = object.contentType; // File content type. const resourceState = object.resourceState; // The resourceState is 'exists' or 'not_exists' (for file/folder deletions). const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1. // Exit if this is triggered on a file that is not an audio. if (!contentType.startsWith('audio/')) { console.log('This is not an audio.'); return; } // Get the file name. const fileName = path.basename(filePath); // Exit if the audio is already converted. if (fileName.endsWith('_output.flac')) { console.log('Already a converted audio.'); return; } // Exit if this is a move or deletion event. if (resourceState === 'not_exists') { console.log('This is a deletion event.'); return; } // Exit if file exists but is not new and is only being triggered // because of a metadata change. if (resourceState === 'exists' && metageneration > 1) { console.log('This is a metadata change event.'); return; } // Download file from bucket. const bucket = gcs.bucket(fileBucket); const tempFilePath = path.join(os.tmpdir(), fileName); // We add a '_output.flac' suffix to target audio file name. That's where we'll upload the converted audio. const targetTempFileName = fileName.replace(/\.[^/.]+$/, "") + '_output.flac'; const targetTempFilePath = path.join(os.tmpdir(), targetTempFileName); const targetStorageFilePath = path.join(path.dirname(filePath), targetTempFileName); return bucket.file(filePath).download({ destination: tempFilePath }).then(() => { console.log('Audio downloaded locally to', tempFilePath); // Convert the audio to mono channel using FFMPEG. const command = ffmpeg(tempFilePath) .setFfmpegPath(ffmpeg_static.path) .audioChannels(1) .audioFrequency(16000) .format('flac') .on('error', (err) => { console.log('An error occurred: ' + err.message); }) .on('end', () => { console.log('Output audio created at', targetTempFilePath); // Uploading the audio. return bucket.upload(targetTempFilePath, {destination: targetStorageFilePath}).then(() => { console.log('Output audio uploaded to', targetStorageFilePath); // Once the audio has been uploaded delete the local file to free up disk space. fs.unlinkSync(tempFilePath); fs.unlinkSync(targetTempFilePath); console.log('Temporary files removed.', targetTempFilePath); }); }) .save(targetTempFilePath); }); });

https://github.com/firebase/functions-samples/blob/master/ffmpeg-convert-audio/functions/index.js


1
投票
实际上,没有。 FFMPEG 处理通常超出

Cloud Functions 配额(10MB 上传)的音频/视频文件。

您需要在 GCP 的 AppEngine 上运行

Node.js。


0
投票

基本上就是举重运动员。它允许您编写后端并将其部署到云端。考虑一下您通常可能开发的 Node Express 服务器。然后将其部署到云端。这就是应用程序引擎。

Firebase / Cloud Functions 通常通过 HTTP 或 PubSub 与 App Engine 通信。

函数是为了轻量级工作而设计的。它们会告诉您事件何时发生(例如,文件上传到存储桶),并且触发的“事件”具有有关该事件的有效负载详细信息(例如,上传到存储桶的对象的详细信息)。

当该事件发生时,如果需要繁重的工作(或者 Node.js 运行时环境上缺少所需的软件),该函数会向 App Engine 发出 HTTP 请求,提供 App Engine 执行以下操作所需的信息:必要的处理。

App Engine 非常灵活。您定义一个 yaml 文件和一个可选的 Dockerfile。

这是一个例子:

runtime: custom # custom means it uses a Dockerfile env: flex manual_scaling: instances: 1 resources: cpu: 1 memory_gb: 0.5 disk_size_gb: 10

在这里定义CPU数量、内存、磁盘大小等。与函数不同的是,磁盘是可写的(我被引导相信,我仍在集成过程中)。

通过 Dockerfile,您可以准确定义要安装的软件。如果您不熟悉 Dockerfile,这里有一个很好的示例:

https://nodejs.org/en/docs/guides/nodejs-docker-webapp

您在本地进行开发,完成后,您可以使用以下方式部署到云:

gcloud app deploy

瞧,您的应用程序出现在云端。 
gcloud

命令随

Google Cloud SDK
一起提供。 请注意,处理完成后,AppEngine 可以通过 HTTP 函数或 PubSub 与函数进行对话。

© www.soinside.com 2019 - 2024. All rights reserved.