Decode SCTE 55-2 (DVS-178 / DAVIC "Mode B") out-of-band (OOB) cable forward data channels from a raw IQ recording, all the way up to the EPG channel lineup carried in the DSM-CC object carousel.
This started as a reverse-engineering project on a mystery WAV file captured with SDR++ from a cable line. It turned out to be the downstream OOB forward data channel of a Charter/Spectrum plant (Scientific-Atlanta / Cisco head-end), and this repo is the cleaned-up, documented toolchain that decodes it.
IQ WAV ─▶ QPSK demod ─▶ differential decode ─▶ derandomize ─▶ SL-ESF sync
─▶ deinterleave ─▶ Reed-Solomon(55,53) ─▶ ATM cells ─▶ AAL5 / IP / UDP
─▶ DSM-CC carousel ─▶ BIOP objects ─▶ channel lineup + strings
- A channel lineup (
callsign → channel number), e.g.WKYC 4,CNN 351,ESPN 302,AMC 278. - Service display names ("Showtime Next", "Canales Latinos", ...).
- MAC control-channel decode (VCI 0x0021): provisioning downstream frequency, upstream service-channel frequency, power levels, slot config, upstream transmission rate.
- Host / OCAP configuration (VCI 0x0fa2): in-band object-carousel QAM frequency and program number, firmware / code-version server URLs, OCAP navigator Xlet app names, multicast parameters, ODN object versions.
- A dump of all human-readable strings (set-top UI text, firmware image names, CVC certificate subjects, EAS placeholders, DSG hub config, ...).
- Intermediate artifacts (
symbols.npy,cells.npy) for further analysis.
| Parameter | Value |
|---|---|
| Standard | SCTE 55-2 (DVS-178 / DAVIC Mode B), Grade A |
| Modulation | Differentially-encoded QPSK, SRRC α = 0.30 |
| Symbol rate | 772 ksym/s → 1.544 Mb/s |
| Randomizer | self-synchronizing LFSR, x⁶ + x + 1 |
| Framing | SL-ESF: 4632-bit superframe = 24 × 193-bit frames |
| Frame sync (FAS) | F1..F6 = 0,0,1,0,1,1 |
| Interleaver | Forney convolutional, I = 5, M = 11 |
| FEC | Reed-Solomon (55,53), GF(256), p(x)=x⁸+x⁴+x³+x²+1 |
| Data link | ATM → AAL5 → IPv4 → UDP (13818/13821) → DSM-CC |
See docs/PROTOCOL.md for the full stack walk-through and
docs/PIPELINE.md for how each module maps to a layer.
Requires Python 3.10+ and NumPy/SciPy.
pip install -r requirements.txt
# or, editable install of the package:
pip install -e .The recording must be an 8-bit IQ WAV (2 channels, I/Q) such as SDR++ produces. Tune the SDR to the OOB carrier (typically 70–130 MHz on the plant) with a sample rate ≥ ~1.5× the 900 kHz signal bandwidth (2.048 MHz works well).
# Inspect a recording (sample rate, carrier offset, expected symbol rate)
python -m oobscte55 analyze recording.wav
# Full pipeline: WAV -> EPG report + artifacts in ./out
python -m oobscte55 decode recording.wav -o out
# Or run stages individually
python -m oobscte55 demod recording.wav -o symbols.npy
python -m oobscte55 cells symbols.npy -o cells.npyOutput of decode:
out/
cells.npy # (N, 53) decoded ATM cells
EPG_REPORT.txt # channel lineup + service names
strings.txt # all readable strings
from oobscte55 import iqfile, demod, framing, fec, atm, carousel, epg
rec = iqfile.read_wav_iq("recording.wav")
symbols = demod.demodulate(rec.samples, rec.sample_rate)
bits = framing.symbols_to_bits(symbols)
payloads = framing.track_superframes(bits)
cells, stats = fec.decode_cells(payloads)
modules, _ = carousel.carousel_from_cells(cells)
lineup = epg.channel_lineup(modules) # {callsign: channel_number}A 30-second capture locks the channel map fully, but the program schedule
modules (airtime*.grp.z) are large and only partially arrive. Capture
several minutes so every carousel module repeats and completes; the same
pipeline then reassembles the full set. See docs/PROTOCOL.md §"Program grid".
This is a passive receive-only project for interoperability research and education, using your own cable line and a general-purpose SDR. It does not descramble premium content or defeat conditional access. Respect your local laws and your service agreement.
MIT — see LICENSE.