AI-віртуальний фон для відеодзвінків на мобільних
Під час розробки мобільного додатку для відеодзвінків клієнти часто стикаються з проблемою: стандартна реалізація віртуального фону через сервер дає затримки та артефакти. В одному проекті замовник використовував хмарний AI від AWS Rekognition — кожен кадр йшов у хмару, повертався через 60–80 мс. У результаті контур флуктував, користувачі скаржилися на якість.
Ми вирішили її, перенісши сегментацію на пристрій. Серверна обробка додає 40–80 мс на кожен кадр, що при 30 fps призводить до помітного розриву контуру та «привиду» при швидких рухах. On-device сегментація вкладається в 8–28 мс, що в 5-10 разів швидше за хмарний інференс. Економія на серверних GPU-обчисленнях може сягати $2000–$3000 на місяць для додатку з 10 000 активних користувачів. Ключова перевага — сегментація на пристрої, а не в хмарі. Це не тільки знижує витрати на інфраструктуру, але й забезпечує конфіденційність користувацьких даних. На кожному кадрі відеопотоку нейромережа виділяє силует людини, застосовує фон (зображення, відео або розмиття) і повертає результат у пайплайн енкодера — все без передачі даних на сервер. Типовий бюджет часу — 33 мс на кадр, і on-device рішення легко в нього вкладається. Для бюджетних пристроїв ми використовуємо легкі моделі, знижуємо частоту кадрів до 24 fps — це дозволяє досягти стабільної роботи без перегріву.
Чому on-device AI-віртуальний фон швидший?
Завдання — виділити силует людини на кожному кадрі відеопотоку (30 fps), застосувати фон і повернути результат у пайплайн до енкодування. Це означає бюджет ~33 мс на кадр, включаючи захоплення, інференс моделі, постобробку та рендеринг.
Серверний варіант: захоплення → відправка → інференс → відповідь → рендеринг. Навіть при ідеальній мережі roundtrip додає 40–80 мс. На практиці — ривки контуру, «привид» при русі.
На пристрої: захоплення → інференс → рендеринг. Все в одному пайплайні. Вартість інфраструктури при серверному підході висока — потрібні GPU-сервери. On-device підхід повністю усуває ці витрати. Економія на серверних GPU-обчисленнях може сягати $2000 на місяць для додатку з 10 000 активних користувачів. В іншому проекті економія склала $3000 на місяць за рахунок відмови від дорогих GPU-інстансів.
Принцип роботи on-device сегментації
Ми використовуємо нейромережі, оптимізовані для мобільних чипів (Neural Engine, GPU, DSP). Інференс виконується локально, жодні дані не покидають пристрій — це одночасно вирішує питання конфіденційності та затримки.
iOS: MLKit + CoreImage або Vision
На iOS використовуємо Vision фреймворк з моделлю VNGeneratePersonSegmentationRequest. Apple додала її в iOS 15 і новіше — працює на Neural Engine без явного завантаження моделі. Точність хороша для фронтальної камери, але починає давати рваний контур при складних зачісках та прозорих елементах одягу.
// Налаштування сегментації
let request = VNGeneratePersonSegmentationRequest()
request.qualityLevel = .balanced // .accurate дає кращий контур, але важче
request.outputPixelFormat = kCVPixelFormatType_OneComponent8
// У обробнику кадрів AVFoundation
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
try handler.perform([request])
guard let mask = request.results?.first?.pixelBuffer else { return }
// mask — CVPixelBuffer 8-bit, застосовуємо через CIBlendWithMask
CIBlendWithMask з CIContext(options: [.workingColorSpace: NSNull()]) — рендеримо в Metal, уникаючи конвертації кольорового простору. Без цього кожен кадр додає ~5 мс тільки на конвертацію.
Для якіснішої сегментації — конвертуємо TFLite модель DeepLab v3 або MediaPipe SelfieSegmentation в Core ML через coremltools та завантажуємо через MLModel. MediaPipe дає стабільний контур навіть при розмитих краях. Apple Vision VNGeneratePersonSegmentationRequest
Android: MLKit Selfie Segmentation
val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.STREAM_MODE) // оптимізовано для відео
.enableRawSizeMask()
.build()
)
// У обробнику CameraX ImageAnalysis
override fun analyze(imageProxy: ImageProxy) {
val inputImage = InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees)
segmenter.process(inputImage)
.addOnSuccessListener { segmentationMask ->
val mask = segmentationMask.buffer
// Застосовуємо фон через RenderScript або Vulkan compute shader
applyBackground(mask, imageProxy)
}
.addOnCompleteListener { imageProxy.close() }
}
STREAM_MODE критичний — він тримає внутрішній стейт між кадрами і працює швидше за SINGLE_IMAGE_MODE. На Pixel 6 з Tensor G2 інференс займає 8–12 мс. На бюджетних пристроях (Snapdragon 695) — 20–28 мс. Для постобробки маски — RenderScript (deprecated в API 31+) або Vulkan compute shader через RenderEffect на Android 12+. MLKit Selfie Segmentation
Порівняння моделей сегментації
| Модель | Платформа | Затримка (мс) | Якість контуру |
|---|---|---|---|
| Vision (Apple) | iOS | 12–20 | Хороша |
| MLKit Selfie Segmentation | Android | 8–12 | Відмінна |
| MediaPipe | Кроссплатформа | 15–25 | Середня |
| Core ML (DeepLab) | iOS | 20–30 | Висока |
Порівняння підходів: серверний vs on-device
| Параметр | Серверна сегментація | On-device сегментація |
|---|---|---|
| Затримка | 150–300 мс (roundtrip) | 8–28 мс (інференс) |
| Залежність від мережі | Критична | Відсутня |
| Конфіденційність | Дані йдуть на сервер | Дані залишаються на пристрої |
| Точність | Висока (велика модель) | Хороша (оптимізовані моделі) |
| Вартість інфраструктури | Висока (GPU-сервери) | Нульова (тільки ПЗ) |
Застосування фону: три варіанти
Статичне зображення — найпростіший випадок. CIBlendWithMask на iOS, PorterDuff compositing на Android.
Розмиття (blur) — фільтр CIGaussianBlur з radius 12–20 застосовується до оригінального кадру, потім маска вибирає між оригіналом та розмитим. На Android — RenderEffect.createBlurEffect (API 31+) або власний blur через Vulkan.
Відеофон — потрібен декодер, синхронізований з таймінгом відеодзвінка. На iOS — AVPlayerItemVideoOutput + Metal текстура. Важко по пам'яті: буфер відеофону + буфер камери + буфер маски + результат. На iPhone 12 з 4 GB це ок, на iPhone SE 2nd gen (3 GB) потрібен aggressive buffer reuse.
Інтеграція в WebRTC-пайплайн
Більшість мобільних рішень для дзвінків будуються на WebRTC — через LiveKit, Daily.co, Agora або нативний WebRTC. Всі вони надають механізм кастомного VideoSource/VideoProcessor для підміни кадрів до енкодування.
У LiveKit SDK для iOS це VideoProcessor протокол:
class BackgroundReplacementProcessor: VideoProcessor {
func process(frame: RTCVideoFrame) -> RTCVideoFrame? {
// Сегментація + застосування фону
// Повертаємо новий RTCVideoFrame з обробленим буфером
}
}
room.localParticipant?.videoTracks.first?.processor = BackgroundReplacementProcessor()
Важливо: RTCVideoFrame працює в CVPixelBuffer з форматом kCVPixelFormatType_420YpCbCr8BiPlanarFullRange. Конвертація в RGB для ML-інференсу і назад — це втрати. Якщо модель приймає YUV — залишаємо формат недоторканим.
Критерії вибору моделі сегментації
Вибір моделі залежить від цільових пристроїв та вимог до якості. Для iOS з A12+ підходить Vision — вбудована модель, не потребує додаткових ресурсів. Для Android з Tensor G2 або Snapdragon 8 Gen 1 — MLKit дає кращу якість. На слабких пристроях (Snapdragon 695, A11) використовуємо MediaPipe або зниження fps.
Оптимізація для слабких пристроїв
На пристроях з обмеженими ресурсами ми знижуємо частоту кадрів до 24 fps і використовуємо легкі моделі (MediaPipe). Також застосовуємо динамічне масштабування вхідного кадру: зменшуємо роздільну здатність до 480p перед інференсом, потім upscale маски. Це скорочує час обробки на 30-40% без помітної втрати якості.
Які результати ви отримаєте? (Що входить в роботу)
Після завершення проекту ви отримуєте повністю інтегровану функцію заміни фону, протестовану на 20+ реальних пристроях. До складу deliverables входять:
- Вихідний код модуля сегментації та обробки фону.
- Детальна технічна документація щодо інтеграції та кастомізації.
- Навчання вашої команди роботі з кодом та конфігураціями.
- Місяць підтримки після запуску для виправлення можливих багів.
- Рекомендації щодо оптимізації для нових версій ОС.
Скільки часу займає інтеграція (під ключ)?
- Аудит поточного WebRTC-стеку та пайплайну кадрів.
- Вибір моделі сегментації під якість/швидкість (Vision, MLKit, Core ML, MediaPipe).
- Розробка прототипу з виміром продуктивності на 10+ пристроях.
- Інтеграція в існуючий WebRTC-пайплайн через VideoProcessor.
- Оптимізація постобробки маски (antialiasing, feathering).
- Тестування на граничних умовах (складний фон, швидкі рухи).
- Документація та навчання команди замовника.
Орієнтири за термінами
Базова реалізація з розмиттям фону (одна платформа) — 2–3 тижні. Повна реалізація з підтримкою статичних зображень та відеофонів, двох платформ, інтеграція в існуючий WebRTC-стек — 5–8 тижнів.
Ми маємо 8+ років досвіду в мобільній розробці, виконали 50+ проектів з відео- та AI-функціями. Гарантуємо стабільну роботу на пристроях старше п'яти років.
Пропонуємо реалізацію під ключ. Пишіть нам для оцінки вашого проекту — отримайте консультацію інженера.







