Skip to content

Cloudflare 推出 Streamline:用 Workers 与容器构建自定义视频管线 ​

译注:本文翻译自 Cloudflare 官方博客,原文标题为 "Streamline: custom video pipelines with Cloudflare Stream and Workers",发布于 2026 年 10 月 2 日。原文链接见文末。

Cloudflare Stream 是一个功能强大的广播平台,对许多客户而言开箱即用。但如果你希望在直播流上渲染动态标注,或者生成一个带硬字幕的托管视频副本,就需要运行自定义的视频管线。Cloudflare 今日发布了一个新的开发者演练场 Streamline,演示如何在 Cloudflare 开发者平台上构建系统,交付这类定制化的视频体验。

为什么需要长生命周期环境 ​

处理管线需要一个持久、长时间运行的环境,能够执行专门的编译代码,并具备可预测的内存与 CPU 容量。视频流可能持续数分钟甚至数小时,因此媒体进程的生命周期必须独立于启动它的请求。应用应当能够启动管线、发送输入、检查状态并停止它,而无需为整个时长保持单一请求打开。

Cloudflare 提供了所需的原语:Containers 是适合媒体处理的长生命周期运行时;Durable Objects 负责编排;Workers 则适合控制信令与监控。在 Streamline 中,媒体引擎运行在 Container 内实时处理媒体,由 Worker 控制,向代理或用户暴露控制、预览与测试能力。即使 Worker 断开连接,处理也会继续。

架构组成 ​

一次 Streamline 部署由两部分构成:负责媒体输入输出与处理的 Media Engine,以及负责创建、配置、观测和停止媒体会话的控制 Application。

Media Engine 包含两个组件:用 Go 编写的 Controller,实现 HTTP 服务器并将请求翻译为媒体引擎可执行的操作;以及执行实际媒体处理的 Processor,当前实现使用 FFmpeg,但这属于内部实现细节,并非面向用户的 API 的一部分。

Media Engine 托管在 Container 中,可从一个 Stream Live 输入拉取 RTMPS 播放流,并向另一个 Stream Live 输入发布 RTMPS 输出;也可以拉取 Cloudflare Stream 的 HLS 清单及其分片,将托管视频作为输入;还能接受由控制应用提供的视频输入(例如摄像头),并通过出站 WebSocket 向 Durable Object 中继发布预览视频。

Application 使用 Workers 构建,可以是全栈浏览器应用、代理或嵌入式系统,包含用户界面(含客户端逻辑、身份与访问策略)以及由 Durable Object 实现的 Orchestrator,负责协调会话、Container 生命周期与预览中继。

容器生命周期与会话管理 ​

控制 Worker 应用发起一个长时间运行的媒体处理会话。会话启动后,应用可以安全地断开并重连,而 Container 会继续处理,直到控制应用将其停止。系统还设置了最大时长,确保会话最终一定会关闭,不会无限运行。

Cloudflare Container 若在设定间隔内未收到任何请求会自动休眠。但在本场景中,管线一旦运行,即使控制应用断开、不再收到请求,也必须继续。为此可以覆盖容器的 onActivityExpired() 回调:若未到过期时间则续期活动,否则销毁容器。

javascript
async onActivityExpired() {
  await this.withControlLock(async () => {
    const session = await this.getRelaySessionLocked()

    if (session?.expiresAt) {
      this.renewActivityTimeout()
      return
    }

    await this.destroy()
  })
}

API 抽象 ​

Go 实现的 HTTP 服务器与关联 Container 的 Durable Object 共同定义了系统的底层接口。Streamline 通过导出两个包提供更高层抽象:@cloudflare/streamline/client 定义基于会话的高层 API;@cloudflare/streamline/ 暴露与容器关联的 Durable Object 基类,负责路由 API 请求、实现预览中继服务器,并提供安全与访问策略钩子。

在远程部署中,控制 Worker 需导入该包并定义 Durable Object 的具体子类;在本地模式下没有 Durable Object,前端定义一层薄适配层,直接连接本地 Docker 实例。

javascript
const streamline = createStreamline({ baseUrl: 'https://media.example' })
const session = await streamline.sessions.create()
const result = await session.start(config)

// 此时管线已在运行,除非发生失败。
console.log(result)

下表列出完整的 API 调用:

客户端方法功能
createStreamline()创建新的 Streamline 实例
streamline.sessions.create()创建新的处理会话
streamline.sessions.resume(id)重连到已有会话
session.start(config)启动新的处理管线
session.ingest(chunk)在“摄像头”模式下发送视频数据块
session.annotation(png)更新透明标注叠加层
session.metrics()接收当前会话的指标
session.stop()停止当前会话的处理

定义并运行视频处理管线 ​

session.start() 接收一个 JSON 配置对象,定义输入、操作与输出。下面的例子以 RTMP 广播为输入,应用带透明度的叠加图像,并将输出发送到 RTMP 目的地,从而实时创建直播流的修改版本。

javascript
const session = await streamline.sessions.create()

const result = await session.start({
  input: { type: 'rtmp', profile: 'primary-input' },
  pipeline: [
    {
      op: 'overlay',
      params: { image: '/app/assets/cf-logo.png', position: 'top-right' },
    },
    {
      op: 'encode',
      params: {
        codec: 'h264',
        preset: 'fast',
        bitrate: '1500k',
        resolution: '1280x720',
        fps: 30,
      },
    },
  ],
  output: { mode: 'rtmp', profile: 'primary-output' },
})

Streamline 也可以通过 HLS 摄取流式视频输入,例如托管在 Cloudflare Stream 上的视频。下面的例子读取内嵌字幕并将其渲染为视频上的文字,再通过 RTMP 输出。

javascript
const streamVideoId = 'your-cloudflare-stream-video-id'
const session = await streamline.sessions.create()

await session.start({
  input: {
    type: 'hls',
    url: `https://videodelivery.net/${streamVideoId}/manifest/video.m3u8`,
  },
  pipeline: [
    { op: 'subtitle', params: { source: 'auto' } },
    {
      op: 'encode',
      params: {
        codec: 'h264',
        preset: 'fast',
        bitrate: '1500k',
        resolution: '1280x720',
        fps: 30,
      },
    },
  ],
  output: { mode: 'rtmp', profile: 'default' },
})

此外,直接从摄像头等来源向 Streamline 发送视频数据,可以快速预览处理管线。代理或嵌入式设备应用也可借此能力,例如发送工厂摄像头画面用于 AI 分析,或将多路摄像头画面合成为复合视图。

原文链接 ​

https://blog.cloudflare.com/streamline/