1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright (c) 2026 G & R Associates LLC
// SPDX-License-Identifier: MIT OR Apache-2.0
// src/waveform/dvb_t_ts.rs
//
// DVB-T MPEG-2 transport-stream (TS) payload adaptation and energy dispersal,
// ETSI EN 300 744 §4.3.1. Real (NB-)DVB-T carries a genuine 188-byte MPEG-2 TS —
// this module models that packet structure so the DVB-T pipeline ingests TS
// packets rather than opaque bytes, applying the standard's exact
// energy-dispersal rules that key off packet boundaries:
//
// • Packets are 188 bytes: one sync byte (0x47) + 187 payload bytes.
// • The PRBS (1 + X^14 + X^15, init 100101010000000) re-initializes at the
// start of every group of EIGHT packets.
// • The sync byte of the FIRST packet in each group is inverted 0x47 → 0xB8
// (the descrambler's re-init signal). The other seven packets keep 0x47.
// • Sync bytes are NOT randomized, but the PRBS generator keeps clocking over
// them (8 steps, output discarded) so the register phase stays aligned; the
// 187 payload bytes of every packet ARE randomized.
//
// This wraps the Phase-1 `DvbTEnergyDispersal` whitener (which is the bit-exact
// PRBS) with the packet framing. The RS(204,188) outer code then protects each
// randomized 188-byte packet (sync byte included) — one TS packet is exactly one
// RS information block, which is why the payload FEC needs no stuffing.
use cratedvb_tDvbTEnergyDispersal;
/// MPEG-2 transport-stream packet length in bytes (1 sync + 187 payload).
pub const TS_PACKET_LEN: usize = 188;
/// Number of payload bytes per TS packet (all but the sync byte).
pub const TS_PAYLOAD_LEN: usize = TS_PACKET_LEN - 1;
/// The MPEG-2 sync byte (`0x47`).
pub const TS_SYNC_BYTE: u8 = 0x47;
/// The inverted sync byte (`0xB8`) marking the first packet of an 8-packet group.
pub const TS_SYNC_BYTE_INVERTED: u8 = 0xB8;
/// Number of TS packets per energy-dispersal group (PRBS re-init period).
pub const TS_DISPERSAL_GROUP: usize = 8;
/// Applies (or inverts) DVB-T energy dispersal over a whole number of 188-byte TS
/// packets, in place. Self-inverse: running scrambled packets through again
/// recovers the originals, because the sync-byte inversion is deterministic per
/// group position and the PRBS is the same data-independent sequence.
///
/// `packets` must be a multiple of [`TS_PACKET_LEN`] bytes and each packet must
/// begin with a sync byte (`0x47` or its inverted form `0xB8`). Per the standard:
/// the PRBS re-inits every 8 packets, the first packet of each group has its sync
/// byte inverted, and the PRBS clocks over every sync byte without randomizing
/// it. Returns the number of packets processed.
///
/// # Panics
///
/// Panics if `packets.len()` is not a multiple of [`TS_PACKET_LEN`].
/// Wraps arbitrary payload bytes into whole TS packets (sync byte + 187 payload),
/// zero-padding the final packet's payload. This is a minimal TS adaptation for
/// the library's own end-to-end use (not a full MPEG-2 multiplexer): every packet
/// gets a plain `0x47` sync byte; `ts_energy_disperse` later inverts the
/// group-leading ones. Returns the packetized byte stream (a multiple of
/// [`TS_PACKET_LEN`]).
/// Recovers the payload bytes from whole TS packets (inverse of [`ts_packetize`]):
/// strips each packet's sync byte and concatenates the 187-byte payloads. The
/// caller trims trailing zero padding via the known original length. Returns
/// `None` if `packets` is not a whole number of TS packets.