Мы регулярно сталкиваемся с ситуацией, когда клиент хочет наложить логотип на стрим с iPhone, но использует обычную UIView поверх AVCaptureVideoPreviewLayer. Результат — логотип не попадает в запись и не виден зрителям. Проблема в том, что UIKit рисует в display pipeline, а нам нужно модифицировать CVPixelBuffer до того, как он уйдёт в видеокодек. Мы решаем эту задачу через Metal, встраивая оверлей прямо в графический конвейер. Ниже — техническая реализация для iOS и Android, с разбором производительности и типичных ошибок.
Оверлей на мобильном стриме — не просто визуальный элемент, а часть пользовательского опыта. Если его нет в записи, зрители не увидят бренд или важную информацию. Технически корректная интеграция требует глубокого понимания видеопайплайна платформы.
Как Metal решает проблему производительности оверлеев?
Пайплайн захвата видео: AVCaptureVideoDataOutput → CMSampleBuffer → CVPixelBuffer → [оверлей] → H.264-энкодер → RTMP/SRT. Оверлей должен применяться к CVPixelBuffer до энкодера. Есть два подхода: CoreImage (проще, но медленнее) и Metal (быстрее, сложнее). Сравним их.
| Параметр | Metal | CoreImage |
|---|---|---|
| Производительность | <1ms на кадр (GPU) | 4–6ms на кадр (CPU) на iPhone 12+ |
| Поддержка анимаций | Полная (Metal shaders) | Ограниченная (CIFilter) |
| Сложность реализации | Высокая | Средняя |
| Рекомендуется для | 1080p60 без дропов | 720p30 или прототипы |
Для продакшн-стримов с разрешением 1080p и 30+ FPS мы используем только Metal. Экономия времени — до 3 недель разработки по сравнению с CPU-методами.
Как работает Metal-пайплайн?
Создаём MTLTexture из CVPixelBuffer через CVMetalTextureCacheCreateTextureFromImage, рендерим оверлей поверх через Metal render pass, результат остаётся в том же pixel buffer. Код:
Пример реализации оверлея на Swift
```swift class OverlayRenderer { private let device: MTLDevice private let commandQueue: MTLCommandQueue private var textureCache: CVMetalTextureCache? private var overlayTexture: MTLTexture?func apply(to pixelBuffer: CVPixelBuffer) -> CVPixelBuffer { var cvTexture: CVMetalTexture? CVMetalTextureCacheCreateTextureFromImage( nil, textureCache!, pixelBuffer, nil, .bgra8Unorm, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer), 0, &cvTexture ) guard let texture = CVMetalTextureGetTexture(cvTexture!) else { return pixelBuffer } let commandBuffer = commandQueue.makeCommandBuffer()! // render pass: основная текстура + overlayTexture поверх // ... commandBuffer.commit() commandBuffer.waitUntilCompleted() return pixelBuffer } }
</details>
Логотип (overlayTexture) загружаем один раз при старте сессии из PNG с альфа-каналом. Не загружайте UIImage на каждый кадр — это добавляет 2–3ms на каждый вызов.
## Как рендерить текстовые оверлеи без потери FPS?
Статический текст (название канала) — просто Metal-текстура, подготовленная через CoreText. Динамический текст (счётчик зрителей, donation-сообщения) рендерить напрямую через Metal нельзя, так как Metal не умеет рисовать текст. Решение: создаём offscreen CALayer с CATextLayer, рисуем в UIGraphicsImageRenderer, получаем UIImage, конвертируем в MTLTexture. Делаем это в фоновом потоке не чаще раза в 500ms для счётчиков и по событию для donation-сообщений.
Fade-in/fade-out для donation-текста реализуем изменением альфа-канала MTLTexture между кадрами — плавное появление за 15–20 кадров (0.5–0.7 секунды).
## Что выбрать для Android: OpenGL ES или Vulkan?
На Android аналог — SurfaceTexture + OpenGL ES 2.0. Камера рендерит в SurfaceTexture, мы накладываем оверлей через GLES20.glBlendFunc, результат уходит в MediaCodec через Surface. Vulkan мощнее, но поддерживается с Android 7+ и требует больше boilerplate. Мы рекомендуем OpenGL ES для совместимости, Vulkan — для сложных эффектов. Сравним их:
| Параметр | OpenGL ES 2.0 | Vulkan |
|----------|---------------|--------|
| Минимальная версия Android | 2.2 (API 8) | 7.0 (API 24) |
| Производительность | Достаточно для 1080p30 | Выше, но избыточно |
| Сложность реализации | Средняя | Высокая |
| Рекомендуется для | Большинства проектов | Спецэффектов |
Позиция оверлея хранится в относительных координатах (0.0–1.0 от размера кадра), что корректно работает при смене разрешения или ориентации. Для ландшафтной ротации пересчитываем overlayRect рендер-пасса автоматически.
## Процесс работы и что входит
Мы реализуем оверлеи под ключ. Этапы:
1. Анализ требований: какие оверлеи, платформы, разрешения, частоты кадров.
2. Проектирование пайплайна: выбор технологии (Metal/OpenGL ES), шаблоны рендеринга.
3. Реализация: интеграция оверлеев в существующий стриминговый движок.
4. Тестирование: проверка на реальных девайсах, измерение FPS, отсутствие дропов.
5. Деплой в App Store / Google Play и поддержка после запуска.
Что входит:
- Документация кода и архитектуры.
- Доступы к репозиторию и CI/CD.
- Обучение вашей команды работе с кодом.
- 3 месяца технической поддержки.
## Сроки и стоимость
Статический логотип + Metal-пайплайн на iOS: 1–1.5 недели. Динамический текст, анимации оверлеев, поддержка iOS + Android: 3–4 недели. Стоимость рассчитывается индивидуально после оценки проекта. Снижение затрат на разработку — до 40% по сравнению с неоптимизированными решениями. Мы имеем 10+ лет опыта в мобильной разработке и 50+ успешных проектов в стриминге. Гарантируем качество и соблюдение сроков.
Подробнее о технологии <cite>[Metal](https://developer.apple.com/documentation/metal)</cite> в официальной документации. Свяжитесь с нами для обсуждения деталей проекта. Закажите консультацию по оптимизации стримингового пайплайна — мы поможем интегрировать оверлеи без потери производительности.







