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

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

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

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

Итак, допишем недостающий фрагмент процедуры CreateNextFrame. Для простоты считаем, что у нас уже написана процедура ReadBehaviour, читающая из потока одно поведение по описанным выше правилам (смотрите описание содержимого структур PBCvideoIdentical, PBCvideoChanged и PBCvideoEncoded). Также считаем, что у нас уже есть процедура чтения N-го поведения из указанного набора в массиве поведений - GetBehaviour.

if Frame[I].cpIndex = $FFFF then begin

// читаем из видеопотока поведение для текущей

// цветовой плоскости пикселя

// в переменную C возвращается код поведения

// в R - количество повторов поведения или индекс,

// если поведение задано в массиве поведений

// (в этом случае переменная C = 11)

// в E - величина изменения плоскости за весь период поведения

// или 0, если C = 00 или C = 11

ReadBehaviour(C, R, E);

// с помощью цикла делаем обслуживание возможных

// внедренных в видеопоток блоков данных

while (C = 00) and (R = 8192) do begin

// здесь должен быть вызов вашей функции обработки

// внедренного в видеопоток блока данных

// а затем продолжаем читать из потока поведение

// для текущей цветовой плоскости пикселя

ReadBehaviour(C, R, E);

end;

// Если поведение закодировано в массиве набором поведений,

// тогда необходимо прочитать первое поведение из набора

// и использовать его данные, так как в опорном кадре

// используются только коды реальных поведений.

// Следующим циклом обеспечивается выбор первого поведения

// при кодировании с помощью набора, а также он обеспечивает

// поддержку безвозратной вложенности наборов поведений.

while C = 11 do begin

Frame[I].cpIndex := R;

Frame[I].cpBehaviour := 0;

// читаем поведение с индексом Frame[I].cpBehaviour = 0

// из набора поведений с индексом Frame[I].cpIndex,

// а результат чтения возвращается в переменные C, R и E

GetBehaviour(Frame[I].cpIndex, Frame[I].cpBehaviour, C, R, E);

end;

// в поле cpExtent заносится величина изменения цветовой

// плоскости за один кадр повтора, а не за весь его период

Frame[I].cpCode := C;

Frame[I].cpRepeat := R;

Frame[I].cpExtent := E / R;

// а теперь нам осталось вычислить поле cpCurrent для прочитанного

// поведения

Dec(Frame[I].cpRepeat);

case Frame[I].cpCode of

01: Frame[I].cpCurrent := Frame[I].cpCurrent + Frame[I].cpExtent;

10: Frame[I].cpCurrent := Frame[I].cpCurrent - Frame[I].cpExtent;

end;

end else begin

// этот фрагмент приведен ниже и описывает, что происходит,

// когда поле cpIndex содержит индекс обслуживаемого набора поведений

end;

Теперь пришло время объяснить, почему поля cpCurrent и cpExtent заданы типами с плавающей точкой. Дело в том, что в поле cpExtent элемента массива опорного кадра хранится величина изменения цветовой плоскости за один кадр повтора, а не за весь его период. Когда величина изменения за весь период делится на количество повторов, остаются дробные части. Отбрасывать дробные части нельзя, потому что динамика изменения цветовой плоскости может быть разная. Из кадра в кадр поле cpCurrent изменяется на величину поля cpExtent. Представьте, что за 100 кадров цветовая плоскость пикселя изменилась всего на 1 процент. Разделив 1 на 100 кадров и округлив результат, мы получим 0. В результате точка на протяжении 100 кадров не изменится на 1 процент, ведь мы будем добавлять к полю cpCurrent нулевое значение поля cpExtent. А вот если мы будем добавлять с дробными частями, точка за 100 кадров плавно достигнет изменения в 1 процент. Округление до целого числа выполняется только в момент вывода цветовых плоскостей пикселя в реальный кадр на экране, но внутри опорного кадра все вычисления делаются исключительно с дробными частями.

И снова возвратимся к программному коду декодера. Нам осталось рассмотреть часть кода, когда в поле cpRepeat не осталось повторов, а в поле cpIndex указан индекс обслуживаемого набора поведений цветовой плоскости. В этом случае нужно взять следующее поведение из обслуживаемого набора и занести его данные в текущий элемент массива опорного кадра. Если же в наборе пройдены все поведения (выполненное поведение было последним в наборе), тогда нужно взять следующее поведение прямо из видеопотока и уже его данные занести в текущий элемент массива опорного кадра. Еще раз вспомним, что при чтении из видеопотока декодер должен уметь обслуживать специальный код внедрения других данных в видеопоток.

// вычисляем индекс следующего поведения в наборе

Inc(Frame[I].cpBehaviour);

// если в наборе еще не закончились поведения, тогда

// читаем следующее поведение из набора, иначе

// сбрасываем cpIndex в 0FFFFh и читаем поведение из общего видеопотока

if (Frame[I].cpBehaviour <> 0) and

(Frame[I].cpBehaviour <= Behaviours.Behaviours[Frame[I].cpIndex].Count) then begin

// читаем следующее поведение набора (индекс следующего

// поведения уже находится в Frame[I].cpBehaviour),

// а результат чтения возвращается в переменные C, R и E

GetBehaviour(Frame[I].cpIndex, Frame[I].cpBehaviour, C, R, E);

// следующим циклом обеспечиваем поддержку безвозратной вложенности

// наборов поведений

while C = 11 do begin

Frame[I].cpIndex := R;

Frame[I].cpBehaviour := 0;

// читаем поведение с индексом Frame[I].cpBehaviour = 0

// из набора поведений с индексом Frame[I].cpIndex,

// а результат чтения возвращается в переменные C, R и E

GetBehaviour(Frame[I].cpIndex, Frame[I].cpBehaviour, C, R, E);

end;

// Заносим данные поведения, прочитанного из набора, в текущий элемент

// массива опорно