Supabase Edge Functions 上的 ffmpeg,卸载为一次 HTTPS 调用。
Edge Functions 跑在 Deno 上,没有 child_process,也就没法拉起 ffmpeg 二进制。保留你现有的函数,把编码交给一次 HTTPS 调用,直接拿回成品文件的 URL。
// 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 });
});为什么 ffmpeg 跑不进你的 Edge Function
Supabase Edge Functions 运行在 Deno 运行时上,而 Deno 没有 child_process,也没有 subprocess API——就算你把 ffmpeg 二进制打包进去,也没有任何办法把它拉起来。更何况,这里的 CPU 和挂钟时间上限是按轻量请求逻辑设计的,撑不住媒体编码那种动辄几秒到几分钟的持续计算。文件一落地就用 Storage 触发器*发起*任务,这一步非常合适;但真正的转码,必须放在能跑起真实编码器的地方。
- Deno 上没有 child_process / subprocess——你无法执行 ffmpeg 二进制
- CPU 和挂钟时间上限是为快速逻辑准备的,不是为媒体编码准备的
- Storage 触发器很适合发起任务,但真正的活儿必须在别处干
- 静态编译的 ffmpeg、WASM、layer 全都卡死在运行时这道坎上,不只是体积问题
团队在 Supabase 上跑 ffmpeg 的几种尝试
在 Fotovid 之前,你只有这些选择——每一个都是你并不想自己扛的活儿。
| Option | What it costs you | Verdict |
|---|---|---|
| 把 ffmpeg 打包进 Supabase 函数 | Deno 没有 child_process——这个二进制根本拉不起来 | |
| 自建容器或虚拟机 | 常驻成本,外加打补丁、扩缩容和监控 | |
| 跑一套任务队列 + worker | 多一套基础设施:队列、worker、重试、死信处理 | |
| 在浏览器里转码(WASM) | 慢、吃内存,在移动端还会崩 | |
| 调用 Fotovid API | 一次 HTTPS 请求;没有东西要运行、打包或扩容 |
三步完成第一次调用
- 1领取免费 API 密钥
注册并创建一个密钥。Fotovid 按 credits 用量计费——$1 = 100 credits,大多数操作只要 1 credit——所以你可以先把主打的水印调用接进来、端到端跑通,再考虑花钱。
- 2在函数里调用水印接口
就在同一个 Edge Function 里(或者上传时被触发的那个 Storage 触发器里),带上 Authorization: Bearer p6_<key_id>:<secret> 请求头,POST 到 https://api.fotovid.co/v1/video/watermark。请求体是统一的信封结构:一个指向视频 HTTPS URL 的 source_url——Supabase Storage 的签名 URL 可以直接用——再加一个描述叠加内容的 params 对象,例如 type 填 image、一个 watermark_image_url、一个类似 bottom-right 的 position,以及 opacity 或 scale。你的函数只发出一次 HTTPS 请求;ffmpeg 的活儿由 Fotovid 在平台外完成,你永远碰不到 Deno 的 CPU 和时间上限。
- 3直接使用托管的结果 URL
响应是扁平的 JSON:一个 id、一个 type,以及指向成品视频(由 Fotovid 托管)的 url。你可以把这个 url 原样返回给调用方,也可以下载下来,在 Supabase Storage 里存一份自己的副本。把托管 URL 当成临时资源——它带有 expires_at——需要长期留存就自己存一份。
