為什麼 ffmpeg 不能在 Deno Deploy 上跑?沒有子行程——所以改呼叫 API。
Deno Deploy 把你的程式碼跑在 V8 isolate 裡,沒有子行程、也沒有 FFI,ffmpeg 二進位檔根本啟動不了。改用 fetch() 呼叫 Fotovid——編碼在別處執行,回應直接給你一個指向檔案的 https 連結。
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,
params: { type: "image", watermark_image_url: logoUrl, position: "bottom-right" },
}),
});
const { url } = await res.json();
return Response.json({ url });
});isolate 模型根本不讓 ffmpeg 執行
Deno Deploy 建立在 V8 isolate 之上,是為了快速的邊緣邏輯而設計,不是為了吃 CPU 的媒體編碼。這裡沒有能啟動原生二進位檔的子行程 API,也沒有能載入它的 FFI,所以 ffmpeg 這個行程從頭到尾都不會啟動。這不是某個設定開關,也不是你可以授予的權限——ffmpeg 需要的底層能力在 isolate 沙箱裡根本不存在。ffmpeg 的 WebAssembly 移植版確實有,但只要碰上真正的影片,就會遠遠超出 isolate 的 CPU 與記憶體上限,而且沒辦法把大檔案串流處理完。
- 沒有子行程:在 isolate 裡,Deno.Command 與 child_process 都無法啟動 ffmpeg 二進位檔。
- 沒有 FFI:你無法用 dlopen 載入原生 ffmpeg 函式庫並直接呼叫。
- Wasm 版 ffmpeg 一遇到真實影片就會耗盡 isolate 的 CPU 與記憶體,也無法串流處理大型輸入。
- 這個平台是為短時間的邊緣請求調校的,不是為長達數秒的編碼工作。
團隊試圖在 Deno Deploy 上跑 ffmpeg 的幾種做法
在 Fotovid 出現之前,你只有這些選項——每一個都是你不會想自己扛下來的苦差事。
| Option | What it costs you | Verdict |
|---|---|---|
| 把 ffmpeg 打包進你的 Deno Deploy 函式 | 沒有子行程可以啟動 ffmpeg 二進位檔 | |
| 自行架設容器或虛擬機 | 全天候開機的成本,外加修補、擴縮與監控 | |
| 自建工作佇列 + worker | 多一整套基礎設施:佇列、worker、重試、死信處理 | |
| 在瀏覽器裡轉檔(WASM) | 又慢又吃記憶體,在手機上還會當掉 | |
| 呼叫 Fotovid API | 一個 HTTPS 請求;沒有東西要跑、要打包、要擴縮 |
三個步驟完成第一次呼叫
- 1拿一把免費的 API 金鑰
註冊並建立金鑰——一開始不用綁信用卡。你會拿到一組 key ID 與 secret,組合成 p6_<key_id>:<secret> 形式的 Bearer token。把它存進 Deno Deploy 的環境變數,你的 isolate 就能通過驗證,完全不必夾帶任何二進位檔。
- 2向浮水印端點送出 POST
在你的 Deno handler 裡,用一般的 fetch 帶著 Bearer token 對 POST https://api.fotovid.co/v1/video/watermark 發出請求。送出標準的請求結構:一個指向輸入影片 HTTPS URL 的 source_url,加上描述浮水印的 params 物件——type(image、text 或 combo)、watermark_image_url 或 text、position(例如 bottom-right)、opacity 與 scale。Fotovid 會抓取來源、在自己的基礎設施上執行 ffmpeg,並趕在你的 isolate 逾時之前回應。
- 3使用回傳的 URL
回應是扁平的 JSON:一個 id、一個 type,以及指向成品(由 Fotovid 託管的影片)的 url,另外還有 expires_at 與 duration。你可以把這個 url 直接交給前端,或在伺服器端抓下來,存一份到你原本就在用的儲存桶。多數操作花費 1 credit,所以一次浮水印呼叫就是從餘額扣掉 1 credit。
