Inter-Frame Coding и Motion Estimation: межкадровое кодирование

Автор: Николай СапуновОбновлено: август 202626 мин чтения
Содержание статьи +

TL;DR

Inter-frame coding (межкадровое кодирование) сжимает видеокадр, описывая, как он сместился и изменился по сравнению с уже декодированными кадрами. Энкодер ищет для каждого блока нового кадра наиболее похожий участок в опорном кадре, сохраняет лишь крошечный указатель – motion vector – и небольшой residual там, где совпадение неидеально. Эта одна идея даёт около 90% всей экономии битов в типичном потоковом видео: P-кадр занимает примерно 50% от размера I-кадра, B-кадр – около 25%, а современные кодеки поднимают планку дальше за счёт affine warps, optical flow и compound prediction. Поймёте inter-frame coding – поймёте, почему часовая серия Netflix умещается в гигабайт, а не в сто.

Зачем это нужно

Настройки GOP, количество B-кадров, число reference frames и пресет motion search напрямую определяют битрейт, задержку, нагрузку на CPU и визуальное качество ваших стримов. Продакт-менеджер, который знает, что «preset slower» удваивает время кодирования главным образом ради более сложного motion search, принимает более точные решения о стоимости. Основатель, который понимает, что low-latency streaming запрещает B-кадры, не удивится, обнаружив, что WebRTC-архитектура тратит больше битов, чем HLS, при одинаковом качестве. Операционный лид, который знает, что панорама камеры обрушивает эффективность сжатия, сможет честно поставить демо и бенчмарки. Тридцать минут на эту ментальную модель окупаются каждой беседой с инженерами и каждой строкой в datasheet поставщика.

Что значит «inter» и одна большая идея

Латинское inter означает «между». Inter-frame coding – это часть видеокодека, которая сжимает один кадр со ссылкой на другие кадры, уже декодированные приёмником. Противоположное – intra-frame coding, которое сжимает кадр, используя только пиксели внутри него самого.

Главная идея межкадрового кодирования: соседние кадры реального видео – почти одна и та же картинка. Два кадра, снятые с разницей в 1/30 секунды, обычно различаются лишь несколькими движущимися объектами на почти неизменном фоне. Описывать кадр 2 целиком, когда кадр 1 уже передал декодеру 95% ответа, – расточительство.

Inter-frame coding выбрасывает это расточительство. Вместо того чтобы описывать кадр 2 с нуля, энкодер говорит декодеру: «Возьми участок в координатах (320, 480) кадра 1, сдвинь его на (+3, −1) пикселя, вставь по адресу (320, 480) кадра 2. Теперь поправь его маленьким блоком ошибки». Сдвиг (+3, −1) – это motion vector. Маленький блок ошибки – это residual. Вместе они стоят несколько байт; полное переописание стоило бы килобайты.

Умножьте экономию на каждый блок в каждом не-ключевом кадре каждого видео – и получите двигатель, построивший весь стриминговый интернет.

Чем inter-frame отличается от intra-frame

У обоих пайплайнов один и тот же back end – transform, quantize, entropy coding – но front end разный. Intra-frame предсказывает блок из соседей в том же кадре. Inter-frame предсказывает блок из патча в другом кадре. Одна и та же машина, разная опора.

Рисунок 1. Intra и inter prediction разделяют back end. Разница – в источнике предсказания: соседи в том же кадре или патч в другом кадре.

Они сосуществуют внутри каждого видеокодека, потому что выигрывают на разном контенте. Intra побеждает на первом кадре, на резких сменах сцены и там, где предыдущий кадр ненадёжен (occlusion, новые объекты, перепады освещения). Inter побеждает на длинных промежутках между такими событиями – а это большая часть видео. Типичный 2-секундный HLS-сегмент H.264 содержит примерно 1 ключевой кадр и 47 межкадровых при 24 fps; на inter-frame coding приходится львиная доля каждого сэкономленного байта.

Типы кадров: I, P и B

Реальный видеопоток содержит три типа кадров. Названия идут из MPEG-1 (1993) и прижились.

I-frame (intra-coded) – полноценная статическая картинка, как JPEG. Может декодироваться сам по себе. Любой видеопоток нуждается в I-кадрах как в точках старта и точках восстановления. I-кадры большие.

P-frame (predicted) кодируется с использованием предсказания из одного или нескольких прошлых опорных кадров. Энкодер копирует патчи из прошлого, применяет motion vectors, добавляет residuals. P-кадр обычно занимает около 50% размера I-кадра того же контента. Цифра сильно зависит от сложности сцены, но 50% – правильный порядок.

B-frame (bi-predicted) кодируется с использованием предсказания и из прошлых, и из будущих опорных кадров. Энкодер может копировать из любого направления и даже усреднять два патча. B-кадры – самые сжимаемые: типично около 25% размера I-кадра. Платой становятся декодер-буфер и задержка: декодеру нужно получить будущий кадр, чтобы отрисовать зависящий от него B-кадр.

Рисунок 2. Три типа кадров и их опоры. У B-кадров стрелки и назад, и вперёд по времени; у P-кадров – только назад. Высота столбиков – типичная стоимость в битах.

Закрепим цифрами. Возьмём 2-секундный HLS-сегмент 1080p24, закодированный x264 на пресете «veryslow», closed GOP длиной 48 кадров и B-паттерн IBBPBBPBBPBB…. Такой сегмент содержит 1 I-кадр, 15 P-кадров и 32 B-кадра.

Допустим, I-кадр стоит 200 кбит, P-кадр в среднем 100 кбит, B-кадр в среднем 50 кбит. Тогда:

total = 1 × 200 + 15 × 100 + 32 × 50
total = 200 + 1500 + 1600
total = 3300 кбит за 2 секунды
битрейт = 1650 кбит/с ≈ 1.65 Mbps

Повторим тот же сегмент с отключёнными B-кадрами – обычное дело в low-latency live-стримах – и энкодеру придётся заменять их P-кадрами. Каждое старое B-слот превращается в P-кадр по 100 кбит.

total = 1 × 200 + 47 × 100
total = 200 + 4700
total = 4900 кбит за 2 секунды
битрейт = 2450 кбит/с ≈ 2.45 Mbps

Отказ от B-кадров стоил около 48% дополнительного битрейта при том же качестве. Это та цена, которую вы платите за меньшую задержку в WebRTC- или LL-HLS-пайплайне.

Motion estimation: поиск, который делает всю работу

Задача энкодера – для каждого блока текущего кадра найти в опорном кадре участок, который лучше всего ему совпадает. Этот поиск называется motion estimation, часто сокращают до ME. Выход motion estimation – motion vector для каждого блока.

Motion vector – это просто два числа: горизонтальный и вертикальный сдвиг, измеренные в пикселях (или sub-pixel единицах). Вектор (+3, −1) говорит: «возьми патч в тех же координатах опорного кадра, сдвинь его на 3 пикселя вправо и 1 вверх, используй как предсказание для текущего блока».

Motion estimation – самый дорогой шаг в видеокодере. Множество исследований ставят его в 60–80% от общего времени кодирования. Каждая сэкономленная минута CPU превращается в более быстрые транскоды, меньшие облачные счета и возможность запустить больше стримов на сервер. Каждый сэкономленный байт в motion vector и residual – байт, который не приходится скачивать пользователю.

Шаг 1 – выбрать область поиска

Энкодер не может позволить себе сравнивать текущий блок со всеми возможными патчами всего опорного кадра. Кадр 1080p содержит около 2 миллионов возможных патчей 16×16; умножьте на 8 000 блоков в кадре – получится 16 миллиардов сравнений на кадр. При 30 fps это полтриллиона сравнений в секунду – невозможно для CPU.

Поэтому энкодер ограничивает поиск маленьким окном вокруг исходных координат блока в опорном кадре – это search range, или merange в терминах x264/x265. Типичные значения: 16, 24 или 32 пикселя. Внутри окна энкодер рассматривает кандидатные патчи и оценивает каждый.

Шаг 2 – оценить кандидатов функцией стоимости

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

Sum of Absolute Differences (SAD) берёт абсолютную разницу между каждой парой пикселей и складывает их. Быстрая, целочисленная, дефолт почти любого real-time энкодера.

Sum of Squared Differences (SSD) возводит каждую разницу в квадрат перед суммированием. Лучше коррелирует с перцептивным качеством, но дороже по compute. Пресеты повышенного качества используют SSD или гибридную метрику SATD, которая прогоняет блок разностей через маленький преобразователь Адамара, чтобы взвесить перцептивные частоты.

Шаг 3 – паттерны поиска, не проверяющие каждого кандидата

Даже внутри окна 32 пикселя brute-force «проверим все позиции» – иногда называемый full search или exhaustive search – слишком медленный для real-time. Окно 32 пикселя содержит около 4 225 позиций. Кодеки применяют умные паттерны, посещающие лишь небольшое подмножество и быстро сходящиеся к хорошему ответу.

Рисунок 3. Четыре motion-search паттерна, от самого медленного и точного (слева) к самому быстрому и менее точному (справа). Production-энкодеры по умолчанию используют hexagon или UMH; full search – для архивного качества.

Паттерны, которые встретятся в документации энкодеров:

Diamond search центрируется на предсказании, проверяет четыре кардинальных соседа плюс центр, прыгает к победителю и повторяет. Дешёвый и быстрый; дефолт пресета me=dia в x264 и нижняя планка для real-time кодирования.

Hexagon search использует кольцо из шести точек вместо креста из четырёх. Шестиугольный паттерн покрывает больше ориентаций за шаг и сходится к лучшим минимумам, чем diamond. Это дефолт x264 и x265 (me=hex) и разумный компромисс скорость/качество.

Uneven Multi-Hexagon (UMH) сначала прогоняет cross search, чтобы поймать крупную трансляционную motion, затем серию шестиугольников с убывающим радиусом, потом diamond refinement. UMH ловит более быстрое движение, чем простой hexagon, и даёт около +0.1 dB PSNR на типичном эталонном наборе – за 30–40% дополнительного времени кодирования.

Enhanced Predictive Zonal Search (EPZS) строит начальное предсказание из motion vectors пространственных и временных соседей (тот же блок в предыдущем кадре, блок слева, блок сверху) и ищет только рядом с этими предсказаниями. Отлично работает на плавных движениях типа панорам; широко применяется в облачных транскодерах.

Full search (он же exhaustive search, me=esa и me=tesa в x264) проверяет каждую позицию. Используется только для placebo-архивных кодов; на практике UMH отстаёт от него на доли dB при долях стоимости.

Практическое правило в x264: me=hex для live и быстрых пресетов, me=umh для VOD, me=esa/tesa для «placebo»-пресетов и никогда – для продакшна.

Шаг 4 – sub-pixel refinement

Лучшее integer-pixel совпадение редко оказывается истинным минимумом. Реальное движение непрерывно, не на пиксельной сетке, и небольшой дополнительный сдвиг почти всегда уменьшает residual.

Поэтому после integer-pixel motion estimation энкодер делает sub-pixel refinement. Он интерполирует опорный кадр на более тонкую сетку – half-pixel, quarter-pixel, eighth-pixel – и ищет в небольшой окрестности победителя на целой сетке. Интерполяция использует маленький фильтр (обычно 6-tap или 8-tap separable); поиск – крошечный diamond.

Выигрыш заметный. Half-pixel motion vectors дали MPEG-2 около 1 dB поверх integer-only. Quarter-pixel – ещё +0.5–0.8 dB. AV1 и VVC поддерживают eighth-pixel accuracy для некоторых типов блоков. Биты на более тонкий вектор почти бесплатные; биты, сэкономленные в residual, – нет.

Пошаговый пример: от поиска к motion vector и стоимости в байтах

Конкретный разбор закрепит модель. Представьте блок 16×16 в текущем кадре, попадающий на часть пиджака мужчины. Опорный кадр из 1/30 секунды назад показывал тот же пиджак, на три пикселя правее и один пиксель ниже (камера панорамировала влево и вверх).

Энкодер выбирает search range 16 пикселей, центрированный на исходных координатах блока в опорном кадре. Прогоняет hexagon search и приходит к integer-pixel кандидату (+3, −1) с SAD = 320. Уточняет до half-pixel и SAD падает до 210 в точке (+3.0, −1.0) – целочисленный кандидат уже был на сетке. Уточняет до quarter-pixel – SAD падает до 198 в (+3.0, −1.25): истинное движение было чуть ниже целочисленной сетки.

Энкодер сохраняет для блока три порции информации. Первое – motion vector (+3.00, −1.25) в quarter-pixel единицах, закодированный как разность с предсказанным вектором (медианой векторов трёх соседних блоков). Второе – один бит, указывающий, что блок использует inter prediction с предыдущим кадром в качестве референса. Третье – residual: блок 16×16 разностей между текущим блоком и сдвинутым опорным патчем. Residual мал – SAD = 198 означает среднюю ошибку около 0.8 уровня на пиксель – так что после трансформа и квантования почти все коэффициенты становятся нулями. Блок в итоге стоит порядка 20 бит в bitstream.

Сравните с intra-кодированием того же блока: примерно 600–800 бит. Inter обходится в ~30 раз дешевле.

Как современные кодеки расширяют базовый рецепт

Описанный однонаправленный трансляционный поиск – это базовая линия H.261 / MPEG-2. Каждое поколение кодеков с тех пор приклеивало инструменты, которые ловят то, что базовая линия не может описать. Шесть инструментов отвечают за основную часть выигрыша.

Variable block sizes

Целый блок 16×16 с одним motion vector – слишком грубо, если блок попадает на два объекта, двигающихся по-разному. H.264 ввёл partitions вплоть до 4×4. H.265 добавил квад-дерево от 64×64 до 4×4. AV1 стартует от superblock 128×128. VVC использует 128×128 CTU с бинарными, тернарными и квадро-сплитами до 4×4. Меньшие блоки стоят больше битов на векторы, но чётко отслеживают границы движения.

Multiple reference frames

Зачем заставлять энкодер предсказывать из непосредственно предыдущего кадра? Может быть, блок лучше совпадает с патчем из трёх кадров назад – например, потому что движущийся передний план кратко закрыл его. H.264 ввёл multi-reference prediction до 16 опорных кадров. AV1 держит семь reference frames в двух категориях: прошлое (LAST, LAST2, LAST3, GOLDEN) и будущее (BWDREF, ALTREF, ALTREF2). VVC поддерживает до 15. Энкодер выбирает поблочно; выигрыш максимален на контенте с периодическим движением и короткими occlusions.

B-frames и compound prediction

B-кадр может предсказывать каждый блок из одного или обоих из двух референсов – прошлого и будущего – и усреднять их. Двунаправленное усреднение сглаживает шум и уменьшает residual. AV1 расширяет это до compound prediction: wedge-based, difference-modulated и distance-weighted blending двух предикторов – что позволяет описывать более сложные границы движения внутри одного блока.

Affine motion: вращение, масштаб, zoom

Одиночный motion vector описывает только трансляцию. Он не описывает вращение, масштаб или перспективный warp. VVC и AV1 добавили affine motion models: вместо одного вектора на блок энкодер сигнализирует две или три control-point векторов на блок, а декодер вычисляет отдельный вектор для каждого 4×4 sub-block интерполяцией. Результат – обработка камерных zoom-ов, dolly shots, поворотов авто и вращающихся логотипов крошечной долей битов по сравнению с независимым вектором на каждый sub-block.

Warped и global motion (визитная карточка AV1)

AV1 стоит между простой трансляционной ME и полным affine. Global motion сигнализирует одну affine-модель на reference frame уровня кадра – полезно, когда весь кадр претерпевает один warp, например camera pan или zoom. Local warped motion выводит параметры warp на уровне блока из motion vectors соседних блоков почти без сигнальных затрат. Вместе эти инструменты ловят длинные участки pan и zoom, на которых трансляционная ME тратит биты впустую.

Optical-flow refinement (BDOF и DMVR в VVC)

VVC добавляет два decoder-side инструмента уточнения, которые улучшают грубый вектор без сигнальных битов. Bi-Directional Optical Flow (BDOF) применяет optical-flow коррекцию на уровне 4×4 sub-block на основе градиентов двух reference patches. Decoder-side Motion Vector Refinement (DMVR) позволяет декодеру запустить маленький block-match вокруг полученного вектора и использовать уточнённую позицию. Оба уменьшают стоимость самого motion vector: энкодер передаёт более грубый вектор и оставляет дополнительную работу декодеру.

Рисунок 4. Motion-compensation пайплайн современного кодека – базовый block-match плюс стопка уточнений. Каждое уточнение добавило своё поколение кодеков.

Что это стоит на энкодере и на декодере

Асимметрия inter-frame coding – одна из его недооценённых черт. Энкодер выполняет колоссальную работу, чтобы найти motion vectors; декодер просто читает векторы и копирует патчи. Кодирование часового фильма в 4K HEVC занимает 15–60 минут CPU на быстром сервере; декодирование того же фильма комфортно идёт на пятилетнем телефоне.

Эта асимметрия – то, что заставляет работать стриминговую экономику. Студия может потратить десять часов GPU на минуту на кодирование Netflix-мастера и амортизировать это на сотни миллионов просмотров. Live-энкодер на спортивном мероприятии получает один шанс закодировать каждый кадр в реальном времени – поэтому live-пресеты отключают B-кадры, сужают search range и переключаются на diamond/hexagon search.

Компромиссы каждого пресета:

ПараметрЧто контролируетВлияние на битрейтВлияние на время кодирования
Search rangeШирина окна поискаШире – ниже битрейт на быстром движенииШире – квадратично медленнее
Search patternКакие позиции проверяютсяЛучше паттерн – ниже битрейтЛучше паттерн – в 2–10 раз медленнее
Sub-pixel depthHalf, quarter, eighth pixelТоньше – ниже битрейтКаждый уровень ≈ ×1.5
Reference framesСколько прошлых/будущих кадровБольше – ниже битрейт, отдача падаетБольше – линейно медленнее
B-frame countСколько B между PБольше B – ниже битрейтБольше B – небольшой хит времени, большой декодер-буфер
Affine / warped motionВключены ли неподвижные моделиНиже битрейт на ротации/zoom+5–15% времени

Практический cheat sheet для x264 и x265 – в скачиваемом PDF.

Типичная ошибка: считать «motion-estimation accuracy» перцептивной точностью

Частое недопонимание между продактом и инженерами возникает вокруг слова «точность». Motion vector «точен», если минимизирует функцию стоимости – обычно SAD, иногда SSD или SATD. Ни одна из этих функций не измеряет перцептивное качество так, как это делают VMAF или SSIM.

В результате два motion vectors с одинаковым SAD могут давать заметно разное визуальное качество после квантования residual на низких битрейтах. Энкодеры пытаются закрыть этот разрыв через rate-distortion optimisation (RDO): каждый кандидат оценивается по полной стоимости (motion vector + residual), а не только по residual; а SATD-based поиски приближают перцептивные частоты. Более медленные пресеты делают больше RDO; быстрые – пропускают его. Если вы шипаете low-bitrate стрим и качество «блочит на движении», ответ редко – «увеличьте битрейт». Чаще – «возьмите более медленный пресет, чтобы энкодер тратил больше RDO-циклов на блок».

Где находится Фора Софт

Настройки inter-frame coding касаются каждого продукта, который Фора Софт поставила с 2005 года. В нашей работе по видеоконференциям и WebRTC low-latency ограничения заставляют использовать пайплайн без B-кадров и узкие search ranges, что мы компенсируем умными bitrate ladders и селективным forward error correction. В сборках OTT и Internet TV мы тюнингуем per-title encoding ladders, эксплуатирующие весь motion-compensation toolset HEVC и AV1, часто срезая 25–40% CDN egress при одинаковом VMAF. В video-surveillance проектах длинные статические участки позволяют нам растягивать огромные GOP и вставлять keyframe адаптивно по scene-change detection. Наша работа по e-learning, телемедицине и AR/VR бьёт в тот же toolbox с других углов – статья, которую вы читаете, дистиллирует десятилетие таких production-решений.

Ключевые выводы

  • Inter-frame coding заменяет полное описание кадра motion vector-ом плюс маленьким residual, экономя львиную долю байт современного видео.
  • P-кадры – около 50% размера I-кадра; B-кадры – около 25%; отключение B-кадров обычно стоит +30–50% битрейта.
  • Motion estimation потребляет 60–80% времени энкодера и является главным рычагом компромисса скорость/качество.
  • Выбор search pattern (diamond, hexagon, UMH, full) и search range вместе задают основную часть этой стоимости.
  • Современные кодеки расширяют базу инструментами multi-reference, affine, warped, global, optical-flow и compound prediction.
  • Энкодер делает тяжёлую работу; декодер просто копирует – эта асимметрия и питает стриминговую экономику.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.