Ой, Я Опаздываю

К нам часто приходят с этой проблемой, но нужно сразу уточнить: обычно это мужчины, а мы доставляем видеоролики.

О чем мы говорим? Речь идет о сокращении задержки между моментом, когда что-то происходит перед камерой, и моментом, когда это достигает зрителя.

Понятно, что лекция по квантовой физике будет транслироваться дольше, чем Comedy Club, но над техническими деталями мы еще работаем.

Прежде чем перейти к обсуждению задержек (они же задержки, задержки), нам необходимо ответить на очень важный вопрос: зачем вообще их уменьшать.

Уменьшите задержку Я хочу почти всегда, но необходимый не всегда.

Так, например, прямой эфир острого политического ток-шоу в принципе должен отстраняться от прямого эфира на 3 минуты, чтобы можно было оперативно отреагировать на резкое развитие дискуссии, а вот вебинар или удаленное управление дрону нужна минимальная задержка, чтобы люди могли спокойно перебивать друг друга, и груз упал точно в цель.

Прежде чем двигаться дальше, давайте констатируем один важный факт: снижение задержки при трансляции видео и звука — дело дорогое, причем нелинейное, поэтому в какой-то момент вам нужно остановиться на необходимой задержке, а для этого нужно вернуться назад и понять.

почему вам нужно его уменьшить.

Это знакомство не просто так.

Мы провели опрос среди наших клиентов, и выяснилось, что есть противоречивое желание: те, кто транслирует телеканалы, хотят потокового вещания с низкой задержкой.

Никто не объяснил почему, я просто хочу.



Генерация задержки

Давайте разберемся, как формируется задержка при передаче видео.

Примерная схема доставки видеосигнала (схема видеотракта) следующая:

  1. Изображение с сенсора камеры записывается в видеопамять.

  2. видеокодер помещает необработанное изображение в буфер кодирования
  3. Алгоритм сжатия видео находит оптимальный способ сжатия нескольких видеокадров в буфере.

  4. сжатый видеокадр отправляется в буфер доставки видео сервера (если он есть)
  5. видеокадр передается по UDP или копируется в буфер ядра TCP для отправки
  6. байты доходят до клиента и добавляются в ядерный буфер для приема сетевых данных
  7. связаться с клиентом
  8. возможно добавлено в буфер сортировки кадров
  9. оттуда они при необходимости добавляются в буфер для компенсации колебаний скорости сети.

  10. из него они передаются в декодер, который накапливает свой буфер для b-кадров
  11. декодер декодирует кадр и отправляет его на отрисовку
Это примерная схема, в некоторых случаях выбрасываются некоторые детали, а в некоторых случаях добавляются дополнительные буферы.

Но в целом мы видим: буферы, буферы, еще буферы, снова буферы.

Почему? Да, потому что буферизация — это распространенный способ снизить затраты и увеличить общую пропускную способность.

Есть еще один момент: буфер помогает сглаживать колебания.

Если скорость передачи по сети колеблется, не беда, на старте загрузим больше байт/кадров и пока интернет восстановится, будем проигрывать то, что есть в буфере.

Те.

Отметим довольно упрощенный тезис: буферы нужны для оптимизация за счет пакетной обработки данных и для компенсация колебаний характеристик видеотракта .

Чтобы сократить задержку между происходящим и тем, что видит зритель, необходимо системно работать на каждом этапе.



Подробности



Снятие с датчика

Вроде бы мелочь, но в старом добром аналоговом телевидении можно начать проигрывать строчку на телевизоре еще до того, как ее закончат снимать (кстати, я тут утрирую, но будет интересно узнать, как это на самом деле является).

Но если присмотреться, то можно понять, что сенсор сегодня минимум 2 мегапикселя, а то и больше.

К нему подключен вовсе не Intel Xeon, а минимально работоспособное железо, которое тратит время на простое копирование данных.

Насколько мне известно, на данный момент не существует широко распространенных технологий передачи видео, позволяющих работать с сырым видео в режиме потоковой передачи пикселей.

Те.

Пока весь кадр не будет захвачен с сенсора, с ним ничего сделать нельзя.

Я не готов дать здесь точную оценку задержки.



Буфер кодирования

Нкодер занимается крайне ресурсоемкой задачей, а также жутко нагружает шину данных между памятью и процессором.

Ему нужно перебрать разные комбинации вариантов сжатия видео, найти разницу между соседними кадрами и проделать кучу сложных математических вычислений.

Учитывая, что FullHD-видео с частотой 25 кадров в секунду составляет порядка гигабита в секунду (100 мегабайт), нагрузка колоссальная.

Но, пожалуйста, не совершайте классическую ошибку, путая загрузку процессора с задержкой.

Время сжатия кадра все равно меньше 1/fps (иначе не придется дергаться, все равно ничего не получится), а кодер создает гораздо большую задержку.

Дело в том, что кодер накапливает в буфере несколько последовательных необработанных кадров, чтобы выдать минимально возможный битрейт с максимально возможным качеством.

Задачи, для которых здесь создается буфер:

  • поддержание среднего битрейта потока.

    Если в одном кадре очень хочется сделать качество лучше, то на остальных кадрах нужно постараться подтянуть его

  • подбор оптимальных кадров для обращения.

    Иногда бывает, что стоит обратиться не к предыдущему кадру, а к следующему.

    Это приводит к кадровым изменениям и экономии трафика до 15-20%.

С этой задержкой можно поиграть, но в первую очередь это приведет к увеличению битрейта.

На сайте есть хороший пост, который оставил нас от Автор libx264 о кодировании с малой задержкой .

Это оно.

Итого здесь можно сделать за 1-2 кадра (по 40 мс), а можно потратить до 3-5 секунд, но сэкономив битрейт. Помните, я говорил вначале, что за низкую задержку приходится платить? Теперь вы можете начать платить в битрейте.



Буфер на сервере

Пожалуй, самый частый вопрос, который мы получаем о задержке: «У меня очень большая задержка при трансляции через HLS, где можно убрать буфер на сервере».

На самом деле буферизация на сервере вполне возможна, например, при упаковке mpegts очень хочется подождать перед отправкой аудиокадров, чтобы поместить несколько кадров в один PES-пакет. Или при упаковке таких протоколов, как HLS или DASH, обычно приходится ждать несколько секунд. Здесь важный момент: например, mpegts любит упаковывать несколько аудиокадров в один кадр PES. Теоретически вы можете открыть пакет PES, начать записывать в него то, что у вас есть, и отправить в сеть, затем отправить видеокадр, а затем продолжить с другим видеокадром.

Но здесь есть общая проблема: аудиокадр PES содержит свою длину, а это значит, что вам нужно накапливать звук.

Накопление означает буфер, означает увеличение задержки.

Некоторые серверы буферизуют кадры даже при использовании покадровых протоколов, таких как RTMP, чтобы снизить нагрузку на процессор, поскольку однократная отправка 100 килобайт обходится дешевле, чем двойная отправка 50 килобайт. Те.

тут все напрямую зависит от протокола: если у нас на сервере HLS или DASH, то буферизация хотя бы сегмента (1-10 секунд) неизбежна.

Если это покадровый протокол, то в этом нет необходимости; можно безопасно отправлять кадры всем клиентам по одному, но это пока делается редко.

Если мы откуда-то получаем RTP, например (от RTSP/RTP-камер), то теоретически мы можем раздавать RTP-пакеты клиентам сразу после их получения.

Это даст невероятное сокращение задержки менее чем на один кадр.

На практике этот подход реализуется редко, поскольку он создает огромную сложность программирования и резко сужает вариативность использования программного обеспечения.

Чаще всего серверы потокового видео работают с кадрами, очищенными от контейнеров и протоколов.

Здесь есть маленькая деталь: есть инициатива.

CMAF с низкой задержкой .

Суть идеи в том, что при поступлении опорного кадра (он же ключевого кадра) сервер объявляет всем клиентам новый сегмент. Все клиенты сразу начинают его загружать, а затем получают покадрово через прогрессивную загрузку http. Таким образом, вы получаете передачу файлов с их кэшированием на промежуточных CDN, а также возможность без задержек получать кадры при подключении к серверу, который может раздавать их без буферизации.

Это все еще инициатива и в разработке, но может стать интересной.

Итого: в принципе мы можем отказаться от кадрового буфера на сервере, если не используем HLS, но даже если HLS, то при особых условиях можно что-нибудь придумать.



Сетевой буфер для отправки

Мы подошли к сути вопроса, камню преткновения и бесконечной пересылке видео туда и обратно: UDP или TCP? Потери или непредсказуемые задержки? А может, совместить? Теоретически в идеальном мире, где нет неудачные роутеры , UDP проходит со скоростью ping или теряется, а TCP может замедлить отправку.

Как только мы начинаем отправлять видео по TCP, возникает вопрос не только о выборе протокола, позволяющего разрезать поток на кадры, но и о размере выходных буферов в ядре.

Чем больше буфер ядра, тем проще распространять программное обеспечение и тем меньше переключений контекста можно выполнить.

Опять же из-за увеличения задержки.

Увеличиваем буферы ядра и быстро теряем контроль над скоростью загрузки — становится сложно контролировать отправку кадров и на сервере становится непонятно, скачивает ли клиент видео или нет. Если шлем UDP, то нужно решить, что делать с потерей пакетов.

Существует возможность повторной передачи пакетов UDP (разновидность суб-TCP), но для этого требуется буферизация на клиенте (см.

ниже).

Есть вариант организовать по сети что-то вроде RAID-5: к каждому UDP-пакету добавляется избыточность, позволяющая восстановить один пакет из, скажем, 5 (см.

FEC, Fountain Codes и т.п.

).

Это может потребовать увеличения задержки сервера для расчета такой избыточности, а также увеличивает битрейт на 10-30%.

Считается, что избыточность не требует дополнительного буфера на клиенте или хотя бы будет 1-2 кадра, а не 5 секунд (125 кадров).

Есть более изощренный вариант: закодировать видео в H264 SVC, т.е.

в один пакет положить данные для восстановления худшего качества кадра, в следующий данные для улучшения качества и так далее.

Потом эти пакеты маркируются разным уровнем значимости и умный, хороший, добрый роутер обязательно разберется по пути и начнет выкидывать самые ненужные кадры, постепенно снижая качество.

Вернемся в реальный мир.

С ФЭК да как хорошие обещания так и реальность от Google: «XOR FEC не работает» .

Это до сих пор неясно и не было ясно уже очень давно.

С другой стороны, FEC уже давно используется в спутниковой доставке, но другого контроля ошибок там нет. С SVC все хорошо, кроме того, что он не взлетает. Напоминает JPEG2000 или вейвлеты: все хороши, но чего-то не хватает для завоевания мира.

Фактически он используется в закрытых реализациях видеоконференцсвязи, где сервер и клиент находятся под контролем, но этот механизм нельзя использовать сразу.

R-UDP на самом деле сложен, заменяет TCP, используется редко и хорошо применим там, где подходит HLS с его задержкой в 30 секунд. Существует опасность ввязаться в повторную реализацию TCP, что можно считать практически невыполнимой задачей.

Есть мнение, что подобный подход с UDP хорошо подходит для отправки по каналам с гигантскими RTT и потерями, поскольку не замедляет передачу для ее подтверждения.

Важным моментом является то, что в случае с потоковым видео вообще нет необходимости замедлять отправителя: трафик подается именно с той скоростью, с которой он необходим.

Если начнет тормозить, то можно вообще не передавать, а выбрать более низкое качество.

TCP, с другой стороны, является очень общим протоколом доставки и имеет предположения, которые неверны для прямого вещания:

  • Вам необходимо либо перенести все данные, либо разорвать соединение.

    Для прямого эфира это не тот случай, можете смело выбрасывать то, что не смогли отправить, лучше видео рассыпется на квадратики, чем начнет залипать

  • Передачу данных можно замедлить, чтобы их можно было передавать быстрее.

    И для прямого вещания это тоже не актуально: либо общей толщины канала хватает для передачи, либо нет. Видеопоток не будет транслироваться быстрее или медленнее (без перенастройки транскодера)

Следствием этого является тот факт, что большой пинг на большом расстоянии может начать замедлять TCP, даже несмотря на то, что пакеты движутся быстро.

UDP будет отправлять пакеты со скоростью реального времени: не быстрее, но и не медленнее, и подтверждение доставки не требуется.



Доставка клиенту

Увеличение задержки при доставке от сервера клиенту складывается из самой задержки передачи пакета и процента потерь.

Высокие потери приведут к замедлению доставки из-за повторной передачи данных в случае TCP. В случае с UDP механизмы восстановления будут активироваться чаще, либо видео будет чаще крошиться.

В любом случае вынужденный выбор маршрута типа: не отправлять видео напрямую из Москвы в Таиланд, а делать это через облако Amazon в Сингапуре (личный опыт), но чудес не бывает, мы уже давно застряли на скорости света, поэтому нет никаких других способов, кроме физического движения, о которых я не могу рассказать вам поближе.

Эта часть может как уложиться в 10 мс, так и растянуться до 300 мс (при таком RTT вообще сложно добиться приличной скорости).

В редких случаях подобные вопросы решает CDN, но на практике особо на это надеяться не стоит и уж точно не стоит доверять маркетологам, готовым обещать что угодно.

Самое смешное, что основная проблема может возникнуть на последнем метре от Wi-Fi роутера до ноутбука.

Иногда достаточно подключить кабель к ноутбуку, чтобы удивиться тому, насколько быстрым может быть Интернет. Продолжение следует. В следующей публикации мы рассмотрим, что происходит с клиентом.

Теги: #стриминг видео #low-latency #разработка систем связи

Вместе с данным постом часто просматривают: