Realtime-подготовка и доставка высокодинамичного (спортивного) видео для мобильных устройств и SmartTV
Автор: Ким Бондаренко
Формат: Доклад
Качество VOD/IPTV в OTT

Немного о качестве. Когда начиналось появление OTT, еще в 2000-х, все провайдеры столкнулись в первую очередь с проблемами буферизации — это когда по сети не успевает доставляться достаточный объем контента к моменту его воспроизведения. Это всех очень сильно раздражало.
Приходилось выбирать между качеством картинки и частотой возникновения буферизации. Сжатие также было недостаточно эффективным, да и сети были недостаточно хорошими. В итоге картинка была очень плохой: повсюду наблюдались DCT-артефакты, квадраты скакали, резкость отсутствовала.
Проблему буферизации индустрия в целом постепенно решила внедрением адаптивного стриминга в протоколах HLS, а затем DASH. В них плеер автоматически переключается на подготовленные дорожки с более низким битрейтом либо плавно меняет битрейт, как вариатор в автомобиле.
Качество картинки стало улучшаться с развитием сетей и форматов сжатия. Декодирование видео в новых форматах, таких как MPEG-4 ASP (DivX) и H.264, требовало значительных вычислительных ресурсов, и какое-то время все так или иначе сталкивались с проблемами производительности.
Спустя какое-то время все устройства, в том числе планшеты и телефоны, то есть мобильные устройства, уже стали справляться с воспроизведением Full HD, и, казалось бы, на этом развитие OTT-индустрии несколько замедлилось.
Но если вы запустите рядом какую-нибудь спортивную трансляцию по кабельному телевидению и ту же трансляцию в каком-нибудь среднестатистическом OTT-сервисе или сервисе мобильного ТВ, то почти везде, за редким исключением, увидите, что чего-то не хватает. А не хватает того, что в кабельном телевидении картинка выглядит более живой.
Динамичность

Связано это с тем, что во втором случае мы имеем дело с 50 кадрами в секунду, а не с 25. Для простоты я буду говорить «50 и 25 кадров в секунду», хотя на практике существуют также системы с 60 и 30 кадрами в секунду. В данном случае это не принципиально.
Исторически частота 25 кадров в секунду пришла к нам из кинопленки. В свое время считалось, что этого более или менее достаточно, чтобы человеческий глаз воспринимал последовательность отдельных изображений как непрерывное движение. Однако в телевидении быстро выяснилось, что этого недостаточно, поэтому сразу перешли к 50 обновлениям изображения в секунду. Причина заключалась в особенностях кинескопных телевизоров. Изображение на экране формировалось построчно, сверху вниз, а люминофор начинал затухать практически сразу после прохождения электронного луча. К тому моменту, когда луч доходил до нижней части экрана, верхняя уже успевала заметно потускнеть. В результате экран постоянно мерцал. При частоте 25 Гц это мерцание было хорошо заметно и быстро утомляло зрителя, тогда как 50 Гц воспринимались значительно комфортнее.
Любительское видео пошло тем же путем. Запись на VHS также велась с частотой 50 обновлений в секунду, чтобы обеспечить совместимость с аналоговыми телевизионными стандартами. Записывать только 25 кадров в секунду было бы значительно сложнее: устройству воспроизведения пришлось бы где-то хранить каждый кадр и показывать его дважды, а в аналоговой электронике для этого просто не существовало удобного способа хранения целых кадров.
25 fps vs 50 fps
Здесь показано одно и то же видео: левая половина — 25 кадров в секунду, правая — 50. Если ваш проигрыватель воспроизводит 50 кадров в секунду без пропусков, разница в плавности динамичных сцен будет хорошо заметна.
Здесь можно увидеть разные типы контента. Сначала идут фрагменты спортивных трансляций, затем — любительское видео. С любительским видео произошла интересная история. Во времена VHS все привыкли к 50 кадрам в секунду. Затем появились первые цифровые видеокамеры, мощности которых уже не хватало для такой частоты кадров, поэтому многие из них записывали видео с частотой 25 кадров в секунду. Сегодня вычислительные возможности устройств снова выросли, и мы фактически вернулись к 50 кадрам в секунду. Современные видеокамеры и даже смартфоны, включая последние модели iPhone, способны записывать видео с такой частотой.
То же самое касается телевизионного вещания. Помимо спорта, это особенно хорошо заметно на бегущих строках. Любой контент с горизонтально движущимся текстом или графикой значительно выигрывает от частоты 50 кадров в секунду.
Далее показан пример рекламной вставки. Исходный ролик был получен в формате 25 кадров в секунду, а затем на backend мы преобразовали его в поток с частотой 50 кадров в секунду.
Как в OTT доставить 50 к/с?

Итак, мы определились с задачей: нужно найти способ подготовить и доставить конечному пользователю видео с частотой 50 кадров в секунду. На смартфоны, планшеты, ПК, set-top boxes, Smart TV и любые другие устройства, с которыми сталкивается OTT-провайдер.
Казалось бы, в чем проблема? Берем, обновляем всю систему, добавляем производительности — и доставляем. Но все не так просто. У существующих провайдеров уже есть большая пользовательская база со старыми устройствами. И оказывается, что где-то 50 кадров в секунду не будут воспроизводиться, где-то видео начнет тормозить, где-то появятся другие проблемы. А бизнес не может себе этого позволить.
Поэтому нужна обратная совместимость. Необходимо, чтобы у всех пользователей, у которых сервис уже работал, он продолжал работать без ухудшения качества и без жалоб. А те пользователи, чьи устройства способны воспроизводить 50 кадров в секунду, должны получить более плавную и динамичную картинку.
И, конечно, хочется не раздувать бюджет в несколько раз: не ставить рядом с текущей backend-системой еще одну такую же или даже более крупную систему и по возможности избежать кратного роста затрат.
Решение проблемы
Итак, какие вообще возможны решения? Первый вариант, который приходит в голову, — сделать так же, как поступили производители телевизоров. Они не могут вмешиваться в backend, поэтому внедрили алгоритмы удвоения частоты кадров, пытаясь из 25-кадрового видеопотока получить 50 кадров уже непосредственно на конечном устройстве.
Есть и второй вариант. Поскольку мы сами являемся OTT-провайдером, у нас гораздо больше свободы. Мы можем предварительно обработать видео на backend, а затем, если устройство это поддерживает, доставить ему уже подготовленный поток.
Разработка

Однако у варианта A есть еще один серьезный недостаток — он слишком требователен к вычислительным ресурсам. Выполнять удвоение частоты кадров на центральном процессоре практически невозможно для всего спектра устройств, которые приходится поддерживать OTT-провайдеру. На практике потребуется использовать графический процессор — GPU.
А что означает использование GPU в мире OTT? Это означает поддерживать огромное разнообразие устройств, графических процессоров и графических API. Несмотря на то что индустрия постепенно движется в сторону Vulkan, экосистема по-прежнему остается весьма неоднородной: Metal, DirectX, OpenGL, OpenCL и другие технологии. Все это разработчикам клиентских приложений придется поддержать.
Кроме того, необходимо добиться того, чтобы воспроизведение оставалось плавным везде. Мы ведь хотим повысить качество видео, а не получить обратный эффект. Если на каком-то устройстве не хватит производительности, начнутся подтормаживания, рассинхронизация звука или другие артефакты воспроизведения. В результате все возможные комбинации устройств и GPU придется тщательно тестировать, что значительно увеличивает стоимость разработки и сопровождения системы.
Батарейка

Артефакты

Вариант Б
Первый шаг — сформировать на backend мастер-поток с частотой 50 кадров в секунду. Если источник уже содержит 50 к/с (например, промышленный телевизионный сигнал), используем его напрямую. Если же исходный материал доступен только в 25 к/с, предварительно восстанавливаем недостающие кадры с помощью алгоритма интерполяции. При этом мы экономим вселенское электричество, и вычисления выполняются всего один раз для всех пользователей, а не отдельно на каждом устройстве.
Однако не все клиентские устройства способны воспроизводить поток с частотой 50 кадров в секунду. Поэтому необходимо обеспечить обратную совместимость, сформировав дополнительные потоки с помощью транскодирования. По сути, 50-кадровый поток становится еще одним уровнем над существующей ABR-лестницей адаптивного стриминга.
После этого остается обеспечить совместимость с конечными устройствами: определить, какие из них способны воспроизводить поток 50 к/с, а для остальных предоставить подходящие варианты. Одновременно формируются младшие потоки с более низким битрейтом, чтобы обеспечить стабильное воспроизведение в сложных сетевых условиях.
Источники

Какие источники видеосигнала встречаются на практике? Обычно OTT-провайдер получает контент через точки захвата. Это могут быть каналы семейства DVB, IP-мультикаст, где поток принимается напрямую с сетевого интерфейса, SDI-сигнал из телевизионной студии и многие другие источники.
При этом внутри одного и того же канала регулярно появляются самые разные типы контента: пользовательские видеоролики, рекламные вставки, архивные материалы и многое другое.
Если заглянуть внутрь такого потока, окажется, что даже на спортивном канале далеко не весь контент имеет частоту 50 кадров в секунду. Частота кадров может динамически изменяться в зависимости от типа материала, причем зачастую без каких-либо явных признаков или меток в метаданных.
Создать поток 50 к/с

Итак, первая задача — сформировать на backend поток с частотой 50 кадров в секунду. Независимо от типа исходного контента, на выходе на данном этапе мы всегда должны получать 50 к/с.
Мы разбиваем эту задачу на два под-этапа. Первый — фильтр деинтерлейсинга. Второй — фильтр удвоения частоты кадров.
Многие представляют деинтерлейсинг как простой видеопроцессор, который лишь убирает «гребенку» с изображения. На самом деле его задача значительно сложнее. Он должен определить тип входного видеопотока и, если это возможно, восстановить из него полноценный поток с частотой 50 кадров в секунду. Если это невозможно, то сформировать максимально качественный прогрессивный поток с частотой 25 кадров в секунду без артефактов чересстрочной развертки.
Второй этап — интеллектуальный фильтр удвоения частоты кадров. Он используется только в тех случаях, когда восстановить исходный поток с частотой 50 кадров в секунду невозможно. По своей сути этот алгоритм аналогичен технологиям, применяемым в современных Smart TV, и требует значительных вычислительных ресурсов. Разница в том, что теперь все вычисления выполняются на backend, где инфраструктура полностью находится под нашим контролем. Мы можем точно оценить требуемую производительность, выбрать аппаратную платформу и при необходимости использовать GPU конкретного производителя.
Deinterlacing

Несколько слов о деинтерлейсинге. Интерлейсинг и деинтерлейсинг появились еще во времена аналогового телевидения. Это вовсе не какая-то устаревшая патология, которая лишь создает «гребенку» на изображении и требует последующего исправления. На самом деле это очень удачный психовизуальный прием, позволивший существенно сократить объем передаваемых данных. Интерлейсинг одновременно решал две задачи. В динамичных сценах зритель воспринимал движение с частотой 50 обновлений в секунду, а в статичных сценах фактически получал изображение с частотой 25 кадров в секунду, но с удвоенным вертикальным разрешением. Все это работало практически автоматически благодаря особенностям кинескопных дисплеев и тому, как человеческие глаза и мозг воспринимают изображение.
Видео с чересстрочной разверткой принято обозначать буквой i (interlaced), а прогрессивное видео — буквой p (progressive). В обозначениях используются строчные буквы i и p.
Виды потоков

Какие типы потоков встречаются на практике? Когда мы начали разрабатывать этот фильтр, оказалось, что и здесь нас ждет настоящий зоопарк. После декодера у нас остаются только растровое изображение каждого кадра и временные метки. На информацию в метаданных, например о том, является ли поток чересстрочным или прогрессивным, на практике полагаться нельзя — она очень часто не соответствует реальному содержимому видео.
По тайм-кодам можно определить поток с частотой 50 кадров в секунду. Однако нередко оказывается, что это вовсе не настоящий p50, а поток с попарно продублированными кадрами. Такой случай фильтр должен распознать и удалить каждый второй кадр.
Бывает и классический чересстрочный поток i25. Из него корректный фильтр деинтерлейсинга должен восстановить полноценный поток p50. Бывает и правильный прогрессивный поток p25 — в этом случае фильтр вообще не должен изменять содержимое видео.
Встречается и более экзотический случай — так называемый смещенный интерлейсинг. Внешне поток выглядит как обычный i25, однако после восстановления p50 оказывается, что соседние кадры попарно дублируются со смещением на полкадра по времени. Обычно это возникает из-за ошибок в производственном пайплайне: сначала 25-кадровый материал преобразовали в 50 кадров в секунду простым дублированием кадров, а затем снова упаковали в интерлейсный поток, но со смещением на одно поле. В результате каждое интерлейсное изображение содержит соседние кадры исходного видеоряда. Ситуация неприятная, но ее можно автоматически обнаружить и восстановить корректный поток p25.
Multisampling
Если после деинтерлейсинга на выходе остается только поток с частотой 25 кадров в секунду, мы все равно преобразуем его в 50-кадровый.
Зачем это нужно? Во-первых, мы хотим, чтобы и CDN, и конечные устройства максимально часто работали с потоком одной структуры — 50 кадров в секунду. Потоки с переменной частотой кадров могут вызывать проблемы: некоторые плееры начинают работать нестабильно, транскодеры могут вести себя непредсказуемо, а различные схемы сложной обработки уже пожатого потока становятся менее надежными.
Во-вторых, это просто выглядит лучше. Даже если исходный материал был записан в 25 кадров в секунду, после интерполяции движение становится более плавным.
В случае спортивного вещания такая обработка чаще всего требуется для рекламных вставок, которые нередко поступают в формате 25 к/с. Аналогичная ситуация встречается в новостных программах и некоторых телевизионных передачах. Если же говорить о развлекательном контенте в целом, то большая его часть по-прежнему производится с частотой 25 кадров в секунду, поэтому интерполяцию приходится применять значительно чаще.
Варианты исполнения

Если не вдаваться во внутреннее устройство мультисэмплинг-фильтра и относиться к нему как к чёрному ящику, то это фильтр, который на вход получает 25 кадров в секунду, а на выходе даёт 50. Но есть нюансы. Можно выделить два варианта:
Первый вариант: генерировать один новый кадр между двумя исходными — 1 between 2, или 1b2. В этом случае кадры будут чередоваться: исходный «чистый», затем сгенерированный «грязный», с возможными заметными артефактами, поскольку он отличается от ближайшего чистого соседа на 1/2.
Второй вариант: генерировать два новых кадра между двумя исходными и выбрасывать исходный поток — 2 between 2, или 2b2. В этом случае все кадры будут примерно одинакового качества, а возможные артефакты будут менее заметными, поскольку каждый кадр отличается от ближайшего чистого соседа на 1/4.

Оба варианта имеют свои плюсы и минусы: Вариант 1b2 позволяет легко создавать более качественные производные 25-кадровые потоки путем отбрасывания грязных кадров. В этом случае младшие потоки вообще не получают артефактов. Также этот вариант немного более производительный, т.к. нам приходится создавать два кадра на каждый межкадровый интервал вместо одного. Не значит, что вдвое производительный, т.к. большую часть времени занимает поиск движения и построение модели для интерполяции. Лишь рендеринг приходится делать дважды.
Зато вариант 2b2 не чередует качественные и некачественные кадры, все кадры одинаковые по качеству. Более того, они обладают лучшим качеством по сравнению с первым вариантом, т.к. каждый сгенерированный кадр незначительно (на ¼ по временной шкале) отличается от исходного кадра.
Первый вариант хорош для случаев, когда применять фильтр приходится редко, когда GPU-ресурсы ограничены и когда высок процент target аудиотории, не поддерживающей 50 к/с. Если же target-аудитория преимущественно с хорошей связью и состоит из мощных ус-в, а также есть запас производительности на backend, лучше подходит второй вариант.
GPGPU Sharing
Поскольку фильтр интерполяции кадров требует значительных вычислительных ресурсов, но при обработке спортивных каналов используется сравнительно редко (в основном только на рекламных вставках и других фрагментах, из которых деинтерлейсер не смог восстановить поток 50 к/с), можно применить достаточно простую оптимизацию:
- Фильтр поддерживает два режима работы: экономичный режим с простым дублированием кадров и полноценный режим интерполяции.
- При работе нескольких каналов на одном GPU в режиме реального времени полноценная интерполяция использует ограниченное число вычислительных слотов.
- Каналы, которым в данный момент не хватает GPU-ресурсов, временно работают в режиме дублирования кадров. Как только слот освобождается (например, когда другой канал возвращается к исходному потоку 50 к/с и интерполяция больше не требуется), он сразу передается следующему каналу.
- Дополнительно можно использовать приоритизацию каналов, отдавая предпочтение наиболее популярным или наиболее важным трансляциям.
В результате грамотное планирование GPU-времени позволяет существенно сократить потребление вычислительных ресурсов при обработке спортивных и новостных каналов без заметного влияния на качество сервиса.
Двухэтапный транскодинг

Также хочется сократить затраты на транскодинг внутри CDN и уменьшить нагрузку на канал связи между точкой захвата и CDN. Поэтому на практике часто используется двухэтапное транскодирование:
- В точке захвата формируется один высококачественный поток.
- Этот поток доставляется в CDN, где уже из него строится вся остальная ABR-лестница.
Теперь покажу, как можно практически бесплатно получить дополнительный поток того же разрешения (зеленая стрелка). В нашей схеме верхним потоком является видео с частотой 50 кадров в секунду, следующим — поток 25 кадров в секунду того же разрешения, но с меньшим битрейтом, а ниже располагаются остальные уровни ABR-лестницы.
Розовым цветом на схеме обозначены ресурсоемкие операции транскодирования, голубым — практически бесплатное копирование. При переходе с 50 на 25 кадров в секунду без изменения пространственного разрешения можно использовать довольно элегантный прием, который позволяет избежать полноценного транскодирования.
Достраивание второго потока

На схеме показана структура исходного потока p50 и производного потока p25, который получается без дополнительного транскодирования. Кадры изображены в хронологическом порядке воспроизведения. В реальном битстриме они располагаются иначе из-за стандартного IPB-переупорядочивания кадров.
Идея метода заключается в следующем. При правильно сформированной структуре B-Pyramid каждый второй B-кадр можно сделать неопорным. Тогда его можно удалить из потока без появления артефактов декодирования. В результате частота кадров уменьшается вдвое, а битрейт снижается примерно на 25–30%, что хорошо соответствует типичному шагу между соседними уровнями ABR-лестницы. При этом старший поток 50 к/с имеет структуру IPBBB, а производный поток 25 к/с — IPB.
Такой подход позволяет существенно сократить объем транскодирования внутри CDN при использовании двухэтапной схемы обработки. По сравнению с классической архитектурой экономия вычислительных ресурсов составляет не менее одной трети, поскольку отпадает необходимость заново транскодировать поток с максимальным битрейтом (а также следующий за ним уровень ABR). Такая архитектура хорошо подходит для построения CDN и позволяет использовать CPU или встроенные GPU серверов для транскодирования остальных ABR-потоков в реальном времени. Кроме того, объем сетевого трафика между точками захвата и CDN сокращается примерно в три раза.
Воспроизведение
После того как мы сформировали поток 50 к/с, возникает следующая задача — воспроизвести его на конечных устройствах. Ведь OTT — это мультиэкранная платформа, а не одно фиксированное устройство.
Наиболее универсальное решение — доставлять и воспроизводить прогрессивный поток. Именно к этому подходу сегодня постепенно приходит вся индустрия. Более того, современные стандарты видеокодирования уже несколько поколений назад полностью отказались от поддержки чересстрочной развертки.
Более сложный вариант — выполнить обратное преобразование p50 → i25. В этом случае слабые устройства могут выполнять деинтерлейсинг до p25, а более производительные — до p50. Однако такой подход имеет ряд недостатков. Многие устройства предоставляют только высокоуровневый API готового видеоплеера и не позволяют вмешиваться в процесс декодирования и отображения видео. В результате невозможно гарантировать корректную обработку чересстрочного потока — например, устройство может воспроизвести i25 как обычный p25. Кроме того, в этой схеме уже нельзя воспользоваться оптимизацией с бесплатным получением второго потока. Наконец, качество изображения может быть немного ниже, поскольку передаются полукадры, содержащие меньше информации и менее эффективно сжимающиеся.
Для OTT мы выбрали доставку прогрессивного видеопотока. Тем не менее система сохраняет возможность экспортировать интерлейсный поток для специализированных сервисов с детерминированным оборудованием, где по тем или иным причинам использование чистого потока 50 к/с нежелательно.
Формирование совместимого видео потока
Поскольку никто не хочет терять существующую аудиторию, необходимо гарантировать, что внедрение нового решения ничего не сломает. При этом у нас появляется поток p50, который может поддерживаться не всеми конечными устройствами.
Кроме того, не для всех каналов имеет смысл расходовать дополнительные вычислительные ресурсы на построение потока 50 к/с. Малопопулярные каналы, а также контент, не предъявляющий высоких требований к плавности движения (фильмы, мультфильмы, юмористические передачи и т.п.), должны иметь возможность обрабатываться по прежней схеме.
Здесь мы вспомнили опыт ранних мобильных устройств. Когда-то многие из них не справлялись даже с воспроизведением SD-видео, а некоторые не поддерживали H.264 и требовали MPEG-4 ASP (DivX). Именно этот опыт подсказал нам решение.
Матрица совместимости

Для этого мы классифицируем клиентские устройства по уровню производительности. Например: SD, HD, FHD и FHD50. На схеме это столбцы. При этом предполагается, что устройство, способное воспроизводить HD, может также воспроизводить SD50, а устройство уровня FHD — поток HD50, и так далее.
Аналогичным образом классифицируются и каналы по максимальному качеству базового потока: SD, SD50, HD, HD50, FHD и FHD50. На схеме это строки.
Затем строится матрица совместимости. Хорошо видно, что ее верхний правый угол постепенно заполняется одинаковыми наборами потоков. Используя эту матрицу, backend точно определяет, какие потоки необходимо сформировать для каждого канала. В свою очередь, стример по этой же матрице определяет, какие варианты включить в плейлист для конкретного устройства. Фактически выбирается вся строка матрицы до соответствующего уровня совместимости. Для HLS это реализуется формированием соответствующих вариантов плейлистов.
Такая матрица легко масштабируется по мере появления новых форматов, например 3K или 4K. Кроме того, этот подход позволяет достаточно гибко комбинировать различные кодеки, например H.264 и HEVC, сохраняя единый механизм выбора потоков.
Заключение
Подводя итог, предложенный подход позволяет эффективно поддерживать высокодинамичный контент: спортивные трансляции, новости, репортажи, документальные фильмы о природе, а также пользовательский видеоконтент.
При этом он позволяет:
- полностью сохранить существующую аудиторию, используя возможности производительных устройств только там, где это действительно возможно;
- не ухудшать качество сервиса для пользователей, находящихся в сложных или нестабильных сетевых условиях;
- снизить энергопотребление на мобильных устройствах;
- избежать кратного увеличения затрат на backend-инфраструктуру и транскодинговую ферму;
- обеспечить готовность к контенту следующего поколения, включая 3Kp50 и 4Kp50 в форматах HEVC (VP9), а в дальнейшем — VVC (H.266) и AV1.