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.