Борьба с потерями пакетов в видеоконференциях
Введение [embedded content]Когда говорят о передачи видео по сети, в основном речь идёт о видео-кодеках и разрешении. Собственно о передаче видео слышно не так и много. Здесь я бы хотел пролить немного света на проблему борьбы с потерями в сети при передачи видео в режиме видеоконференций. Почему потери — это так важно? Да потому что нельзя просто так взять и пропустить хоть один видео пакет (в отличии от аудио), т.к. любой приличный видео-кодек основан на том, что последовательные кадры отличаются не сильно и достаточно закодировать и передать только разницу между кадрами. Получается, что (почти) любой кадр зависит от предыдущих. И картинка при потерях разваливается (хотя некоторым это даже нравится). Почему видеоконференции? Потому что есть очень жесткое ограничение на реальное время, ведь задержка в 500 мс на круг (туда-обратно) уже начинает раздражать пользователей.Какие же существуют методы борьбы с потерями видео-пакетов? Мы здесь рассмотрим самый распространённый вариант — передача медиа по протоколу RTP — поверх UDP.RTP и UDPМедиа данные реального времени как правило передаются по протоколу RTP (RFC 3550). Здесь нам важно знать про него три вещи:
Пакеты пронумерованы по порядку. Так что любой разрыв в порядковом номере (sequence number) означает потерю (хотя может означать и задержку пакета — тут разница может оказаться очень тонкой). Помимо RTP пакетов стандарт предусматривает также служебные RTCP пакеты, с помощью которых можно всякое (см. ниже). Как правило RTP реализован поверх UDP. Это обеспечивает скорейшую доставку каждого отдельного пакета. Чуть больше про TCP написано ниже. Сразу замечу, что здесь речь идёт о пакетных сетях, например IP. А в таких сетях данные портятся (теряются) сразу большими порциями — пакетами. Так что многие методы восстановления одиночных/немногочисленных ошибок в сигнале (популярные, например, в DVB) здесь не работают.Мы будем рассматривать борьбу с потерями в исторической перспективе (благо технология видеоконференций достаточно молодая и ни один метод ещё не устарел окончательно).Пассивные методы Разбиение видеопотока на независимые кускиПервый успешный видео-кодек для конференции в сети — H.263. В нём были хорошо проработаны основные пассивные методы борьбы с потерями. Самый простой из них — разбить видео на куски, которые будут независимы друг от друга. Тем самым потеря пакета из одного куска не сказывается на декодировании остальных.Разбивать на куски нужно как минимум по времени, а можно ещё и по пространству. Разбитие по времени заключается в периодической (обычно раз в 2 с) генерации ключевого кадра. Это такой кадр, который не зависит от всей предыдущей истории, а значит и кодируется значительно (~5–10 раз) хуже обычного кадра. Без генерации ключевых кадров при любом количестве потерь рано или поздно картинка развалится.По пространству кадр тоже можно разбить. Для этого в H.263 используются GOBs, а в H.264 — slices. По сути это одно и тоже — куски кадра, кодирование которых не зависит друг от друга. Но для правильной работы нужно также обеспечить для каждого слайса независимость от других слайсов предыдущих кадров. Получается, как будто кодируются параллельно несколько видеопоследовательностей, из которых на выходе геометрически собирается итоговая картинка. Это, конечно, сильно портит качество кодирования (или повышает битрейт, что, в сущности, тоже самое).Зависимости между слайсами двух последовательных изображений. Оранжевым указаны участки, которые могли бы быть предсказаны по предыдущему изображению, если бы не ограничения по слайсам (а значит эти участки могли бы быть сжаты в 5–10 раз эффективнее)Тут важно заметить, что если генерация ключевых кадров — стандартная процедура (например, первый кадр всегда ключевой), то обеспечение истинной независимости слайсов — весьма нетривиальная задача, которая может потребовать переделывания енкодера (а откуда у вас енкодер и как трудно его переделать никому не ведомо).Восстановление ошибокПример восстановления одного потерянного слайса (пакета)Если уж потеря произошла, можно попробовать максимально восстановить потерянные данные по имеющимся (error resilience). Тут есть один стандартный метод, заложенные в H.263 кодеке: потерянный GOB восстанавливается за счёт линейной интерполяции окружающих GOBов. Но в общем случае картина более сложная и ошибка декодирования распространяется с каждым новым кадром (т.к. на новых кадрах могут быть ссылки на повреждённые участки предыдущего кадра), так что для разумного замазывания испорченных мест придёт применять изощрённые механизмы. В общем труда здесь много, а через 2 секунды придёт ключевой кадр и всю картинку обновит, так что хорошие реализации этого метода существуют, похоже, только в воображении разработчиков.Forward Error CorrectionЕщё один хороший метод борьбы с потерями — использовать избыточные данные, т.е. посылать больше, чем нужно. Но простое дублирование тут выглядит не очень хорошо ровно потому, что есть методы во всех отношениях более качественные. Называется это FEC (RFC 5109) и устроенно следующим образом. Выбирается группа медиа (информационных) пакетов заданного размера (например 5), а на их основе сознаются несколько (примерно столько же или меньше) FEC пакетов. Легко добиться, чтобы FEC пакет восстанавливал любой пакет из информационной группы (parity-codes, например RFC 6015). Несколько труднее, но можно, добиться того, чтобы N FEC пакетов восстанавливали N информационных при групповых потерях (например, коды Рида-Соломона, RFC 5510). В общем метод эффективный, часто легко реализуемый, но весьма дорогостоящий в плане канала связи.Активные методы Перезапросы пакетов и ключевых кадровС развитием видеоконференций быстро стало ясно, что пассивными методами многого не добьёшся. Начали применять активные методы, которые по своей сути очевидны — нужно заново отправлять потерянные пакеты. Существует три разных перезапроса: Перезапрос пакета (NACK — negative acknowledgement). Потеряли пакет — попросили его ещё раз — получили — декодировали. Запрос ключевого кадра (FIR — full intra-frame request). Если декодер понимает, что всё пошло плохо и достаточно давно, можно сразу просить ключевой кадр, который сотрёт всю историю и можно будет начать декодирование с чистого листа. Запрос обновления определённой области кадра. Декодер может сообщить енкодеру, что какой-то пакет потерян. На основе этой информации енкодер вычисляет, как далеко распространилась ошибка по кадру и обновляет тем или иным способом повреждённый регион. Как это реализовать понятно только теоретически, практических реализаций я не встречал. С методами вроде определились –, а как это реализовано на практике. А на практике есть RTCP пакеты — вот ими и можно воспользоваться. Cтандартов отправки таких запросов как минимум три: RFC 2032. На самом деле это стандарт упаковки потока кодека H.261 в RTP пакеты. Но этим стандартом предусмотрены и перезапросы первых двух типов. Этот стандарт устарел и заменён на RFC 4587, в котором предлагается такие пакеты игнорировать. RFC 4585. Действующий стандарт. Предусматривает все три варианта и даже больше. По на практике используется именно NACK и FIR. RFC 5104. Тоже действующий стандарт. Частично дублирует RFC 4585 (но не совместим с ним) плюс куча другой фунциональности. Ясно, что активные методы намного сложнее в реализации, чем пассивные. И не потому, что трудно сформировать запрос или перепослать пакет (хотя поддержка одновременно трёх стандартов несколько осложняет вопрос). А потому что здесь нужно уже контролировать происходящее, чтобы перезапросы не были слишком ранними (когда «потерянный» пакет просто ещё не успел дойти) или слишком поздними (когда уже давно пора было бы отобразить картинку). Ну, а в случае временных больших проблем в сети пассивные методы восстанавливают связь в течении 2-х секунд (приход ключевого кадра), в то время как наивная реализация перезапросов может запросто перегрузить сеть и не восстановиться никогда (примерно так подвисало видео в скайпе несколько лет назад).Пример зависания видео после 3х секундного разрыва связи при наивной реализации перезапросов.Но эти методы при адекватной реализации являются ещё и намного более качественными. Нет необходимости снижать качество за счёт генерации ключевых кадров, разбиения на слайсы или чтобы дать место FEC пакетам. В целом, можно добиться очень небольшого оверхеда по битрейту с тем же результатом, что и у «дорогих» пассивных методов.TCPСтало более-менее понятно, почему не используется протокол TCP. Это самый наивный метод перезапроса пакетов без серьёзных возможностей его контролировать. К тому же в нём предусмотрен только перезапрос пакета, а перезапрос ключевого кадра в любом случае придётся реализовывать поверх.Интеллектуальные методы Мы тут касались пока что только борьбы с потерями. А как же ширина канала? Да — ширина канала важна, и проявляется она в конечном счёте теми же потерями (плюс увеличением времени доставки пакета). Если видео-кодек настроен на битрейт, который превышает ширину канала связи, то пытаться бороться с потерями в этом случае — занятие малоосмысленное. В этом случае нужно снижать битрейт кодека. Вот здесь то вся хитрость и начинается. Как определить, какой битрейт выставить? Основные идеи следующие: Необходимо точно и оперативно следить за текущей ситуацией в сети. Например, через RTCP XR (RFC 3611) можно получать отчёт о доставленных пакетах и их задержках. При ухудшении условий сбрасывать битрейт (что такое ухудшение условий? Как быстро сбрасывать?). При нормализации условий можно начать прощупывать верхнюю границу битрейта. Чтобы при этом картинка не разваливалась, можно, например, включить FEC и поднимать битрейт. При наступлении проблем FEC позволит картинке остаться корректной. В общем именно интеллектуальные методы оценки параметров сети и подстройки под них на сегодня и определяют качество систем видеоконференции. У каждого серьёзного производителя есть своё проприетарное решение. И именно развитие этой технологии является основным конкурентным преимуществом систем видеоконференций на сегодняшний день.Кстати, стандарт 3GPP TS 26.114 (один из главных стандартов для построения промышленных VoIP сетей) утверждает, что в нём содержится описание подобного алгоритма для аудио. Не вполне ясно, насколько описанный алгоритм хорош, но для видео он не подходит.Машина состояний алгоритма адаптации к сетевым условиям в представлении художника (из 3GPP TS 26.114)