INTEGRITY Документация

Привязка к Workers API

A привязка подключает ваш Worker на внешние ресурсы на Developer Platform, например Media Transformations, Бакеты R2, или Пространства имён KV.

Вы можете подключить Media Transformations API к своему Worker, чтобы преобразовывать, изменять размер и извлекать контент из видео без необходимости делать их доступными по URL.

Например, используя Media Transformations в Workers, вы можете:

Настройка

Привязка Media включается отдельно для каждого Worker.

Bindings можно настроить в Cloudflare dashboard для вашего Worker или в конфигурационном файле Wrangler в каталоге проекта.

Чтобы привязать Media Transformations к вашему Worker, добавьте следующее в конец файла конфигурации Wrangler:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "media": {
    "binding": "MEDIA"
  }
}
[media]
binding = "MEDIA" # available in your Worker on env.MEDIA

В коде Worker можно взаимодействовать с этой привязкой с помощью env.MEDIA.input() чтобы создать объект, управляющий видео (передаётся как ReadableStream).

Методы

Привязка Media Transformations аналогична Привязка Images, за исключением того, что порядок вызовов методов фиксирован, а результат input() нельзя использовать повторно в нескольких преобразованиях.

.input()

Точка входа для привязки Media, принимающая необработанный контент.

.transform() (необязательно)

Определяет, как входное видео должно быть преобразовано с помощью изменения размера или обрезки. Этот метод необязателен: если изменение размера или обрезка не нужны, можно вызвать .output() напрямую к результату .input().

.output()

Определяет, что извлекать из видео и как будет отформатирован результат. См. требования к исходному видео и ограничения об ограничениях на входные и выходные данные.

Методы получения результата

После настройки вывода доступны три метода получения результата. Они возвращают Promise и требуют использования await:

Примеры

Создание оптимизированного видеоклипа

Измените размер видео и извлеките пятисекундный фрагмент:

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();
	},
};

Извлечение статичного кадра

Извлечение одного кадра в виде 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();
	},
};

Определение контента с помощью Media Transformations и Workers AI

Извлеките кадр (статичное изображение) из видео, а затем используйте модель, например UForm-Gen в Workers AI чтобы создать субтитры.

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();
	},
};

Транскрибация аудио с помощью Media Transformations и Workers AI

Извлеките аудио, а затем транскрибируйте его с помощью Whisper on Workers AI.

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

Преобразование видео с сохранением результата напрямую в 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 });
	},
};

Обработка ошибок

Ошибки могут возникать на разных этапах цепочки вызовов метода:

При ошибке выбрасывается MediaError, который расширяет стандартный Error интерфейс с дополнительной информацией:

Используйте 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.

Billing

См. страницу Stream Цены сведения о стоимости. Преобразования, выполненные через binding, оплачиваются по количеству операций, а не по уникальности запросов. Для оптимальной стоимости и производительности кэшируйте или сохраняйте результаты для повторного использования.

Локальная разработка

API Media Transformations доступен в удалённом режиме для локальной разработки с помощью Wrangler, интерфейс командной строки для Workers. Операции преобразования будут выполняться с использованием удалённого ресурса и оплачиваются сверх включённого бесплатного тарифа.

Чтобы включить использование в локальной разработке, добавьте 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