Любой ролик в интернете, будь то трансляция с камеры наблюдения или фильм на стриминге, состоит не из отдельных цельных снимков, а из цепочки взаимозависимых блоков данных. Один кадр хранит полную картинку, следующие двадцать девять хранят только то, что изменилось по сравнению с предыдущим. Эта экономия и делает видео лёгким для передачи по сети, но у неё есть обратная сторона: стоит потеряться одному фрагменту в середине цепочки, и картинка на экране рассыпается на цветные квадраты, зависает или начинает "плыть" рваными блоками. Чтобы понять, почему так происходит, нужно разобраться, как устроено межкадровое сжатие внутри H.264 и HEVC и зачем кодек вообще делит кадры на три разных типа.
Как внутрикадровое сжатие I-кадра превращает изображение в набор независимых блоков
I-кадр, или опорный кадр, кодируется полностью самостоятельно, без обращения к соседним изображениям в потоке. По сути, это обычная фотография, сжатая примерно так же, как сжимается статичный снимок: кодек делит картинку на квадратные области и ищет избыточность внутри одного и того же изображения, а не между кадрами. В H.264 базовой единицей такого деления служит макроблок размером 16 на 16 пикселей, внутри которого возможна ещё более мелкая разбивка вплоть до блоков 4 на 4. Для этих мелких блоков предусмотрено девять направлений внутрикадрового предсказания, а для блоков 16 на 16 их четыре: кодек пытается угадать значение пикселей по уже раскодированным соседним точкам и записывает в поток только разницу между предсказанием и реальным значением.
После предсказания идёт дискретное косинусное преобразование, переводящее блок пикселей в набор частотных коэффициентов, а затем квантование, которое отбрасывает малозначимые высокочастотные детали ради экономии места. Именно квантование определяет ту самую видимую "квадратность" при сильном сжатии: чем грубее шаг квантования, тем заметнее границы между соседними блоками 8 на 8 или 16 на 16 пикселей, из-за чего плавные переходы цвета превращаются в ступенчатую мозаику даже без единой ошибки передачи. Завершает обработку энтропийное кодирование: в H.264 используются два конкурирующих метода, CAVLC и CABAC, причём второй даёт выигрыш в сжатии порядка 10-15 процентов ценой более высокой нагрузки на процессор при декодировании. Именно поэтому в профиле Baseline, рассчитанном на слабые устройства и видеозвонки, CABAC и B-кадры отключены вовсе, а используется только более лёгкий CAVLC.
Что происходит внутри P-кадра, когда кодек предсказывает только смещение объектов
P-кадр, или предсказанный кадр, устроен принципиально иначе. Вместо того чтобы заново описывать каждый пиксель, кодировщик сравнивает текущий кадр с одним или несколькими уже раскодированными предыдущими кадрами и ищет для каждого макроблока наиболее похожий участок на референсном изображении. Найденное смещение записывается в виде вектора движения, а в поток попадает лишь остаточная разница между предсказанным блоком и реальным. Если человек в кадре просто сдвинулся на несколько пикселей вправо, кодеку незачем пересылать заново всю его фигуру: достаточно вектора смещения и небольшой поправки на изменение освещения или ракурса.
В стандарте H.264 P-кадр может опираться сразу на несколько предыдущих раскодированных изображений, а не только на одно, как это было в более старых форматах вроде MPEG-2. Это заметно повышает точность предсказания в сценах со сложным движением, когда объект временно перекрывается чем-то и снова появляется спустя пару кадров. Именно за счёт такого предсказания P-кадры занимают в потоке в разы меньше данных, чем I-кадры: если типичная секунда трансляции при частоте 30 кадров в секунду и длине группы кадров в две секунды содержит один I-кадр, двадцать девять P-кадров и тридцать B-кадров, то основной объём "тяжёлых" данных приходится именно на единственный опорный кадр, а не на десятки последующих.
Почему B-кадры сжимаются сильнее всего, опираясь одновременно на прошлое и будущее
B-кадр, или двунаправленный кадр, идёт ещё дальше в экономии: он строит предсказание не только по прошлым раскодированным кадрам, но и по будущим, которые кодировщик уже обработал, хотя зритель их пока не увидел. Из-за этого порядок кадров в потоке данных и порядок их показа на экране не совпадают: декодер сначала должен получить и раскодировать более поздний по времени показа кадр, чтобы использовать его как опорный для более раннего B-кадра. Такая перестановка требует буферизации на стороне плеера и добавляет небольшую задержку, зато позволяет B-кадрам занимать меньше всего места среди всех трёх типов, поскольку у кодека есть сразу два источника для предсказания и усреднения.
В H.264, в отличие от старых форматов, B-кадр тоже может использоваться как опорный для других B-кадров, а число референсных изображений не ограничено одним кадром в прошлом и одним в будущем. Это гибкая, но и более хрупкая конструкция: чем длиннее и запутаннее цепочка зависимостей между кадрами, тем сильнее одна повреждённая ссылка внутри неё сказывается на всех кадрах, которые от неё зависят. Профили, рассчитанные на минимальную задержку, например видеозвонки или системы видеонаблюдения реального времени, часто вовсе отказываются от B-кадров ради предсказуемой скорости обработки.
Как устроена группа кадров и почему её длина определяет баланс между качеством и объёмом потока
Последовательность кадров от одного опорного до следующего называется группой кадров, или GOP. Она всегда начинается с I-кадра, за которым следует определённое число P- и B-кадров, прежде чем появится новый опорный кадр и цикл повторится. Длина GOP, то есть интервал между соседними опорными кадрами, является одним из ключевых параметров кодирования: короткий GOP означает, что полные кадры передаются чаще, поток становится тяжелее, зато при переключении канала или потере части данных картинка восстанавливается быстрее. Длинный GOP экономит битрейт, потому что "тяжёлых" I-кадров становится меньше, но при этом растёт время до момента, когда искажённая последовательность сможет полностью очиститься.
Для систем видеонаблюдения это особенно ощутимо: чем реже следует опорный кадр, тем ниже нагрузка на канал связи, но тем заметнее становятся артефакты межкадрового сжатия, и тем сильнее восстановленное изображение в конце группы кадров может отличаться от реальной картинки с камеры. Приходится искать компромисс между стабильностью потока и точностью изображения, и универсального правильного значения GOP не существует, всё зависит от сцены, доступной полосы пропускания и требований к задержке.
Что происходит с картинкой, если потерять один пакет с данными P-кадра
Здесь и кроется ответ на вопрос, почему видео вдруг рассыпается на квадраты посреди совершенно нормальной трансляции. I-кадр кодируется независимо, поэтому повреждение одного I-кадра портит только его самого, а следующий опорный кадр полностью "перезагрузит" картинку. Но P-кадр и B-кадр не содержат полного изображения, а хранят лишь разницу относительно других кадров. Если пакет с данными такого кадра потерялся или пришёл повреждённым, декодер не может вычислить, куда именно сдвинулся тот или иной макроблок, и вынужден либо повторить последний удачно раскодированный участок, либо просто оставить блок как есть.
Дальше срабатывает эффект накопления ошибки. Каждый следующий P-кадр в группе кадров опирается на предыдущий, а тот, в свою очередь, уже содержит артефакт. Ошибка не исчезает, она копируется и множится от кадра к кадру, накладываясь на новые смещения объектов, пока не появится очередной I-кадр и не "перезапустит" изображение с чистого листа. Внешне это выглядит как область из квадратных или прямоугольных блоков неправильного цвета, которая держится на экране несколько кадров подряд, иногда смещается вместе с движением в кадре, а затем резко исчезает в момент прихода следующего опорного кадра. Именно поэтому короткий интервал между опорными кадрами так ценится там, где важна надёжность передачи по нестабильной сети: чем быстрее придёт следующий I-кадр, тем быстрее самоисправится картинка после сбоя.
Отдельно стоит учитывать разницу между потерей данных P-кадра и B-кадра. Поскольку на B-кадр, как правило, никто больше не ссылается, повреждение одного B-кадра затрагивает обычно только его самого и исчезает уже на следующем показанном изображении. А вот повреждение P-кадра, стоящего в начале цепочки, способно испортить десятки последующих кадров вплоть до конца текущей группы. Вот почему при нестабильном канале связи разумно снижать длину GOP или переключаться на схему кодирования без B-кадров вовсе, жертвуя частью экономии битрейта ради предсказуемости восстановления после ошибки.
Чем HEVC отличается от H.264 в устройстве блоков кодирования и насколько сильнее сжимает
Общий принцип деления на опорные и предсказанные кадры в HEVC остался тем же самым, но сама единица кодирования изменилась кардинально. Вместо фиксированного макроблока 16 на 16 пикселей в HEVC применяется дерево кодирования, или CTU, с базовым размером до 64 на 64 пикселя. Такой крупный блок затем может рекурсивно делиться по принципу квадродерева на более мелкие блоки кодирования вплоть до 8 на 8 пикселей, и решение о том, насколько мелко дробить конкретный участок кадра, кодировщик принимает на основе расчёта соотношения качества и объёма данных для каждого варианта разбиения. Крупные однородные области, например небо или стену, можно закодировать одним большим блоком, а мелкую детализированную текстуру раздробить на множество маленьких, и именно эта гибкость даёт основной прирост эффективности по сравнению с жёсткой сеткой макроблоков в H.264.
Вдобавок к более гибкой геометрии блоков в HEVC добавили новый фильтр сглаживания границ, работающий на уровне отдельных пикселей и дополняющий обычный деблокинг-фильтр, унаследованный от H.264. Он заметно уменьшает видимость границ между соседними блоками кодирования и снижает выраженность цветовых полос на плавных градиентах. По оценке исследовательского отдела BBC, при равном субъективном качестве картинки HEVC даёт в среднем 59 процентов экономии битрейта относительно H.264, а по формальным объективным метрикам вроде PSNR выигрыш составляет около 44 процентов, причём эффект тем заметнее, чем выше разрешение исходного изображения. На практике это означает, что фильм в разрешении 4K, занимающий около 50 гигабайт при кодировании H.264, в HEVC способен уместиться примерно в 25 гигабайт при сопоставимом визуальном качестве.
Расплатой за такую эффективность служит вычислительная сложность. Перебор всех возможных вариантов дробления CTU на более мелкие блоки кодирования, увеличенное число режимов внутрикадрового предсказания и более сложный алгоритм поиска векторов движения требуют заметно больше ресурсов процессора как на этапе кодирования, так и при декодировании. Именно поэтому массовое распространение HEVC шло медленнее, чем можно было ожидать исходя из одной только экономии трафика: устройствам попросту требовалось время, чтобы обзавестись достаточно мощным аппаратным декодером.
Как использовать понимание структуры кадров на практике при настройке потока
Зная механику I-, P- и B-кадров, проще осознанно подходить к настройке кодирования под конкретную задачу, а не полагаться на настройки по умолчанию. Разберём основные практические выводы:
- для потоковых трансляций и записей, которые не будут перематываться на лету, стоит выбирать более длинный GOP и активно использовать B-кадры ради максимальной экономии битрейта при приемлемом качестве;
- для систем видеонаблюдения и любых сценариев, где важна быстрая перемотка или устойчивость к потере пакетов в сети, разумнее сократить длину GOP и по возможности отказаться от B-кадров, приняв рост битрейта как разумную цену за предсказуемое восстановление после сбоя;
- при выборе между H.264 и HEVC для задач с ограниченной полосой пропускания и достаточной вычислительной мощностью декодирующего устройства HEVC даёт заметный выигрыш в объёме данных при сопоставимом визуальном качестве.
Такой подход избавляет от ситуации, когда красивая картинка на демонстрационном стенде превращается в рассыпающуюся мозаику из квадратов на реальном канале связи с нестабильной пропускной способностью, потому что параметры кодирования изначально выбирались без учёта того, как именно устроена цепочка зависимостей между кадрами.
Понимание разницы между тремя типами кадров помогает и в обратной, диагностической задаче. Когда на экране регулярно появляются блочные искажения строго определённой формы, которые держатся несколько кадров подряд и синхронно смещаются с движением объекта, это почти наверняка указывает на потери в канале передачи данных, а не на неисправность камеры или экрана. А если артефакты выглядят как случайный цветной шум без привязки к движению, причина скорее в самой аппаратной части тракта, а не в логике межкадрового сжатия. Такое разделение экономит время при поиске неисправности, потому что сразу подсказывает, в какую сторону смотреть: в настройки сети и параметры GOP или в исправность оборудования.