なぜffmpegはDeno Deployで動かないのか?subprocessがないので、APIを呼びましょう。
Deno DeployはコードをV8 isolate上で実行するため、subprocessも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を大量に使うメディアエンコード向けではありません。ネイティブバイナリを起動するsubprocess APIも、読み込むためのFFIも存在しないため、ffmpegプロセスはそもそも起動できません。これは設定フラグや付与できる権限の問題ではなく、ffmpegが必要とするプリミティブがisolateサンドボックスに存在しないという構造的な制約です。ffmpegのWebAssembly移植版も存在しますが、実際の動画を扱うとisolateのCPU・メモリ上限を大きく超えてしまい、大きなファイルをストリーム処理することもできません。
- subprocessなし:isolate内ではDeno.Commandもchild_processもffmpegバイナリを起動できません。
- FFIなし:ネイティブのffmpegライブラリをdlopenして直接呼び出すことはできません。
- Wasm版ffmpegは実際の動画でisolateのCPU・メモリを使い果たし、大きな入力をストリーム処理できません。
- このプラットフォームは短時間のエッジリクエスト向けに最適化されており、数秒に及ぶエンコードジョブ向けではありません。
Deno Deployでffmpegを動かそうとするチームの試み
Fotovid登場以前の選択肢は以下の通りです。どれも自分では抱えたくない作業ばかりです。
| Option | What it costs you | Verdict |
|---|---|---|
| Deno Deploy関数にffmpegをバンドルする | ffmpegバイナリを起動するためのsubprocessがない | |
| コンテナやVMを自前でホストする | 常時稼働のコストに加え、パッチ適用・スケーリング・監視が必要 | |
| ジョブキュー+ワーカーを構築する | 新たなインフラが必要:キュー、ワーカー、リトライ、デッドレター処理 | |
| ブラウザ内でトランスコードする(WASM) | 遅くてメモリを大量消費し、モバイルではクラッシュする | |
| Fotovid APIを呼び出す | HTTPSリクエスト1回だけ。実行・パッケージ化・スケーリングは不要 |
最初の呼び出しまで、たったの3ステップ
- 1無料のAPIキーを取得する
サインアップしてキーを作成しましょう。最初はクレジットカード不要です。取得したkey IDとsecretを組み合わせると、p6_<key_id>:<secret>という形式のBearerトークンになります。これをDeno Deployの環境変数に保存すれば、バイナリを一切配布することなくisolateから認証できます。
- 2ウォーターマークエンドポイントにPOSTする
Denoのハンドラから、Bearerトークンを付けて通常のfetchでhttps://api.fotovid.co/v1/video/watermarkにPOSTします。送るのは標準のエンベロープです。入力動画のHTTPS URLを指すsource_urlと、ウォーターマークの内容を記述するparamsオブジェクトを含めます。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消費するだけです。
