166 lines
5.0 KiB
Plaintext
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.
|