Цель данной статьи – познакомить читателя с алгоритмами сжатия и декодирования видеоизображений, а также дать описание двух спецификаций сжатия видеозаписей и рассмотреть вопросы сжатия видеоизображений при помощи библиотеки Intel® Integrated Performance Primitives (Intel® IPP).
Сжатие высококачественных видеозаписей с высокой полосой пропускания [PDF 2 МБ]
Кодеры и декодеры видеозаписей и изображений, которые в терминологии программного обеспечения носят название кодеков, предназначены для сжатия мультимедийных данных с целью их хранения или передачи. Необработанные изображения имеют достаточно большой размер, а современные технологии практически не позволяют работать с несжатым цифровым видео. Более того, нет необходимости работать с мультимедийными данными в несжатом формате (кроме как для захвата и отображения), к тому же, с учетом возможностей современных процессоров, такие операции были бы неэффективными. Считывание с диска и распаковка сжатой видеозаписи происходит гораздо быстрее, чем несжатой.
В основе большинства алгоритмов сжатия лежит принцип избыточности и предсказуемости данных, что позволяет сократить объем информации, необходимый для кодирования видеосигнала. Среди наиболее распространенных методов можно выделить кодирование длин серий (run-length, RLE), в ходе которого происходит преобразование серий данных в цепочки с указанием количества повторов. Еще одним распространенным способом является неравномерное кодирование (variable-length), при котором данные фиксированной длины кодируются в виде данных переменной длины, в зависимости от частоты их использования. В качестве примера неравномерного кодирования можно привести алгоритм сжатия Хаффмана и арифметическое кодирование. Оба способа принято относить к методам сжатия без потери данных.
Другой способ кодирования основывается на принципе ограниченного восприятия. Несомненно, для некоторых типов данных, таких как текст или исполняемые двоичные файлы, сжатие должно проходить без потерь. Метод сжатия, при котором «a» иногда меняется на «A» будет недопустим. Независимое кодирование Хаффмана является полностью обратимым. Однако существуют методы сжатия мультимедийной информации, при которых ее полное обратное преобразование будет не только затруднительным, но и практически невозможным. Такие методы называют сжатием с потерями. Это означает, что данные до и после сжатия могут отличаться друг от друга. Однако в большинстве случаев потери являются незначительными или не очевидными для зрителя. Как и при кодировании звукозаписей, алгоритм сжатия служит для преобразования данных в области, из которых информация может быть исключена без ощутимого воздействия на материал.
Для сжатия большинства мультимедийных данных обычно используются методы кодирования, основанные на преобразовании. При использовании таких методов позиционная информация преобразовывается в частотную или позиционно-частотную информацию. Преимуществом сжатия является то, что для представления важной информации требуется меньшее количество данных. Соответственно, для представления более важной информации используется большее количество бит, а менее важной – меньшее количество бит. Модель восприятия диктует степень важности информации, но, как правило, информация с более высокой частотностью считается менее важной.
На рисунке 1 показана структура схемы кодирования и декодирования, основанная на преобразовании.
Рисунок 1. Упрощенная схема кодирования изображений с преобразованием
В алгоритмах сжатия видеоизображений обычно используется второй источник избыточности и повторяемости видеокадров. Кодек кодирует необработанные видеокадры или разницу между последовательными кадрами, часто компенсирующую движение.
В библиотеке Intel IPP сжатие видеозаписей происходит аналогично сжатию файлов формата JPEG с несколькими вариантами. Библиотека Intel IPP содержит компоненты кодеков и модели, образующие неполные кодеки для нескольких алгоритмов сжатия. В частности, библиотека включает:
Далее мы расскажем о каждом из этих элементов для двух алгоритмов сжатия MPEG-2 и H.264, а также приведем описание и примеры UMC. Все описания указанных выше элементов будут рассмотрены на примерах из моделей кодеков.
В данном разделе приводится описание видеочасти стандарта MPEG-2.
Стандарт MPEG-2 предназначен для высококачественных видеозаписей с высокой полосой пропускания. Это наиболее известный стандарт, поскольку он используется для кодирования видеозаписей в форматах DVD и HDTV. Для достижения приемлемого уровня кодирования требуются значительные вычислительные ресурсы, но процесс может выполняться в реальном времени на системах с современными процессорами. Декодирование потока MPEG-2 осуществляется довольно просто и может выполняться практически любым процессором либо бытовыми DVD-проигрывателями.
Проигрыватели формата MPEG-2 должны также уметь воспроизводить видео стандарта MPEG-1. Стандарт сжатия MPEG-1 во многом аналогичен MPEG-2, но отличается потоком битов с меньшим разрешением и компенсацией движения. Этот стандарт используется для сжатия видеоизображения формата VCD.
MPEG-2 является сложным форматом с множеством настроек. Он включает семь профилей коэффициентов сжатия и наборы функций, четыре уровня настройки разрешения, скорости потока и частоты кадров, а также три типа кадров. Код потока достаточно сложный и требует применения нескольких таблиц. Но, несмотря на то, что в его основе заложены сложные для расчета элементы сжатия и распаковки, стандарт с концептуальной точки зрения четко сформулирован. Элементы данного стандарта будут рассмотрены в настоящем разделе.
Компоненты MPEG-2
Компоненты MPEG-2 очень похожи на JPEG компоненты: процесс кодирования в MPEG-2 основан на дискретном косинусном преобразовании (DCT, Discrete Cosine Transform) и использует алгоритм кодирования Хаффмана с квантованными коэффициентами DCT. Однако, форматы потока данных отличаются, как и все таблицы. В отличие от JPEG, при кодировании в MPEG-2 используется ограниченный, но очень большой набор частот кадров и размеров. Но самым существенным отличием является принцип использования избыточности между кадрами.
Кадры в MPEG бывают трех видов: I-кадры (intra-кадры или опорные кадры), P-кадры (прогнозируемые) и B-кадры (двунаправленные). Последовательности типов кадров могут быть различными, но определяющей характеристикой является алгоритм предсказания. Intra-кадры независимы от других, что делает удобным их использование в качестве опорных. Фактически, они являются самостоятельными сжатыми изображениями. Для сравнения, P-кадры предсказываются на основе предшествующего P- или I-кадра, а B-кадры предсказываются по предшествующему или следующему P- или I-кадру. Однако отдельные блоки в таких кадрах могут относиться либо не относиться к Intra-кадрам.
Формат MPEG построен на иерархии блоков, макроблоков, срезов и кадров. Размер блоков составляет 8х8 пикселей на один канал. Макроблоки представляет собой совокупность блоков размером 16х16 пикселей, и занимают все три канала. В зависимости от субдискретизации макроблок может состоять из 6, 8 или 12 блоков. Например, в макроблоке YCbCr 4:2:0 – четыре блока Y, один Cb и один Cr.
Далее будет описаны основные блоки кодека MPEG-2 в порядке кодирования. На рисунке 2 представлены взаимосвязи между этими блоками.
Оценка и компенсация движения
Ключом к эффективности кодирования видеосигнала является использование предыдущих или последующих кадров для прогнозирования значения каждого пикселя. При сжатии изображений, в качестве опорного значения для каждого пикселя может использоваться только блок в другой части изображения, но при сжатии видеоизображения может потребоваться использование изображения того же объекта. Вместо сжатия пикселей, обладающих высоким уровнем энтропии, при кодировании видео может происходить сжатие различий между сходными пикселями, которые имеют намного более низкий уровень энтропии.
Однако объекты и фон видеоизображения не всегда неподвижны. Для создания по-настоящему эффективной связи с другими видеокадрами, кодек должен учитывать движение между кадрами. Эта задача решается посредством оценки и компенсации движения. Наряду с видео данными, каждому блоку также соответствовать векторы движения, которые определяют степень смещения определенного кадра по отношению к опорному изображению. Прежде чем принимать во внимание разницу между текущим и опорным кадром, кодек смещает опорный кадр на соответствующую величину. Расчет векторов движения называется оценкой движения, а адаптация движения называется компенсацией движения.
Подобная компенсация движения является важной и ресурсоемкой операцией при сжатии видео. Фактически, существенная разница между стандартами MPEG-1 и MPEG-2 заключается в переходе от точности уровня пикселя к точности уровня полупикселя. Такое изменение позволяет добиться значительного качества при заданном потоке данных, но и делает процесс кодирования в MPEG-2 более длительным.
Дискретное косинусное преобразование (DCT)
Как и сжатие в JPEG, сжатие в MPEG основывается на дискретном косинусном преобразовании. Кодек рассчитывает значение DCT для каждого блока размером 8x8 пикселей или разницу данных для каждого кадра. Информацию о частотности проще упорядочить по степени важности для зрителя и квантовать; при этом используются неизменяемые области каждого кадра.
Рисунок 2. Высокоуровневые блоки кодирования и декодирования в MPEG-2
Квантование
Для различных типов блоков в MPEG квантование выполняется по-разному. Существуют различные матрицы значений коэффициентов для Intra- и не Intra-макроблоков, а также данных о цвете и насыщенности. Для всех матриц также используется шкала. Каждый макроблок может изменяться по шкале и матрице квантования.
Для Intra-блоков, коэффициент DC или нулевой частоты квантуется путем отбрасывания младших бит (от 0 до 3), то есть путем смещения вправо на величину от нуля до трех бит. Коэффициенты AC присваиваются шагам квантования согласно общей шкале и матрице. Квантование происходит в линейном режиме.
Для не Intra-блоков, DC-составляющая содержит менее важную информацию и с большей вероятностью стремится к нулю. Таким образом, составляющие DC и AC квантуются одинаково по не Intra-матрице квантования и шкале.
Кодирование по алгоритму Хаффмана
Чтобы меньший уровень энтропии видео данных приводил к уменьшению скорости передачи данных в потоке, данные необходимо перекодировать с использованием меньшего количества бит. В стандарте MPEG, так же как и JPEG, данная операция называется схемой кодирования переменных длин по алгоритму Хаффмана. Каждый отрезок данных представляется кодом, длина которого обратно связана с его частотой. По причине сложности кодирования в MPEG-2, существуют десятки таблиц кодов для коэффициентов, типов блоков и другой информации.
Для Intra-блоков коэффициент DC не кодируется напрямую. Вместо этого использует разница между ним и предсказывающим блоком. Предсказывающий блок может быть значением DC (при наличии) и Intra-значением или постоянным средним значением, во втором случае.
Для упорядочивания коэффициентов DCT используется две матрицы сканирования. Для одной формируется зигзагообразный шаблон, близкий к диагональной симметрии для не чередующихся блоков, а другая образует измененный зигзагообразный профиль для чередующихся блоков. Матрицы располагают коэффициенты в порядке повышения частоты, пытаясь сделать длины серий данных максимальными.
Кодер выполняет кодирование данных потока для этой матрицы. Каждая пара уровня потока представляет число последовательных точек определенного уровня. Для наиболее распространенных пар, коды помещаются в таблицу Хаффмана. Менее частные коды, например цепочки длиной более 31, заключается в управляющую последовательность с 6-битной серией и 12-битным уровнем.
В библиотеке Intel IPP содержится эффективная модель кодера и декодера для формата MPEG-2. Поскольку существуют различные варианты, это всего лишь модель, а не утвержденный кодек.
В каждом из функциональных компонентов кодека записаны сотни вызовов функций Intel IPP. Основная часть кода в модели служит для интерпретации потока битов и манипуляции с данными, но большая часть времени уходит на декодирование пикселей. В связи с этим практически все вызовы Intel IPP используются для блоков декодирования пикселей. В частности, основные высокоуровневые функции принадлежат классу
MPEG2VideoDecoderBase:
DecodeSlice_FrameI_420
DecodeSlice_FramePB_420
DecodeSlice_FieldPB_420
DecodeSlice_FrameI_422
DecodeSlice_FramePB_422
DecodeSlice_FieldPB_422
Эти функции декодируют структуру изображения, а затем переходят к выполнению функции декодирования отдельных блоков, такую как ippiDecodeIntra8x8IDCT_MPEG2_1u8u. На рисунке 2 показаны основные отрывки кода этих двух функций.
Status MPEG2VideoDecoderBase::DecodeSlice_FrameI_420(
IppVideoContext *video)
{
...
DECODE_VLC(macroblock_type, video->bs, vlcMBType[0]);
if (load_dct_type) {
GET_1BIT(video->bs, dct_type);
}
if (macroblock_type & IPPVC_MB_QUANT)
{
DECODE_QUANTIZER_SCALE(video->bs,
video->cur_q_scale);
}
if (PictureHeader.concealment_motion_vectors)
{
if (PictureHeader.picture_structure !=
IPPVC_FRAME_PICTURE) {
SKIP_BITS(video->bs, 1);
}
mv_decode(0, 0, video);
SKIP_BITS(video->bs, 1);
}
RECONSTRUCT_INTRA_MB_420(video->bs, dct_type);
}
}//DecodeSlice_FrameI_420
#define RECONSTRUCT_INTRA_MB_420(BITSTREAM, DCT_TYPE) \
RECONSTRUCT_INTRA_MB(BITSTREAM, 6, DCT_TYPE)
#define RECONSTRUCT_INTRA_MB(BITSTREAM, NUM_BLK, DCT_TYPE) \
{ \ ...
for (blk = 0; blk < NUM_BLK; blk++) { \
sts = ippiDecodeIntra8x8IDCT_MPEG2_1u8u( ... ); \
} \
}
Status MPEG2VideoDecoderBase::DecodeSlice_FramePB_420(
IppVideoContext *video)
{
...
if (video->prediction_type == IPPVC_MC_DP) {
mc_dualprime_frame_420(video);
} else {
mc_frame_forward_420(video);
if (video->macroblock_motion_backward) {
mc_frame_backward_add_420(video);
}
}
} else {
if (video->macroblock_motion_backward) {
mc_frame_backward_420(video);
} else {
RESET_PMV(video->PMV)
mc_frame_forward0_420(video);
}
}
if (macroblock_type & IPPVC_MB_PATTERN) {
RECONSTRUCT_INTER_MB_420(video->bs, dct_type);
}
}
return UMC_OK;
}//DecodeSlice_FramePB_420
void MPEG2VideoDecoderBase::mc_frame_forward0_422(
IppVideoContext *video)
{
MC_FORWARD0(16, frame_buffer.Y_comp_pitch,
frame_buffer.U_comp_pitch);
}
#define MC_FORWARD0(H, PITCH_L, PITCH_C) \
...
ippiCopy16x16_8u_C1R(ref_Y_data + offset_l, PITCH_L, \
cur_Y_data + offset_l, PITCH_L); \
ippiCopy8x##H##_8u_C1R(ref_U_data + offset_c, PITCH_C, \
cur_U_data + offset_c, PITCH_C); \
ippiCopy8x##H##_8u_C1R(ref_V_data + offset_c, PITCH_C, \
cur_V_data + offset_c, PITCH_C);
#define RECONSTRUCT_INTER_MB_420(BITSTREAM, DCT_TYPE) \
RECONSTRUCT_INTER_MB(BITSTREAM, 6, DCT_TYPE)
#define RECONSTRUCT_INTER_MB(BITSTREAM, NUM_BLK, DCT_TYPE) \
...
for (blk = 0; blk < NUM_BLK; blk++) { \
...
sts = ippiDecodeInter8x8IDCTAdd_MPEG2_1u8u(...);
Рисунок 2. Структура декодирования Intra-макроблока в MPEG-2
При декодировании две группы функций Intel IPP образуют большую часть конвейера декодирования. Между ними встраивается часть декодера MPEG-2, по крайней мере, для Intra-блоков.
Первая группа – это ippiReconstructDCTBlock_MPEG2 для не Intra-блоков, а вторая – ippiReconstructDCTBlockIntra_MPEG2 для Intra-блоков. Указанные функции выполняют декодирование данных алгоритма Хаффмана, заново упорядочивают и деквантуют их. Источником выступает закодированный по методу Хаффмана поток битов, указывающий на верхнюю часть блока, а объектом – блок размером 8x8 последовательных коэффициентов DCT.
В алгоритме декодирования Хаффмана используются отдельные таблицы для кодов AC и DC в формате, отвечающим структуре спецификации Intel IPP. Аргумент матрицы сканирования определяет используемый зигзагообразный шаблон. Функции также принимают два аргумента для квантования, матрицу и коэффициент масштабирования. Каждый элемент умножается на соответствующий элемент в матрице квантования, и затем на общий коэффициент масштабирования.
Функция ReconstructDCTBlockIntra также принимает два аргумента для обработки коэффициента DC: опорное значение и смещение. Функция выполняет сложение опорного значения, которое часто берется из последнего блока, с коэффициентом DC. Коэффициент DC смещается аргументом смещения, который может иметь значение от нуля до трех бит, как уже было сказано ранее.
Вторая основная функция – обратное DCT. Две наиболее полезные функции DCT – это ippiDCT8x8InvLSClip_16s8u_C1R для Intra-блоков и ippiDCT8x8Inv_16s_C1R для не Intra-блоков. Кроме того, могут использоваться варианты без смещения уровня и обрезания. Первая функция выполняет обратное DCT с блоком 8x8 и затем преобразовывает данные в Ipp8u со смещением уровня. В результате получаются пиксели. Вторая функция применяет обратное DCT и оставляет результат в Ipp16s – получаются значения расхождения. Декодер теперь должен сложить полученные значения расхождения с опорным блоком с компенсацией движения.
На рисунке 4 показаны группы функций, выполняющие декодирование внутреннего макроблока 4:2:0. На вход подается поток битов и несколько предварительно рассчитанных таблиц. Результатом DCT являются данные о пикселях непосредственно в плоскости изображения. Четыре блока Y-данных помещаются в массив размером 2x2 в соответствующем изображении, а блоки U и V помещаются в аналогичное положение в плоскостях U и V. Результат отображается непосредственно на соответствующем экране. Кроме того, плоскости U и V можно восстановить для получения изображения YCbCr 4:4:4, или преобразовать все три плоскости при помощи других функций Intel IPP в RGB для просмотра.
ippiReconstructDCTBlockIntra_MPEG2_32s(
&video->bitstream_current_data,
&video->bitstream_bit_ptr,
pContext->vlcTables.ippTableB5a,
pContext->Table_RL,
scan_1[pContext->PictureHeader.alternate_scan],
q_scale[pContext->PictureHeader.q_scale_type]
[pContext->quantizer_scale],
video->curr_intra_quantizer_matrix,
&pContext->slice.dct_dc_y_past,
pContext->curr_intra_dc_multi,
pContext->block.idct, &dummy);
ippiReconstructDCTBlockIntra_MPEG2_32s(
…
pContext->block.idct+64, &dummy);
…
// Repeat two more times for other Y blocks
ippiReconstructDCTBlockIntra_MPEG2_32s(…)
…
VIDEO_FRAME_BUFFER* frame =
&video->frame_buffer.frame_p_c_n
[video->frame_buffer.curr_index];
// Inverse DCT and place in 16x16 block of image
ippiDCT8x8InvLSClip_16s8u_C1R(
pContext->block.idct,
frame->Y_comp_data + pContext->offset_l,
pitch_Y, 0, 0, 255);
ippiDCT8x8InvLSClip_16s8u_C1R(
pContext->block.idct,
frame->Y_comp_data + pContext->offset_l + 8,
pitch_Y, 0, 0, 255);
ippiDCT8x8InvLSClip_16s8u_C1R(
pContext->block.idct,
frame->Y_comp_data + pContext->offset_l + 8*pitch_Y,
pitch_Y, 0, 0, 255);
ippiDCT8x8InvLSClip_16s8u_C1R(
pContext->block.idct,
frame->Y_comp_data +
pContext->offset_l + 8*pitch_Y + 8,
pitch_Y, 0, 0, 255);
…
ippiReconstructDCTBlockIntra_MPEG2_32s(
&video->bitstream_current_data,
&video->bitstream_bit_ptr,
pContext->vlcTables.ippTableB5b,
pContext->Table_RL,
scan_1[pContext->PictureHeader.alternate_scan],
q_scale[pContext->PictureHeader.q_scale_type]
[pContext->quantizer_scale],
video->curr_chroma_intra_quantizer_matrix,
&pContext->slice.dct_dc_cb_past,
pContext->curr_intra_dc_multi,
pContext->block.idct, &i1);
ippiReconstructDCTBlockIntra_MPEG2_32s(
…
&pContext->slice.dct_dc_cr_past,
pContext->curr_intra_dc_multi,
pContext->block.idct + 64,&i2);
ippiDCT8x8InvLSClip_16s8u_C1R (
pContext->block.idct,
frame->U_comp_data + pContext->offset_c,
pitch_UV, 0,0,255);
ippiDCT8x8InvLSClip_16s8u_C1R (
pContext->block.idct + 64,
frame->V_comp_data + pContext->offset_c,
pitch_UV, 0,0,255);
Рисунок 3. Декодирование Intra-макроблока в MPEG-2
Подставной параметр перед первым вызовом ippiReconstructDCTBlock здесь отсутствует, но может использоваться для оптимизации. Возврат значения 1 означает, что только коэффициент DC не равен нулю и обратное DCT можно пропустить. Если значение меньше 10, то все ненулевые коэффициенты находятся в первом блоке 4x4, и можно использовать обратное DCT блока 4х4.
Вместо функции ippiDCT8x8InvLSClip_16s8u_C1R можно вызвать ippiDCT8x8Inv_16s8u_C1R, поскольку данные ограничиваются диапазоном от 0 до 255 по умолчанию.
В случае с не Intra-блоками, ссылка на матрицу квантования может быть равна 0. При этом будут использоваться матрицы по умолчанию.
На рисунке 4 представлен еще один подход к декодированию с использованием модели MPEG-2 для Intel IPP 5.2. Вместо использования функции ippiReconstructDCTBlock для декодирования, здесь реализуется псевдо-IPP функция под названием ippiDecodeIntra8x8IDCT_MPEG2_1u8u. Указанная функция охватывает практически весь цикл декодирования – от кодирования переменных длин до компенсации движения.
При использовании этой функции большая часть процесса декодирования выполняется на языке C++ с широким применением макросов и логики состояний. Декодирование по модели Хаффмана в этой модели выполняется на языке C++ с использованием макросов. Квантование выполняется на языке C++ для каждой модели по мере ее декодирования. Компенсация движения выполняется вместе с DCT одним из макросов DCT.
Вызовы функций используют несколько функций DCT. Большая часть DCT выполняется двумя полезными функциями: ippiDCT8x8Inv_16s8u_C1R и ippiDCT8x8Inv_16s_C1R для Intra- и не Intra-блоков соответственно. Первая функция преобразует результат в Ipp8u, поскольку для внутренних блоков эти значения представляют пиксели. Вторая функция оставляет результат в Ipp16s, поскольку получаемые значения является значениями расхождения, прибавляемыми к опорному блоку с компенсацией движения. В модели также используются другие функции DCT, например специализированная функция ippiDCT8x8Inv_AANTransposed, которая допускает, что дискретные значения транспонированы и образуют зигзагообразный профиль, и устанавливает явные нулевые коэффициенты в конце. Для блоков, содержащих преимущественно нули, декодер также использует функцию ippiDCT8x8Inv_4x4_16s_C1.
MP2_FUNC(IppStatus, ippiDecodeInter8x8IDCTAdd_MPEG2_1u8u, (
Ipp8u** BitStream_curr_ptr,
Ipp32s* BitStream_bit_offset,
IppiDecodeInterSpec_MPEG2* pQuantSpec,
Ipp32s quant,
Ipp8u* pSrcDst,
Ipp32s srcDstStep))
{
// VLC decode & dequantize for one block
for (;;) {
if ((code & 0xc0000000) == 0x80000000) {
break;
} else if (code >= 0x08000000) {
tbl = MPEG2_VLC_TAB1[UHBITS(code - 0x08000000, 8)];
common:
i++;
UNPACK_VLC1(tbl, run, val, len)
i += run;
i &= 63; // just in case
j = scanMatrix[i];
q = pQuantMatrix[j];
val = val * quant;
val = (val * q) >> 5;
sign = SHBITS(code << len, 1);
APPLY_SIGN(val, sign);
SKIP_BITS(BS, (len+1));
pDstBlock[j] = val;
mask ^= val;
SHOW_HI9BITS(BS, code);
continue;
} else if (code >= 0x04000000) {
...
}
}
...
pDstBlock[63] ^= mask & 1;
SKIP_BITS(BS, 2);
COPY_BITSTREAM(*BitStream, BS)
IDCT_INTER(pDstBlock, i, idct, pSrcDst, srcDstStep);
return ippStsOk;
}
#define FUNC_DCT8x8 ippiDCT8x8Inv_16s_C1
#define FUNC_DCT4x4 ippiDCT8x8Inv_4x4_16s_C1
#define FUNC_DCT2x2 ippiDCT8x8Inv_2x2_16s_C1
#define FUNC_DCT8x8Intra ippiDCT8x8Inv_16s8u_C1R
#define FUNC_ADD8x8 ippiAdd8x8_16s8u_C1IRS
#define IDCT_INTER(SRC, NUM, BUFF, DST, STEP) \
if (NUM < 10) { \
if (!NUM) { \
IDCTAdd_1x1to8x8(SRC[0], DST, STEP); \
} else \
IDCT_INTER_1x4(SRC, NUM, DST, STEP) \
/*if (NUM < 2) { \
FUNC_DCT2x2(SRC, BUFF); \
FUNC_ADD8x8(BUFF, 16, DST, STEP); \
} else*/ { \
FUNC_DCT4x4(SRC, BUFF); \
FUNC_ADD8x8(BUFF, 16, DST, STEP); \
} \
} else { \
FUNC_DCT8x8(SRC, BUFF); \
FUNC_ADD8x8(BUFF, 16, DST, STEP); \
}
Рисунок 4. Вариант декодирования не Intra-макроблока в MPEG-2
Функции DCT библиотеки Intel IPP также поддерживают альтернативную, гибридную структуру YUV-данных, состоящую из двух плоскостей – Y и UV. В плоскости UV U- и V-данные чередуются. В этом случае, макроблок состоит из блока UV-данных размером 16x8. В альтернативной структуре функция библиотеки Intel IPP ippiDCT8x8Inv_AANTransposed_16s_P2C2R поддерживает не Intra-кадры, а функция ippiDCT8x8Inv_AANTransposed_16s8u_P2C2R – Intra-кадры. Функция ippiMC16x8UV_8u_C1 и ippiMC16x8BUV_8u_C1 поддерживает компенсацию движения в этой конфигурации.
При кодировании функции практически аналогичны функциям декодирования, перечисленным выше. Для Intra-блоков функция прямого DCT ippiDCT8x8Fwd_8u16s_C1R преобразует блок пикселей Ipp8u в коэффициенты DCT Ipp16s. Затем функция ippiQuantIntra_MPEG2 выполняет квантование, а функция ippiPutIntraBlock рассчитывает пары серий, которые кодируются по алгоритму Хаффмана. Параметры для двух последних функций очень похожи на параметры, используемые для аналогичных функций декодирования.
Для не Intra-блоков, функция ippiDCT8x8Fwd_16s_C1R преобразует разностную информацию в коэффициенты DCT, функция ippiQuant_MPEG2 выполняет квантование, а функция ippiPutNonIntraBlock рассчитывает и кодирует пары серий.
Оценка и компенсация движения
Процесс оценки движения кодером требует значительных вычислительных ресурсов, поскольку, в сущности, требуется провести повторную оценку эффективности потенциальных векторов компенсации движения. Однако возможные векторы движения выбираются при помощи функции быстрой оценки, которая позволяет ускорить выполнение алгоритма. Функции библиотеки Intel IPP ippiSAD16x16, ippiSqrDiff16x16 и ippiSqrDiff16x16 сравнивают блоки из одного кадра с блоками опорного кадра, для которых была выполнена компенсация движения. Функция ippiSAD вычисляет сумму абсолютной разницы между пикселями, в то время как ippiSqrDiff определяет сумму квадратов разностей. В модели Intel IPP используется первая функция.
После того, как кодер определяет пространство возможных векторов движения, он может использовать многие функции ippiGetDiff для вычисления разницы между текущим и опорным кадром после компенсации движения.
Алгоритм компенсации движения необходим как кодеру, так и декодеру. Для объединения опорного кадра с данными о декодированной разнице, в алгоритмах из библиотеки Intel IPP могут использоваться функции ippiMC или ippiAdd. На рисунке 6 показан такой алгоритм для макроблока из B-кадра 4:2:0.
// Determine whether shift is half or full pel
// in horizontal and vertical directions
// Motion vectors are in half-pels in bitstream
// The bit code generated is:
// FF = 0000b; FH = 0100b; HF = 1000b; HH = 1100b
flag1 = pContext->macroblock.prediction_type |
((pContext->macroblock.vector[0] & 1) << 3) |
((pContext->macroblock.vector[1] & 1) << 2);
flag2 = pContext->macroblock.prediction_type|
((pContext->macroblock.vector[0] & 2) << 2) |
((pContext->macroblock.vector[1] & 2) << 1);
flag3 = pContext->macroblock.prediction_type|
((pContext->macroblock.vector[2] & 1) << 3) |
((pContext->macroblock.vector[3] & 1) << 2);
flag4 = pContext->macroblock.prediction_type|
((pContext->macroblock.vector[2] & 2) << 2) |
((pContext->macroblock.vector[3] & 2) << 1);
// Convert motion vectors from half-pels to full-pel
// also convert for chroma subsampling
// down, previous frame
vector_luma[1] = pContext->macroblock.vector[1] >>1;
vector_chroma[1] = pContext->macroblock.vector[1] >>2;
// right, previous frame
vector_luma[0] = pContext->macroblock.vector[0] >> 1;
vector_chroma[0] = pContext->macroblock.vector[0] >> 2;
// down, subsequent frame
vector_luma[3] = pContext->macroblock.vector[3] >> 1;
vector_chroma[3] = pContext->macroblock.vector[3] >> 2;
// right, subsequent frame
vector_luma[2] = pContext->macroblock.vector[2] >> 1;
vector_chroma[2] = pContext->macroblock.vector[2] >> 2;
offs1 =
(pContext->macroblock.motion_vertical_field_select[0] +
vector_luma[1] + pContext->row_l) * pitch_y +
vector_luma[0] + pContext->col_l,
offs2 =
(pContext->macroblock.motion_vertical_field_select[1] +
vector_luma[3] + pContext->row_l) * pitch_y +
vector_luma[2] + pContext->col_l,
i = ippiMC16x16B_8u_C1(
ref_Y_data1 + offs1, ptc_y, flag1,
ref_Y_data2 + offs2, ptc_y, flag3,
pContext->block.idct, 32,
frame->Y_comp_data + pContext->offset_l,
ptc_y, 0);
assert(i == ippStsOk);
offs1 =
(pContext->macroblock.motion_vertical_field_select[0] +
vector_chroma[1] + pContext->row_c )* pitch_uv +
vector_chroma[0] + pContext->col_c;
offs2 =
(pContext->macroblock.motion_vertical_field_select[1] +
vector_chroma[3] + pContext->row_c )* pitch_uv +
vector_chroma[2] + pContext->col_c;
i = ippiMC8x8B_8u_C1(
ref_U_data1 + offs1, ptc_uv, flag2,
ref_U_data2 + offs2, ptc_uv, flag4,
pContext->block.idct+256,16,
frame->U_comp_data + pContext->offset_c,
ptc_uv, 0);
assert(i == ippStsOk);
i = ippiMC8x8B_8u_C1(
ref_V_data1 + offs1, ptc_uv,flag2,
ref_V_data2 + offs2, ptc_uv,flag4,
pContext->block.idct+320,16,
frame->V_comp_data + pContext->offset_c,
ptc_uv, 0);
assert(i == ippStsOk);
Рисунок 5. Двунаправленная компенсация движения в MPEG-2
Сначала точность векторов движения необходимо перевести от полупикселей к полным пикселям, поскольку информация о полупикселях передается в функцию ippiMC в виде флага. Код опускает наименее значимый бит каждого вектора движения и использует его для создания флага. Затем начальная точка каждого опорного блока смещается по вертикали и горизонтали на величину вектора движения.
Поскольку этот код используется для двунаправленного прогнозирования, все эти действия повторяются для двух отдельных векторов движения и двух отдельных опорных кадров. На этом заключительном этапе декодирования результат помещается непосредственно в получаемый кадр YCbCr.
Преобразование цветовой палитры
Стандартные функции преобразования цветовой палитры из библиотеки Intel IPP поддерживают преобразование в формат YCbCr 4:2:2, 4:2:0 и 4:4:4 и обратно. Поскольку, в принципе, эти функции представляют собой наборы преобразования цветов, они называются RGBToYUV422 / YUV422ToRGB, RGBToYUV420 / YUV420ToRGB и RGBToYUV / YUVToRGB. Эти функции поддерживают чередующиеся и планарные YCbCr-данные. На рисунке 7 представлено преобразование декодированных пикселей MPEG-2 в палитру RGB для отображения.
src[0] = frame->Y_comp_data +
pContext->Video[0].frame_buffer.video_memory_offset;
src[1] = frame->V_comp_data +
pContext-Video[0].frame_buffer.video_memory_offset/4;
src[2] = frame->U_comp_data +
pContext->Video[0].frame_buffer.video_memory_offset/4;
srcStep[0] = frame->Y_comp_pitch;
srcStep[1] = pitch_UV;
srcStep[2] = pitch_UV;
ippiYUV420ToRGB_8u_P3AC4R(src, srcStep, video_memory +
pContext->Video[0].frame_buffer.video_memory_offset/4,
roi.width<<2, roi);
Рисунок 6. Преобразование цветовой модели YCbCr 4:2:0 в RGB для просмотра
Два семейства видеокодеков с номенклатурой H.26x и MPEG-x пересекаются. MPEG-2 имеет название H.262 в схеме H.26x. Подобный образом, другой популярный кодек – H.264 – является подмножеством стандарта MPEG-4, который также известен под названием MPEG-4 Advanced Video Coding (AVC). Его целью, как и всех кодеков группы MPEG-4, было сжатие видеосигнала с приемлемым качеством при очень низкой скорости потока, примерно в два раза ниже, чем той, которая использовалась в его предшественниках, MPEG-2 и H.263.
В настоящем разделе приводится описание компонентов стандарта H.264 и рассказывается о том, как каждый из этих компонентов реализован в Intel IPP.
Компоненты H.264
Как и ранние представители семейства H.26x, стандарт H.264 предусматривает два режима кодирования для отдельных видеокадров – Intra (опорные) и Inter (промежуточные). В первом случае, кадр видеоизображения кодируется как независимое изображение без опоры на другие изображения в видеопоследовательности. Во втором случае, для предсказания значений используются предыдущие и, возможно, следующие кадры. На рисунке 7 показаны высокоуровневые блоки, задействованные в кодировании и декодировании Intra-кадров по алгоритму H.264. На рисунке 9 представлен процесс кодирования и декодирования для Inter-кадров.
Далее в данном разделе приводится описание каждого из этих блоков в порядке их обработки кодером.
Рисунок 7. Кодирование и декодирование Intra-кадров по алгоритму H.264
Рисунок 8. Кодирование и декодирование Inter-кадров по алгоритму H.264
Оценка и компенсация движения
Блоки в H.264 (в Inter- или Intra-кадрах) можно представлять относительно предыдущих или последующих блоков или кадров. В Inter-кадрах это называется оценкой движения и относится к блокам в других кадрах. Значительное сжатие происходит именно здесь. Как и в других методах сжатия видеоизображений, здесь действует утверждение, что энтропия значительно меньше в разнице между схожими блоками, чем в абсолютных значениях этих блоков. Это особенно справедливо, если разница между исходным и восстановленным блоками приходится на смещение от блока, расположенного в другом кадре.
Стандарт H.264 предусматривает очень гибкую поддержку компенсации движения. В процессе оценки возможен выбор опорных изображений из 32 других кадров. Также, можно установить связи с изображениями, которые необходимо сформировать интерполяцией.
Кодер отвечает за определение опорного изображения, блока и вектора движения. Такой блок, как правило, выбирается путем поиска среди возможных вариантов, начиная с наиболее вероятного. Затем кодер рассчитывает и выполняет кодирование разницы между предыдущими, закодированными блоками и новыми данными.
При декодировании (после декодирования опорных блоков) опорные данные и декодированные разностные данные складываются. С определенной вероятностью блоки и кадры декодируются вне временной последовательности, поскольку кадры можно кодировать по отношению к опережающим блокам и кадрам.
Кодирование по алгоритму H.264 поддерживает точность векторов движения до субпикселя, что означает, что опорный блок фактически вычисляется путем интерполяции внутри блока реальных пикселей. Векторы движения для блоков яркости выражены с точностью до четверти пикселя, а цветоразностные блоки – с точностью до восьмой части пикселя.
Такое субпиксельное разрешение значительно усложняет алгоритмику и процесс расчета. На процесс декодирования, требующий выполнение субпиксельной компенсации движения один раз для каждого блока, приходится от 10 до 20 процентов работы конвейера. Основная часть этого времени уходит на интерполяцию значений между пикселями для формирования опорных блоков с субпиксельным смещением. Ресурсоемкость процесса субпиксельной оценки зависит от алгоритма декодирования, но процесс может потребовать повторного выполнения компенсации движения.
Алгоритм интерполяции для формирования опорных блоков со смещением определяется по разному для блоков яркости и цветности. Для блоков яркости интерполяция выполняется в два этапа – интерполяция с точностью до полупикселя, и затем до четверти пикселя. Затем, путем фильтрования по горизонтали и вертикали получаются значения полупикселей:
[1 -5 20 20 -5 1]/32
Интерполяция с точностью до четверти пикселя выполняется по линейно усредненным, смежным полупикселям.
Компенсация движения цветовых блоков выполняется путем билинейной интерполяции с точности до четверти пикселя или восьмой части пикселя в зависимости от формата цветности. Каждое положение полупикселя представляет собой линейную группу соседних пикселей.
На рисунке 9 показано, какие пиксели используются для обоих вариантов интерполяции.
После выполнения интерполяции и создания опорного блока, алгоритм добавляет опорный блок к информации о декодированной разнице для получения восстановленного блока. Кодер выполняет это действие для получения восстановленных опорных кадров, а декодер – для получения выходных кадров.
Рисунок 9. Субпиксельная интерполяция для компенсации движения по алгоритму H.264
Прогнозирование Intra-кадров
Структура Intra-кадров позволяет им не зависеть от предшествующих или следующих за ними кадров при восстановлении. Однако, в стандарте H.264 ранние блоки могут использоваться кодером из одного кадра в качестве опорных для новых блоков. Процесс прогнозирования Intra-кадров может обеспечить дополнительное сжатие Intra-макроблоков и может оказаться особенно эффективным, если будет найден соответствующим образом подходящий опорный блок.
Опорные блоки не используются так же, как промежуточные блоки прогнозирования, то есть не принимают попиксельную разницу фактических блоков смежных кадров. Вместо этого, значение прогнозирования текущего блока рассчитывается как среднее значение ряда пикселей, граничащих с ним. То, какие пиксели выбираются и как они используются для расчета блока, зависит от режима предсказания Intra-кадров. На рисунке 10 показаны направления, которым могут следовать пиксели, а также номера режимов, определенных спецификацией H.264 [JVT-G050].
Данная операция также может оказаться одной из самых ресурсоемких в вычислительном плане частей процесса кодирования. Для полного просчета всех возможных вариантов, кодер должен сравнить блок яркости 16x16 или цветности 8x8 с 4 другими блоками, и каждый блок яркости 4x4 или 8x8 с 9 другими боками.
Рисунок 10. Номера режимов для прогнозирования Intra-кадров по алгоритму H.264
Поскольку кодер способен обрабатывать разные размеры блоков, желательна схема, обеспечивающая достижение оптимального компромисса между необходимым числом битов для представления видеопоследовательности и точностью результатов.
Преобразование
Вместо DCT, алгоритм H.264 использует целочисленное преобразование в качестве основного режима преобразования для пересчета разностных данных между пространственными и частотными областями. Преобразование выполняется приближением DCT, что проще с вычислительной точки зрения и обеспечивает отсутствие потери данных. Базовое преобразование, показанное на рисунке 11, можно реализовать только при помощи смещения и сложения.
Такое преобразование блока 4x4 является лишь одной разновидностью преобразования по алгоритму H.264. В H.264 определяются преобразования для блоков 2x2 и 4x4 в базовом профиле, а дополнительные профили поддерживают преобразование для блоков большего размера – прямоугольных или квадратных с размерами со степенью двух.
Алгоритм применяет преобразование по отдельности для первого, или яркостного, DC и компонента цветности. В базовом профиле, в алгоритме H.264 используется одно преобразование DC-коэффициентов цветности блока 2x2, преобразование DC-коэффициентов яркости блока 4x4 и основное преобразование блока 4x4 для всех других коэффициентов.
Рисунок 11. Матрицы для преобразования по алгоритму H.264
Квантование
На этапе квантования происходит сокращение объема информации путем деления каждого коэффициента на определенное число с целью уменьшения количества возможных значений, которые может принимать результат. Поскольку это приводит к сужению диапазона значений, статистическое кодирование позволяет выразить значения в более компактной форме.
Квантование по алгоритму H.264 с точки зрения арифметики представлено двухступенчатой операцией. Сначала каждый коэффициент в блоке 4x4 умножается на фиксированное значение коэффициента. Это позволяет масштабировать коэффициенты в зависимости от значимости или информации. Затем происходит деление на подстраиваемое значение параметра квантования (ПК). Это дает определенный «рычаг» для настройки качества и конечной скорости потока в результате кодирования. Две операции можно объединить в отдельную операцию умножения и смещения.
ПК выражен в виде целого числа от 0 до 51. Это целое число нелинейно преобразуется в длину шага квантования (QStep). Каждые 6 шагов увеличивают длину шага на 2, и между каждой парой длин шагов степени двух N и 2N получается 5 шагов: 1,125N, 1,25N, 1,375N, 1,625N, 1,75N.
Переорганизация
При статистическом кодировании коэффициентов каждого макроблока, блоки обрабатываются кодеком в определенном порядке. Упорядочивание позволяет увеличить количество последовательных нулей.
Сохранение подобного порядка при расчете результата преобразования и квантования является принятой практикой.
Статистическое кодирование
Алгоритм H.264 определяет два режима статистического кодирования – контекстно-зависимое адаптивное кодирование с переменной длиной кодового слова (CAVLC) и контекстно-зависимое адаптивное бинарное арифметическое кодирование (CABAC).
Режим CAVLC можно рассматривать в качестве базового кодирования с переменной длиной кодового слова. Это традиционный алгоритм кодирования с переменной длиной кодового слова на основе таблицы кодов переменной длины бит с уникальными префиксами, но для большей эффективности стандарт определяет дополнительные таблицы. Выбор из таких таблиц и длина суффикса значений коэффициента фиксированной длины основывается на локальной статистике текущего потока в рамках контекста.
В режиме CAVLC используется 12 дополнительных кодовых таблиц: 6 для описания содержимого блока преобразования в целом, 4 для указания числа коэффициентов, 1 для указания общей величины квантованного значения коэффициента и 1 для представления последовательностей квантованных коэффициентов с нулевым значением. Эффективность выполнения таблиц кодирования с переменной длиной кодового слова вкупе с предельным адаптивным кодированием для повышения эффективности процесса позволяет достичь компромисса между скоростью выполнения и производительностью.
Режим CABAC доказал свою эффективность сжатия, превысив показатели режима CAVLC примерно на 10 процентов, однако режим CABAC гораздо сложнее в вычислительном плане. Сначала происходит выбор подходящей модели согласно группе прежних наблюдений за соответствующими элементами синтаксиса – это называется контекстным моделированием. Затем, если заданный символ имеет не двоичное значение, он будет сопоставлен с последовательностью двоичных решений, так называемых элементов кодированного сигнала. Подобная бинаризация выполняется с определенным двоичным значением на основе древовидной структуры, подобной коду VLC. После чего каждый элемент кодируется механизмом адаптивного двоичного арифметического кодирования с помощью вероятностных оценок, зависящих от определенного контекста. Схема выполнения конвейера показана на рисунке 12.
Рисунок 12. Конвейер арифметического кодирования по алгоритму H.264
Фильтр сглаживания блоков
Последним этапом перед восстановлением является обработка фильтром сглаживания блоков. Этот фильтр призван сгладить зрительную неравномерность между блоками преобразования, и именно он применяется только к пикселям, приближенным к этим границам – не более 4 с каждой стороны границ блока. Фильтр состоит из отдельных горизонтальных и вертикальных фильтров. На рисунке 13 показаны границы в макроблоке и пиксели, являющиеся объектом обработки горизонтальным фильтром вдоль вертикальной границы.
Стандарт H.264 устанавливает применение фильтра к кадрам после деквантования и прежде, чем изображение будет использоваться в качестве опорного для компенсации движения. Для Intra-кадров он используется после прогнозирования Intra-кадров.
Фильтрование в процессе декодирования требует значительных вычислительных ресурсов, отнимая от 15 до 30 процентов ресурсов ЦП для потоков с низким битовым потоков, где фильтрование используется особенно интенсивно.
Фильтр разделения блоков является адаптивным, и его эффективность настраивается автоматически согласно устойчивости границ и разнице между значениями пикселей на границе. Границы Intra-блоков устойчивей, чем Inter-блоков, так же как устойчивей, если рассматриваемые блоки имеют разностные опорные изображения, и устойчивей вдоль границы макроблока. Разницы значений пикселей должны быть меньше порогового значения, которое уменьшается с повышением качества. При малой величине параметра квантования, приводящей к повышению качества сжатых данных, любое значительное отклонение считается скорее особенностью изображения, чем ошибкой, и эффективность фильтра таким образом снижается. При малом значении длины шага квантования фильтр полностью отключается. Кодер может также принудительно отключить фильтр или настроить его эффективность на уровне среза.
Рисунок 13. Горизонтальный фильтр сглаживания блоков по алгоритму H.264
В этом разделе описана реализация большинства составляющих блоков алгоритма H.264 в библиотеке Intel IPP. Как и в предыдущем разделе, описание каждого блока приводится в порядке их обработки кодером.
Компенсация движения (интерполяция остаточных или прогнозируемых блоков)
Часть алгоритма H.264, требующая наибольшего объема вычислений, заключается в создании опорных блоков. Поскольку алгоритм H.264 допускает смещение на долю пикселя от фактических данных, в реализации должен использоваться определенный фильтр интерполяции для расчета блоков.
В библиотеке Intel IPP определен набор функций интерполяции для выполнения интерполяции в различных участках изображения. В число функций входят следующие:
ippiInterpolateLuma_H264_[8u|16u]_C1R
ippiInterpolateLumaTop_H264_[8u|16u]_C1R
ippiInterpolateLumaBottom_H264_[8u|16u]_C1R
ippiInterpolateLumaBlock_H264_[8u|16u]_C1R
ippiInterpolateChroma_H264_[8u|16u]_C1R
ippiInterpolateChromaTop_H264_[8u|16u]_C1R
ippiInterpolateChromaBottom_H264_[8u|16u]_C1R
ippiInterpolateChromaBlock_H264_[8u|16u]_C1R
Указанные функции подразделяются на две группы: функции, обрабатывающие плоскость яркости и функции, обрабатывающие плоскости цветности. Их также можно разделить на подфункции, обрабатывающие блоки, для которых имеют значение все данные, а также данные, появляющиеся на границе кадров, за пределами которых они отсутствуют.
Функции, обрабатывающие все не пограничные блоки кадра (ippiInterpolateLuma_H264 и ippiInterpolateChroma_H264) не учитывают интегральную часть векторов движения. Они выполняют только интерполяцию. Входящий указатель для опорных данных должен всегда указывать на опорный блок со смещением на целое значение. Затем функции рассчитывают интерполированный опорный блок, используя 2 или 3 бита, определяющих неполный вектор движения с точностью до четвертой или восьмой части пикселя.
Среди других функций, функции со словом «Top» или «Bottom» в названии выполняют интерполяцию данных на границе кадра. Параметры функций указывают, насколько удален опорный блок от изображения. Путем репликации пограничного ряда функции создают несуществующие данные за пределами изображения с последующей обычной интерполяцией.
Функция последнего типа со словом «Block» в названии выполняет интерполяцию над всем опорным блоком внутри изображения, но также учитывает весь вектор движения, выполняя расчет смещения. На рисунке 14 показано выполнение таких функций.
Функция SelectPredictionMethod определяет, должен ли алгоритм учитывать версии функций, выполняющих обработку пограничных данных. Остальная часть кода взята из другой, неопределенной функции.
Основная часть кода функции подготавливает все аргументы для функций интерполяции. В переменных «mvx» и «mvy» хранятся полные векторы движения. В этом коде переменные «xh» и «yh» задаются для младших битов вектора движения – дробной части. Затем, после усечения векторов движения до максимального диапазона, в коде задаются переменные «xint» и «yint» для целочисленной части вектора движения. В конце происходит расчет указателя на опорный блок смещения и вызывается соответствующая функция из библиотеки Intel IPP.
Обратите внимание, что репликация пограничных данных применяется к областям вверху и внизу, но не справа и слева. Такая с