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() 回调:若未到过期时间则续期活动,否则销毁容器。
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 实例。
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 目的地,从而实时创建直播流的修改版本。
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 输出。
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 分析,或将多路摄像头画面合成为复合视图。