Skip to main content

mpeg_pes/
stream_id.rs

1//! `stream_id` — identifies the elementary stream a PES packet belongs to
2//! (ISO/IEC 13818-1 Table 2-22). Certain values carry no optional PES header.
3
4/// 8-bit `stream_id` of a PES packet.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize))]
7pub struct StreamId(pub u8);
8
9// Special stream_ids that do NOT carry the optional PES header (the bytes after
10// PES_packet_length are the payload directly) — ISO/IEC 13818-1 §2.4.3.6.
11const PROGRAM_STREAM_MAP: u8 = 0xBC;
12const PADDING_STREAM: u8 = 0xBE;
13const PRIVATE_STREAM_2: u8 = 0xBF;
14const ECM_STREAM: u8 = 0xF0;
15const EMM_STREAM: u8 = 0xF1;
16const DSMCC_STREAM: u8 = 0xF2;
17const H222_1_TYPE_E: u8 = 0xF8;
18const PROGRAM_STREAM_DIRECTORY: u8 = 0xFF;
19
20impl StreamId {
21    /// `program_stream_map` (0xBC).
22    pub const PROGRAM_STREAM_MAP: StreamId = StreamId(PROGRAM_STREAM_MAP);
23    /// `padding_stream` (0xBE).
24    pub const PADDING_STREAM: StreamId = StreamId(PADDING_STREAM);
25    /// `private_stream_2` (0xBF).
26    pub const PRIVATE_STREAM_2: StreamId = StreamId(PRIVATE_STREAM_2);
27
28    /// True if this `stream_id` carries the optional PES header (flags +
29    /// `PES_header_data_length` + PTS/DTS). False for the special streams whose
30    /// `PES_packet_data_byte`s follow `PES_packet_length` directly.
31    #[must_use]
32    pub const fn has_optional_header(self) -> bool {
33        !matches!(
34            self.0,
35            PROGRAM_STREAM_MAP
36                | PADDING_STREAM
37                | PRIVATE_STREAM_2
38                | ECM_STREAM
39                | EMM_STREAM
40                | DSMCC_STREAM
41                | H222_1_TYPE_E
42                | PROGRAM_STREAM_DIRECTORY
43        )
44    }
45
46    /// True for an audio stream (`110x xxxx`, 0xC0–0xDF).
47    #[must_use]
48    pub const fn is_audio(self) -> bool {
49        self.0 & 0xE0 == 0xC0
50    }
51
52    /// True for a video stream (`1110 xxxx`, 0xE0–0xEF).
53    #[must_use]
54    pub const fn is_video(self) -> bool {
55        self.0 & 0xF0 == 0xE0
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn classification() {
65        assert!(StreamId(0xC0).is_audio());
66        assert!(StreamId(0xE0).is_video());
67        assert!(StreamId(0xE0).has_optional_header());
68        assert!(StreamId(0xBD).has_optional_header()); // private_stream_1 does
69        assert!(!StreamId::PADDING_STREAM.has_optional_header());
70        assert!(!StreamId::PROGRAM_STREAM_MAP.has_optional_header());
71        assert!(!StreamId(0xFF).has_optional_header());
72    }
73}