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

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

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

го кадра. В поле 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 в 0FFFFh, так как мы уже читаем поведение

// из видеопотока, а не из массива поведений

Frame[I].cpIndex := $FFFF;

Frame[I].cpBehaviour := 0;

// А теперь читаем поведение из видеопотока. Следующий фрагмент

// кода один в один похож на участок рассмотренного выше кода,

// поэтому здесь я его не комментирую

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;

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

end;

Frame[I].cpCode := C;

Frame[I].cpRepeat := R;

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

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;

После цикла по всем элементам массива опорного кадра в полях cpCurrent элементов массива находятся значения, которые должны быть занесены в реальный кадр на экране. Собственно говоря, картинка реального кадра уже получена в опорном кадре, но данные картинки еще нужно перевести из процентных отношений в прямые значения, если они не были такими (установлен бит RatioType поля Properties заголовка видеопотока). Затем полученные прямые значения нужно перевести из YCbCr в RGB, если установлен бит ColorSpace поля Properties. Но нужно обратить внимание, что содержимое полей cpCurrent элементов массива опорного кадра ни в коем случае нельзя изменять, так как нам нужны непереведенные значения для декодирования следующего кадра. Для перевода из YCbCr в RGB необходимо извлекать из массива опорного кадра сразу по три цветовых плоскости пикселя, потому что формулам преобразования YCbCr в RGB нужны значения трех плоскостей. Поэтому процедура отображения кадра на экране будет иметь два цикла - по высоте и по ширине кадра.

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

var

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

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

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

procedure ShowFrame;

var

W: Word; // ширина

H: Word; // высота

I: DWord; // индекс плоскости в массиве опорного кадра

Y: Double; // значение плоскости Y

Cb: Double; // значение плоскости Cb

Cr: Double; // значение плоскости Cr

R: Byte; // значение красного цвета

G: Byte; // значение зеленого цвета

B: Byte; // значение синего цвета

begin

// в цикле рисуем все пиксели на реальном экране

// (допустим его имя VideoScreen)

for H := 1 to Header.Height do begin

for W := 1 to Header.Width do begin

I := (H-1) * Header.Width * 3 + (W-1) * 3;

// читаем значения трех цветовых плоскостей пикселя

// из соответствующих элементов массива опорного кадра

Cr := Frame[I].cpCurrent;

Y := Frame[I+1].cpCurrent;

Cb := Frame[I+2].cpCurrent;

// если значения заданы с помощью процентных

// отношений (установлен бит RatioType поля Properties),

// тогда перевести их в прямые значения

0thenbegin">if Header.Properties and 2 <> 0 then begin

Cr := Cr * (256 / 100);

Y := Y * (256 / 100);

Cb := Cb * (256 / 100);

end;

// если прямые значения необходимо перевести

// из YCbCr в RGB (установлен бит ColorSpace поля Properties),

// тогда перевести их в RGB, иначе они уже заданы в виде RGB

0thenbegin">if Header.Properties and 1 <> 0 then begin

R := Trunc(Y + 1.402 * (Cr - 128));

G := Trunc(Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128));

B := Trunc(Y + 1.772 * (Cb - 128));

end else begin

R := Trunc(Cr);

G := Trunc(Y);

B := Trunc(Cb);

end;

// а теперь осталось занести цвет пикселя (он находится

// в переменных R, G и B) в реальный кадр на экране, где

// координаты пикселя заданы переменными W и H

// (в Canvas цвет хранится как BGR, а не как RGB)

VideoScreen.Canvas.Pixels[W-1, H-1] := (B * $10000) or (G * $100) or R;

end;

end;

// +1 кадр видеофильма показали на экране,

// и если видеопоток закончился (счетчик кадров

// достиг количества кадров в видео), тогда остановить программу

Inc(FrameNum);

=Header.FrameCountthenHalt;">if FrameNum >= Header.FrameCount then Halt;

end;

Если из приведенного кода убрать все комментарии, можно заметить, что программный код декодера небольшой. К тому же алгоритм декодирования оказывается простым и быстрым. Кстати, программный код декодера можно оптимизировать еще в более компактный, так как перестановкой проверки поля cpIndex сначала на реальный индекс (а не на 0FFFFh) можно добиться исключения одинаковых фрагментов кода, читающих поведение из общего видеопотока или набора поведений из массива поведений. Но это уже вы сами решайте, как вам будет удобнее.

За счет чего происходит сжатие

В качестве примера я взял из фильма "Шестой день" поведение красной цветовой плоскости произвольного пикселя в центральной части кадра. Всего взято 100 кадров, что равно 4 секундам фильма при скорости 25 кадров в секунду. Специально выбрал фрагмент фильма, где развивается динамичное действие. Через кадр быстро проезжает машина, а за ней появляется новая сцена с вертолетом. А теперь посмотрим, как вела себя цветовая плоскость R на протяжении 100 кадров.

185, 193, 194, 194, 192, 197, 197, 207, 207, 204, 204, 201, 201, 197, 200, 197, 208, 210, 208, 206, 209, 209, 216, 216, 216, 215, 214, 214, 214, 214, 214, 214, 217, 217, 216, 216, 215, 216, 079, 030, 028, 009, 047, 021, 008, 017, 060, 025, 024, 018, 013, 015, 015, 017, 017, 017, 017, 017, 017, 016, 016, 016, 012, 011, 015, 015, 015, 014, 005, 006, 008, 008, 008, 008, 008, 004, 011, 012, 012, 012, 012, 012, 012, 012, 012, 012, 012, 012, 012, 012, 007, 007, 006, 053, 054, 058, 053, 052, 050, 047

Здесь указаны непосредственные значения красной цветовой плоскости пикселя для каждого ?/p>