Originally published at ffmpeg-micro.com
You're adding video processing to a Firebase app. You install a static FFmpeg binary, write a Cloud Function that triggers on upload, deploy it, and watch it die. The function times out, the binary bloats your deployment, and GCP bills you for memory you didn't actually need.
The Timeout Wall
Firebase Cloud Functions v1 default to a 60-second timeout. You can push that to 540 seconds (9 minutes) on v2 functions, and that's a hard cap.
Transcoding a 5-minute 1080p video to H.264 takes 8-15 minutes on Cloud Functions CPU allocation. The 540-second ceiling doesn't come close.
The Memory and CPU Trap
Cloud Functions v2 gives you up to 32 GB of memory, but CPU allocation is tied to memory. At 2 GB memory, you get 1 vCPU. FFmpeg encoding is CPU-bound, not memory-bound. You end up over-provisioning memory just to get more CPU.
Binary Bundling Problems
Getting FFmpeg into a Cloud Function means either bundling via npm (ffmpeg-static, 70-100 MB), including the binary directly, or downloading at runtime. Cloud Functions has a 100 MB compressed deployment limit.
The Fix: Call an API Instead
Keep your function small and offload the encoding:
import { onObjectFinalized } from "firebase-functions/v2/storage";
import { defineSecret } from "firebase-functions/params";
import { getStorage } from "firebase-admin/storage";
import { initializeApp } from "firebase-admin/app";
initializeApp();
const ffmpegMicroKey = defineSecret("FFMPEG_MICRO_API_KEY");
export const processUploadedVideo = onObjectFinalized(
{
bucket: "my-app-videos",
secrets: [ffmpegMicroKey],
memory: "256MiB",
timeoutSeconds: 60,
},
async (event) => {
const { name, contentType } = event.data;
if (!contentType?.startsWith("video/")) return;
const bucket = getStorage().bucket(event.data.bucket);
const [signedUrl] = await bucket.file(name!).getSignedUrl({
action: "read",
expires: Date.now() + 60 * 60 * 1000,
});
const response = await fetch(
"https://api.ffmpeg-micro.com/v1/transcodes",
{
method: "POST",
headers: {
Authorization: `Bearer ${ffmpegMicroKey.value()}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
inputs: [{ url: signedUrl }],
outputFormat: "mp4",
preset: { quality: "high", resolution: "1080p" },
}),
}
);
const job = await response.json();
console.log(`Transcode job ${job.id} started for ${name}`);
}
);
This function deploys in seconds, cold-starts in under a second, and needs only 256 MB of memory.
Top comments (0)