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

📄 aiccabacdecoder.pas

📁 很好的源代码
💻 PAS
字号:
unit AICCabacDecoder;
{ Advanced Image Coding (AIC)
  ===========================
  Context Adaptive Binary Arithmetic Coding: Decoder. 
  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
  TAICCabacDecoder = class(TAICCabac)
  { Context Adaptive Binary Arithmetic Coding: Decoder }
  private
    FValue: Cardinal;
    procedure StartDecoding;
    { Initializes the decoder by reading the first few bits from the stream }
    procedure GetByte;
    { Read the next byte from the buffer. If the buffer is empty or used up,
      ReadBuffer is called to fill the buffer from the stream }
    procedure ReadBuffer;
    { Fills the buffer from the stream }
    function DecodeSymbol(var Context: TCabacContext): Cardinal;
    { Decodes a single symbol (0 or 1) using the given context }
    function DecodeSymbolEqProb: Cardinal;
    { Decodes 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 }
    function DecodeUnaryExpGolombLevel(var Context: TCabacContext): Cardinal;
    { Decodes a value that is stored as an Exponential Golomb code.
      Each bit of the Golomb code was coded with the given context }
    function DecodeExpGolombEqProb(K: Integer): Cardinal;
    { Decodes a value that is stored 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 ReadSignificanceMap(const ChannelType: TAICChannelType;
      var Coef: TAICIntBlock);
    { Decodes the map of significant coeficients for channel ChannelType.
      Each significant coefficient will have value 1 in the Coef array.
      Insignificant coefficients will have value 0.
      The contexts CtxCoefficientMap and CtxLastCoefficient are used to
      decode these values }
    procedure ReadSignificantCoefficients(const ChannelType: TAICChannelType;
      var Coef: TAICIntBlock);
    { For every significant coefficient in Coef (that is, with value 1), the
      value of this coefficient is decoded from the stream using the contexts
      CtxCoefGreaterOne and CtxCoefAbsolute. }
  public
    procedure AfterConstruction; override;
    { Initializes the decoder }

    function ReadPredictionMode: Integer;
    { Decodes the prediction mode using the CtxPredictionMode contexts }
    procedure ReadCoefficients(const ChannelType: TAICChannelType;
      out Coef: TAICIntBlock);
    { Decodes the DCT coefficients for channel ChannelType. The coefficients
      are stored in the zig zag ordered Coef array.
      The context CtxCodedBlock is used to determine if there are any
      significant coefficients. If not, all values are set to 0. }
  end;

implementation

uses
  Math;

{ TAICCabacDecoder }

procedure TAICCabacDecoder.AfterConstruction;
begin
  inherited;
  StartDecoding;
end;

function TAICCabacDecoder.DecodeExpGolombEqProb(K: Integer): Cardinal;
var
  L, BinarySymbol: Integer;
begin
  Result := 0;
  BinarySymbol := 0;
  repeat
    L := DecodeSymbolEqProb;
    if L = 1 then begin
      Inc(Result,1 shl K);
      Inc(K);
    end;
  until L = 0;
  while K <> 0 do begin
    Dec(K);
    if DecodeSymbolEqProb = 1 then
      BinarySymbol := BinarySymbol or (1 shl K);
  end;
  Inc(Result,BinarySymbol);
end;

function TAICCabacDecoder.DecodeSymbol(
  var Context: TCabacContext): Cardinal;
var
  RLPS: Cardinal;
begin
  Result := Context.MPS;
  RLPS := CabacRLPSTable[Context.State,(Range shr 6) and 3];
  Dec(Range,RLPS);

  if FValue < Range then
    Context.State := CabacACNextStateMPS[Context.State]
  else begin
    Dec(FValue,Range);
    Range := RLPS;
    Result := 1 - Result;
    if Context.State = 0 then
      Context.MPS := Context.MPS xor 1;
    Context.State := CabacACNextStateLPS[Context.State];
  end;

  while Range < CabacQuarter do begin
    Range := Range shl 1;
    Dec(BitsToGo);
    if BitsToGo < 0 then
      GetByte;
    FValue := (FValue shl 1) or ((Buffer shr BitsToGo) and 1);
  end;
end;

function TAICCabacDecoder.DecodeSymbolEqProb: Cardinal;
begin
  Result := 0;
  FValue := FValue shl 1;
  Dec(BitsToGo);
  if BitsToGo < 0 then
    GetByte;
  FValue := FValue or ((Buffer shr BitsToGo) and 1);
  if FValue >= Range then begin
    Result := 1;
    Dec(FValue,Range);
  end;
end;

function TAICCabacDecoder.DecodeUnaryExpGolombLevel(
  var Context: TCabacContext): Cardinal;
var
  K, L: Cardinal;
begin
  Result := DecodeSymbol(Context);
  if Result <> 0 then begin
    Result := 0;
    K := 1;
    repeat
      L := DecodeSymbol(Context);
      Inc(Result);
      Inc(K);
    until (L = 0) or (K = CabacExpStart);
    if L <> 0 then
      Inc(Result,DecodeExpGolombEqProb(0) + 1);
  end;
end;

procedure TAICCabacDecoder.GetByte;
begin
  if CodeStreamLen = 0 then
    ReadBuffer;
  Buffer := CodeStream[CodeStreamLen];
  BitsToGo := 7;
  Inc(CodeStreamLen);
  if CodeStreamLen >= CabacCodeStreamSize then
    CodeStreamLen := 0;
end;

procedure TAICCabacDecoder.ReadBuffer;
begin
  Stream.Read(CodeStream[0],CabacCodeStreamSize);
end;

procedure TAICCabacDecoder.ReadCoefficients(
  const ChannelType: TAICChannelType; out Coef: TAICIntBlock);
begin
  if DecodeSymbol(CtxCodedBlock) <> 0 then begin
    ReadSignificanceMap(ChannelType,Coef);
    ReadSignificantCoefficients(ChannelType,Coef);
  end else
    FillChar(Coef,SizeOf(Coef),0);
end;

function TAICCabacDecoder.ReadPredictionMode: Integer;
var
  ActSym: Integer;
begin
  ActSym := DecodeSymbol(CtxPredictionMode[0]);
  if ActSym = 1 then
    Result := -1
  else begin
    Result := DecodeSymbol(CtxPredictionMode[1]);
    Result := Result or (Integer(DecodeSymbol(CtxPredictionMode[1])) shl 1);
    Result := Result or (Integer(DecodeSymbol(CtxPredictionMode[1])) shl 2);
  end;
end;

procedure TAICCabacDecoder.ReadSignificanceMap(
  const ChannelType: TAICChannelType; var Coef: TAICIntBlock);
var
  CtxMap, CtxLast: PCabacContext;
  I, Sig: Integer;
begin
  CtxMap := @CtxCoefficientMap[ChannelType,0];
  CtxLast := @CtxLastCoefficient[ChannelType,0];
  for I := 0 to 62 do begin
    Sig := DecodeSymbol(CtxMap^);
    if Sig <> 0 then begin
      Coef[I] := 1;
      if DecodeSymbol(CtxLast^) <> 0 then begin
        FillChar(Coef[I + 1],(63 - I) * SizeOf(Integer),0);
        Exit;
      end;
    end else
      Coef[I] := 0;
    Inc(CtxMap);
    Inc(CtxLast);
  end;
  { last coefficient must be significant if no last symbol was received }
  Coef[63] := 1;
end;

procedure TAICCabacDecoder.ReadSignificantCoefficients(
  const ChannelType: TAICChannelType; var Coef: TAICIntBlock);
var
  I, C1, C2, C, Ctx: Integer;
begin
  C1 := 1; C2 := 0;
  for I := 63 downto 0 do begin
    C := Coef[I];
    if C <> 0 then begin
      Ctx := Min(C1,4);
      Inc(C,DecodeSymbol(CtxCoefGreaterOne[ChannelType,Ctx]));
      if C = 2 then begin
        Ctx := Min(C2,4);
        Inc(C,DecodeUnaryExpGolombLevel(CtxCoefAbsolute[ChannelType,Ctx]));
        C1 := 0;
        Inc(C2);
      end else if C1 <> 0 then
        Inc(C1);
      if DecodeSymbolEqProb <> 0 then
        C := -C;
      Coef[I] := C;
    end;
  end;
end;

procedure TAICCabacDecoder.StartDecoding;
var
  I: Cardinal;
begin
  FValue := 0;
  BitsToGo := 0;
  for I := 0 to CabacBits - 2 do begin
    Dec(BitsToGo);
    if BitsToGo < 0 then
      GetByte;
    FValue := (FValue shl 1) or ((Buffer shr BitsToGo) and 1);
  end;
  Range := CabacHalf - 2;
end;

end.

⌨️ 快捷键说明

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