Виртуальный фон
Кейс по встраиванию виртуального фона в браузерную видеоконференцию как части боевого видеостека, а не отдельного демо-эффекта.
Задача
Реализовать виртуальный фон в конференции с несколькими режимами:
- размытие фона;
- замена фона на изображение;
- замена фона на видео.
За основу для сегментации человека был взят MediaPipe.
Контекст
Функция должна была работать внутри уже существующего клиентского пайплайна видеоконференции. Недостаточно было просто получить маску человека и нарисовать кадр на canvas.
Нужно было встроить обработку в реальный поток камеры так, чтобы не ломались:
- включение и выключение камеры;
- переключение между устройствами;
- отправка локального видео в
WebRTC; - пользовательский интерфейс выбора фона;
- загрузка и хранение пользовательских фонов.
Как работало решение
Видео с камеры передавалось в обработчик, где для каждого кадра строилась маска человека. Дальше на основе этой маски выполнялась композиция итогового кадра:
- человек оставался на переднем плане;
- задний план размывался либо заменялся;
- результат собирался на скрытом
canvas.
После этого из canvas формировался новый видеопоток через canvas.captureStream(), и уже он подменял исходный поток камеры для дальнейшей отправки в конференцию.
Такой подход позволил встроить виртуальный фон в существующую логику WebRTC без перестройки остальной схемы работы конференции.
Что пришлось решить
1. Управление производительностью
Сегментация и перерисовка кадра создают заметную нагрузку на клиентскую машину. Поэтому обработка работала с отдельной частотой видеопроцессора: итоговый поток можно было считать с собственным videoProcessorFps, отдельно от базового framerate камеры.
Это позволило разделить две вещи:
- с какой частотой камера отдает исходный поток;
- с какой частотой поверх него выполняется тяжелая сегментация и сборка итогового кадра.
За счет этого можно было снижать нагрузку на CPU без полного отключения эффекта: не прогонять сегментацию на каждом кадре исходного потока, если машина пользователя не справляется.
Дополнительно использовались ограничения по width, height и framerate входного потока. Это позволяло снижать стоимость сегментации и композитинга еще до этапа обработки.
2. Борьба с просадкой fps
Для такой функции проблема не только в высоком CPU, но и в том, что при перегрузке пользователь сразу видит просадку плавности. Поэтому был реализован адаптивный профиль обработки:
- отдельный
videoProcessorFpsдля ограничения частоты тяжелой обработки; - управление параметрами входного потока камеры через
width,height,framerate; - возможность горячо перезапустить локальный видеопоток с новыми параметрами без развала конференции;
- продуктовый режим
virtual_bg_blur_only, когда можно оставить только наиболее легкий сценарий без картинки и видео; - адаптивное снижение
videoProcessorFps, если время обработки кадра стабильно превышало бюджет кадра; - автоматическое понижение разрешения входного видео при длительной перегрузке;
- профили качества
low,medium,high, в которых одновременно менялисьfps, разрешение и тип фона; - приоритет размытия над видеофоном на слабых машинах, потому что видеофон почти всегда тяжелее статического изображения и блюра;
- автоматический возврат к более высокому
fpsи качеству после стабилизации нагрузки.
За счет этого виртуальный фон не пытался любой ценой держать максимальное качество, а динамически удерживал стабильную плавность. Для видеозвонка это важнее, чем максимально "красивый" фон ценой перегруженного CPU и дерганого видео.
3. Встраивание в живой видеопайплайн
Виртуальный фон был встроен не как отдельный preview-виджет, а как часть объекта работы с камерой.
Для этого:
- исходный поток камеры сохранялся отдельно;
- обработанный поток формировался поверх него;
- при включении и выключении видеопроцессора поток можно было переключать без полного пересоздания всей логики конференции;
- при смене камеры происходил корректный рестарт видеозахвата;
- при обновлении локального потока выполнялась горячая подмена потока в
WebRTC.
Это дало "бесшовное" переключение фона во время звонка без развала сессии. Дополнительно такая схема позволила быстро менять профиль качества: снижать параметры видеопотока и тут же переключать обработанный стрим без переподключения пользователя к конференции.
4. API для пользовательских изображений
Для фоновых картинок была сделана серверная часть:
- загрузка изображения;
- получение списка доступных фонов пользователя;
- выдача конкретного файла;
- удаление загруженного фона.
Дополнительно были учтены прикладные ограничения:
- проверка допустимых расширений;
- ограничение размера файла;
- ограничение количества загруженных фонов на пользователя;
- дедупликация по содержимому файла через хэш.
Это превратило функцию из локального эффекта "только на текущей вкладке" в полноценную пользовательскую возможность.
5. Хранение видеофонов на клиенте
Для видеофонов использовалась браузерная IndexedDB, чтобы не загружать тяжелые файлы заново при каждом использовании и не завязывать работу функции только на сеть.
Отдельно пришлось решать вопросы жизненного цикла таких данных: когда видео еще используется, а когда его уже можно выгружать и освобождать память.
6. Работа с ресурсами
Для обработки использовались скрытые video-элементы и canvas, которые участвовали в построении результирующего потока. В такой задаче легко получить утечки памяти и "висящие" ресурсы, особенно если пользователь:
- часто включает и выключает камеру;
- меняет фон на лету;
- переключается между камерами;
- несколько раз открывает и закрывает связанные элементы интерфейса.
Поэтому отдельно была сделана логика освобождения ресурсов. Для видеофонов реализовал механизм подсчета ссылок, чтобы корректно освобождать память после закрытия использующих их элементов.
С точки зрения борьбы с производительностью это тоже важно: утечки video, canvas и загруженных видеофонов со временем бьют по памяти, а затем начинают ухудшать и fps, и общую отзывчивость интерфейса.
7. UI и продуктовые ограничения
В интерфейс была добавлена возможность выбрать режим виртуального фона: размытие, картинка или видео. При этом на уровне настроек конференции была предусмотрена и продуктовая опция, позволяющая оставить только режим размытия, если полноценные фоны в конкретном сценарии нежелательны.
Это было полезно не только как бизнес-настройка, но и как средство контроля производительности: для части клиентов или тарифов можно было осознанно оставить только более легкий режим.
Результат
В итоге в продукте появился полноценный виртуальный фон, встроенный в конференцию:
- с несколькими режимами работы;
- с горячим переключением во время звонка;
- с пользовательской загрузкой фонов;
- с хранением тяжелых видеофонов на клиенте;
- с учетом производительности и освобождения ресурсов.