Ми регулярно стикаємося з ситуацією, коли клієнт хоче накласти логотип на стрім з 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> в офіційній документації. Зв'яжіться з нами для обговорення деталей проєкту. Замовте консультацію з оптимізації стрімінгового пайплайну — ми допоможемо інтегрувати оверлеї без втрати продуктивності.







