ArithmeticCoding 1.0.6
dotnet add package ArithmeticCoding --version 1.0.6
NuGet\Install-Package ArithmeticCoding -Version 1.0.6
<PackageReference Include="ArithmeticCoding" Version="1.0.6" />
<PackageVersion Include="ArithmeticCoding" Version="1.0.6" />
<PackageReference Include="ArithmeticCoding" />
paket add ArithmeticCoding --version 1.0.6
#r "nuget: ArithmeticCoding, 1.0.6"
#:package ArithmeticCoding@1.0.6
#addin nuget:?package=ArithmeticCoding&version=1.0.6
#tool nuget:?package=ArithmeticCoding&version=1.0.6
Arithmetic Coding for .NET
<img align="right" src="https://github.com/winscripter/ArithmeticCoding/blob/master/media/Logo/logo.png?raw=true" width="128" height="128">
ArithmeticCoding is a lightweight and fast library for .NET that simplifies implementation of arithmetically coded data found in codecs/file formats. It implements arithmetic decoding/encoding algorithms. It comes with:
- An AV1 Symbol decoder
- An H.263 SAC (Syntax-Based Arithmetic) decoder/encoder
- An H.264 CABAC decoder
- More upcoming
It can do all of this in fully managed .NET - it does not rely on native dependencies, everything is written in C# code. Zero P/Invoke.
Arithmetic coding can be a very complex task. If you ever tried to write a file format or codec in C# or any other programming language, i.e. H.264, you know how hard it can be to implement arithmetic coding correctly and efficiently. This library aims to solve that problem by providing a simple and efficient API for arithmetic coding operations.
You'll need at least .NET Standard 2.0 or .NET Framework 4.6.1 to use this library. Modern versions, such as .NET 10.0, are also supported.
Getting started
To get started with ArithmeticCoding, you can install it via NuGet. Use the following command in the Package Manager Console:
dotnet add package ArithmeticCoding
Alternatively, if you use Visual Studio, you may do so by right-clicking on your project in the Solution Explorer, selecting "Manage NuGet Packages...", and searching for "ArithmeticCoding". Choose the package and click to Install it.
H.264
Here is an example of using the H.264 CABAC decoder. You'll need to implement IH264MacroblockProvider; see
Implementing IH264MacroblockProvider.
You should also implement IBitstreamReader, see
Implementing IBitstreamReader. The slice
type can be derived from the slice_type syntax element from the Slice Header (see clause 7.4.3 in the H.264 spec; table 7-6). The slice QP
is defined with the QPY variable, which is specified in around at the bottom of clause 7.4.5 in the H.264 spec. Finally, codIOffset
is read once during CABAC initialization right before reading the first syntax element, or, after all the cabac_alignment_one_bit bits.
using ArithmeticCoding;
using ArithmeticCoding.H264;
byte[] cabacData = { /* your CABAC encoded data */ };
IH264MacroblockProvider provider = new MyMacroblockProvider(); // Implement this interface to provide macroblock data
H264CabacSliceType sliceType = H264CabacSliceType.P; // Specify the slice type
int sliceQPy = 26; // Specify the slice QP
using var ms = new MemoryStream(cabacData);
IBitstreamReader bitstreamReader = new MyBitstreamReader(ms); // Implement this interface to read bits from the bitstream
int codIOffset = bitstreamReader.ReadBits(9); // Read the initial CABAC offset from the bitstream. (Do this right after reading all the necessary cabac_init bits)
H264CabacDecoder decoder = new H264CabacDecoder(sliceType, sliceQPy, provider, codIOffset, bitstreamReader);
I know... setup can be a bit involved, but once you have everything in place, using the decoder is super straightforward.
Here is an example of reading the mb_skip_flag syntax element:
bool mbSkipFlag = decoder.DecodeSkipFlag();
That's... pretty much it! You can now use the decoder to read other syntax elements as needed.
Here's another example with coded_block_pattern:
int codedBlockPattern = decoder.DecodeCodedBlockPattern();
Yep... like I said, super straightforward. 👍
Now, a few syntax elements do require a few input parameters in order to decode them. For instance,
you need to provide the decoder the value of mbPartIdx and subMbPartIdx to decode mvd_l0 or
mvd_l1, as you can see here:
decoder.MacroblockPartitionIndex = 1; // Example (mbPartIdx)
decoder.SubMacroblockPartitionIndex = 2; // Example (subMbPartIdx)
int mvdL0 = decoder.DecodeMotionVectorDifferenceL0(); // Reading mvd_l0
In Visual Studio, if you hover over methods starting with Decode, say, DecodeSkipFlag(), you'll
see documentation regarding what syntax element that method decodes. But if that Decode method requires
input parameters, like DecodeMotionVectorDifferenceL0, documentation actually states which properties
you'll need to set up before you call the Decode method.
Example with mvd_lX (requires mbPartIdx, subMbPartIdx):
Example with mb_skip_flag (no prior setup required):
To obtain input values:
MacroblockPartitionIndexandSubMacroblockPartitionIndexmap into variablesmbPartIdxandsubMbPartIdx, respectively. Their assignment is specified directly in clause 7.3.5.1 and 7.3.5.2 in the H.264 spec. Also, to decodemvd_l0,mvd_l1,ref_idx_l0, orref_idx_l1: if you're parsingmb_pred(), you only have to providembPartIdx. And if you're parsingsub_mb_pred(), you have to providembPartIdxandsubMbPartIdx.subMbPartIdx, when parsingmb_pred(), can be 0.ResidualBlockKindis an enum that represents the current residual transform coefficient block that you're parsing, inresidual(startIdx, endIdx). Think Intra16x16DCLevel, LumaLevel8x8, CbIntra16x16ACLevel, you name it.LevelListIndexis the index of the transform coefficient level inside of a block. For instance, inresidual_block_cabac, it is the index that you're using to assign tocoeffLevel.NumC8x8is assigned in clause 7.3.5.3 in the H.264 spec. If ChromaArrayType is not 1 or 2, its value can be left as 0.NumDecodedAbsLevelGreaterThan1andNumDecodedAbsLevelEqualTo1is the total number of coefficients incoeffLevelinresidual_block_cabacwhose values are > 1 and == 1, respectively.
H.263
Import the namespace:
using ArithmeticCoding.H263;
H.263 uses what's known as a Syntax-Based Arithmetic (SAC) coder. It relies on cumulative
frequencies for decoding symbols. Before we get started, you'll need to implement the
IH263PscFifo interface which implements a Picture Start Code (PSC) First-in First-out (FIFO).
See Implementing IH263PscFifo.
IH263PscFifo pscFifo = ...; // <-- Implement
Let's start with the decoder.
H263SyntaxBasedArithmeticDecoder sacDecoder = new();
int lumaCodedBlockPattern = sacDecoder.DecodeSymbol(
H263SyntaxBasedArithmeticModels.CbpY, pscFifo);
// Async is also supported
int asyncLumaCodedBlockPattern = await sacDecoder.DecodeSymbolAsync(
H263SyntaxBasedArithmeticModels.CbpY.ToArray(), pscFifo);
The encoder part is also very simple.
H263SyntaxBasedArithmeticEncoder sacEncoder = new();
const int index = 4; // example index
sacEncoder.EncodeSymbol(index, H263SyntaxBasedArithmeticModels.CbpY, pscFifo);
// Async is also supported
await sacEncoder.EncodeSymbolAsync(index, H263SyntaxBasedArithmeticModels.CbpY.ToArray(), pscFifo);
AV1
Currently, ArithmeticCoding includes an AV1 Symbol Decoder. For comprehensive AV1 entropy coding support, Symbol Encoding/CDF support may be introduced in future versions. For now, here's how to use the symbol decoder.
disable_cdf_update is a syntax element. sz is the input parameter for the initialization process.
using ArithmeticCoding.Av1;
IBitstreamReader bitstreamReader = ...; // <-- Implement
const int sz = 10; // <-- Implement
const bool disable_cdf_update = false; // <-- Implement
var symbolDecoder = new Av1SymbolDecoder(
bitstreamReader, sz, disable_cdf_update);
This will immediately read a few bits off of the bit-stream. This is necessary for proper initialization.
You can now use this to read AV1 bools, literals or symbols, as follows.
int boolean = symbolDecoder.ReadBooleanAsInt32();
int literal = symbolDecoder.ReadLiteral(5);
int customSymbol = symbolDecoder.ReadSymbol(provide CDF here);
Powers
Use of this library makes manual .NET implementations (remember, C#, VB.NET and even F#) of supported file formats and codecs that include arithmetically coded data significantly easier and faster to implement.
The license is very permissive (MIT License), so you can use this library in both open-source and commercial projects without worrying about licensing issues.
It is also greatly optimized for performance, so you can expect efficient arithmetic coding operations.
Got any questions?
You're more than welcome to ask for help through the GitHub Issues page.
In GitHub Issues, you can report bugs, request features, or seek assistance with using the library.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.