Deno Deploy 上的 ffmpeg

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 之前,能选的就这些——每一条都是你并不想自己扛下来的活儿。

OptionWhat it costs youVerdict
把 ffmpeg 打包进 Deno Deploy 函数没有子进程可以拉起 ffmpeg 二进制
自建容器或虚拟机常驻成本,外加打补丁、扩缩容和监控
自己搭任务队列 + worker多一套基础设施:队列、worker、重试、死信处理
在浏览器里转码(WASM)慢、吃内存,在移动端还会直接崩
调用 Fotovid API一次 HTTPS 请求;没有东西要跑、要打包、要扩容
How it works

三步完成第一次调用

  1. 1
    领一个免费 API 密钥

    注册后创建密钥——起步不用绑卡。你会拿到一个 key ID 和一个 secret,二者拼成形如 p6_<key_id>:<secret> 的 Bearer token。把它存进 Deno Deploy 的环境变量,你的 isolate 不必随包携带任何二进制就能完成鉴权。

  2. 2
    向水印接口发起 POST

    在你的 Deno handler 里,带上 Bearer token 用普通的 fetch 发起 POST https://api.fotovid.co/v1/video/watermark。请求体是统一的信封结构:source_url 指向输入视频的 HTTPS URL,再加一个描述水印的 params 对象——type(image、text 或 combo)、watermark_image_url 或 text、position(比如 bottom-right)、opacity 和 scale。Fotovid 会自己拉取源文件,在它自己的基础设施上运行 ffmpeg,并在你的 isolate 超时之前把结果返回。

  3. 3
    拿返回的 URL 直接用

    响应是一层扁平的 JSON:一个 id、一个 type,以及指向成品视频(由 Fotovid 托管)的 url,外加 expires_at 和 duration。你可以把这个 url 直接交给客户端,也可以在服务端把它拉下来,存进你本来就在用的存储桶。多数操作只消耗 1 credit,所以一次水印调用就是从余额里扣 1 credit。

常见问题

一次 API 调用即可上线

领一个免费密钥,五分钟内完成你的第一次调用。