rsvk/Component/StrucAriEncoderUnit.pas

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.