Muxer — Statistical Multiplex

TSDuck-based MPEG Transport Stream multiplexer with full PSI/SI support

MPTS-multiplex & Adaptive Hybrid Statmux

Stream Manager mux samler flere SPTS-streams til én CBR MPTS-udgang (DVB/IPTV). Adaptive Hybrid Statmux kombinerer en CBR-core-fyldning med VBR-balancerede encoders til konstant mux-udgang.

1. Encoderlag (FFmpeg per stream)

Når forældren har statmux aktiveret, kører hver FFmpeg-encoder begrænset-VBR: -b:v <avg> -minrate <min> -maxrate <max> -bufsize <max×2>. VBV-buffer = 2× max giver ~2 s toppreserv. Statmux-streams får også et deterministisk GOP-offset (-force_key_frames) per stream_id, så I-frame-toppe ikke falder sammen på tværs af kanaler.

2. Muxlag (TSDuck tsp-pipeline)

tsp -I null (∞ NULL-pakker @ linehastighed) → -P merge tsp -I ip <stream> (overlejrer virkelige pakker) → -P continuity (alarmskip) → -P pcradjust --bitrate X (omskriver PCRs) → -P pcrverify --jitter-max 500µs → -P bitrate_monitor (ratealarm ±5 %) → -P regulate --bitrate X --packet-burst 32 → -O ip <out> --packet-burst 7 --enforce-burst.

3. Outputlag (UDP)

regulate-plugin udsender nøjagtigt mux.bitrate bps på ledningen. Input, der hænger efter → NULL-pakker fylder hullet. Input, der toppe → intern FIFO-buffer (4096 pakker ≈ 0,3 s @ 19 Mbps) absorberer. --enforce-burst tvinger 7 TS-pakker per UDP-datagram (1316 B, IPTV-standard).

Anbefalet dimensionering (Σ min / avg / max vs mux.bitrate)

Mux top bar viser 3 summer med farvestatus. Regler:

Σ avg ≤ 85 % mux.bitrate — gennemsnitligt målsum på tværs af alle kanaler plus lyd. Det er mux-'budgettet'. 15 % statistisk reserve beskytter mod toppesammenfald. Grøn ≤ 85 %, amber ≤ 100 %, rød > 100 %.

Σ max ≤ 160 % mux.bitrate — topp Ceiling sum. Tilladt at overstige kapacitet (det er pointen med statmux — toppe falder sjældent sammen). Grøn ≤ 160 %, amber ≤ 200 %, rød > 200 % (drops ved vedvarende top).

Σ min ≤ 50 % mux.bitrate — encoder-gulvsum. Et sikkert gulv sikrer, at encoderen ikke falder til unødigt lav kvalitet på stille scener. Grøn ≤ 50 %, amber ≤ 90 %, rød > 90 %.

Eksempel: 4 HD-kanaler i en 19 Mbps DVB-T-mux

Ledigt budget efter PSI/SI/EIT: ~18,5 Mbps. Σ avg = 4 × 4,0 = 16 Mbps (86 % — amber grænseflade, sænk yderligere). Σ max = 4 × 6,0 = 24 Mbps (130 % — grøn, OK). Σ min = 4 × 3,0 = 12 Mbps (65 % — amber, OK). Mål: avg ~85 % af budget, max ≤ 160 %.

Diagnostics & alarmer

På ≥ 10 alarms i 60s vises en flash-notifikation i Mux UI, der anbefaler en bithastighedsreduktion. Auto-back-off er IKKE aktiv — operatøren beslutter.

-P bitrate_monitor --periodic 60 --min/max ±5% — alarm, hvis faktisk hastighed afviger ud over ±5 % af mål. Betyder, at regulate er sultet (input døde).

-P continuity — sporer TS-continuity-telegrafer. Logger en advarsel ved hvert drop (over-subscription, FFmpeg-krash, NIC-jitter).

-P pcrverify --jitter-max 500000 — DVB tillader PCR-jitter ≤ 500 µs. Alarm = pcradjust kan ikke følge med eller kilden har ødelagte PCRs.

Glitches & deres årsager

GOP-sammenfald — alle encoders udsender I-frames samtidigt, toppesammenfald. Løsning: GOP-offset (allerede til stede for statmux, hash(stream_id) mod gop_size).

Input-signal-tab — enkelt kanal bliver sort, mux fortsætter (takket være -I null-base). Varighed ~3-8 s for FFmpeg-genstart.

Over-subscription (vedvarende toppe > kapacitet) — blokke/lyd hæver ~50-200 ms. Løsning: sænk stream-gennemsnit med 5-10 % eller fjern en kanal.

PCR-drift — STB-hæven hvert par sekunder. Løsning: pcradjust i pipeline (allerede til stede), se pcrverify-alarmer.

STB VBV-underrun — STB mister sync og genopnår (~2-3 s). Løsning: encoder bufsize = 2 × maxrate (allerede), sænk maxrate.

tsp-pipelineparametre (mux_worker.ex)

--max-input-packets 4096 / --max-flushed-packets 4096 (intern FIFO ≈ 0,3 s @ 19 Mbps). --receive-buffer-size 16777216 (16 MB UDP rcv-buffer per input). --packet-burst 32 (regulate) / 7 (output, IPTV-standard). --enforce-burst (hvert UDP-datagram er nøjagtigt 7 pakker).

Empirisk kapacitetsberegning (CLT)

Top-bar-badge `📐 rec X.XM` viser den anbefalede mux-kapacitet udledt fra den centrale grænseværdisætning. Summen af uafhængige VBR-streams nærmer sig en normalfordeling, så Mux = μ_total + z·σ_total + margin. σ_i estimeres fra hver inputs VBR-område som (max−min)/4 (antager, at området dækker ±2σ). Marginen = 10 % af μ_total kompenserer for PSI/SI-overhead, encoder-rate-control-jitter og stream-korrelation, som ren CLT undervurderer.

Badge-farve: 🟢 grøn = cap ≥ 99,7 % rec (konservativ) · 🟡 amber = mellem 99 % og 99,7 % · 🔴 rød = cap < 99 % (underudstyret, risiko for drops) · 🔵 blå = cap ikke indstillet.

z-score per dækkingsmål: 90 % z=1,28 · 95 % z=1,65 · 99 % z=2,33 · 99,7 % z=3,00 (standard) · 99,99 % z=3,72 (broadcast-grade). Badge-værktøjstipet viser alle niveauer; klik anvender 99,7 %-anbefalingen på mux.bitrate (mux-genstart påkrævet).

σ_eff = σ_total × statmux_factor (statmux_factor = 0,7 når Statmux er TIL, ellers 1,0)

Anbefalede værdier per kanal (HD H.264)

1080p25 HD-kanal: avg = 4000-5000 kbps, min = avg × 0,75 (~3000-3750), max = avg × 1,5 (~6000-7500). UI udfylder automatisk min/max fra avg. Statmux UI udfylder automatisk avg fra streamens transcoder-profil. SD-kanal: avg = 2000-2500 kbps. UHD: avg = 12000-18000 kbps.

Adaptiv Hybrid StatMux

Adaptive Hybrid Statmux er en runtime-mekanisme, der skifter ubrugt kapacitet fra kerne-streams (beskyttet, fuld VBR) til balancerede streams (ofret). "Hybrid", fordi to forskellige rate-control-regimer kører side om side (CBR-core-fyldning + VBR-balanceret); "adaptiv", fordi routeren genevaluerer én gang i sekundet fra en HLS-forudsigelseslookahead. Operatøren markerer streams som balanceret via højre-side-tjekboksen; systemet for-koder dem til tre tiers (HIGH/MED/MIN), og routeren skifter atomært symlinket baseret på resterende headroom efter at have forudset kerne-toppe.

Kapacitet — hvordan bithastighed opdeles

Mux-kapacitet 38 Mbps
  ┌──────────────────────────────────────────────────────────────────┐
  │█████████████████████████████████████████████████████░░░░░░░░░░░░│
  └──────────────────────────────────────────────────────────────────┘
   ◀────── core_max (forudset fra 6 HLS-segmenter) ─▶◀── balanced ──▶
                                                       per_balanced
                                                       = (cap − core_max
                                                          − SI-overhead
                                                          − lyd) / N

  Eksempel: cap=38000  core_max=29000  SI=200  audio_total=1280  N_balanced=2
           remaining = 38000 − 29000 − 200 − 1280 = 7520 kbps
           per_balanced_max = 7520 / 2 = 3760 kbps
           clamp(3760, 500, 3000) = 3000 kbps  ← loft for balanceret VBR

Praktisk gevinst (10 streams × 3 Mbps avg, 4 Mbps max)

Uden Adaptive Hybrid Statmux skal du dimensionere muxet til worst-case Σ max. Med Adaptive Hybrid Statmux dimensionerer du omkring Σ avg + en statistisk buffer (broadcast-korrelation ρ=0,15). Ægte gevinst ~5 Mbps på en 38 Mbps-mux, eller +1 stream ved samme kap.

Ren CBR (encoder fast)

VBR uden Statmux

Adaptive Hybrid Statmux TIL

URL ↔ Statmux-eksklusivitet

Brugerdefineret URL-inputoverride og Statmux er gensidigt eksklusive. Med Statmux til, afhænger den balancerede transcoder af den lokale encoder-HLS til at kontrollere bithastigheden. En ekstern URL ville omgå denne kontrolsløjfe. UI'en håndhæver dette begge veje — tjekboksen låses, når der er en konfliktende kombination, og værktøjstipet viser, hvilken stream der blokerer.

Pipeline (encoder → balanceret transcoder → mux ffmpeg → tsp)

┌─────────────────────────┐
          │  Encoder (NVDEC→NVENC)  │ ← UDP-satellit
   STREAM │  /dev/shm/stream_X/h264/│
          │  → muxed.m3u8 + segmenter│
          └────────────┬────────────┘
                       │
              ┌────────┴────────┐
              │                 │
        role="core"        role="balanced"
        (beskyttet)        (ofret)
              │                 │
              │                 ▼
              │     ┌───────────────────────────┐
              │     │  BalancedTranscoder       │
              │     │  ffmpeg p1 NVENC VBR      │
              │     │  -maxrate dynamisk        │ ← Adaptive Hybrid router
              │     │  /dev/shm/stream_X_       │   1 s tick (forudsiger fra
              │     │   balanced/h264/...m3u8   │   6 HLS-segmenter, atomær
              │     └───────────┬───────────────┘   symlink-swap HIGH/MED/MIN)
              │                 │
              ▼                 ▼
          ┌─────────────────────────┐
          │  ffmpeg-as-mux          │ ← /dev/shm/mux_X/pipe.sh
          │  -f mpegts pipe:1       │
          │  -muxrate <cap>         │
          └────────────┬────────────┘
                       │ shell-rør
                       ▼
          ┌─────────────────────────┐
          │  tsp -I file -          │
          │  continuity → regulate  │
          │  → pcradjust → bitrate_ │
          │     monitor             │
          │  -P nit -P sdt -P inject│
          │     (DVB SI-tabeller)   │
          └────────────┬────────────┘
                       │
                       ▼ UDP-multicast
                  239.x.x.x:1234

Dimensionering af kerne VBR min/avg/max for statmux

Statistisk gevinst sker kun, når encoders har et bredt VBR-område — når max ≈ avg, er encoderen effektivt CBR, og routeren har intet at omfordele. Konfigurer `min/avg/max` per stream, så Σmax er bekvemt over mux-kapaciteten (over-subscription = headroom for statistisk gevinst), mens Σavg sidder bekvemt under den.

Udarbejdet eksempel — 38 Mbps-mux, 10 HD-core + 2 balancerede:

  Gammel (CBR-låst):       min=2000  avg=3000  max=4000
     Σmax = 10×4000 + 2×7600 = 55200 kbps  (1,45× cap — lille gevinst)
     σ_per_stream = (4000−2000)/4 = 500 kbps  (ubetydelig — flad)
     Σ statistisk headroom ≈ 1,5 Mbps

  Anbefalet (bred VBR): min=1500  avg=3000  max=6000
     Σmax = 10×6000 + 2×7600 = 75200 kbps  (1,98× cap — sund gevinst)
     Σavg = 10×3000 + 2×3000 =  36000 kbps  (95% cap — bekvemt)
     Σmin = 10×1500 + 2×500  =  16000 kbps  (42% cap — bekvemt gulv)
     σ_per_stream = (6000−1500)/4 = 1125 kbps  (betydningsfuld)
     Σ statistisk headroom ≈ 4 Mbps

  Ægte fordel: på action-scener toppen kernerne ved 5−6 Mbps (HD-detajler), routeren skærer balancerede til MIN-tier, total wire forbliver ved 38 Mbps.
Anbefalet område per kerne-stream:

  • min  ≈ avg × 0.5  (encoder kan droppe på stille scener)
  • avg  = nominalt mål efter opløsning (HD ≈ 3 Mbps, FullHD ≈ 5 Mbps, UHD ≈ 12 Mbps)
  • max  ≈ avg × 2.0  (encoder kan toppe på action — sport, actionfilm)

Mux-kapacitetsvagter (skal gælde):

  • Σ avg core + Σ avg balanced  ≤  mux.bitrate × 0.85   (bekvem mål)
  • Σ max core + Σ max balanced  ≤  mux.bitrate × 2.0    (over-subscription-gevinst)
  • Σ min core + Σ min balanced  ≤  mux.bitrate × 0.6    (worst-case gulv)

σ_per_stream = (max − min) / 4  (antager ±2σ-område)
σ_total = √((1−ρ) · Σσ²ᵢ + ρ · (Σσᵢ)²)   ρ = 0.15 broadcast typisk
σ_eff = σ_total × 0.7                     (statmux-faktor når TIL)
Mux_99.7% = μ_total + 3 · σ_eff           (vises i top-bar 📐 rec)

Tips & fejlfinding

Mindst 1 balanceret stream — uden en har den Adaptive Hybrid-router intet at knække under toppe, så gevinst = 0

Musik- og info-kanaler er de bedste kandidater — 90 %+ tolerance til rate-shedding

Spor via `[balance-router]`-logposter — viser `core_max`, `remaining`, tier-overgange for hvert 1 s tick

Hvis `core_max > capacity` (CORE OVERPEAK-advarsel i log), reducer kerne-streamantal eller sænk encoder maxrate

Operatørworkflow

Tilføj streams til mux (kanaltilordning forbliver manuel)

Slå Statmux til på mux-headeren (gul chip). Når aktiveret, skifter alle encoders til VBR og genstarter

Markér ofrede streams via højre-side orange tjekboks — typisk musik/info-kanaler, hvor rate-shedding er usynlig

Klar. Den Adaptive Hybrid-router læser en 6-segments HLS-forudsigelse fra kerne-streams hvert 1. sekund og skifter atomært symlinket mellem HIGH/MED/MIN-tiers

StatMux – statistisk multiplex nativ

The mux runs on a native C NIF (single-host, replaced the old gst_mux.py). Each channel has its own CBR encoder; the NIF demultiplexes them, statistically allocates bitrate by scene complexity, pads with NULL packets to a fixed wire cap, and emits one MPTS UDP multicast. This help describes the current UI: chart, headroom slider, diff gauge, channel cards.

Klasse: lukket-sløjfe feedback statmux med C1 look-ahead (feedforward) over VBR-encodere — broadcast statmux-princip, drevet fra kildens kompleksitet.

Arkitektur og dataflow

Architecture diagram

UDP multicast SSM, per kanal

Encodere

kildens kompleksitet

Loopback

egen linje / stream

allokator (Σ ≤ pool)

buffer

null-polstring → CBR

CBR wire ved cap

forvent kompleks scene inden dippen

målt wire — kalibrering

målbitrate

Hver kanal kører på sin egen linje op til Mux (separat encoder + loopback-forbindelse), hvor alle samles i én MPTS multicast-linje ved en præcis fast bitrate. Allokatoren er den centrale hjerne (1 GenServer per Mux), tick ~0,85 s.

Hjerne: feedback + C1 look-ahead

Allokatoren kombinerer to signaler — en forudsigelse fra kildens kompleksitet (fremad) og den målte wire (bagud). Dette nærmer sig broadcast statmuxes der kender en frames pris inden kodning.

C1 måler indholdskompleksitet ved dekoderen — som leder encoder-outputtet med pipeline-latenstiden. Den relative kompleksitetsændring (korrelation r≈0,92 med bits) anvendes på målbitraten i BEGGE retninger FØR encoderen producerer den: en stigende scene pre-allokeres (ingen dip), en faldende frigiver bits tidligt for andre.

Målt wire (feedback)

Præcise per-stream bits udsendt af Mux (afsendersidets tællere) kalibrerer kompleksitet→bitrate-mapping og holder summen præcis på poolen. Ground-truth-anker — C1-forudsigelsen er ikke perfekt (r 0,92), den efterfølgende wire korrigerer den.

Leveringsevne

En streams krav er bakket op af hvad encoderen faktisk producerer (× spidsbelastningsrum). En nem kanal kan ikke hamstre båndbredde den ikke kan bruge — den frigiver den til de sultne.

Udlignet kvalitet

Målet er ikke ens bitrate men ens kvalitet — kontinuerligt tryk flytter bits fra høj-kvalitets-kanaler (lav QP) mod lav-kvalitets-kanaler (høj QP).

Forudsigende omfordeling

Når C1 signalerer at en kanal falder, overdrages dens båndbredde til de andre i samme tick — de rammer op inden faldet faktisk når wire.

Per-channel weight = complexity_q12 × max_bps (action scene + higher max ⇒ more bits).

Per-stream budget = global budget × weight / Σweights, clamp [min_bps, max_bps], recomputed every 10 ms.

×headroom % (slider) on the encoder target → Σ real encoder < wire cap ⇒ rings drain empty ⇒ clean video.

Stale-exclusion: a dead input (no receive > 2 s) is dropped from the splitter — its share goes to live channels, not wasted; re-included automatically on recovery.

NULL pad fills the difference to the wire cap (strictly CBR). Encoder feedback: ZMQ complexity → BalanceRouter → set_bitrate.

CBR wire: buffer + null-polstring + pacing

Outputtet er en præcis CBR-stream ved den konfigurerede cap. Tre lag garanterer det:

Stående buffer ~1 s

Afsendelseskøen holder et stående niveau på ~1 s wire der absorberer sub-sekund GOP-dips (mellem I-frames). Verificeret fra optagelse: 0,5–1 s absorberer 88–91 % af dips.

Null-polstring

Når indhold er under cap, udfyldes forskellen med MPEG-TS null-pakker (PID 0x1FFF). Wire rammer derfor ALTID cap — DVB-kompatibel.

Præcis pacing

Egress er paced til den præcise cap (busy-spin ABSTIME); en 12 ms gælds-clamp forhindrer indhentnings-bursts efter et kort stop → ingen PCR-jitter, ingen over-cap-spidsbelastninger.

Bitrate chart (main)

Stacked area — each channel has its colour (matching its card below). Σ of all + NULL pad = wire cap. Switch the time window 10m / 1h / 24h; pills next to it = event counts (CC / PCR / BR / OVF) for the selected window.

Farvede bånd

Hver kanal har en stabil farve; tykkelse = dens øjeblikkelige bitrate. Overhead (PSI/EIT) er grå i bunden, null-polstring er struktureret hvid øverst.

Cap / Max-linje

Den stiplede linje øverst = konfigureret cap (wire-loft). Indhold + null-polstring sidder altid under den.

Null-bånd

Det prikkede hvide bånd øverst = null-polstring (ledig kapacitet). Jo tyndere det er, jo mere fyldt er wire; det forsvinder ved krævende indhold.

Drop-markeringer

Røde markeringer på tidslinjen = afsendelseskø-overflow (drop). Nul i stabil tilstand; bursts kun ved boot/flood.

Interval (30s–30m)

Knapper skifter tidsvinduet øjeblikkeligt (klientsiden), den aktive har grå baggrund. Grafen akkumulerer 30 min i browseren.

Værktøjstip

Svæv viser per-kanal bitrate, QP og kvalitetsindeks på det pågældende tidspunkt (historisk værdi, ikke live).

cap %

Aktuelt pool-reguleringsniveau (pool/(pool−trim)). >100% = overtryk (fylder buffer), <100% = trimmer.

Reserve (slider)

Toleranceband over cap — hvor meget der skal holdes som null-reserve. 0 = fyld præcis N; positiv = større reserve (sikrere); negativ = let overfyldning.

Buffer (drops)

Overskriften viser afsendelseskø-udnyttelse % og kumulative drops. Knappen 'ryd drops' nulstiller tælleren.

GOP

Fælles GOP-længde for alle kanaler i Mux (låst i videoprofiler ved start). Wall-stagger spreder I-frames i tid så de ikke kolliderer.

VBV

Encoder VBV-bufferstørrelse (ms). Mindre udjævner I-frames (godt for bevægelseskanaler), større giver et mere detaljeret I-frame. Standard 850; per-stream override mulig.

Channel cards (Programs)

The section header has a 'Collapse / Expand all' toggle. Expand a card by clicking it or clicking its colour band in the chart. The left coloured strip with checkbox = channel membership in the mux.

dark = running OK

orange = starting / restarting

grey + dimmed = down/error and checkbox OFF (intentionally disabled — no alarm)

red + BLINKING = FAULT — channel is in the mux (checkbox ON) but the stream is down/error

PSI/SI-tabeller (komplet DVB-sæt)

StatMux genererer det fulde sæt obligatoriske MPEG-TS / DVB-tabeller direkte i NIF-Mux — ingen ekstern SI-indsætter. Tabeller er jævnt timet ind i streamen så en STB altid hurtigt henter PSI/SI efter ny indstilling.

Tabel

PID

Interval

Formål / kilde

EIT ↔ EPG: fuld integration

EIT (Event Information Table, PID 0x12) er ikke statisk — det er fuldt koblet til applikationens EPG-system. Operatøren tildeler hver kanal i Mux en EPG-tjeneste (eit_epg_service_id), og Mux genererer live EIT fra dens planlagte hændelser.

Sizing / recommendations

mux.bitrate = wire CBR cap (typ. 37 Mbps for 12 SD/HD channels).

Σ avg ≲ cap (comfortable target) · Σ max oversubscribed 1.5–2× cap (that is the point of statmux — peaks rarely coincide) · Σ min = worst-case floor.

Set per-stream min/avg/max in Stream → Transcoder profile (auto-syncs to mux_input). Action/sport 8–10 M, news/talking head 1–2 M, min never < 800 k.

The headroom slider is a quick live lever of reserve vs. tightness — no restart.

Relation til broadcast statmuxes

Vi laver reel statistisk multipleksning — dynamisk bitomfordeling på tværs af VBR-kanaler der deler en fast wire, med kvalitetsudligning. Mekanisk er vi tæt på professionelle headend statmuxes (cap-justering, 1 s buffer, null-polstring, GOP/B-frames, gulv-override).

Hvad vi har

CBR wire ved cap · 1 s buffer · per-stream proportional allokering · C1 look-ahead feedforward · kvalitetsudligning · forudsigende omfordeling · null-polstring · præcis pacing.

Hvor vi adskiller os

En broadcast statmux bruger encoderens rate-distortion-estimat (præcis frame-pris, encoderen er slave for allokatoren). Vi bruger C1 kildens kompleksitet (r≈0,92) + en VBR-encoder der vælger sin egen QP — en hardwarebegrænsning, ikke en designbegrænsning. Klasse: feedback + look-ahead i stedet for ren feedforward.

Fejlfinding

Symptom

Årsag / fix

Channel red and blinking

In the mux (checkbox ON) but stream down/error → check the source/encoder of that stream. Self-recovers once restored.

Lots of NULL / large grey area

Calm content or low headroom — normal (statmux gain). For tighter utilization raise the headroom slider or per-stream max_bps.

Picture freezes / glitches

Headroom too high (rings not draining) → lower the slider to 80–82 %. Watch the diff gauge / NULL.

After restart streams=0 / all NULL

Mux started before the encoders — self-heal automatically reaches 12 within ~30 s (1 s tick retry). No manual action.

Diff gauge stuck at 0 / chart empty

No live samples (mux stopped or encoders not running) — check both the mux and stream status.

Arkitektur (end-to-end)

SAT UDP SSM ─┐
             ├─ gst_encoder.py(K1)  CBR ─ TCP127 ─┐        ZMK kompleksitet
   (per      ├─ gst_encoder.py(K2)  CBR ─ TCP127 ─┤            ▲   │
   chan)     └─ gst_encoder.py(Kn)  CBR ─ TCP127 ─┤            │   ▼
                                                  ▼     BalanceRouter
                                   ┌─────── NIF StatMux ───────┐  │ set_bitrate
                                   │ per-input ring (drop-old) │◄─┘
                                   │ 2-pass drain (A prio, V)  │
                                   │ allocator: w=cmplx×max    │
                                   │ ×headroom% (slider 78-90) │
                                   │ stale-exclusion (>2s)     │
                                   │ NULL pad -> wire cap CBR  │
                                   │ PCR pass-through          │
                                   └────────────┬──────────────┘
                                                ▼
                                   MPTS  UDP-multicast (CBR cap)

gst_encoder.py per stream: SAT UDP SSM input → nvh264enc rc-mode=cbr. Bithastighed drives af BalanceRouter via set_bitrate. Scene kompleksitet (SAD/px) rapporteres over ZMK til allokatoren.

Per-input ring (TCP loopback fra encoder), 2-pass dræn (audio prioritet, video fuld), proportional allokatør, NULL pad præcist til wire cap (CBR), PCR pass-through fra encoder.

Én MPTS (PAT/PMT/SDT genereret af NIF) → UDP multicast på output-VLAN. Wire er strengt CBR ved mux.bitrate (NULL stuffing).

Række 1: ⚠ (valideringsproblemer) · PNR · navn i en ramme (farve = tilstand).

Række 2+: min·avg·max kbps · forudsagt kompleksitet Δ lav/med/høj/peak · INPUT LOST · ⚙URL · encoder Mbps · SID · service_type.

Navnefarve = stream-tilstand:

Mbps
 37 ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌  <= cap 37.0 Mbit (rød, wire CBR loft)
    · · · · · · · · · · · · · · · · ·     <= fri plads = NULL padding
    ·· grå · sorte prikker · reserve ··       (ubrugt kapacitet)
 31 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  <= headroom 85% · 31.5 Mbit (orange,
    ▓▓▓▓ JOJ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓     encoder sigter her)
    ▒▒▒▒ Markíza ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
    ░░░░ TA3 ░░░░░░░░░░░░░░░░░░░░░░░░░░  <= klik på bånd → udvid kort
  0 └──────────────────────────────────
        tid ->           10m │ 1h │ 24h     CC0 PCR0 BR0 OVF0

Rød 'cap'-linje: wire CBR loft (mux.bitrate) — NULL udfylder op til her.

Orange 'headroom N%' linje: = cap × headroom slider / 100. Encoder set_bitrate sigter her. Flytter sig med slideren.

Gråt område med sorte prikker mellem indhold og cap = NULL padding (ubrugt reserve). Flere prikker = mere reserve.

Klik på kanalens farvebånd → udvider automatisk den kanals kort nedenfor.

Plan

MuxEitAdapter læser hændelser fra EPG-systemet per tjeneste, bygger DVB EIT-sektioner (navn, tidspunkt, varighed, beskrivelse, genre) og pakketerer dem på PID 0x12. Sektionsversioner øges ved EPG-ændring — STB'en henter opdateringen.

EIT injiceres direkte i NIF-Mux, jævnt I null-rummet (1 pakke / N output + p/f periodisk) — erstatter den bursty eksterne tsp-kaskade. Spids/avg ≈ 1,1, ingen indholdsudsætning, cap holder.

Tabel 0x4E — den aktuelle + næste hændelse. Injiceret hvert ≤2 s for øjeblikkelig 'nu/næste' aktualitet på STB.

Mux regenererer periodisk EIT .bin fra EPG (~15 s) — en EPG-planændring når wire uden genstart. Mux-overskriften viser 'EIT ✓' når aktiv.

Tabeller 0x50/0x51 — den fulde plan timer/dage frem (segmenter). Fordelt jævnt i streamen.

Diff-gauge (ovenfor diagrammet)

Indikator for real flow vs cap. Center = cap (0). Markør venstre (grøn) = reserve (Σ indhold under cap); højre (rød) = overflow. Live, flytter sig hvert tick.

-5 Mbps CAP 37000 kbps +5 Mbps

[#### grøn = reserve ####│::: rød = over cap :::]

^ -3200k

(Σ indhold ~3,2 Mbps under cap = sund reserve)

Headroom-slider (78–90 %, standard 85)

Lavere (→78): mere NULL reserve, sikrere, mindre stram cap udnyttelse.

Højere (→90): strammere cap udnyttelse, mindre NULL.

⚠ ≥88 %: slider bliver gul – tæt på ring-overflow freeze loftet. Hård-klem 78–90 (kan ikke nå 100 – beskyttelse mod fryset video).

Asymmetri: sænkning tilføjer pålideligt reserve; hævet er begrænset af per-stream max_bps clamp (allokatør skubber ikke en kanal ud over dens max → sikker).

Styrer hvor meget af cap encoderne sigter på: encoder target = budget × headroom% / 100 (orange linje i diagrammet). Ændres live (effekt fra næste 10 ms tick), persistent i SystemConfig.

Signaltab / kanalfejl (isolering)

Én kanal mislykkes (encoder crash / signaltab) ⇒ muxet kører videre, andre kanaler uafængede, wire holder capen (NULL absorberer ud faldet), CC=0 på overlevere. Per-input ring-tråde er uafhængige. Den mislykkede kanal viser et rødt blinkende navn + INPUT LOST-badge; encoderen er supervisorgenstartet, og kanalen reparerer sig selv.

PCR / timing

PCR og PES PTS/DTS er pass-through fra encoderen (enkelt klokkedomæne ⇒ sammenhængende, ingen drift). Rest-PCR jitter ~ti ms er iboende (10 ms output tick + UDP) – STB/VLC PLL tåler det, CC=0. Hård DVB-S2 modulator overholdelse er ikke inden for scope for det nuværende IPTV-use-case.

CAT — betinget adgang (kun ved scrambling / ECM).

EIT — hændelsesinformation (EPG) — fra EPG-systemet, se nedenfor.

NIT — netværksinfo (netværk-ID, navn, transportstream).

PAT — programliste (mapper PNR → PMT PID).

PMT — per program: video-/lyd-/PCR-PID'er, codecs, deskriptorer.

SDT — tjenestenavne og udbydere (hvad STB'en viser i listen).

TDT/TOT — tid og dato + lokal offset (STB-ur).

TSDuck Plugins Used

merge
regulate
pat
pmt
sdt
nit
eitinject
timeref
bitrate_monitor
continuity
psimerge
count