Expand description
The CPU path: striped JPEG and whole-frame software H.264 (libx264 or OpenH264, by build),
with per-region change detection.
The CPU encode path: JPEG through turbojpeg in horizontal stripes, and H.264 through the
build’s software encoder — libx264 with the gpl feature, Cisco OpenH264 without it
(software_encoder) — as one whole-frame session.
JPEG frames are split into stripes coded in parallel via rayon; each stripe is hashed against
the previous frame for change detection, and only dirty stripes are sent, statelessly. H.264
is one region covering the frame, its encoder kept across frames for inter-prediction, and
both libraries emit the same wire framing. Both run the same per-region send and cleanup
decision (encode_cpu).
Structs§
- Coded 🔒
- A frame x264 coded: its bits, the quantizer it was planned or held at, whether it was a key
frame, and whether it was held (
hold_quantizer). - Encoded
Stripe - One encoded stripe: the compressed bytes plus geometry and identity metadata.
- Frame
Timing - When a frame was captured and when its encode began and ended, as CLOCK_MONOTONIC nanoseconds, so a consumer can attribute a frame’s age to the host rather than the network or the decoder. An encoder leaves them zero; the capture that ran it stamps every stripe of the frame.
- H264
Encoder Wrapper - One long-lived libx264 session for a frame, holding the raw
x264_thandle alongside a mirror of its live parameters so the encoder can be retuned per frame instead of rebuilt. - Input
Layout 🔒 - Where each plane of an NV12 picture lies in its buffer:
stridebytes a row, the first pixeloffsetbytes in, the buffersizebytes. - LastKey 🔒
- A key frame’s first attempt (
H264EncoderWrapper::aim_key): its bits, the quantizer it was planned or held at, the rate factor it was coded under, and whether it was held there. - Nv12
Planes - A frame’s 8-bit 4:2:0 picture as NV12, a luma plane and an interleaved chroma one, laid out
as an x264 session encodes it in place (
x264_param_input_layout): each planestridebytes a row within a buffer padded and aligned as x264’s own frames are, which x264 reads without copying it and writes the padding of. Tightly packed where the build has no x264, whose OpenH264 session takes no such picture. - Stripe
State - Everything one region of the frame must remember between frames: its reused buffers, its own live encoder, and the motion / paint-over / damage bookkeeping that drives its send decision.
Enums§
- Input 🔒
- The planes of a picture handed to x264: 4:2:0 or 4:4:4 planes of either depth, each its stride in bytes, or an 8-bit 4:2:0 picture as NV12.
Constants§
- CBR_
VBV_ FRAMES - Frames of the target a constant-rate x264 session is given as its buffer where the caller
names no
video_vbv_multiplier. x264’s row-level control prices each row against a slice’s share of the buffer, so in the frame and a half the other encoders take it coded a moving 1080p window on a 2560x1600 screen at half its target: 1.95 Mbit/s of 4 at 30.4 dB, 2.96 in four frames, 3.52 at 34.6 dB in eight, 3.68 in fifteen, with no latency lost on a LAN (6.2 ms to draw and decode at 1.5 frames, 5.5 at 8). Eight frames hold a frame’s worst case to 133 ms of the rate at 60 fps, where fifteen added queue on a slow link for 4% more of the target. - CLEANUP_
STAGGER_ 🔒FRAMES - The frames the JPEG stripes’ cleanups of one still screen are spread over (
encode_cpu). - CLEANUP_
VBV_ 🔒FRAMES - Frames of the target a constant-rate x264 session is given as its buffer while its cleanup
runs through the rate control, or
CLEANUP_FRAME_Sof its rate where that is more: in the session’s buffer of a frame and a half x264’s row-level control prices a still screen’s whole residual against the buffer and coarsens the rows it names a fine quantizer for, so a screen of text at 2 Mbit/s at 1080p sat at 31 dB while the quantizer x264 planned read 19; in four it reached 46 dB in five seconds with no frame over a budget and a half. A row finer than its reference is priced at its whole intra cost against a slice’s share of the buffer: at 60 fps four frames held a 1080p page at 0.5 Mbit/s at quantizer 30 and 25-35 dB, or at 51 after a scroll, where 0.2 s reached 55.7 dB in 30 s. - JPEG_
COMPRESSOR 🔒 - Reused libjpeg-turbo compressor kept per worker thread to avoid paying a
tjInitCompress/tjDestroyround trip for every stripe of every frame. - KEY_
STEPS 🔒 - Quantizer steps a halving of a capped CRF’s key frame is taken to need where it is aimed into
the bucket’s room (
H264EncoderWrapper::aim_key,fit_key), an encode at most aimed: text keeps 17 steps a halving between quantizers 12 and 35 (10.1 to 4.1 Mbit at 1280x720) where the quantizer’s own scale says 6, so an aim of 6 lands a second attempt past the room. - MAX_
POOLED_ 🔒BANDS - The most bands a conversion keeps a pool for (
on_band_pool); more run on rayon’s global pool. A session converts in as many bands as its encode threads, eight at most (session::threads_up_to). - MAX_
STRIPES 🔒 - Most stripes a JPEG frame is cut into, whatever the encoder host’s core count.
- MAX_
STRIPE_ CAPACITY - Upper bound on the horizontal stripes the CPU encoder splits a frame into, so the persistent per-stripe state vector can be reserved to a fixed capacity once, up front.
- MIN_
STRIPE_ 🔒HEIGHT - No JPEG stripe is shorter than this many rows.
- OWED_
FINER 🔒 - Quantizer steps finer than the paint-over one a capped CRF codes a block owed its paint-over
at (
ledger::BlockLedger::refresh_owed): a refinement’s, and two more, the predicted frame over a coarser picture landing short of it: a 720p page under a 4 Mbit/s peak came to 48.1 dB at one more and 49.4 at two, where the uncapped session’s paint-over leaves it at 48.5. - X264_
REFRESH_ 🔒FINER - Quality index steps finer than the session’s own a capped CRF refreshes its coarse blocks at
(
ledger::BlockLedger::refresh), one pastledger::REFRESH_FINER: refreshing a 720p page of text it coded at quantizer 51, x264 came to 37.7 dB three steps finer, 0.9 dB under the uncapped session’s on one to three slice threads, and to 38.5-38.6 four steps finer, within 0.3 dB of it on any, for 3 % more bytes. The uncapped session’s own picture moves with its slice threads (37.9-38.8 dB) rather than with the quantizers its scroll ends at, which are coarser than the refresh’s (26-29 against 22). - YUV10_
SHIFT 🔒 - The fixed-point scale of the 10-bit conversion’s coefficients.
Statics§
- X264_
OPEN_ 🔒CLOSE_ LOCK - Process-global lock that serializes libx264 encoder open/close, because those calls are not thread-safe yet several captures in one process open their sessions concurrently.
Functions§
- acknowledge_
reference - Every consumer holds frame
frame_id, or where notheldwas sent it: OpenH264 confirms the long-term reference it marked there. x264 keeps none. - band_
heights 🔒 - The rows of each band a conversion of
heightrows splits into for up tobandsthreads (convert_to_yuv_mt):height / bandsfloored to an even number and at least 2, the last band taking the rest wherever fewer than a band and 2 rows would be left after it. One band wherebands <= 1or the image fits one. - cleanup_
vbv_ 🔒kbit - The buffer, in kbit, of an x264 session at
bitrate_kbpswhile it is cleaned up (CLEANUP_VBV_FRAMES). - compute_
stripe_ 🔒geometries - Divide
heightintoncontiguous regions as(y_start, height), by codec. - convert_
to_ 🔒nv12_ mt - Convert a packed buffer, B,G,R,A or with
rgba_inputR,G,B,A, to 8-bit 4:2:0 BT.709 limited range as NV12, a luma plane and an interleaved chroma onestridesbytes a row, the picture x264 encodes in place (Nv12Planes), in the bandsconvert_to_yuv_mtsplits it into. Its samples are the onesconvert_to_yuv_mtwrites to I420, the chroma interleaved. - convert_
to_ 🔒yuv10_ mt - Convert a packed BGRA/RGBA buffer to planar 10-bit YUV (4:2:0 or 4:4:4) in 16-bit samples,
for the software encoders’ 10-bit sessions, across up to
bandsthreads asconvert_to_yuv_mtsplits them. - convert_
to_ 🔒yuv_ mt - Convert a packed BGRA/RGBA buffer to planar YUV (4:2:0 or 4:4:4) for the software H.264
encoders, spreading the conversion across up to
bandsthreads so it never bottlenecks a frame. - encode_
cpu - The CPU path’s per-frame entry point: decide per region whether it needs sending, and encode those as JPEG stripes across the rayon pool or as one H.264 frame through the build’s software encoder (libx264 or OpenH264).
- encode_
cpu_ from encode_cpuwith the frame’s picture already converted (planes): an 8-bit 4:2:0 x264 session encodes it in place and leavesraw_pixelsunread, which a capture converting straight from the screen’s memory never wrote. x264 reads the picture through the next encode (held_input).- fast_
hash 🔒 - Fast, non-cryptographic 64-bit content hash used only for in-memory change detection.
- h264_
bit_ depth - The bits per sample the software H.264 session codes
settingsat: 10 where they ask for it and the build’s libx264 opens such a session, else 8. - held_
input - The picture the software H.264 session still reads after its last encode returned
(
H264EncoderWrapper::held_input), which its owner leaves unchanged:Nonefor any other session. - invalidate_
reference - Leave frame
frame_idand every frame after it out of the software H.264 session’s predictions: x264 through its reference window, OpenH264 from a long-term reference every consumer holds. False when the encoder cannot, and the caller codes a key frame instead. - ledger_
frame 🔒 - One frame of a region’s
ledger, the region at rowsytoy + height: the rectangles ofchangedthat reach it, in its own coordinates, read with whether it changed (dirty) and whether its hash saw it change (observed,BlockLedger::frame_reported). - on_
band_ 🔒pool - Run
convert, a conversion’s parallel bands, on a pool ofbandsthreads: one a band count, built the first time a conversion asks for it and kept for the process. - qp_
offset 🔒 - What libx264 adds to a quantizer above 8 bits: its quantizer bounds, a frame’s forced quantizer, and the one it reports are all on a scale that starts six below zero for every bit past eight, while the rate factor is not. Added going in and taken off coming out, so a session’s quantizers mean what they do at 8 bits whatever its depth.
- rate_
control 🔒 - The
(bitrate_kbps, vbv_kbit)the software H.264 encoder is programmed with: the CBR target, with a buffer ofCBR_VBV_FRAMESunlessvideo_vbv_multipliernames one, or the peak of a CRF a positivevideo_vbv_multipliercaps. An uncapped CRF gets a buffer of 0. - release_
input - Stop the software H.264 session reading the picture it holds (
held_input). - stripe_
count - How many horizontal regions a frame of
heightis split into, which is the choice of how much encode parallelism to spend on it. - stripes_
at_ 🔒once - Whether a frame’s
nJPEG stripes are coded at once across the rayon pool, or one after another on the encode thread: one region, or a session withoutcpu_encode_threading, takes no other. - stripes_
held_ still - Whether a frame that holds still codes the software H.264 session at the paint-over quality
instead of its own (
encode_cpu): at a constant quality, where its cleanup falls due, its burst is held, or it keeps the quality it was cleaned up at. A constant rate holds none there. - stripes_
hold_ quantizer - Whether the software H.264 session holds its cleanup at the quantizer asked for: libx264
does under either rate control, and OpenH264 moves its quantizer only at a constant quality
(
Openh264Encoder::update_qp), so a session that holds none is cleaned up through its rate control (encode_cpu), never by a key frame, which that would starve. - x264_
frame_ 🔒rate - The rate an x264 session is opened at: the capture’s, or 30 frames per second where it names less than one.
- x264_
input_ 🔒layout - The planes an 8-bit 4:2:0 x264 session of
widthxheightencodes in place, which the library lays out for the CPU it runs on;Nonewhere the linked x264 is not patched to. - yuv10_
coefficients 🔒 - The BT.709 coefficients that take 8-bit R, G, B to 10-bit Y, Cb, Cr at
full_rangeor limited range, scaled by1 << YUV10_SHIFT: a row each for Y, Cb, and Cr, then the luma offset. The chroma offset is the 10-bit midpoint at either range.