Алгоритм сжатия видео 'pixel behaviour check'

Информация - Компьютеры, программирование

Другие материалы по предмету Компьютеры, программирование

Чтобы вам было понятнее, рассмотрим шаг за шагом работу декодера. Не стоит считать описанные мной методы реализации декодера и его структуры истинно верными. Я лишь стремился проще объяснить принцип декодирования, не особо вдаваясь в вопросы качества реализации декодера. Вы сами в состоянии определить, как максимально качественно написать его начинку. Если есть желание, можете скачать исходники примера PBC Playerа здесь (205 Кбайт). Исходники написаны в Delphi, а программный код (стиль программирования) не гарантирует высокую производительность и безошибочность реализации.

Нам понадобится опорный кадр. Спроектируем его структуру так, чтобы хранить в нем сведения не только для декодирования первого кадра, но и каждого следующего. Опорный кадр будет представлять собой динамический массив с данными о поведении всех пикселей изображения. В каждом пикселе имеется по три цветовых плоскости, поэтому количество элементов в этом массиве будет равно ШИРИНА * ВЫСОТА * 3. Теперь опишем массив, элементы которого будут представлены структурой ColorPlane. Я намеренно добавил префикс "cp" к именам полей этой структуры, чтобы вы не путали их со сходными полями структур PBCvideoIdentical, PBCvideoChanged и PBCvideoEncoded.

type ColorPlane = record

cpIndex: Word; // индекс закодированного набора поведений

cpBehaviour: Byte; // индекс текущего поведения, выполняемого из набора

cpCode: Byte; // код выполняемого поведения

cpRepeat: Word; // количество кадров повторения поведения

cpCurrent: Double; // текущее значение цветовой плоскости пикселя

cpExtent: Double; // величина изменения плоскости за один кадр

end;

// глобальные переменные

var

Frame: array of ColorPlane; // опорный кадр

Отмечу, что структура ColorPlane в таком виде не позволит использовать кодирование наборов поведений через другие наборы, когда один набор на каком-то своем участке может ссылаться на содержимое другого набора. В наборах поведений допустимо использовать поведения с кодом 11 (закодирован в массиве поведений), а значит, можно реализовать высокую вложенность наборов поведений. Это может помочь сильнее сжимать видео. Приведу пример, где зацикленные друг на друга наборы приводят к эффективному сжатию.

Допустим, у нас есть видеофрагмент в 1000 кадров. Пусть он состоит из одной точки. В каждом нечетном кадре точка имеет черный цвет, а в каждом четном - белый. И вот так 1000 кадров она постоянно "моргает". В закодированном потоке окажется всего два элемента (набора поведений) в массиве поведений, причем каждый набор поведений будет состоять всего из двух поведений, где второе поведение всегда будет ссылаться на другой набор поведений (второе поведение первого набора - на второй набор, второе поведение второго набора - на первый набор). И будет еще одно поведение в общем видеопотоке (поток после массива поведений), которое ссылается на один из наборов поведений. Декодер, считав поведение из общего видеопотока, по ссылке попадает на один из наборов и начинает обслуживать его поведения. В первом поведении набора указано, что точка имеет белый цвет один кадр, а второе поведение набора отсылает декодер на второй набор. Во втором наборе первое поведение указывает, что точка имеет черный цвет один кадр, а второе поведение отсылает декодер на первый набор. И так в цикле декодер отрисовывает 1000 кадров видеофрагмента, больше ничего не читая из видеопотока.

Пример не совсем удачный, хотя объясняет суть организации вложенности наборов поведений. Но ведь вложенность может быть и с возвратом, когда один набор ссылается на другой набор, но за своей ссылкой содержит еще продолжение поведений (ссылка внутри набора, или несколько ссылок в наборе). Вот это и не позволит использовать указанное содержимое структуры ColorPlane, так как в ней не предусмотрен контроль вложенности наборов. А теперь возвратимся к работе декодера, и позже объясню, почему поля cpCurrent и cpExtent в структуре ColorPlane заданы типами с плавающей точкой.

Первым делом декодер читает заголовок видеопотока. Получив ширину и высоту кадра видеофильма (поля Width и Height структуры PBCvideoHeader), декодер устанавливает размер массива опорного кадра по формуле Width * Height * 3. Значения полей StartRCr, StartGY и StartBCb заносятся в поля cpCurrent соответствующих элементов массива опорного кадра. Декодеру нужно сразу заполнить цветовые плоскости опорного кадра соответствующими начальными значениями. Первые три элемента массива принадлежат первому пикселю (его координаты = 0,0), следующие три элемента - второму пикселю (0,1), следующие - третьему, и так далее. Поэтому в поле cpCurrent первого элемента массива заносится значение поля StartRCr, во второй элемент массива - значение поля StartGY, в третий элемент - значение поля StartBCb, в четвертый элемент - снова поле StartRCr, в пятый - поле StartGY, и так далее. Все остальные поля элементов массива обнуляются. Замечу, что поле cpIndex обнуляется значением 0FFFFh. Декодер использует это поле, чтобы выяснить, обслуживается ли в настоящий момент для данной цветовой плоскости пикселя поведение из видеопотока или оно берется из массива поведений. Индекс набора поведений может лежать только в пределах от 0 до 8191 (всего получается 8192 набора поведений), а значение 0FFFFh находится за пределами массива, поэтому декодер легко определяет, что текущее поведение взято не из массива поведений, а прямо из видеопотока. Для наглядности приведу фрагмент программы.

// глобальные переменные

var

Header: PBCvideoHeader; // заголовок видеопотока

Behaviours: PBCvideoBehaviours; // массив поведений

Frame: array of ColorPlane; // опорный кадр

FrameNum: DWord; // номер текущего кадра

procedu