⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aiccabacencoder.pas

📁 很好的源代码
💻 PAS
字号:
unit AICCabacEncoder;
{ Advanced Image Coding (AIC)
  ===========================
  Context Adaptive Binary Arithmetic Coding: Encoder.
  Parts of the code in this unit are based on the H.264 reference software.
  See JM.txt for license details. }

interface

uses
  AICCabac, AICCommon;

type
  TAICCabacEncoder = class(TAICCabac)
  { Context Adaptive Binary Arithmetic Coding: Encoder }
   private
    FBitsToFollow: Integer;
    procedure StartEncoding;
    { Initializes the encoder }
    procedure StopEncoding;
    { Stops encoding by flushing the buffer }
    procedure PutOneBit(const Bit: Cardinal);
    { Adds one bit (0 or 1) to the buffer.
      When a complete Byte is reached, PutByte is called }
    procedure PutOneBitPlusOutstanding(const Bit: Cardinal);
    { Adds one bit (0 or 1) and any outstanding bits to the buffer
      When a complete Byte is reached, PutByte is called }
    procedure PutByte;
    { Adds 8 encoded bits to the buffer. When the buffer becomes full,
      FlushBuffer is called. }
    procedure FlushBuffer;
    { Writes the contents of the buffer to the stream }
    procedure EncodeSymbol(Symbol: Cardinal; var Context: TCabacContext);
    { Encodes a single symbol (0 or 1) using the given context }
    procedure EncodeSymbolEqProb(const Symbol: Cardinal);
    { Encodes a single symbol (0 or 1) without a context. This is used when
      the probabilities of a symbol being 0 or 1 are both approximately 50%
      and thus a context is not useful }
    procedure EncodeUnaryExpGolombLevel(const Symbol: Cardinal;
      var Context: TCabacContext);
    { Encodes a value as an Exponential Golomb code.
      Each bit of the Golomb code will be coded with the given context }
    procedure EncodeExpGolombEqProb(Symbol: Cardinal; K: Integer);
    { Encodes a value as an Exponential Golomb code.
      No context is used for each bit of the Golomb code, because the
      probabilities of these bits being 0 or 1 are almost equal. }
    procedure WriteSignificanceMap(const ChannelType: TAICChannelType;
      const Coef: TAICIntBlock; CoefCount: Integer);
    { Encodes a map of significant coeficients for channel ChannelType.
      The map is encoded as an array of 0 or 1 values, where 0 is used to
      signal an insignificant coefficient, and 1 is used to signal a
      significant coefficient.
      The contexts CtxCoefficientMap and CtxLastCoefficient are used to
      encode these values }
    procedure WriteSignificantCoefficients(const ChannelType: TAICChannelType;
      const Coef: TAICIntBlock);
    { For every significant coefficient in Coef (that is, with value <> 0), the
      value of this coefficient is encoded from using the contexts
      CtxCoefGreaterOne and CtxCoefAbsolute. }
  public
    procedure AfterConstruction; override;
    { Initialized the encoder }
    procedure BeforeDestruction; override;
    { Stops encoding by flushing the buffer }

    procedure WritePredictionMode(const Value: Integer);
    { Encodes the prediction mode using the CtxPredictionMode contexts }
    procedure WriteCoefficients(const ChannelType: TAICChannelType;
      const Coef: TAICIntBlock);
    { Encodes the DCT coefficients for channel ChannelType. The coefficients
      are stored in the zig zag ordered Coef array.
      The context CtxCodedBlock is used to encode a 0 or 1 value to indicate
      if there are any significant coefficients (that is, if at least one
      coefficient in Coef isn't 0) }
  end;

implementation

uses
  Math;

{ TAICCabacEncoder }

procedure TAICCabacEncoder.AfterConstruction;
begin
  inherited;
  StartEncoding;
end;

procedure TAICCabacEncoder.BeforeDestruction;
begin
  inherited;
  StopEncoding;
end;

procedure TAICCabacEncoder.EncodeExpGolombEqProb(Symbol: Cardinal;
  K: Integer);
begin
  while True do begin
    if Symbol >= (1 shl K) then begin
      EncodeSymbolEqProb(1);
      Dec(Symbol,1 shl K);
      Inc(K);
    end else begin
      EncodeSymbolEqProb(0);
      while K > 0 do begin
        Dec(K);
        EncodeSymbolEqProb((Symbol shr K) and 1);
      end;
      Break;
    end;
  end;
end;

procedure TAICCabacEncoder.EncodeSymbol(Symbol: Cardinal;
  var Context: TCabacContext);
var
  RLPS: Cardinal;
begin
  RLPS := CabacRLPSTable[Context.State,(Range shr 6) and 3];
  if Symbol <> 0 then
    Symbol := 1;
  Dec(Range,RLPS);

  if Symbol <> Context.MPS then begin
    Inc(Low,Range);
    Range := RLPS;
    if Context.State = 0 then
      Context.MPS := Context.MPS xor 1;
    Context.State := CabacACNextStateLPS[Context.State];
  end else
    Context.State := CabacACNextStateMPS[Context.State];

  // Renormalisation
  while Range < CabacQuarter do begin
    if (Low >= CabacHalf) then begin
      PutOneBitPlusOutstanding(1);
      Dec(Low,CabacHalf);
    end else if Low < CabacQuarter then
      PutOneBitPlusOutstanding(0)
    else begin
      Inc(FBitsToFollow);
      Dec(Low,CabacQuarter);
    end;
    Low := Low shl 1;
    Range := Range shl 1;
  end;
end;

procedure TAICCabacEncoder.EncodeSymbolEqProb(const Symbol: Cardinal);
begin
  Low := Low shl 1;
  if Symbol <> 0 then
    Inc(Low,Range);
  if Low >= CabacOne then begin
    PutOneBitPlusOutstanding(1);
    Dec(Low,CabacOne);
  end else if Low < CabacHalf then
    PutOneBitPlusOutstanding(0)
  else begin
    Inc(FBitsToFollow);
    Dec(Low,CabacHalf);
  end;
end;

procedure TAICCabacEncoder.EncodeUnaryExpGolombLevel(
  const Symbol: Cardinal; var Context: TCabacContext);
var
  K, L: Cardinal;
begin
  if Symbol = 0 then
    EncodeSymbol(0,Context)
  else begin
    EncodeSymbol(1,Context);
    L := Symbol - 1;
    K := 1 + 1;
    while (L > 0) and (K <= CabacExpStart) do begin
      EncodeSymbol(1,Context);
      Dec(L); Inc(K);
    end;
    if Symbol < CabacExpStart then
      EncodeSymbol(0,Context)
    else
      EncodeExpGolombEqProb(Symbol - CabacExpStart,0);
  end;
end;

procedure TAICCabacEncoder.FlushBuffer;
begin
  Stream.WriteBuffer(CodeStream[0],CodeStreamLen);
  CodeStreamLen := 0;
end;

procedure TAICCabacEncoder.PutByte;
begin
  CodeStream[CodeStreamLen] := Buffer and $FF;
  BitsToGo := 8;
  Inc(CodeStreamLen);
  if CodeStreamLen >= CabacCodeStreamSize then
    FlushBuffer;
end;

procedure TAICCabacEncoder.PutOneBit(const Bit: Cardinal);
begin
  Buffer := (Buffer shl 1) or Bit;
  Dec(BitsToGo);
  if BitsToGo = 0 then
    PutByte;
end;

procedure TAICCabacEncoder.PutOneBitPlusOutstanding(const Bit: Cardinal);
begin
  PutOneBit(Bit);
  while FBitsToFollow > 0 do begin
    Dec(FBitsToFollow);
    PutOneBit(1 - Bit);
  end;
end;

procedure TAICCabacEncoder.StartEncoding;
begin
  BitsToGo := 9;
  Range := CabacHalf - 2;
end;

procedure TAICCabacEncoder.StopEncoding;
begin
  PutOneBitPlusOutstanding((Low shr (CabacBits - 1)) and 1);
  PutOneBit((Low shr (CabacBits - 2)) and 1);
  PutOneBit(1);
  while BitsToGo <> 8 do
    PutOneBit(0);
  FlushBuffer;
end;

procedure TAICCabacEncoder.WriteCoefficients(
  const ChannelType: TAICChannelType; const Coef: TAICIntBlock);
var
  I, CoefCount: Integer;
begin
  CoefCount := 0;
  for I := 0 to 63 do
    if Coef[I] <> 0 then
      Inc(CoefCount);

  if CoefCount > 0 then begin
    EncodeSymbol(1,CtxCodedBlock);
    WriteSignificanceMap(ChannelType,Coef,CoefCount);
    WriteSignificantCoefficients(ChannelType,Coef);
  end else
    EncodeSymbol(0,CtxCodedBlock);
end;

procedure TAICCabacEncoder.WritePredictionMode(const Value: Integer);
begin
  if Value < 0 then
    EncodeSymbol(1,CtxPredictionMode[0])
  else begin
    EncodeSymbol(0,CtxPredictionMode[0]);
    EncodeSymbol( Value and 1       ,CtxPredictionMode[1]);
    EncodeSymbol((Value shr 1) and 1,CtxPredictionMode[1]);
    EncodeSymbol((Value shr 2) and 1,CtxPredictionMode[1]);
  end;
end;

procedure TAICCabacEncoder.WriteSignificanceMap(
  const ChannelType: TAICChannelType; const Coef: TAICIntBlock;
  CoefCount: Integer);
var
  CtxMap, CtxLast: PCabacContext;
  I, Sig, Last: Integer;
begin
  CtxMap := @CtxCoefficientMap[ChannelType,0];
  CtxLast := @CtxLastCoefficient[ChannelType,0];
  for I := 0 to 62 do begin
    if Coef[I] = 0 then
      Sig := 0
    else
      Sig := 1;
    EncodeSymbol(Sig,CtxMap^);
    if Sig <> 0 then begin
      Dec(CoefCount);
      if CoefCount = 0 then
        Last := 1
      else
        Last := 0;
      EncodeSymbol(Last,CtxLast^);
      if Last <> 0 then
        Exit;
    end;
    Inc(CtxMap);
    Inc(CtxLast);
  end;
  { We don't need to encode the significance of the last coefficient, since
    this can be determined from the CtxLast context }
end;

procedure TAICCabacEncoder.WriteSignificantCoefficients(
  const ChannelType: TAICChannelType; const Coef: TAICIntBlock);
var
  I, C, C1, C2, Ctx, Sign, GreaterOne: Integer;
begin
  C1 := 1; C2 := 0;
  for I := 63 downto 0 do begin
    C := Coef[I];
    if C <> 0 then begin
      if C > 0 then
        Sign := 0
      else begin
        Sign := 1;
        C := -C;
      end;

      if C > 1 then
        GreaterOne := 1
      else
        GreaterOne := 0;

      Ctx := Min(C1,4);
      EncodeSymbol(GreaterOne,CtxCoefGreaterOne[ChannelType,Ctx]);

      if GreaterOne <> 0 then begin
        Ctx := Min(C2,4);
        EncodeUnaryExpGolombLevel(C - 2,CtxCoefAbsolute[ChannelType,Ctx]);
        C1 := 0;
        Inc(C2);
      end else if C1 <> 0 then
        Inc(C1);

      EncodeSymbolEqProb(Sign);
    end;
  end;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -