Skip to main content

mpeg_ts/
pid.rs

1//! MPEG-TS Packet Identifier (PID) types and well-known PID constants.
2//!
3//! Specified by ITU-T H.222.0 §2.4 (= ISO/IEC 13818-1). DVB-specific
4//! well-known PID assignments are also listed in ETSI EN 300 468 §5.1.3 Table 1.
5
6/// A 13-bit MPEG-TS Packet Identifier.
7///
8/// Thin newtype over the wire `u16`. Values are masked to 13 bits on
9/// construction (`0x0000..=0x1FFF`), matching the transport header field
10/// width (ISO/IEC 13818-1 §2.4.3.2).
11#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize))]
13#[cfg_attr(feature = "serde", serde(transparent))]
14pub struct Pid(u16);
15
16impl Pid {
17    /// Mask covering the 13 valid PID bits.
18    pub const MASK: u16 = 0x1FFF;
19
20    /// Construct a `Pid`, masking to the low 13 bits.
21    #[must_use]
22    pub const fn new(value: u16) -> Self {
23        Self(value & Self::MASK)
24    }
25
26    /// Construct a `Pid` from the low 13 bits of `value`, **deliberately**
27    /// discarding the rest: the explicit name for extracting the 13-bit PID
28    /// field out of a wider wire word (e.g. `reserved(3)` + `PID(13)`), where
29    /// masking is the specified behaviour. Identical to [`Pid::new`]; prefer
30    /// this at parse sites so the intent is visible and a caller-supplied
31    /// value is never masked by accident (use [`Pid::try_new`] for those).
32    ///
33    /// ```
34    /// use mpeg_ts::pid::Pid;
35    /// // reserved(3) = 0b111 followed by PID 0x0100.
36    /// assert_eq!(Pid::from_wire_masked(0xE100).value(), 0x0100);
37    /// assert!(Pid::try_new(0xE100).is_err());
38    /// ```
39    #[must_use]
40    pub const fn from_wire_masked(value: u16) -> Self {
41        Self(value & Self::MASK)
42    }
43
44    /// Construct a `Pid`, rejecting any value above [`Pid::MASK`] (`0x1FFF`).
45    ///
46    /// Use this at API boundaries that take a caller-supplied value; use
47    /// [`Pid::new`] only where the bits are already masked by the wire format.
48    ///
49    /// # Errors
50    /// [`PidOutOfRange`] when `value > 0x1FFF`.
51    pub const fn try_new(value: u16) -> Result<Self, PidOutOfRange> {
52        if value > Self::MASK {
53            Err(PidOutOfRange { value })
54        } else {
55            Ok(Self(value))
56        }
57    }
58
59    /// The raw 13-bit value.
60    #[must_use]
61    pub const fn value(self) -> u16 {
62        self.0
63    }
64}
65
66/// A value that does not fit the 13-bit PID field (ISO/IEC 13818-1 §2.4.3.2).
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68#[non_exhaustive]
69pub struct PidOutOfRange {
70    /// The rejected value.
71    pub value: u16,
72}
73
74impl core::fmt::Display for PidOutOfRange {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        write!(
77            f,
78            "PID 0x{:04X} exceeds the 13-bit range 0x0000..=0x1FFF",
79            self.value
80        )
81    }
82}
83
84impl core::error::Error for PidOutOfRange {}
85
86impl TryFrom<u16> for Pid {
87    type Error = PidOutOfRange;
88    fn try_from(value: u16) -> Result<Self, Self::Error> {
89        Self::try_new(value)
90    }
91}
92
93impl From<Pid> for u16 {
94    fn from(pid: Pid) -> Self {
95        pid.0
96    }
97}
98
99impl core::fmt::Debug for Pid {
100    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101        write!(f, "Pid(0x{:04X})", self.0)
102    }
103}
104
105impl core::fmt::UpperHex for Pid {
106    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107        core::fmt::UpperHex::fmt(&self.0, f)
108    }
109}
110
111impl core::fmt::LowerHex for Pid {
112    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113        core::fmt::LowerHex::fmt(&self.0, f)
114    }
115}
116
117impl core::fmt::Display for Pid {
118    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
119        write!(f, "0x{:04X}", self.0)
120    }
121}
122
123/// Well-known PIDs. The transport stream MUST carry the corresponding tables
124/// on these PIDs.
125///
126/// **API 2.0 type change:** constants are now [`crate::pid::Pid`] instead of `u16`.
127/// Call `.value()` to obtain the raw `u16`, or use `Pid::from(u16)` /
128/// `u16::from(Pid)` for conversions.
129pub mod well_known {
130    use super::Pid;
131
132    /// Program Association Table (MPEG-2).
133    pub const PAT: Pid = Pid::new(0x0000);
134    /// Conditional Access Table (MPEG-2).
135    pub const CAT: Pid = Pid::new(0x0001);
136    /// Transport Stream Description Table (MPEG-2).
137    pub const TSDT: Pid = Pid::new(0x0002);
138    /// IPMP Control Information Table (MPEG-2).
139    pub const IPMP_CIT: Pid = Pid::new(0x0003);
140    /// Network Information Table (DVB).
141    pub const NIT: Pid = Pid::new(0x0010);
142    /// Service Description Table + Bouquet Association Table (DVB).
143    pub const SDT_BAT: Pid = Pid::new(0x0011);
144    /// Event Information Table (DVB).
145    pub const EIT: Pid = Pid::new(0x0012);
146    /// Running Status Table (DVB).
147    pub const RST: Pid = Pid::new(0x0013);
148    /// Time and Date + Time Offset + Stuffing (DVB).
149    pub const TDT_TOT: Pid = Pid::new(0x0014);
150    /// Network synchronisation.
151    pub const NETWORK_SYNC: Pid = Pid::new(0x0015);
152    /// Resolution Notification Table.
153    pub const RNT: Pid = Pid::new(0x0016);
154    /// Satellite Access Table (EN 300 468 Table 1).
155    pub const SAT: Pid = Pid::new(0x001B);
156    /// Link-local inband signalling (reserved).
157    pub const INBAND_SIGNALLING: Pid = Pid::new(0x001C);
158    /// Measurement (reserved).
159    pub const MEASUREMENT: Pid = Pid::new(0x001D);
160    /// Discontinuity Information Table.
161    pub const DIT: Pid = Pid::new(0x001E);
162    /// Selection Information Table.
163    pub const SIT: Pid = Pid::new(0x001F);
164
165    /// ATSC PSIP base PID.
166    pub const ATSC_PSIP: Pid = Pid::new(0x1FFB);
167
168    /// Null-packet padding PID. Payload is ignored.
169    pub const NULL: Pid = Pid::new(0x1FFF);
170}