mpeg2ts_reader/
lib.rs

1//! Structures for parsing MPEG2 Transport Stream data, per the _ISO/IEC 13818-1_ standard.
2//!
3//! # Design principals
4//!
5//!  * *Avoid copying and allocating* if possible.  Most of the implementation works by borrowing
6//!    slices of the underlying byte buffer.  The implementation tries to avoid buffering up
7//!    intermediate data where practical.
8//!  * *Non-blocking*.  It should be possible to integrate this library into a system non-blocking
9//!    event-loop.  The caller has to 'push' data.
10//!  * *Extensible*.  The standard calls out a number of 'reserved values' and other points of
11//!    extension.  This library should make it possible for other crates to implement such
12//!    extensions.
13//!  * *Minimal*.  Lots of commonly used Transport Stream functionality is specified in standards
14//!    from by ISDB / DVB / ATSC / SCTE / etc. and not in 13818-1 itself.  I hope support for these
15//!    features can be added via external crates.  (None implemented any yet!)
16//!  * *Transport Neutral*.  There is currently no code here supporting consuming from files or the
17//!    network.  The APIs accept `&[u8]`, and the caller handles providing the data from wherever.
18//!
19//!
20//! # Planned API changes
21//!
22//! - Add 'context' objects
23//!   - Real usage will likely need to thread context objects through the API in order to
24//!     track application-specific details.
25//!   - Currently mutable state is stored in the instance for each type of syntax parser, and
26//!     it would be nice to explore extracting this out into parser-specific context types
27//! - Event generation / remove `warn!()`
28//!   - currently problems are reported to the `log` crate
29//!   - I would much prefer a way to emit 'events' for interesting data that can't just be an error
30//!     return value, and to not have any logging code mixed with parsing logic
31//! - General
32//!   - lots of places return `Option` but should return `Result` and a descriptive error
33
34#![forbid(unsafe_code)]
35#![deny(rust_2018_idioms, future_incompatible, missing_docs)]
36
37pub mod packet;
38#[macro_use]
39pub mod demultiplex;
40pub mod descriptor;
41pub mod mpegts_crc;
42pub mod pes;
43pub mod psi;
44
45use std::fmt;
46use std::fmt::Formatter;
47// expose access to FormatIdentifier, which is part of the public API of
48// descriptor::registration::RegistrationDescriptor
49pub use smptera_format_identifiers_rust as smptera;
50
51/// The types of Elementary Stream specified in _ISO/IEC 13818-1_.
52///
53/// As returned by
54/// [`StreamInfo::stream_type()`](psi/pmt/struct.StreamInfo.html#method.stream_type).
55#[derive(PartialEq, Eq, Hash, Clone, Copy)]
56pub struct StreamType(pub u8);
57
58impl StreamType {
59    // 0x00 reserved
60    /// ISO/IEC 11172 Video
61    pub const ISO_11172_VIDEO: StreamType = StreamType(0x01);
62    /// ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream
63    pub const H262: StreamType = StreamType(0x02);
64    /// ISO/IEC 11172 Audio
65    pub const ISO_11172_AUDIO: StreamType = StreamType(0x03);
66    /// ISO/IEC 13818-3 Audio
67    pub const ISO_138183_AUDIO: StreamType = StreamType(0x04);
68    /// ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections
69    pub const H222_0_PRIVATE_SECTIONS: StreamType = StreamType(0x05);
70    /// ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data
71    pub const H222_0_PES_PRIVATE_DATA: StreamType = StreamType(0x06);
72    /// ISO/IEC 13522 MHEG
73    pub const MHEG: StreamType = StreamType(0x07);
74    /// ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC
75    pub const H222_0_DSM_CC: StreamType = StreamType(0x08);
76    /// ITU-T Rec. H.222.1
77    pub const H2221: StreamType = StreamType(0x09);
78    /// ISO/IEC 13818-6 DSM CC multiprotocol encapsulation
79    pub const ISO_13818_6_MULTIPROTOCOL_ENCAPSULATION: StreamType = StreamType(0x0A);
80    /// ISO/IEC 13818-6 DSM CC U-N messages
81    pub const DSMCC_UN_MESSAGES: StreamType = StreamType(0x0B);
82    /// ISO/IEC 13818-6 DSM CC stream descriptors
83    pub const DSMCC_STREAM_DESCRIPTORS: StreamType = StreamType(0x0C);
84    /// ISO/IEC 13818-6 DSM CC tabled data
85    pub const DSMCC_SECTIONS: StreamType = StreamType(0x0D);
86    /// ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary
87    pub const H222_0_AUXILIARY: StreamType = StreamType(0x0E);
88    /// ISO/IEC 13818-7 Audio with ADTS transport syntax
89    pub const ADTS: StreamType = StreamType(0x0F);
90    /// ISO/IEC 14496-2 Visual
91    pub const ISO_14496_2_VISUAL: StreamType = StreamType(0x10);
92    /// ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1
93    pub const LATM: StreamType = StreamType(0x11);
94    /// ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets
95    pub const FLEX_MUX_PES: StreamType = StreamType(0x12);
96    /// ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections.
97    pub const FLEX_MUX_ISO_14496_SECTIONS: StreamType = StreamType(0x13);
98    /// ISO/IEC 13818-6 Synchronized Download Protocol
99    pub const SYNCHRONIZED_DOWNLOAD_PROTOCOL: StreamType = StreamType(0x14);
100    /// Metadata carried in PES packets
101    pub const METADATA_IN_PES: StreamType = StreamType(0x15);
102    /// Metadata carried in metadata_sections
103    pub const METADATA_IN_METADATA_SECTIONS: StreamType = StreamType(0x16);
104    /// Metadata carried in ISO/IEC 13818-6 Data Carousel
105    pub const DSMCC_DATA_CAROUSEL_METADATA: StreamType = StreamType(0x17);
106    /// Metadata carried in ISO/IEC 13818-6 Object Carousel
107    pub const DSMCC_OBJECT_CAROUSEL_METADATA: StreamType = StreamType(0x18);
108    /// Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol
109    pub const SYNCHRONIZED_DOWNLOAD_PROTOCOL_METADATA: StreamType = StreamType(0x19);
110    /// IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP)
111    pub const IPMP: StreamType = StreamType(0x1a);
112    /// AVC video stream as defined in ITU-T Rec. H.264 | ISO/IEC 14496-10 Video
113    pub const H264: StreamType = StreamType(0x1b);
114    /// ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS
115    pub const AUDIO_WITHOUT_TRANSPORT_SYNTAX: StreamType = StreamType(0x1c);
116    /// ISO/IEC 14496-17 Text
117    pub const ISO_14496_17_TEXT: StreamType = StreamType(0x1d);
118    // 0x1e-0x23 reserved
119    /// ITU-T Rec. H.265 and ISO/IEC 23008-2
120    pub const H265: StreamType = StreamType(0x24);
121    // 0x26-0x41 reserved
122    /// Chinese Video Standard
123    pub const CHINESE_VIDEO_STANDARD: StreamType = StreamType(0x42);
124    // 0x43-0x7f reserved
125    // 0x80 privately defined
126    /// Dolby Digital (AC-3) audio for ATSC
127    pub const ATSC_DOLBY_DIGITAL_AUDIO: StreamType = StreamType(0x81);
128    // 0x82-0x94 privately defined
129    /// ATSC Data Service Table, Network Resources Table
130    pub const ATSC_DSMCC_NETWORK_RESOURCES_TABLE: StreamType = StreamType(0x95);
131    // 0x95-0xc1 privately defined
132    /// PES packets containing ATSC streaming synchronous data
133    pub const ATSC_DSMCC_SYNCHRONOUS_DATA: StreamType = StreamType(0xc2);
134    // 0xc3-0xff privately defined,
135
136    /// `true` if packets of a stream with this `stream_type` will carry data in Packetized
137    /// Elementary Stream format.
138    pub fn is_pes(self) -> bool {
139        matches!(
140            self,
141            StreamType::ISO_11172_VIDEO
142                | StreamType::H262
143                | StreamType::ISO_11172_AUDIO
144                | StreamType::ISO_138183_AUDIO
145                | StreamType::H222_0_PES_PRIVATE_DATA
146                | StreamType::MHEG
147                | StreamType::H222_0_DSM_CC
148                | StreamType::H2221
149                | StreamType::ISO_13818_6_MULTIPROTOCOL_ENCAPSULATION
150                | StreamType::DSMCC_UN_MESSAGES
151                | StreamType::DSMCC_STREAM_DESCRIPTORS
152                | StreamType::DSMCC_SECTIONS
153                | StreamType::H222_0_AUXILIARY
154                | StreamType::ADTS
155                | StreamType::ISO_14496_2_VISUAL
156                | StreamType::LATM
157                | StreamType::FLEX_MUX_PES
158                | StreamType::FLEX_MUX_ISO_14496_SECTIONS
159                | StreamType::SYNCHRONIZED_DOWNLOAD_PROTOCOL
160                | StreamType::METADATA_IN_PES
161                | StreamType::METADATA_IN_METADATA_SECTIONS
162                | StreamType::DSMCC_DATA_CAROUSEL_METADATA
163                | StreamType::DSMCC_OBJECT_CAROUSEL_METADATA
164                | StreamType::SYNCHRONIZED_DOWNLOAD_PROTOCOL_METADATA
165                | StreamType::IPMP
166                | StreamType::H264
167                | StreamType::AUDIO_WITHOUT_TRANSPORT_SYNTAX
168                | StreamType::ISO_14496_17_TEXT
169                | StreamType::H265
170                | StreamType::CHINESE_VIDEO_STANDARD
171                | StreamType::ATSC_DOLBY_DIGITAL_AUDIO
172                | StreamType::ATSC_DSMCC_NETWORK_RESOURCES_TABLE
173                | StreamType::ATSC_DSMCC_SYNCHRONOUS_DATA
174        )
175    }
176}
177impl fmt::Debug for StreamType {
178    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
179        match *self {
180            StreamType::ISO_11172_VIDEO => f.write_str("ISO_11172_VIDEO"),
181            StreamType::H262 => f.write_str("H262"),
182            StreamType::ISO_11172_AUDIO => f.write_str("ISO_11172_AUDIO"),
183            StreamType::ISO_138183_AUDIO => f.write_str("ISO_138183_AUDIO"),
184            StreamType::H222_0_PRIVATE_SECTIONS => f.write_str("H222_0_PRIVATE_SECTIONS"),
185            StreamType::H222_0_PES_PRIVATE_DATA => f.write_str("H222_0_PES_PRIVATE_DATA"),
186            StreamType::MHEG => f.write_str("MHEG"),
187            StreamType::H222_0_DSM_CC => f.write_str("H222_0_DSM_CC"),
188            StreamType::H2221 => f.write_str("H2221"),
189            StreamType::ISO_13818_6_MULTIPROTOCOL_ENCAPSULATION => {
190                f.write_str("ISO_13818_6_MULTIPROTOCOL_ENCAPSULATION")
191            }
192            StreamType::DSMCC_UN_MESSAGES => f.write_str("DSMCC_UN_MESSAGES"),
193            StreamType::DSMCC_STREAM_DESCRIPTORS => f.write_str("DSMCC_STREAM_DESCRIPTORS"),
194            StreamType::DSMCC_SECTIONS => f.write_str("DSMCC_SECTIONS"),
195            StreamType::H222_0_AUXILIARY => f.write_str("H222_0_AUXILIARY"),
196            StreamType::ADTS => f.write_str("ADTS"),
197            StreamType::ISO_14496_2_VISUAL => f.write_str("ISO_14496_2_VISUAL"),
198            StreamType::LATM => f.write_str("LATM"),
199            StreamType::FLEX_MUX_PES => f.write_str("FLEX_MUX_PES"),
200            StreamType::FLEX_MUX_ISO_14496_SECTIONS => f.write_str("FLEX_MUX_ISO_14496_SECTIONS"),
201            StreamType::SYNCHRONIZED_DOWNLOAD_PROTOCOL => {
202                f.write_str("SYNCHRONIZED_DOWNLOAD_PROTOCOL")
203            }
204            StreamType::METADATA_IN_PES => f.write_str("METADATA_IN_PES"),
205            StreamType::METADATA_IN_METADATA_SECTIONS => {
206                f.write_str("METADATA_IN_METADATA_SECTIONS")
207            }
208            StreamType::DSMCC_DATA_CAROUSEL_METADATA => f.write_str("DSMCC_DATA_CAROUSEL_METADATA"),
209            StreamType::DSMCC_OBJECT_CAROUSEL_METADATA => {
210                f.write_str("DSMCC_OBJECT_CAROUSEL_METADATA")
211            }
212            StreamType::SYNCHRONIZED_DOWNLOAD_PROTOCOL_METADATA => {
213                f.write_str("SYNCHRONIZED_DOWNLOAD_PROTOCOL_METADATA")
214            }
215            StreamType::IPMP => f.write_str("IPMP"),
216            StreamType::H264 => f.write_str("H264"),
217            StreamType::AUDIO_WITHOUT_TRANSPORT_SYNTAX => {
218                f.write_str("AUDIO_WITHOUT_TRANSPORT_SYNTAX")
219            }
220            StreamType::ISO_14496_17_TEXT => f.write_str("ISO_14496_17_TEXT"),
221            StreamType::H265 => f.write_str("H265"),
222            StreamType::CHINESE_VIDEO_STANDARD => f.write_str("CHINESE_VIDEO_STANDARD"),
223            StreamType::ATSC_DOLBY_DIGITAL_AUDIO => f.write_str("ATSC_DOLBY_DIGITAL_AUDIO"),
224            StreamType::ATSC_DSMCC_NETWORK_RESOURCES_TABLE => {
225                f.write_str("ATSC_DSMCC_NETWORK_RESOURCES_TABLE")
226            }
227            StreamType::ATSC_DSMCC_SYNCHRONOUS_DATA => f.write_str("ATSC_DSMCC_SYNCHRONOUS_DATA"),
228            _ => {
229                if self.0 >= 0x80 {
230                    f.write_fmt(format_args!("PRIVATE({})", self.0))
231                } else {
232                    f.write_fmt(format_args!("RESERVED({})", self.0))
233                }
234            }
235        }
236    }
237}
238
239impl From<StreamType> for u8 {
240    fn from(val: StreamType) -> Self {
241        val.0
242    }
243}
244impl From<u8> for StreamType {
245    fn from(val: u8) -> Self {
246        StreamType(val)
247    }
248}
249
250/// The identifier of TS Packets containing 'stuffing' data, with value `0x1fff`
251pub const STUFFING_PID: packet::Pid = packet::Pid::new(0x1fff);
252
253#[cfg(test)]
254mod test {
255    use super::StreamType;
256
257    fn is_reserved(st: &StreamType) -> bool {
258        match st.0 {
259            0x00 | 0x1e..=0x23 | 0x25..=0x41 | 0x43..=0x7f => true,
260            _ => false,
261        }
262    }
263
264    fn is_private(st: &StreamType) -> bool {
265        match st.0 {
266            // TODO: 0x95 now public, or is ATSC_DSMCC_NETWORK_RESOURCES_TABLE incorrect?
267            0x80 | 0x82..=0x94 | 0x96..=0xc1 | 0xc3..=0xff => true,
268            _ => false,
269        }
270    }
271
272    #[test]
273    fn pes() {
274        for st in 0..=255 {
275            let ty = StreamType(st);
276            if ty == StreamType::H222_0_PRIVATE_SECTIONS || is_reserved(&ty) || is_private(&ty) {
277                assert!(!ty.is_pes(), "{:?}", ty);
278            } else {
279                assert!(ty.is_pes(), "{:?}", ty);
280            }
281            assert_eq!(ty, StreamType::from(u8::from(ty)));
282            let _ = format!("{:?}", ty);
283        }
284    }
285}