Виртуальная камера для WebRTC
Небольшое введение
Едва ли кто-то избежал использования видеоконференций. К назначенному времени проверяем свой skype look, усаживаемся поудобнее и общаемся с коллегами.
Строго говоря, при всем многообразии платформ, вариантов немного: либо вебкамера, либо коллеги целый час наблюдают на экране ваши инициалы. Использовать камеру бывает не всегда удобно, да и конфузы случаются. Второй вариант смотрится несколько недружелюбно…
А еще варианты? да пожалуйста!
если есть возможность пропатчить фронтенд, запускаем легковесную модельку, чтобы замылить или заменить фон. Правда, от невыспавшейся физиономии это не спасает
можно подойти к задаче по-взрослому: под linux, например, запускаем v4l2loopback и рисуем в виртуальную вебкамеру что душе угодно, в зависимости от фантазий и возможностей железа. Если GPU позволяет, можно пропатчить, например, rad-nerf и вложить свою речь в уста Обамы, или даже тайком записать начальника на видео и по нему, за несколько часов, обучить модель. При рендеринге, правда, появится изрядная задержка, и придется либо мириться с липсинком, либо использовать в виртуальные аудиоустройства, либо ухудшать фонемную анимацию за счет использования мел-спектрограмм. И хорошо бы, чтобы ваша ноутбучная GTX 4060 не перегрелась за время разговора
а если в ноуте GPU слабенькая? Тоже не беда, зацикливаем свой ролик, и wav2lip дорисует на нем движения губ, густо замазывая погрешности. Красота!
Правда, с масштабируемостью у подобных подходов беда. Да и, вообще, как-то тупиково все это.
И мы пойдем другим путем!
Итак, есть желание рассказать про нашу собственную технологию виртуальной () персонифицированной () камеры для WebRTC (*).
Начнем с последнего слова (*). Если вы не используете совсем уж динозавров типа skype, то с вероятностью, стремящейся к единице, вы еженедельно сталкиваетесь с WebRTC.
Строго говоря, WebRTC — это целый сонм технологий. Тут и работа с локальными устройствами, и проковыривание всяких там nat-ов, и контроль соединения, и разнообразные заморочки с кодированием аудио-видео, и шифрование…
Но, в контексте данной задачи, нам важно, чтобы
JS код в браузере захватил аудиоустройство пользователя (getUserMedia).
В peerconnection должны уйти аудио и видео треки, синхронные между собой А посередине вся магия. О ней мы и поговорим.
Наша камера (*) виртуальная, потому что видеокамеру вашего девайса мы не используем, но видео выдаем. Откуда же возьмется видеодорожка? Странный вопрос. Из канваса, конечно! Ибо для WebRTC, по большому счету, безразлично, откуда появился видеотрек: из камеры ли, из канваса или с экрана. Таким образом, нам надо анимировать 3D модель и отрендерить кадры в канвас.
Пара слов про анимацию
Грубо говоря, анимацию можно условно разделить на 2 части: «фоновая», не связанная с произносимыми звуками (микродвижения и моргание глаз, повороты головы, движение на лбу и переносице, кадык и тп), и фонемная, соответствующая произносимому звуку. Очевидно, для первой части анимации можно использовать предзаготовленные паттерны, для второй необходимо в реальном времени (или близко к тому) вычислять некоторые параметры, что мы и делаем посредством легковесных моделей.
Итак, частотой кадров мы должны синтезировать картинки на основе 3D модели и входных векторов, описывающих состояние анимационных паттернов в данный момент времени.
Оставив в стороне сетки, есть два основных способа рендеринга 3D модели:
на основе параметрической модели (рига)
морфинг с весовыми коэффициентами, определяемыми параметрами выше. Именно так мы и делаем:
идентифицируем юзера (вы же не хотите, чтобы под вашей моделью пользовался какой-нибудь тролль?)
скачиваем с облака Флексатар — условно говоря, файл с набором данных для image based rendering. Можно себе это условно представить как набор изображений 3D модели с разных ракурсов (на всякий случай, нет в английском такого слова) и с разными снапшотами мимики. Да, автокоррекция все еще пытается исправить слово Флексатар, но мы сделаем все возможное, чтобы оно, вместе с нашей технологией, стало массовым
Отправляем аудио с микрофона на обработку, добавляем к полученному вектору анимационный, «смешиваем» картинки и отрисовываем с WebGL.
Аудиодорожку, задержанную на часть скользящего окна для вычислений, отправляем вместе с видео из канваса.
После этого ничего не подозревающий SFU сервер, раздающий треки участникам внутри комнаты, отправит ваше медиа коллегам, и они увидят, как вашим голосом говорит Крош или Нюша из Смешариков.
А как же задержка? Не страшно, коллеги ничего не заметят. Мы же можем разговаривать по телефону с людьми с другой стороны планеты, хотя задержка при этом выше, особенно с использованием спутниковых каналов и кодеков.
Задержка — это же эхо? Тоже нет: эхо — отражение от «дальнего конца», то есть акустическая петля вашего голоса из динамиков коллег в их же микрофоны, и WebRTC борется с этим штатным образом.
Что касается задержки на время обработки, это всегда компромисс. Одна крайность — обрабатывается фраза целиком, происходит распознавание текста с коррекцией на основе языковой модели. Далее используется forced alignment для привязки правильных фонем ко времени, и качество анимации лимитируется только профессионализмом разработчика алгоритма. Например, чтобы губы не шлепали, они должны «склеиваться» и тянуться при разлипании. Но мы же не про кино, и задачей является создание комфортной иллюзии живого собеседника в реалтайме, и мы не можем себе позволить коррекцию. Качество несколько ухудшается, и это плата за время:»- Нет в мире совершенства! — вздохнул Лис»
Создание 3D моделей
Мы не всегда хотим разговаривать с коллегами в образе жизнерадостного Копатыча. Переходим к самому интересному: (*) персонифицированная. За 5 лет выработали свой алгоритм создания 3D модели, на основе которой создается Флексатар. Да, если есть потребность, мы умеем экспортировать 3D объект в виде меша требуемой полиномиальности и текстур, но для задач реалтайм общения этого не надо.
Для расчетов требуется GPU, но на 3080 это занимает порядка 15 секунд при смешной загрузке. Для создания флексатара потребуются 5 фото: одно фронтальное и 4 с небольшим (что важно) поворотом головы. И это можно сделать прямо из браузера, а в конце статьи есть ссылка на гит, как заставить модель говорить.
Для лучшего качества, в нашем тестфлайте на iOS есть еще возможность создать модель челюстей и вписать их в нужное место головы, что значительно улучшает визуальное восприятие. Но с веба тоже вполне разумно, на наш взгляд, получается.
Поскольку это 3D, мы можем не просто создавать флексатары, но и смешивать их, добавляя неуловимые ассоциации. Но это уже другая история.
Гиты и приглашения
Исходники анимирования аудиозаписи в браузере: https://github.com/dmisol/sfu2/blob/main/static/webgl.html
Гит с виртуальной вебкамерой: https://github.com/dmisol/flexatar-virtual-webcam
Помимо этого, у нас запущен тестовый сервер, https://flexatar.com с серверной версией рендеринга, где SFU на библиотеке PION (GOLANG) декодирует OPUS аудио для обработки и собирает свежеотрендеренные кадры в H264 видеодорожку. На этом сервере можно создать свой флексатар, пообщаться с другими людьми (если они онлайн), а также посмотреть браузерную анимацию на WebGL. *Естественно, когда он жив и не используется для экспериментов
Исходники SFU тут https://github.com/dmisol/sfu2
Вся работа производилась на протяжении 5 лет очень небольшой командой, без финансирования и, в общем случае, в свободное от основной работы время (успешно избегая конфликта интересов).
В настоящий момент, помимо улучшения качества, мы занимаемся
портированием серверной части на AWS и, частично, Яндекс облако.
Планируем интеграции с различными SFU, для начала, Janus и Livekit.