Ой, у меня задержка

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

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

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

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

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

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

    Формирование задержки


    Давайте разберемся, как формируется задержка при передаче видео. Примерная схема доставки видео сигнала (схема видеотракта) следующая:

    1. с сенсора камеры снимается изображение в видеопамять
    2. видео энкодер кладет сырое изображение в буфер кодирования
    3. алгоритм сжатия видео находит оптимальный способ компрессии нескольких видео кадров в буфере
    4. сжатый видеокадр отправляется в серверный буфер доставки видео (если такой есть)
    5. видеокадр передается по UDP или копируется в ядерный буфер TCP для отправки
    6. байты долетают до клиента и складываются в ядерный буфер приемки сетевых данных
    7. доходят до клиента
    8. возможно складываются в буфер сортировки кадров
    9. оттуда складываются при необходимости в буфер компенсации флуктуации скорости сети
    10. из него отправляются в декодер, который накапливает свой буфер для b-frames
    11. декодер декодирует кадр и отправляет его на отрисовку

    Это примерная схема, в некоторых случаях какие-то детали выкидываются, где-то добавляются ещё буферы. Но в целом, мы видим: буферы, буферы, ещё раз буферы, опять буферы.

    Почему? Да потому что буферизация — это обычный способ снизить стоимость, повысить общую пропускную способность. Есть ещё один момент: буфер помогает сгладить колебания. Колеблется скорость передачи по сети – не беда, закачаем на старте побольше байт/кадров и пока интернет восстанавливается, будем играть то, что лежит в буфере.

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

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

    Детали


    Снятие с сенсора


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

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

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

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

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


    Энкодер занимается крайне ресурсоёмкой задачей, а так же жутко нагружает шину передачи данных между памятью и процессором. Ему надо перебрать разные комбинации вариантов сжатия видео, найти разницу между соседними кадрами и сделать кучу сложных математических вычислений. Учитывая, что FullHD видео на 25 кадрах в секунду — это порядка гигабита в секунду (100 мегабайт), нагрузка огромная. Но просьба не совершать классическую ошибку и не путать нагрузку на процессор с задержкой. Время, которое уходит на сжатие кадра всё равно меньше 1/fps (иначе уже можно не дергаться, всё равно ничего не получится), а задержку энкодер создает гораздо больше.

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

    • поддержание среднеровного битрейта потока. Если в одном кадре очень хочется сделать качество получше, значит на остальных кадрах надо постараться поджаться
    • выбор оптимальных кадров, на которые можно ссылаться. Иногда так бывает, что стоит сослаться не на предыдущий кадр, а на следующий. Таким образом возникают перестановки кадров и экономия трафика до 15-20%

    С этой задержкой можно играть, но прежде всего это будет приведет к росту битрейта. Есть хороший пост на покинувшем нас сайте от автора libx264 о low latency кодировании. Вот это оно.

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

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

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


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

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

    Важный момент здесь: например в mpegts любят упаковывать в один PES кадр несколько аудиокадров. Теоретически можно открыть PES пакет, начать в него писать то что есть и слать это в сеть, потом послать видеокадр, а потом продолжить с другим видеокадром. Но здесь есть обычная проблема: в аудио PES кадре идет его длина, значит надо накопить аудио. Накопить, означает буфер, означает рост задержки.

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

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

    Если мы получаем откуда-то например RTP (с камер RTSP/RTP), то теоретически можем раздавать клиентам сразу RTP пакеты по их получению. Это даст чумовое снижение задержки меньше одного фрейма. На практике этот подход реализуется редко, потому что создает огромную сложность программирования и резко сужает вариативность использования софта. Чаще всего видеостриминговые серверы работают с кадрами, очищенными от контейнеров и протоколов.

    Здесь есть маленькая деталь: существует инициатива CMAF low latency. Суть идеи в том, что когда приходит опорный кадр (он же keyframe), то сервер анонсирует новый сегмент всем клиентам. Все клиенты срочно начинают его скачивать и тут они получают кадр за кадром через http progressive download.

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

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

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

    Сетевой буфер на отправку


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

    В теории, в идеальном мире, где нет неудачных роутеров, UDP проходит со скоростью прохождения пинга или теряется, а TCP может тормозить отправку.

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

    Увеличиваем ядерные буферы и быстро теряем контроль за скоростью скачивания — становится тяжело контролировать отправку кадров и на сервере становится непонятно: клиент скачивает видео или уже нет.

    Если шлем по UDP, то надо решать, чего делать с потерей пакетов. Есть вариант с повторной пересылкой UDP пакетов (эдакий недо-TCP), но он требует буферизации на клиенте (см ниже). Есть вариант с организацией чего-то типа RAID-5 поверх сети: в каждый udp пакет кладется избыточность, позволяющая восстановить один пакет из, скажем, 5 (см FEC, Fountain Codes и т.п.). Это может требовать роста задержки на сервере для вычисления такой избыточности, а так же поднимает битрейт на 10-30%. Считается, что избыточность не требует экстра буфера на клиенте, или по крайней мере он будет 1-2 кадра, но не 5 секунд (125 кадров)

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

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

    С FEC есть как хорошие обещания так и реалии от гугла: «XOR FEC не работает». Пока непонятно и непонятно уже очень давно. С другой стороны в спутникой доставке FEC давно используется, но там нет никакого другого контроля за ошибками.

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

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

    Есть мнение, что подобный подход с UDP хорошо годится на пересылке через каналы с гигантским RTT и потерями, потому что не тормозит пересылку на её подтверждение. Важный момент заключается в том, что в случае с видеостримингом тормозить отправляющего вообще не нужно: трафик подается ровно с той скоростью, с которой он нужен. Если начать тормозить, то можно вообще не передавать, а выбирать поменьше качество. В свою очередь TCP это очень общий протокол доставки и у него есть допущения, которые неверны для прямого эфира:

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

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

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


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

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

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

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

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

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

    Комментарии 33

      +1
      Переключаясь по вкладкам, и увидев заголовок, долго не мог осознать на том ли я ресурсе нахожусь
        +2

        Кликбейт такой кликбейт.

        0

        Насчёт предложения переписать tcp и о том, что это долго. Так подумать, а в сфере протоколов низкого уровня ничего и не менялось десятилетие, большой срок для ИТ. Это потому что найден золотой ключ, ничего не нужно улучшать? Или все же (как для стриминга) потребность есть но дорого, долго и никто из крупных корпораций не подписался на это?

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

          во-вторых, стриминг видео действительно немного отличается от данных. Тут очень ровные потоки данных: всплесков трафика зачастую не бывает. Во-вторых можно терять данные, выбрасывать их. Из потока текстовых данных обычно выбрасывать ничего не хочется.
            +1
            Вы используете TCP BBR congestion control? Google использует его для раздачи видео YouTube, сильно помогает.
              0
              да, есть несколько разных рекомендаций. С bbr не сталкивался, есть рекомендации по hybla.

              честно говоря, лично я ни разу не видел, что бы у клиента всё было плохо и смена tcp cc всё делала сразу хорошо. Как правило смена OVH на хостинг помогает сразу и радикально.
                0
                А что не так с OVH? Стоят железные сервера, всё ништяк. Кроме тех случаев, когда у них с сетью что-то, но это редко бывает.
                  0
                  очень любят реселлить сеть, продавая 10 гигабит по 100 баксов. а наши клиенты это любят брать и хотят верить в чудеса и сказки.
                0

                Стриминг на ютюбе далеко не гладкий. Периодические зависания для них вполне норма.

                0
                Чисто теоретический вопрос — SCTP нельзя использовать в качестве транспорта? Он как раз про надежность и про ровные потоки данных, в тяжелых телекомах он весьма популярен. Хотя я не уверен, что он проедет через public internet, где-то едет, где-то — нет.
                  0
                  можно и где-то могут даже пользоваться. Можно даже указать на то, что SCTP сразу multihomed и позволяет слать пакеты по разным каналам (что бы было веселее собирать на клиентской части), но пока это не массово, как и сам SCTP. Он есть в webrtc для передачи данных и им пользуются для torrent-like вещания, ошибочно называя это p2p стримингом, но это всё таки про HLS.
                  0
                  А на всякие варианты по-верх UDP не смотрели (enet)?
                    0
                    классическая схема с доставкой по UDP выглядит так: рассылающий сервер хранит у себя последние N пакетов. Принимающий клиент держит буфер и если в буфере оказываются дырки (все пакеты нумерованные), то он шлет серверу команду: перепошли мне пакет.

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

                    Но что-то такая схема не особо пошла.
                  0
                  Как было сказано на одной из конференций: «Представьте что вам нужно транспортное средство, которое одновременно будет ездить по асфальту, луне, пустыне и болоту, оно будет ездить, но везде плохо, например по скорости проиграет обычному автомобилю на асфальте» Так и TCP он должен работать в ДЦ c 40G каналами и через спутник, где высокое Latency, поэтому он такой какой есть, его улучшают, но придумать что-то такое же универсальное, очень тяжело.
                    0
                    да вот как-то получилось, что сравнение то так себе: TCP в целом везде неплох и его очень сложно поменять на что-то другое.
                  0

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

                    0
                    да, такая система работает у нас в серверной мозаике в видеофиксации судебных заседаний. Получилось обеспечить синхронизацию губ на соседних IP камерах.

                    Надо ставить метки абсолютного времени на кадры (UTC), но это очень сложно сделать, потому что IP камера не может сообщить, когда был снят кадр, можно лишь узнать, когда он был получен в сжатом виде, т.е. надо мерять ту самую задержку в энкодере.
                    0
                    В мире беспилотников ( любительских) в FPV сегменте, до сих пор нет хорошей связки цифрового видео тракта и передачи видео картинки в очки (с минимальной задержкой < 50 мс). Обычно это либо HD картинка максимум, но большая задержка, либо намного хуже качество и аналоговая, но с минимум задержки, либо рвется связь видео потока. Исключение DJI продукция. Хотелось бы узнать, как с высоты вашего опыта можно было бы реализовать ( и на каких решениях, протоколах, кодеках) передачу FullHD ( или выше) с носителя, где видео тракт, скажем, максимум по весу = 500 грамм с камерой на борту, мог бы передаваться по усиленному каналу WIFI ( 500 метров и больше), для трансляции в FPV шлем full hd цифрой. Очень насущная проблема. И да, очень важна минимальная задержка ( идеал <25 мс).
                      0
                      я бы думал в таком направлении: писать оригинальное качество на флешку, а слать возможно плавающее качество. Транспортом выбрать UDP, возможно FEC. И поглубже поковыряться в wifi: там есть свои задержки, лаги и ретрансмиты.
                        +1
                        Первое выкинуть wi-fi. Дальше осовыные зедержки это на приеме кадра и запихивание его в SoC для сжатия. И еще надо учитывать fps матрицы. Например если у нас 30 фпс то мы не можем сделать задержку меньше 33мс просто физически(SoC который может обрабатывать на сжатие не полный кадр мне ни разу не попадался). Соответственно нам нужно матрица минимум 60 фпс а лучше 120. И потом мы просто отбрасываем лишние кадры.
                        Тоесть для FPV больше критична матрица и SoC которые умеет быстро сжимать и который умеет отдвать нарезанные кадры с енкодера.
                        Плавающее качество мне кажется плохим решением из-за радиоканала.
                          0
                          на что менять wifi?
                            0
                            Ну для fpv используется свой радиоканал с односторонним передатчиком и приемником.
                              0
                              аналоговый fullhd видеолинк типа AHD в камерах? Может всё таки есть какая-то разумная цифра?
                                0
                                Нет цифра. Например можно взять что-то типа dvb-t просто уйти по частотам и просто формируем mpegts. Например у нас на очень старом SoC который только-только тянет fullhd, и модульной камере от панасонике на обычном HD при передаче на комп и софтовом декодировании получается 250мс.
                                  0
                                  Из готового есть разнообразные цифровые радиомодули до 2Мбит (знаю что мало — да и в реальных условиях будет еще хуже) или можно делать свое, взяв за основу какой-нибудь SDR вроде HackRF — благо, вся математика уже написана. Кстати, dvb-t вроде какие-то любители уже запускали, но там вопрос про задержки не стоял. В любом случае, довести до ума это будет сложно — DJI не зря за свои игрушки столько денег хочет
                          0
                          речь ведь о «локальном» стриминге, тут можно посмотреть на протокол/либу NDI. Использует «слабое» сжатие (FullHD ~100Mbs) поскольку рассчитан на гигабитную сеть и минимальную задержку, легко прикручивается. Если у Вас айфон и вайфай (5гц) то можете протестить на нашем JustWifiCam (аппстор). Вот один из юзкейсов использования.
                          image
                            0
                            У вас будет задержка явно несопостовимая для FPV. Меньше 100мс на обычных смартфонах можно и не мечтать.
                              0
                              речь об использованиях смартфона для FPV и не шла. речь о протоколе NDI который можно попробовать использовать для FPV.
                                0
                                Ага а канал где вы такой возьмете? Знаете 100мб/с с коптера это очень круто. И если хардварный энкодинг h264 есть то вот зачем нужен какойто левый формат и софтовое сжатие?
                                Сжимать в h264 можно быстро особенно если аппаратно делать(а только так и надо)
                          0
                          А у вас нет таблицы типа протокол/size/Cpu/latency?

                          Из собственных экспериментов могу сказать, что самый быстрый протокол из тех, что я сумел настроить и использовать это WebRTC.
                            0
                            webrtc стандартный для новых браузеров и по udp, поэтому у него не будет (не должно быть) плавающей задержки.
                              0
                              Немного странная логика: если что то используется для новых браузеров и по UDP, то у него нет задержки.
                                0
                                UDP выбран за то, что у него не возникает плавающей сетевой задержки. Она ожидается достаточно стабильной в районе времени пинга (половины, понятно).

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое