Skip to main content

oxideav_mpegts/
stream_type.rs

1//! `stream_type` byte → richer enum, scoped to BD-relevant values.
2//!
3//! Values are per ISO/IEC 13818-1 Table 2-29 plus the HDMV-extended
4//! range BD-ROM Part 3 §5 uses (`0x80..=0xFF`).
5
6/// One elementary-stream codec class.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum StreamType {
9    /// `0x02` ISO/IEC 13818-2 (MPEG-2 video).
10    Mpeg2Video,
11    /// `0x1B` ITU-T H.264 / ISO/IEC 14496-10 (AVC).
12    AvcVideo,
13    /// `0x24` ITU-T H.265 / ISO/IEC 23008-2 (HEVC).
14    HevcVideo,
15    /// `0xEA` SMPTE VC-1 (Microsoft Windows Media Video 9).
16    Vc1Video,
17    /// `0x80` Linear PCM audio (BD: big-endian, BD-ROM Part 3 §5.4).
18    LpcmAudio,
19    /// `0x81` Dolby AC-3.
20    Ac3Audio,
21    /// `0x82` DTS.
22    DtsAudio,
23    /// `0x83` Dolby TrueHD.
24    TruehdAudio,
25    /// `0x84` Dolby Digital Plus (E-AC-3).
26    EAc3Audio,
27    /// `0x85` DTS-HD High Resolution.
28    DtsHdAudio,
29    /// `0x86` DTS-HD Master Audio.
30    DtsHdMaAudio,
31    /// `0xA1` E-AC-3 secondary audio.
32    EAc3SecondaryAudio,
33    /// `0xA2` DTS-HD secondary audio.
34    DtsHdSecondaryAudio,
35    /// `0x90` HDMV Presentation Graphic Stream (PGS) subtitles.
36    PgsSubtitle,
37    /// `0x91` HDMV Interactive Graphics Stream (IGS).
38    IgsInteractive,
39    /// `0x92` HDMV Text Subtitle Stream (TextST).
40    TextSubtitle,
41    /// Any other value — kept as the raw byte for diagnostics.
42    Other(u8),
43}
44
45impl StreamType {
46    /// Map a raw `stream_type` byte to the enum.
47    pub fn from_raw(b: u8) -> Self {
48        match b {
49            0x02 => Self::Mpeg2Video,
50            0x1B => Self::AvcVideo,
51            0x24 => Self::HevcVideo,
52            0xEA => Self::Vc1Video,
53            0x80 => Self::LpcmAudio,
54            0x81 => Self::Ac3Audio,
55            0x82 => Self::DtsAudio,
56            0x83 => Self::TruehdAudio,
57            0x84 => Self::EAc3Audio,
58            0x85 => Self::DtsHdAudio,
59            0x86 => Self::DtsHdMaAudio,
60            0xA1 => Self::EAc3SecondaryAudio,
61            0xA2 => Self::DtsHdSecondaryAudio,
62            0x90 => Self::PgsSubtitle,
63            0x91 => Self::IgsInteractive,
64            0x92 => Self::TextSubtitle,
65            other => Self::Other(other),
66        }
67    }
68
69    /// Inverse of [`Self::from_raw`].
70    pub fn as_raw(self) -> u8 {
71        match self {
72            Self::Mpeg2Video => 0x02,
73            Self::AvcVideo => 0x1B,
74            Self::HevcVideo => 0x24,
75            Self::Vc1Video => 0xEA,
76            Self::LpcmAudio => 0x80,
77            Self::Ac3Audio => 0x81,
78            Self::DtsAudio => 0x82,
79            Self::TruehdAudio => 0x83,
80            Self::EAc3Audio => 0x84,
81            Self::DtsHdAudio => 0x85,
82            Self::DtsHdMaAudio => 0x86,
83            Self::EAc3SecondaryAudio => 0xA1,
84            Self::DtsHdSecondaryAudio => 0xA2,
85            Self::PgsSubtitle => 0x90,
86            Self::IgsInteractive => 0x91,
87            Self::TextSubtitle => 0x92,
88            Self::Other(b) => b,
89        }
90    }
91
92    /// `true` when the stream carries primary video.
93    pub fn is_video(self) -> bool {
94        matches!(
95            self,
96            Self::Mpeg2Video | Self::AvcVideo | Self::HevcVideo | Self::Vc1Video
97        )
98    }
99
100    /// `true` when the stream carries audio (primary or secondary).
101    pub fn is_audio(self) -> bool {
102        matches!(
103            self,
104            Self::LpcmAudio
105                | Self::Ac3Audio
106                | Self::DtsAudio
107                | Self::TruehdAudio
108                | Self::EAc3Audio
109                | Self::DtsHdAudio
110                | Self::DtsHdMaAudio
111                | Self::EAc3SecondaryAudio
112                | Self::DtsHdSecondaryAudio
113        )
114    }
115
116    /// `true` when the stream carries subtitles or interactive graphics.
117    pub fn is_subtitle(self) -> bool {
118        matches!(
119            self,
120            Self::PgsSubtitle | Self::IgsInteractive | Self::TextSubtitle
121        )
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn round_trip_known_types() {
131        for raw in [
132            0x02u8, 0x1B, 0x24, 0xEA, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x90, 0x91, 0x92,
133            0xA1, 0xA2,
134        ] {
135            assert_eq!(StreamType::from_raw(raw).as_raw(), raw);
136        }
137    }
138
139    #[test]
140    fn unknown_types_pass_through() {
141        let s = StreamType::from_raw(0x77);
142        assert_eq!(s, StreamType::Other(0x77));
143        assert_eq!(s.as_raw(), 0x77);
144        assert!(!s.is_video() && !s.is_audio() && !s.is_subtitle());
145    }
146
147    #[test]
148    fn classification() {
149        assert!(StreamType::AvcVideo.is_video());
150        assert!(StreamType::Ac3Audio.is_audio());
151        assert!(StreamType::PgsSubtitle.is_subtitle());
152    }
153}