Содержание статьи +
- TL;DR
- Зачем это вам
- Что происходит в quantization, в одном абзаце
- Шаг квантования – что означает это число
- Параметр квантования – одна настройка, логарифмическая шкала
- Пример на одном блоке
- Dead zone – маленький приём, который многое значит
- Матрицы квантования – разная точность для разных частот
- Зависимое квантование – полушаг VVC
- Adaptive quantization – тратить биты там, куда смотрит глаз
- Как сравниваются кодеки – одна таблица
- CRF, CBR, VBR – квантизация под другими именами
- Частые артефакты при квантовании
- Где здесь Фора Софт
- Ключевые выводы
- Что почитать дальше
TL;DR
Квантование – единственный этап видеокодека, на котором информация теряется безвозвратно: каждый размытый край, каждый «грязный» блок неба, каждый плоский участок, где должен быть градиент, но его нет, – всё это результат именно этого шага. Кодер делит каждый коэффициент преобразования на шаг квантования, округляет до ближайшего целого, и маленькие числа превращаются в нули, которые почти ничего не стоят при передаче. У каждого кодека своя обёртка вокруг одной и той же идеи: H.264 использует параметр квантования от 0 до 51, при этом шаг удваивается каждые шесть пунктов; HEVC и VP9 применяют ту же шкалу, но на более крупных блоках; AV1 называет это qindex и предлагает 256 уровней; VVC добавляет зависимое квантование, фактически давая кодеру ещё полшага. Освойте квантование – и одной настройкой вы сможете управлять качеством, битрейтом и видимыми артефактами.
Зачем это вам
Главное число, которое настраивает оператор кодера, – это QP (quantization parameter, параметр, контролирующий степень округления коэффициентов). Когда стриминговая платформа снижает битрейт вдвое, чтобы сэкономить на CDN, почти вся экономия достигается за счёт увеличения QP – а не за счёт «умного кодека», новых алгоритмов или аппаратных улучшений. Продакт-менеджер, способный прочитать значение QP в логе FFmpeg и предсказать, будет ли результат смотримым или испорченным, отсекает половину плохих идей в encoding-роудмапе ещё до выхода в продакшн. Основатель, объясняющий инвесторам, почему «снижение битрейта на 30%» иногда выглядит чисто, а иногда – блочно, понимает единственный источник перцептивного риска во всём видеопайплайне. Технический лидер, знающий, когда использовать плоскую матрицу квантования, а когда – кастомную, выигрывает 1–2 пункта VMAF на сервисе, отдающем миллион часов в сутки – а это уже деньги.
Что происходит в quantization, в одном абзаце
Quantization – это процесс уменьшения количества бит, используемых для представления чисел в нейронной сети, что позволяет сократить размер модели и ускорить вычисления за счёт небольшой потери точности. Вместо хранения весов и активаций с высокой точностью (например, в формате float32), они округляются до более низкого уровня точности (например, до int8 или даже бинарных значений), что особенно эффективно при развертывании моделей на устройствах с ограниченными ресурсами.
После того как стадия предсказания сгенерировала residual-блок, а преобразование распределило его энергию по сетке коэффициентов – эти шаги мы подробно разбирали в статьях о внутрикадровом кодировании, межкадровом кодировании и оценке движения и преобразовательном кодировании, – кодер делит каждый коэффициент на шаг квантования и округляет результат до ближайшего целого числа. Это и есть квантование. Шаг – это одно число, которое задаёт оператор: маленький шаг сохраняет большую часть точности и даёт большой битовый поток, большой шаг обнуляет почти все коэффициенты и приводит к компактному битовому потоку. Когда декодер восстанавливает блок, он умножает оставшиеся целые значения на тот же шаг, но ошибка округления при этом теряется навсегда. Эта ошибка округления – единственное место во всём кодеке, где информация теряется безвозвратно; все остальные операции в принципе обратимы.
Шаг квантования – что означает это число
Шаг, обычно обозначаемый как Qstep, – это расстояние на числовой оси между двумя значениями, которые кодек может представить. Если Qstep равен 8, а коэффициент – 21, кодер округляет результат деления 21 ÷ 8 до 3, передаёт это целое число, а декодер умножает его обратно и получает 24 – ошибка составляет 3. Если Qstep равен 32, а коэффициент остаётся тем же – 21, кодер округляет 21 ÷ 32 до 1, декодер выдаёт 32, ошибка – 11. Чем больше шаг, тем выше средняя ошибка на коэффициент, но тем меньше целых чисел приходится передавать энтропийному кодеру.
Арифметика проста:
quantized = round(coefficient / Qstep) # кодер
recovered = quantized × Qstep # декодер
error = recovered − coefficient # всегда |error| ≤ Qstep / 2Подставим коэффициент 87 и значение Qstep = 16:
quantized = round(87 / 16) = round(5.4375) = 5
recovered = 5 × 16 = 80
error = 80 − 87 = −7Ошибка ограничена половиной шага – в данном случае половиной 16, то есть 8, – и граница точная. Каждая ячейка transform-блока получает свою независимую ошибку в пределах этой границы, а сумма этих ошибок, прошедшая через обратный transform, и становится тем, что зритель в итоге воспринимает как снижение качества.
Почему файлы становятся меньше? Потому что большинство ячеек типичного transform-блока содержат небольшие числа, и как только Qstep превышает эти значения, они округляются до нуля. Энтропийный кодер почти не тратит битов на длинные последовательности нулей. Большие числа в верхнем левом углу – структурная энергия блока – остаются, и стоимость представления блока сокращается с «16 целых чисел» до «два ненулевых коэффициента плюс флаг, что остальное – нули».
Параметр квантования – одна настройка, логарифмическая шкала
Современные кодеки не отображают Qstep напрямую. Вместо этого они используют небольшое целое число – quantization parameter (QP) в H.264, HEVC, VP9 и VVC, а также qindex в AV1, из которого Qstep вычисляется по фиксированной математической формуле. Связь между ними логарифмическая – и это сделано намеренно: человеческий глаз реагирует на относительные изменения ошибки, а не на абсолютные. Поэтому удвоение Qstep должно соответствовать одному перцептивному «щелчку», а не пятидесяти.
В H.264, HEVC, VP9 и VVC действует одно и то же правило: Qstep удваивается каждые шесть пунктов QP. Конкретно:
Qstep(QP) = 2 ** ((QP − 4) / 6)Это фиксирует Qstep на 1 при QP = 4, на 2 при QP = 10, на 4 при QP = 16, на 8 при QP = 22, на 16 при QP = 28, на 32 при QP = 34 и так далее. Минимальный QP в стандарте – 0; для 8-битного контента диапазон H.264 / HEVC составляет от 0 до 51, с расширениями для 10-битного (0..63) и 12-битного (0..75) контента. Каждое увеличение QP на единицу повышает шаг примерно на 12,2%, а каждые шесть пунктов – в точности удваивают его. Кодер выбирает значение QP, декодер считывает его, и оба вычисляют Qstep одинаково.
Правило удвоения делает QP интуитивно понятным, как только с ним поработаешь. Переход с QP 23 на QP 29 удваивает среднюю ошибку квантования, а с QP 23 на QP 35 – увеличивает её в четыре раза. Стриминг-инженер, запоминающий четыре опорные точки – QP 23 для «прозрачного качества», QP 28 для «хорошо», QP 33 для «смотрибельно на маленьком экране», QP 38 для «заметно мягкая картинка» – может предсказать результат транскодинга, даже не запуская его.
AV1 использует более тонкую шкалу под названием qindex с диапазоном от 0 до 255. Соответствие между qindex и Qstep не является чистой степенью двойки – вместо этого применяется таблица, откалиброванная так, чтобы обеспечить более плавное управление на высоком конце диапазона и охватить более широкий диапазон, чем у шкалы 0..51. Примерное соотношение: qindex ≈ 4 × QP, так что qindex 100 в AV1 примерно соответствует QP 25 в HEVC. Таблицы в AV1 разделены по типу коэффициентов – отдельно для DC и AC, а также по цветовым плоскостям (luma и chroma), что позволяет AV1 точнее контролировать, сколько ошибок выделяется на каждый компонент.
Пример на одном блоке
Возьмём 4×4 transform-блок из гладкого участка неба после intra-предсказания. DCT-коэффициенты могут выглядеть так (числа подобраны для удобства чтения, в реальности значения обычно больше):
96 8 2 0
12 4 1 0
3 1 0 0
0 0 0 0При QP = 22 шаг равен 8. Делим значение каждой ячейки на 8 и округляем результат.
12 1 0 0
2 1 0 0
0 0 0 0
0 0 0 0Шестнадцать ячеек на входе; четыре ненулевых значения на выходе. Энтропийный кодер передаёт эти четыре числа вместе с коротким флагом – примерно пятнадцать бит вместо нескольких сотен, которые потребовались бы для передачи необработанного блока. Декодер выполняет обратное умножение:
96 8 0 0
16 8 0 0
0 0 0 0
0 0 0 0По сравнению с оригиналом нижний левый «12» стал «16» – ошибка 4; «4» во втором столбце превратилось в «8»; «2» в верхней строке исчезло; и так далее. Ошибки не превышают 4 (половину шага). После обратного преобразования блок для зрителя становится неотличим от оригинального неба.
Теперь тот же блок при QP = 34. Шаг 32:
3 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0Уцелела одна ячейка. Битстрим короче на пятнадцать бит. Декодер восстанавливает блок как плоский патч со значением 3 × 32 = 96 в DC-позиции и нулями во всём остальном – равномерный 4×4 субблок средней яркости. В оригинале была мягкая вариация по четырём строкам и четырём столбцам; теперь она потеряна навсегда. На плоском небе зритель этого не заметит. На лице тот же QP сделает щёку похожей на мазок краски. В этом и состоит всё искусство выбора QP.
Dead zone – маленький приём, который многое значит
Реальный кодек не использует учебное правило quantized = round(coefficient / Qstep). Вместо этого применяется асимметричная версия, при которой маленькие положительные коэффициенты сдвигаются к нулю. Интервал [−Qstep/2, +Qstep/2], в учебниках отображаемый в ноль, расширяется примерно до [−2·Qstep/3, +2·Qstep/3]. Этот расширенный интервал называется dead zone – мёртвая зона, – и внутри него любой коэффициент, будь то маленький положительный или отрицательный, округляется до нуля, а не до ±1.
Зачем асимметрия? Потому что ноль – особенный. Длинная последовательность нулей занимает почти ноль бит; одиночная ±1 посередине нарушает run и стоит реальный бит. Отправляя маленькие коэффициенты в dead zone, мы немного увеличиваем искажение, но получаем реальную экономию бит – и на естественном контенте этот обмен почти всегда оправдан.
Ширина dead zone – скрытый параметр кодера: декодеру не важно, какую ширину выбрал кодер, потому что он просто умножает целое значение обратно на Qstep. Reference-реализация H.264 использует dead zone примерно в 5/6 Qstep для intra-блоков и 2/3 Qstep для inter-блоков; в AV1 форма немного отличается. Настройка dead zone – одна из самых простых визуальных «ручек» в распоряжении команды кодера, и выигрыш вполне реальный: 5–10% битрейта при неизменном VMAF при хорошо подобранной dead zone.
Матрицы квантования – разная точность для разных частот
Глаз более терпим к ошибкам в высокочастотных коэффициентах, чем в низкочастотных. Квантование с постоянным шагом (Qstep) тратит точность на высокочастотные компоненты, которые зритель не замечает. Современные кодеки позволяют использовать матрицу квантования – поэлементный множитель к Qstep, который уменьшает шаг квантования для высоких частот и увеличивает его для низких.
Для блока 8×8 default-матрица в стиле JPEG может выглядеть так:
16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99В верхнем левом углу множитель равен 16, в нижнем правом – 99. При базовом Qstep = 8 эффективный шаг в нижнем правом углу составляет 8 × 99 / 16 ≈ 49, то есть примерно в шесть раз грубее учебного шага, тогда как в верхнем левом углу он остаётся близким к учебному значению. Зритель не замечает потери в высокочастотных ячейках, поскольку глаз на этих частотах не способен различать мелкие детали.
H.264, HEVC и VVC позволяют кодеру выбирать между плоскими матрицами (все ячейки умножаются на одно и то же значение – эквивалент отсутствия матрицы), стандартными матрицами, заложенными в спецификацию, и пользовательскими матрицами, передаваемыми в битстриме. В AV1 используются фиксированные матрицы из стандарта, зависящие от размера преобразования; кодер не может их переопределить, но может выбрать одну из небольшого встроенного набора. У VP9 поддерживается только плоская квантовая матрица.
Практический совет для стриминг-инженеров: плоские матрицы хорошо подходят для межкадровой компрессии и черновых прогонов. Стандартные матрицы показывают лучшие результаты на внутрикадровых кадрах и при медленных пресетах. Кастомные матрицы оправданы только в случае наличия эталонного контента определённого типа – анимация, screen capture, спорт – и чётко измеряемой цели.
Зависимое квантование – полушаг VVC
VVC, финализированный в 2020 году и принятый как ITU-T H.266, добавил новый инструмент – dependent quantization – позволяющий кодеру эффективно удвоить точность квантования без увеличения целочисленной шкалы. Идея, впервые предложенная Хайко Шварцем и коллегами из Heinrich Hertz Institute, заключается в переключении между двумя квантизаторами с уровнями реконструкции, сдвинутыми на полшага, в зависимости от чётности предыдущих коэффициентов в порядке их обхода.
В обычном кодеке при Qstep = 8 уровни реконструкции составляют 0, ±8, ±16, ±24 и так далее. Метод dependent quantization добавляет второй набор уровней, сдвинутый на полшага: 0, ±4, ±12, ±20 – и позволяет кодеру выбирать, к какому из наборов относится каждый коэффициент, по правилу «выбор зависит от предыдущего коэффициента». Маленький конечный автомат с четырьмя состояниями кодирует, какой квантизатор активен на каждом шаге.
Результат – более плотная решётка реконструкции. Кодер находит такие комбинации значений, которые аппроксимируют исходный блок точнее, чем это может сделать одиночный квантизатор, а энтропийный кодер тратит лишь один дополнительный бит на блок для сигнализации состояния автомата. Dependent quantization экономит от 3% до 5% битрейта при сохранении качества в типичном VVC-кодировании и включена по умолчанию в большинстве production-кодеров VVC.
«Pitfall. Некоторые команды отключают dependent quantization в VVC, прочитав спецификацию и решив, что это «дорого». На естественном контенте выигрыш действительно есть, а нагрузка на кодер составляет всего один-два процента – недостаточно, чтобы оправдать отключение. Отключайте этот инструмент только для маломощных декодеров, которые явно не поддерживают его.»
Adaptive quantization – тратить биты там, куда смотрит глаз
Покадровый QP – слишком грубый подход. В кадре есть плоские области, где высокий QP незаметен, и детализированные участки, где он сразу бросается в глаза; тратить одинаковое количество бит на оба типа – расточительно. Каждый современный кодер поддерживает адаптивную квантование – поблочный сдвиг QP, при котором QP понижается в детализированных или перцептивно важных блоках и повышается в плоских.
Простейшая схема – variance-based adaptive quantization, обычно с флагом aq-mode=1. Кодер вычисляет дисперсию каждого макроблока (или CTU, или суперблока) и снижает QP в тех областях, где дисперсия высока. Более продвинутая схема, aq-mode=2, использует модель «spatial complexity», которая аккуратнее работает как с очень однородными участками (где может появиться полосатость), так и с сильно текстурированными (где глаза не различают мелкие детали). x264, x265, libvpx, libaom и SVT-AV1 – все поддерживают подобные подходы; названия и значения по умолчанию различаются, но принцип остаётся тем же.
Вторая ось – temporal adaptive quantization, иногда называемая MB-tree в x264 и x265. Кодер выполняет обратный проход, оценивая, насколько часто каждый блок в reference-кадре будет использоваться последующими блоками, и снижает QP для тех блоков, к которым будет больше обращений. Такие инвестиции окупаются в большинстве кадров. MB-Tree – главная причина, по которой современный x265-кодек при одинаковом QP выглядит лучше, чем тот же кодек с отключённой функцией: выигрыш в 10–20% по PSNR-эквивалентному битрейту – вполне обычное явление.
Третья ось – psycho-visual quantization, семейство приёмов, основанных на наблюдении: человеческий глаз предпочитает сохранение высокочастотной «энергии» (текстур) по сравнению с плоским сглаживанием. Флаги --psy-rd и --psy-rdoq в x264/x265 корректируют стоимость rate-distortion при выборе квантования так, что кодер отдаёт предпочтение блокам с сохранённой видимой текстурой, даже если это приводит к небольшому увеличению численного искажения. В результате PSNR может быть хуже, но субъективное восприятие и оценка по VMAF на настроенных моделях – лучше. Подробнее – в статье метриках качества: PSNR, SSIM, VMAF.
Как сравниваются кодеки – одна таблица
В таблице ниже приведены основные характеристики квантования кодеков, которые мы отгружали или использовали в production в Фора Софт. Столбцы слева направо: кодек, QP-шкала, правило шага, поддержка матриц, dependent quantization, инструменты adaptive quantization.
| Кодек | QP-шкала | Правило шага | Матрицы | Dependent Q | Adaptive Q |
|---|---|---|---|---|---|
| H.264 / AVC | 0..51 (8-bit) | удваивается каждые 6 | Default + custom | Нет | На стороне кодера (x264) |
| H.265 / HEVC | 0..51 (8-bit), расширение до 63/75 | удваивается каждые 6 | Default + custom, поблочная delta | Нет | На стороне кодера (x265, MB-tree) |
| VP9 | 0..255 qindex | калиброванная таблица | Только плоский | Нет | На стороне кодера (libvpx) |
| AV1 | 0..255 qindex | калиброванная таблица, на DC/AC и на плоскость | Встроенный набор, без override | Нет | Встроенные segment-карты + логика кодера |
| VVC / H.266 | 0..63 (8-bit), расширение до 75 (10-bit) | удваивается каждые 6 | Default + custom + LFNST-aware | Да (по умолчанию) | На стороне кодера + tools-aware |
Паттерн поколений очевиден: базовое правило шага практически не менялось с H.264, но каждое новое поколение добавляет всё более тонкие инструменты – поблочный delta QP, таблицы на плоскость, частотозависимые матрицы, dependent quantization – позволяющие кодеру точнее распределять биты. Quantization – одна и та же идея, применяемая всё более хирургически.
CRF, CBR, VBR – квантизация под другими именами
Большинство флагов кодера, с которыми реально работают стриминг-инженеры – CRF (Constant Rate Factor), CBR (Constant Bit Rate), VBR (Variable Bit Rate), ABR (Average Bit Rate) – являются режимами управления битрейтом, которые динамически подстраивают QP под заданные параметры. Подробно о каждом из них – в статье rate control: CBR, VBR, CRF.
CRF – самый простой в понимании режим: кодер берёт базовый QP, ориентированный на постоянное перцептивное качество, и применяет адаптивную квантование, чтобы варьировать QP по блокам. CRF 23 в x264 примерно соответствует среднему QP, на котором кодер остановился бы, если бы ему поручили закодировать фильм 1080p в «прозрачном качестве»; CRF 28 в x265 примерно соответствует той же точке. Цифра на ручке – не буквально QP, но управляет тем же базовым параметром.
CBR и VBR накладывают буферную модель поверх логики CRF. CBR ограничивает QP кодера таким значением, чтобы уложиться в целевой битовый бюджет каждую секунду; VBR позволяет кодеру тратить больше бит на динамичные сцены и меньше – на статичные, также изменяя QP. Шкала QP – это основа; режим управления битрейтом – политика, определяющая, где на этой шкале находиться.
Следствие для продуктовых решений – краткое. Каждое «снизить битрейт» на практике означает «повысить QP». Если QP становится слишком высоким, блоки теряют детализацию, края размываются, градиенты превращаются в ступеньки. Никакой магии в rate control нет – он не скрывает потерю качества, а лишь решает, когда её распределить.
Частые артефакты при квантовании
Когда зритель жалуется на плохой стрим, причина почти всегда в квантовании, которое тратит биты не по назначению. Пять симптомов особенно чётко указывают на одну и ту же проблему.
Blockiness – видимая граница между transform-блоками. Когда значение QP слишком высокое, каждый блок реконструируется как почти однородный фрагмент, и переход между соседними фрагментами становится заметным. Современные кодеки применяют in-loop deblocking filter, который сглаживает эти границы – подробнее об этом см. в статье in-loop filtering, – однако у фильтра есть пределы. При QP выше 38 в H.264 он уже не справляется.
Banding – видимые ступеньки в градиенте: закат, дымка, синяя стена – там, где в оригинале был плавный переход, а в закодированном изображении видны две-три равномерные полосы. Причина – квантование на низких частотах на гладком изображении: DC-коэффициент каждого блока округляется до ближайшего целого, и шаг округления проявляется как полоса. Banding – классическая проблема 8-битного кодирования и главный аргумент в пользу 10-битного даже для SDR; подробнее – в статье 8-бит vs 10-бит кодирование.
Blurring – потеря высокочастотных деталей: текст становится «пушистым», волосы – размытой массой, трава – сплошным пятном. Причина – quantization matrix, обнуляющая высокочастотные коэффициенты. При значениях QP выше определённого порога высокочастотные элементы матрицы обнуляются даже для настоящих границ, и обратный transform восстанавливает блок как низкочастотную версию.
Ringing – ореол волнистых артефактов вокруг резкого края. Причина – асимметричное квантование высокочастотных коэффициентов, которые DCT распределяет по области вокруг края; если часть из них сохраняется, а большинство обнуляется, реконструированный блок отображает оставшиеся как видимую рябь. Ringing – классический недостаток кодеков, использующих только DCT, при кодировании мультфильмов и текста, а также классическая причина, по которой были разработаны DST и ADST, которые мы рассмотрели в статье transform coding.
Mosquito noise – быстро меняющиеся мелкие артефакты вокруг движущихся краёв. Причина в том, что квантование отличается от кадра к кадру, из-за чего сохраняющиеся высокочастотные коэффициенты на границах «мерцают». Устраняется на стороне кодера: более точный контроль битрейта и меньшая вариация QP между соседними кадрами – а не на стороне декодера.
Где здесь Фора Софт
Мы применяем quantization-тюнинг в production-кодировании с 2010 года в таких областях, как видеостриминг, OTT и интернет-ТВ, видеоконференции и видеонаблюдение. Эффективные шаги, которые экономят ресурсы, обычно одинаковы: выбрать оптимальный анкер CRF или qindex для каждого типа контента, убедиться, что адаптивная квантование включена и правильно настроена под конкретный жанр (спорт, talking-head, анимация, screen capture), при необходимости внедрить небольшую кастомную матрицу квантования для наименее эффективного типа контента, если это оправдано цифрами, и обязательно проверять каждое изменение через A/B-тест на реальных устройствах пользователей. На WebRTC SFU нам удавалось достигать экономии трафика на 20–30% без заметной потери качества, просто настроив поведение кодера по QP для контента типа talking-head.
Ключевые выводы
- Квантование – единственный этап кодека, на котором информация теряется безвозвратно.
- Параметр квантования (QP) управляет логарифмическим шагом: каждые шесть единиц шаг удваивается.
- В AV1 диапазон qindex 0..255 обеспечивает в четыре раза более точную градацию, чем диапазон 0..51.
- Матрицы квантования повышают точность в областях, на которые обращает внимание глаз, и снижают её там, где он не фокусируется.
- Адаптивное квантование перераспределяет биты в пользу перцептивно значимых блоков внутри кадра.
- Любой режим управления битрейтом (CRF, CBR, VBR) – это стратегия динамического выбора QP.