📄 aiccabacdecoder.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 + -