rsvk/Component/StrucAriDecoderUnit.pas

166 lines
5.0 KiB
Plaintext

unit StrucAriDecoderUnit;
{-------------------------------------------------------------------------------
Structured Arithmetic Decoder Unit
----------------------------------
reSource v2.6
Copyright (C) 1998-2001 Victor Kasenda / gruv
http://go.to/gruv
email: vickas@singnet.com.sg
uses the Group Arithmetic Model to decode the symbols
-------------------------------------------------------------------------------}
(**) interface (**)
uses
GroupAriModelUnit;
type
TStrucAriDecoder = class
private
low, high, value: longint;
HeadAriModel: THeadAriModel;
protected
function InputBit: byte; virtual; abstract;
function InputBits( count: byte ): longint; virtual; abstract;
public
constructor Create;
destructor Destroy; override;
// for decoding
procedure DecodeSymbol(var symbol: integer);
procedure StartDecoding;
procedure DoneDecoding;
end;
(**) implementation (**)
constructor TStrucAriDecoder.Create;
begin
inherited Create;
end;
destructor TStrucAriDecoder.Destroy;
begin
inherited Destroy;
end;
procedure TStrucAriDecoder.StartDecoding;
var
i: longint;
begin
HeadAriModel := THeadAriModel.Create;
value := 0; // input bits to fill the
for i := 1 to CODE_VALUE_BITS do // code value
value := 2 * value + InputBit;
low := 0; // full code range
high := TOP_VALUE;
end;
procedure TStrucAriDecoder.DoneDecoding;
begin
HeadAriModel.Free;
end;
{-------------------------------------------------------------------------------
DecodeSymbol
------------
decodes the next symbol in the stream and returns the symbol in symbol.
Algo:
The decoding process is either 1 or 2 steps, depending on whether the group
has one or more members.
The design of the algo is such that the unique groups are zero and one.
The symbols correspond to the unique group values.
1) Decode the group number (step 1)
2) If the group has several members, then
a) decode the residue to obtain the member symbol (step 2)
b) convert the member symbol to the corresponding symbol and return this.
ELSE
Otherwise, the symbol is unique in the group and the group_num is the symbol.
return this.
-------------------------------------------------------------------------------}
procedure TStrucAriDecoder.DecodeSymbol(var symbol: integer);
procedure DoDecodeSymbol(var symbol: integer; AriModel: TGroupAriModel);
var
range: longint; // size of current code region
cum: integer; // cumulative frequancy calculated
index: integer; // index of the symbol
begin
range := high - low + 1;
// find cum freq for value
cum := ((value-low+1) * AriModel.cum_freq[0] -1) div range;
// find the symbol that straddles the range
index := 1;
while (AriModel.cum_freq[index] > cum) do inc(index);
// return the symbol
symbol := AriModel.IndexToSymbol(index);
// narrow the code region to that allooted to this symbol
high := low + (range * AriModel.cum_freq[index-1]) div AriModel.cum_freq[0] -1;
low := low + (range * AriModel.cum_freq[index]) div AriModel.cum_freq[0];
// remove the bits that represent the current symbol to get the next symbol's
// range
repeat
if (high < HALF) then
begin
{nothing} // expand low half
end
else if (low >= HALF) then // expand high half
begin
dec(value, HALF);
dec(low, HALF); // substract offset to top
dec(high, HALF);
end else if ((low >= FIRST_QTR) and // expand middle half
(high < THIRD_QTR)) then
begin
dec(value, FIRST_QTR);
dec(low, FIRST_QTR);
dec(high, FIRST_QTR); // substract offset to middle
end else break; // otherwise exit loop
low := 2 * low;
high := 2 * high + 1; // scale up code range
value := 2 * value + InputBit; // move in next input bit
until false;
// update the model with the new symbol found
AriModel.UpdateModel(index);
end;
var
group_num: integer; // group number for the symbol
group_symbol: integer; // the group symbol in the respective group (group_num)
begin
DoDecodeSymbol(group_num, HeadAriModel.MainAriModel);
if HeadAriModel.HasResidue(group_num) then
begin
// decode the group_symbol using the respetive AriModel
DoDecodeSymbol(group_symbol, HeadAriModel.AriModelList[group_num]);
// convert the group_symbol to its corresponding symbol using the group_num
symbol := HeadAriModel.GroupSymbolToSymbol(group_symbol, group_num);
end
else
begin
// the group has only one character
// therefore the symbol is the group_num
symbol := group_num;
end;
end;
end.