バインディング は、Worker を Developer Platform 上の外部リソース(Media Transformations、R2 バケット、KV 名前空間 など)に接続します。
Media Transformations API を Worker にバインドすると、URL 経由で公開しなくても、動画の変換、リサイズ、コンテンツ抽出ができます。
たとえば Workers 内で Media Transformations を使うと、次のことができます。
- 非公開の R2 バケットや、保護されたソースに保存した動画を変換する
- 動画を最適化し、ブラウザーへ配信せず、出力を R2 に直接保存する
- 動画から静止画やスプライトシートを抽出し、Workers AI で分類や説明に使う
- 動画ファイルから音声トラックを抽出し、Workers AI で動的に文字起こしする
Media バインディングは Worker 単位で有効にします。
バインディング は、Worker 向けの Cloudflare ダッシュボード、またはプロジェクトディレクトリの Wrangler 設定ファイルで構成できます。
Media Transformations を Worker にバインドするには、Wrangler 設定ファイルの末尾に次を追加します。
{
"$schema": "./node_modules/wrangler/config-schema.json",
"media": {
"binding": "MEDIA"
}
}[media]
binding = "MEDIA" # available in your Worker on env.MEDIAWorker コード内では env.MEDIA.input() を使い、動画(ReadableStream として渡す)を操作できるオブジェクトを構築します。
Media Transformations のバインディングは Images バインディング に似ています。ただし、メソッドチェーンの順序は固定で、input() の結果を複数の変換で再利用できません。
Media バインディングの起点です。生のコンテンツを受け取ります。
- 動画バイトを含む
ReadableStream<Uint8Array>を受け取ります。
動画入力のリサイズまたはクロップ方法を定義します。このメソッドは任意です。リサイズやクロップが不要なら、.input() の結果に対して直接 .output() を呼べます。
- 次のパラメーターを受け取ります(すべて任意)。
width: 目標の幅(ピクセル、10〜2000)。height: 目標の高さ(ピクセル、10〜2000)。fit: 指定した寸法に動画を合わせる方法です。contain: アスペクト比を保ち、出力寸法の内側に収まるよう全体をスケールします。cover: 出力寸法を完全に覆うようスケールし、中央寄せでクロップします。scale-down:containと同じですが、縮小のみです。拡大しません。
- 詳細は 動画変換のオプション を参照してください。
動画から何を抽出し、出力をどうフォーマットするかを定義します。入力と出力の制約は ソース動画の要件 と 制限 を参照してください。
- 次のパラメーターを受け取ります。
mode: 生成する出力の種類です。video: 最適化した H.264/AAC の MP4 ファイルを出力します。frame: 静止画(JPEG または PNG)を出力します。spritesheet: 複数フレームを含む JPEG を出力します。audio: AAC エンコードの M4A ファイルを出力します。
time: 抽出の開始タイムスタンプ(例:"2s"、"1m")。デフォルト:"0s"。duration:video、audio、spritesheetモードの出力時間(例:"5s")。imageCount: スプライトシートに含めるフレーム数です。format:frameモード(jpg、png)またはaudioモード(m4a)の出力形式です。audio:videoモードで音声を含めるかどうかを示す Boolean です。デフォルト:true。
出力を設定したあと、結果を受け取るメソッドが 3 つあります。いずれも Promise を返すので、await する必要があります。
.response():Promise<Response>を返します。変換後のメディアを HTTP Response オブジェクトとして返し、クライアントへ返すかキャッシュに保存できます。.media():Promise<ReadableStream<Uint8Array>>を返します。変換後のメディアをバイトストリームとして返します。.contentType():Promise<string>を返します。出力の MIME タイプです(例:video/mp4、image/jpeg、audio/mp4)。
動画をリサイズし、5 秒のクリップを抽出します。
export default {
async fetch(request, env) {
const video = await env.R2_BUCKET.get("input.mp4");
const result = env.MEDIA.input(video.body)
.transform({ width: 480, height: 270 })
.output({ mode: "video", time: "0s", duration: "5s" });
return await result.response();
},
};1 フレームを JPEG サムネイルとして抽出します。
export default {
async fetch(request, env) {
const video = await env.R2_BUCKET.get("input.mp4");
const result = env.MEDIA.input(video.body)
.transform({ width: 640, height: 360 })
.output({ mode: "frame", time: "2s", format: "jpg" });
return await result.response();
},
};動画からフレーム(静止画)を抽出し、Workers AI の UForm-Gen などのモデルでキャプションを生成します。
export default {
async fetch(request, env) {
// First, load the video file from a source like R2 (or a fetch)
// Loading from R2
const video = await env.R2_BUCKET.get("input.mp4");
// Or using a fetch:
// const video = await fetch('https://example.com/video.mp4');
// Isolate a frame (still image)
const frame = await env.MEDIA.input(video.body)
.transform({ width: 720 })
.output({
mode: 'frame',
time: '3s',
})
.response();
// Set up the payload for Workers AI
const payload = {
image: [...new Uint8Array(await frame.arrayBuffer())],
prompt: "Generate a caption for this image",
max_tokens: 512,
};
const response = await env.AI.run(
"@cf/unum/uform-gen2-qwen-500m",
payload
);
return new Response(JSON.stringify(response));
}
}動画から音声トラックを M4A ファイルとして抽出します。リサイズが不要なため、.transform() を省略する例です。
export default {
async fetch(request, env) {
const video = await env.R2_BUCKET.get("input.mp4");
const result = env.MEDIA.input(video.body).output({
mode: "audio",
time: "0s",
duration: "30s",
});
return await result.response();
},
};音声を抽出し、Workers AI の Whisper で文字起こしします。
export default {
async fetch(request, env) {
// First, load the video file from a source like R2 (or a fetch)
// Loading from R2
const video = await env.R2_BUCKET.get("input.mp4");
// Or using a fetch:
// const video = await fetch('https://example.com/video.mp4');
// Extract audio using the media transformations binding:
const audio = await env.MEDIA.input(video.body)
.transform()
.output({
mode: 'audio',
})
.response();
// Prepare and run Workers AI inference
const payload = {
audio: [...new Uint8Array(await audio.arrayBuffer())],
};
const response = await env.AI.run(
"@cf/openai/whisper",
payload
);
// response will have props {text, word_count, vtt, words}
return new Response(
JSON.stringify(response, null, 2),
{
headers: {'Content-Type': 'application/json'}
}
);
}
}動画を変換し、結果を R2 に直接保存します。
export default {
async fetch(request, env) {
const video = await env.R2_BUCKET.get("input.mp4");
const result = env.MEDIA.input(video.body)
.transform({ width: 480, height: 270, fit: "contain" })
.output({ mode: "video", time: "0s", duration: "10s", audio: false });
// Store the transformed video directly in R2
await env.R2_BUCKET.put("output-480p.mp4", await result.media(), {
httpMetadata: { contentType: await result.contentType() },
});
return new Response("Video transformed and stored", { status: 200 });
},
};エラーは、メソッドチェーンの異なる地点で投げられます。
.input()は、アカウント制限(無料枠またはサブスクリプション)やサービス障害に関するエラーを投げることがあります。.output()は、変換操作そのものに関するエラー(無効なパラメーターや未対応の入力形式など)を投げることがあります。
エラーは MediaError を投げます。標準の Error インターフェースを拡張し、次の追加情報を持ちます。
code: 数値のエラーコードです。message: エラーの説明です。stack: 任意のスタックトレースです。
エラーは try...catch ブロックで処理します。
export default {
async fetch(request, env) {
const video = await env.R2_BUCKET.get("input.mp4");
try {
const result = env.MEDIA.input(video.body)
.transform({ width: 480, height: 270 })
.output({ mode: "video", time: "0s", duration: "5s" });
return await result.response();
} catch (e) {
if (e instanceof Error && "code" in e) {
// Handle MediaError
return new Response(`Transformation failed: ${e.message}`, {
status: 500,
});
}
throw e;
}
},
};URL 経由の変換と異なり、Media バインディングのレスポンスは自動ではキャッシュされません。Workers では Cache API を直接使い、キャッシュ動作をカスタマイズできます。スクリプト内で、変換結果を Cloudflare のキャッシュまたは R2 ストレージに保存するロジックを実装できます。
料金は Stream の 料金 を参照してください。バインディング経由の変換は、リクエストの一意性ではなく操作単位で課金されます。コストと性能を最適化するには、出力をキャッシュまたは保存して再利用してください。
Media Transformations API は、Workers のコマンドラインインターフェースである Wrangler によるローカル開発では、リモートモードで利用できます。変換操作はリモートリソースで実行され、無料枠を超えた分は使用量課金の対象です。
ローカル開発で使うには、バインディング設定に remote を追加します。
{
"$schema": "./node_modules/wrangler/config-schema.json",
"media": {
"binding": "MEDIA",
"remote": true
}
}[media]
binding = "MEDIA" # available in your Worker on env.MEDIA
remote = true次を実行します。
npx wrangler dev