ffmpeg trên Supabase Edge Functions

ffmpeg cho Supabase Edge Functions — đẩy việc encode ra ngoài chỉ với một lệnh gọi HTTPS.

Edge Functions chạy trên Deno nên không có child_process để spawn binary ffmpeg. Giữ nguyên function của bạn, đẩy việc encode sang một lệnh gọi HTTPS và nhận lại URL file đã xử lý xong.

// supabase/functions/watermark/index.ts
Deno.serve(async (req) => {
  const { videoUrl, logoUrl } = await req.json();

  const res = await fetch("https://api.fotovid.co/v1/video/watermark", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${Deno.env.get("FOTOVID_API_KEY")}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      source_url: videoUrl, // a Supabase Storage signed URL works here
      params: { type: "image", watermark_image_url: logoUrl, position: "bottom-right" },
    }),
  });

  const { url } = await res.json();
  return Response.json({ url });
});

Vì sao ffmpeg không chạy được trong Edge Function của bạn

Supabase Edge Functions chạy trên Deno runtime, vốn không có child_process hay subprocess API — nên dù bạn có bundle binary ffmpeg vào, cũng chẳng có gì để spawn nó cả. Chưa kể, giới hạn CPU và wall-clock ở đây được tính cho logic xử lý request nhẹ nhàng, không phải cho quá trình xử lý liên tục kéo dài vài giây đến vài phút mà việc encode media cần. Storage trigger là nơi lý tưởng để *khởi động* job ngay khi file được tải lên, nhưng việc transcode thực sự phải diễn ra ở nơi có thể chạy một encoder thật sự.

  • Deno không có child_process / subprocess — bạn không thể exec binary ffmpeg
  • Giới hạn CPU và wall-clock nhắm đến logic xử lý nhanh, không phải encode media
  • Storage trigger lý tưởng để khởi động job, nhưng phần xử lý phải chạy ở nơi khác
  • Build ffmpeg tĩnh, WASM, hay layer đều bế tắc vì runtime, chứ không chỉ vì kích thước

Các cách team thường thử để chạy ffmpeg trên Supabase

Trước khi có Fotovid, đây là những lựa chọn — mỗi cái đều là việc bạn chẳng muốn ôm vào người.

OptionWhat it costs youVerdict
Bundle ffmpeg vào function Supabase của bạnDeno không có child_process — bạn không thể spawn binary
Tự host container hoặc VMChi phí chạy 24/7 cộng thêm vá lỗi, scale và giám sát
Chạy job queue + workerHạ tầng mới: queue, worker, retry, xử lý dead-letter
Transcode ngay trong browser (WASM)Chậm, ngốn bộ nhớ và crash trên mobile
Gọi Fotovid APIMột request HTTPS; không cần chạy, đóng gói, hay scale gì cả
How it works

Lệnh gọi đầu tiên của bạn trong ba bước

  1. 1
    Lấy API key miễn phí

    Đăng ký và tạo key. Fotovid hoạt động theo credits — $1 = 100 credits và hầu hết thao tác tốn 1 credit — nên bạn có thể kết nối lệnh gọi watermark chủ lực và test toàn bộ luồng trước khi tốn bất kỳ chi phí nào.

  2. 2
    Gọi endpoint watermark từ function của bạn

    Ngay trong cùng Edge Function đó (hoặc Storage trigger được kích hoạt khi upload), POST đến https://api.fotovid.co/v1/video/watermark kèm header Authorization: Bearer p6_<key_id>:<secret>. Gửi envelope chuẩn: một source_url trỏ đến URL HTTPS của video — signed URL của Supabase Storage dùng được trực tiếp — cộng với một object params mô tả overlay, ví dụ type image, một watermark_image_url, vị trí như bottom-right và opacity hoặc scale. Function của bạn chỉ cần thực hiện một request HTTPS; Fotovid chạy phần xử lý ffmpeg off-platform, nên bạn không bao giờ đụng đến giới hạn CPU hay thời gian của Deno.

  3. 3
    Dùng URL kết quả được host sẵn

    Response là flat JSON: một id, một type và một url trỏ đến video đã xử lý xong, được host trên Fotovid. Trả url đó thẳng về cho caller của bạn, hoặc tải về và lưu bản riêng trong Supabase Storage. Coi URL host này là tạm thời — nó có expires_at — nên hãy lưu lại bản sao nếu bạn cần giữ lâu dài.

Câu hỏi thường gặp

Triển khai chỉ với một lệnh gọi API

Lấy một key miễn phí và thực hiện lệnh gọi đầu tiên trong chưa đầy năm phút.