188 lines
5.5 KiB
Plaintext
188 lines
5.5 KiB
Plaintext
unit StrucAriEncoderUnit;
|
|
{-------------------------------------------------------------------------------
|
|
Structured Arithmetic Encoder 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 encode the symbols
|
|
|
|
first_level_symbol: 0-9
|
|
second_level_symbol: 0 - (NumberOfEntries-1)
|
|
|
|
Each entry in the AriModelList corresponds to the AriModel for the first_level_symbol.
|
|
|
|
-------------------------------------------------------------------------------}
|
|
|
|
|
|
(**) interface (**)
|
|
uses GroupAriModelUnit;
|
|
|
|
|
|
type
|
|
TStrucAriEncoder = class
|
|
private
|
|
high, low: integer; // ends of current code region
|
|
bits_to_follow: integer;
|
|
procedure BitPlusFollow(bit: byte);
|
|
protected
|
|
HeadAriModel: THeadAriModel;
|
|
|
|
procedure OutputBit(bit: byte); virtual; abstract;
|
|
procedure OutputBits(code: longint; count: byte); virtual; abstract;
|
|
|
|
procedure StartEncoding;
|
|
procedure DoneEncoding;
|
|
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
{procedure EncodeByte(a: byte);}
|
|
procedure EncodeSymbol(symbol: integer);
|
|
end;
|
|
|
|
|
|
(**) implementation (**)
|
|
|
|
|
|
|
|
constructor TStrucAriEncoder.Create;
|
|
begin
|
|
inherited Create;
|
|
end;
|
|
|
|
destructor TStrucAriEncoder.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ At the end of the encoding process, there are still significant bits left
|
|
in the high and low registers. We output two bits, plus as many underflow
|
|
bits as are necessary }
|
|
|
|
procedure TStrucAriEncoder.BitPlusFollow(bit: byte);
|
|
begin
|
|
OutputBit(bit);
|
|
// output bits_to_follow opposite bits. Set bits_to_follow to zero.
|
|
while (bits_to_follow > 0) do
|
|
begin
|
|
if bit = 0 then
|
|
OutputBit(1)
|
|
else
|
|
OutputBit(0);
|
|
|
|
dec(bits_to_follow);
|
|
end;
|
|
end;
|
|
|
|
procedure TStrucAriEncoder.StartEncoding;
|
|
begin
|
|
low := 0; // full code region
|
|
high := TOP_VALUE;
|
|
bits_to_follow := 0; // no bits to follow next
|
|
HeadAriModel := THeadAriModel.Create;
|
|
end;
|
|
|
|
procedure TStrucAriEncoder.DoneEncoding;
|
|
begin
|
|
// output two bits that select the quarter that the
|
|
// current code range contains
|
|
inc(bits_to_follow);
|
|
if (low < FIRST_QTR) then
|
|
BitPlusFollow(0)
|
|
else
|
|
BitPlusFollow(1);
|
|
|
|
//OutputBits(0, 15); //16 or 15 or none?
|
|
HeadAriModel.Free;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
EncodeSymbol
|
|
------------
|
|
encodes the symbol 'symbol'.
|
|
|
|
Algo:
|
|
The encoding process is either 1 or 2 steps, depending on whether the group
|
|
has several 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) Get the group number for the symbol
|
|
2) Encode the group number (step 1)
|
|
3) If the group has residue, then
|
|
a) Get the group symbol for the corresponding symbol in its group
|
|
b) Encode the group symbol (step 2)
|
|
-------------------------------------------------------------------------------}
|
|
|
|
procedure TStrucAriEncoder.EncodeSymbol(symbol: integer);
|
|
|
|
procedure DoEncodeSymbol(symbol_index: integer; AriModel: TGroupAriModel);
|
|
var
|
|
range: integer;
|
|
begin
|
|
// narrow the code region to that alloted to this symbol
|
|
range := high-low + 1;
|
|
high := low + (((range * AriModel.cum_freq[symbol_index-1]) div AriModel.cum_freq[0]) -1);
|
|
low := low + ((range * AriModel.cum_freq[symbol_index]) div AriModel.cum_freq[0]);
|
|
|
|
// loop to output bits
|
|
repeat
|
|
if (high < HALF) then
|
|
BitPlusFollow(0) // output 0 if in low half (MSB=0)
|
|
else if (low >= HALF) then
|
|
begin
|
|
BitPlusFollow(1); // output 1 if in high half (MSB=1)
|
|
dec(low, HALF); // set MSB to 0 for both low and high
|
|
dec(high, HALF);
|
|
end
|
|
else if ((low >= FIRST_QTR) and (high < THIRD_QTR)) then
|
|
begin
|
|
inc(bits_to_follow); // output an opposite bit later if in middle half
|
|
dec(low, FIRST_QTR); // substract offset to middle
|
|
dec(high, FIRST_QTR);
|
|
end
|
|
else break;
|
|
|
|
low := 2 * low; // scale up code region
|
|
high := 2 * high + 1;
|
|
until false;
|
|
|
|
AriModel.UpdateModel(symbol_index); // update the model with the symbol
|
|
end;
|
|
|
|
var
|
|
AriModel: TGroupAriModel; // AriModel. reused through the levels
|
|
symbol_index: integer; // index for symbols. reused through the levels
|
|
group_num, group_symbol: integer; // 2nd and 3rd level symbols
|
|
begin
|
|
// get the group number from the HeadAriModel
|
|
group_num := HeadAriModel.GetGroupNum(symbol);
|
|
// retrieve the AriModel and symbol_index for group_num
|
|
HeadAriModel.GetSymbolInfo(group_num, AriModel, symbol_index);
|
|
// encode the group number
|
|
DoEncodeSymbol(symbol_index, AriModel);
|
|
|
|
// encode any residue
|
|
if HeadAriModel.HasResidue(group_num) then
|
|
begin
|
|
// convert the symbol to a group symbol in its respective group (group_num)
|
|
group_symbol := HeadAriModel.SymbolToGroupSymbol(symbol, group_num);
|
|
// get the AriModel and symbol_index for the group_symbol
|
|
HeadAriModel.GetGroupSymbolInfo(group_symbol, group_num, AriModel, symbol_index);
|
|
Assert(AriModel <> nil);
|
|
// encode the group_symbol or residue
|
|
DoEncodeSymbol(symbol_index, AriModel);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|
|
|
|
|