Proxeno.Kiln 0.2.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Proxeno.Kiln --version 0.2.0
                    
NuGet\Install-Package Proxeno.Kiln -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Proxeno.Kiln" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Proxeno.Kiln" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Proxeno.Kiln" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Proxeno.Kiln --version 0.2.0
                    
#r "nuget: Proxeno.Kiln, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Proxeno.Kiln@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Proxeno.Kiln&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Proxeno.Kiln&version=0.2.0
                    
Install as a Cake Tool

Kiln

Kiln

CI NuGet version NuGet downloads License: Apache-2.0 .NET 10

A from-scratch H.264 encoder for .NET. Pure managed, SIMD-accelerated C#, zero native dependencies, Apache-2.0. Feed it raw frames and it hands back a standards-compliant H.264 baseline bitstream — the whole codec (bitstream, transforms, intra/inter prediction, motion search, entropy coding, deblocking) is implemented here, in this repository, against the ITU-T H.264 specification. No native codec to cross-compile, ship, or keep patched.

Status: pre-release (0.x). APIs will change. Every capability listed here is backed by a test in this repository — including smoke tests that decode every produced stream with an independent reference decoder as an oracle — and the What Kiln is not section says plainly what isn't here.

What you can build

Kiln is the encode step: one .NET process turns rendered or captured frames into an H.264 stream you can send anywhere, with no native runtime on the box. It's built for low-latency, real-time video, such as:

  • Game & cloud-gaming streaming — render and encode on a server, play in a browser or thin client with well-under-a-second glass-to-glass latency.
  • Screen capture & remote desktop — a headless host encoding its own output frame by frame.
  • Camera & robotics video — live feeds from cameras, drones, or robots to an operator's screen.
  • A source for a WebRTC / RTP pipeline — Kiln emits Annex B access units that drop straight into a stack like Keryx or any RTP packetizer.
  • Anywhere you need low-latency managed H.264 inside a .NET process without bundling a native codec or taking on GPL/LGPL linkage.

Goals

  • Pure managed. 100% C# on .NET 10 with hardware intrinsics — NEON/AdvSimd on arm64, AVX2 and SSSE3 on x64, scalar fallback everywhere else. No native library to cross-compile, ship, or patch.
  • Genuinely open. Apache-2.0, original work that links no copyleft code — embed it in commercial or proprietary products where GPL/LGPL codec linkage is a problem. That's exactly why it exists.
  • Faithful to the spec. Written against ITU-T H.264 (ISO/IEC 14496-10); every numeric table that originates in the spec carries its clause/table citation in the source (Table 9-4, §8.5.9, §9.2.1, …).
  • Real-time first. Predictable per-frame latency over maximum compression: a steady stream of low-latency frames beats a slow exhaustive search.
  • Honest about scope. A 0.x that tells you exactly what is proven and what isn't here yet.

Quick start

using Kiln;

var encoder = new H264BaselineEncoder(1280, 720, new H264BaselineEncoderOptions
{
    QuantizationParameter = 28,
    KeyframeIntervalFrames = 120,
    SliceCount = 4,               // parallel slice encoding
});

var annexB = new byte[1280 * 720 * 2];

// Planar I420 input; u/v are half-resolution planes.
var written = encoder.EncodeFrame(y, u, v, strideY: 1280, strideUv: 640, annexB);
var wasIdr = encoder.LastFrameWasIdr;
// annexB[0..written] is a complete Annex B access unit (SPS/PPS included on IDR).

What you get

A real encoder, not a toy — the parts a low-latency streaming server actually needs:

  • Baseline bitstream that just plays. Constrained baseline profile, IDR + P-frames, CAVLC entropy coding, Annex B output (SPS/PPS carried on every IDR) that streams straight into a WebRTC or RTP packetizer and decodes on browsers and hardware decoders.
  • Genuine coding tools. Intra 4×4 / 16×16 with RD mode selection, P-slice inter prediction with sub-pel SATD motion search, P_Skip, and multiple reference frames.
  • Quality knobs. In-loop deblocking, optional greedy trellis quantization, variance-based spatial adaptive QP, and per-frame rate control.
  • Parallelism built in. Multi-slice frames encode their slices in parallel and bound the region a lost packet can damage.
  • SIMD with a safety net. NEON/AdvSimd, AVX2 and SSSE3 kernels selected at runtime, each covered by parity tests against a scalar reference; CI runs the full suite on Linux, Windows and macOS so both architectures stay green.
  • Streaming companions. Kiln.RateControl (a low-latency rate controller with network feedback) and Kiln.Recovery (IDR budgeting / keyframe recovery policy) are public companion namespaces for server use.
  • Verified. 2,174 tests — spec-roundtrip decoding, SIMD/scalar parity, golden-frame regression, PSNR fidelity floors, adversarial neighbour-availability sweeps, and independent-decoder smoke tests over every produced stream.

Options reference

Option Default What it does
QuantizationParameter 28 Base QP, 0–51.
KeyframeIntervalFrames 60 IDR every N coded frames (frame 0 is always IDR). EncodeFrame(forceKeyframe: true) overrides.
SliceCount 1 Slices per frame; >1 encodes slices in parallel and bounds loss regions.
MaxReferenceFrames 2 1 = single-ref (WebRTC / hardware-decoder safe), 2 = multi-reference P.
TargetBitsPerFrame 0 (off) Per-MB QP adaptation toward a per-frame bit budget.
FastSearch true Hex/diamond integer ME + qpel refinement; false = exhaustive integer search.
UseMotionSatd true SATD scoring for integer-pel ME candidates (SAD for fractional refinement).
EnableIntraInPFallback true Allows I16x16/I4x4 macroblocks inside P-frames when inter prediction fails.
TrellisLevel 0 1 = greedy per-coefficient trellis quantization (better RD, ~5% CPU).
AdaptiveQuantStrength 0.0 Variance-based spatial AQ; 1.0 = standard, typical 0.5–1.5.
PreferRealtimeLatencyTuning false Speed-biased P-frame ME / chroma-DC handling.
LightweightDeblocking false Disables in-loop deblocking (bitstream-signalled) to cut CPU.
PreferHardwareIntrinsics true Runtime SIMD kernel selection; false forces scalar.
SubPartitionRangeCap 16 Sub-partition ME radius cap (per-frame complexity budget applies).
ProfileIdc / LevelIdc 66 / 0 (auto) Signalled profile (baseline) and level. LevelIdc = 0 auto-selects the lowest level whose MaxFS admits the frame, floored at 3.1; set explicitly to pin a level.
ChromaDcRdLambda, Intra4x4SadLambda derived Expert RD-lambda overrides; leave null.

Performance

Measured on Apple M5 Max (arm64, NEON/AdvSimd), .NET 10, BenchmarkDotNet, quiet machine — the committed perf-gate baseline numbers (perf/).

Benchmark Mean Min
SATD 4x4 kernel (Satd4x4_Once) 11.2 ns 11.1 ns
SATD 4x4 x 9 intra modes (SatdMany4x4_9Modes) 99.3 ns 99.2 ns
SAD 8x8 dispatch 3.5 ns 3.4 ns
SAD 16x16 dispatch (stride 720) 6.4 ns 6.4 ns
Full-MB 16x16 ME search, range 8 76.4 us 76.1 us
Steady P-frame encode, 1280x720, 1 slice 2.24 ms 2.20 ms

That 2.24 ms figure is measured on the committed benchmark's near-static synthetic content, and it is not what a camera or a game scene costs. Textured, moving content is roughly an order of magnitude more expensive per frame. On a deterministic scroll-plus-noise source, steady P-frames measure:

Resolution 1 slice 4 slices
640x480 19.8 ms 13.0 ms
1280x720 26.9 ms 15.6 ms
1920x1080 32.8 ms 18.8 ms

Size your deployment from those numbers, not from the kernel microbenchmarks above. Note also that slices do not divide the work cleanly — most of what remains after motion estimation (skip evaluation, deblocking, CAVLC) does not parallelize, so 4 slices buys roughly 1.75x at 1080p rather than 4x. Perf discipline is part of the repo: bench/Kiln.Benchmarks (BenchmarkDotNet) plus scripts/h264-simd-capture-baseline.sh and scripts/h264-simd-perf-gate.sh gate changes against the committed baseline in perf/. See docs/perf-gate.md.

What Kiln is not

Not an x264 competitor. No B-frames, no CABAC, no 8×8 transform, no interlace; 4:2:0 8-bit only. If you need maximum compression at any CPU cost, use a full-profile encoder. If you need clean-licensed, dependency-free, low-latency H.264 inside a .NET process, you are in the right place.

Frame dimensions need not be multiples of 16: sizes like 1920×1080 or 1366×768 are supported via SPS frame cropping — the encoder pads to the 16×16 macroblock grid internally and signals the true display size, which is what decoders output. Dimensions must be even (4:2:0 chroma is subsampled 2×2, so odd extents are unrepresentable). By default the encoder signals the lowest H.264 level whose frame-size limit (MaxFS, Annex A Table A-1) admits the padded picture, floored at Level 3.1 — 1920×1080 codes as 1920×1088 (8160 macroblocks) and signals Level 4.0 automatically. Set H264BaselineEncoderOptions.LevelIdc explicitly to pin a level; an explicit level that is too small for the frame throws, naming the lowest sufficient level. The chosen level is readable from H264BaselineEncoder.LevelIdc.

0.x behavioural change: LevelIdc previously defaulted to 31 (Level 3.1) and the constructor threw for frames above 1280×720. The default is now 0 = auto-select. Streams ≤720p with default options are byte-identical to before (the auto floor is still 3.1); larger frames now construct and encode instead of throwing. EncodeFrame's output span now has a documented recommended size, H264BaselineEncoder.RecommendedOutputBufferSize.

The Adaptation (resolution/fps ladders) and Queue (latest-frame dropping) namespaces ship inside the library, fully tested but not yet wired into the encoder — experimental, and their APIs may change or move without notice. See docs/architecture.md.

Installing

Published on nuget.org as Proxeno.Kiln. The package id is Proxeno.Kiln; the assembly and namespace stay Kiln, so code uses using Kiln;.

dotnet add package Proxeno.Kiln

Try it

samples/Kiln.Capture records your camera to a playable .m4v — capture, colour conversion, H.264 encode and MP4 muxing, all managed, no native binaries anywhere in the pipeline:

dotnet run --project samples/Kiln.Capture -- list
dotnet run --project samples/Kiln.Capture -- record --seconds 10 --output capture.m4v

Documentation

License

Apache-2.0 — see LICENSE. © Kiln contributors.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.0 104 8/26/2026
0.5.0 96 8/25/2026
0.4.0 98 8/25/2026
0.3.1 99 8/25/2026
0.3.0 104 8/25/2026
0.2.0 97 8/25/2026
0.1.2 93 8/22/2026
0.1.1 89 8/22/2026
0.1.0 156 8/22/2026

0.2.0 — FIX: P_Skip motion vectors were derived incorrectly when a neighbouring macroblock used a non-zero reference index (ITU-T H.264 8.4.1.1), so the encoder's reconstruction could diverge from a conformant decoder's and compound into visible drift on motion content; upgrading is recommended. Frame dimensions no longer need to be multiples of 16 — sizes such as 1920x1080 are supported via SPS frame cropping (dimensions must be even). BREAKING: Width/Height are now display dimensions, with new CodedWidth/CodedHeight for the macroblock-aligned size, and LastReconstructedY/U/V return the uncropped coded plane. LevelIdc now defaults to 0 (auto-select from frame size). Output quality is substantially better on moving content and no longer varies with SliceCount. See the GitHub release notes for the full list.