Skip to main content

oxideav_core/
stream.rs

1//! Stream metadata shared between containers and codecs.
2
3use crate::format::{MediaType, PixelFormat, SampleFormat};
4use crate::rational::Rational;
5use crate::time::TimeBase;
6
7/// A stable identifier for a codec. Codec crates register a `CodecId` so the
8/// codec registry can look them up by name.
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10pub struct CodecId(pub String);
11
12impl CodecId {
13    pub fn new(s: impl Into<String>) -> Self {
14        Self(s.into())
15    }
16
17    pub fn as_str(&self) -> &str {
18        &self.0
19    }
20}
21
22impl From<&str> for CodecId {
23    fn from(s: &str) -> Self {
24        Self(s.to_owned())
25    }
26}
27
28impl std::fmt::Display for CodecId {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        write!(f, "{}", self.0)
31    }
32}
33
34/// Codec-level parameters shared between demuxer/muxer and en/decoder.
35#[derive(Clone, Debug)]
36pub struct CodecParameters {
37    pub codec_id: CodecId,
38    pub media_type: MediaType,
39
40    // Audio-specific
41    pub sample_rate: Option<u32>,
42    pub channels: Option<u16>,
43    pub sample_format: Option<SampleFormat>,
44
45    // Video-specific
46    pub width: Option<u32>,
47    pub height: Option<u32>,
48    pub pixel_format: Option<PixelFormat>,
49    pub frame_rate: Option<Rational>,
50
51    /// Per-codec setup bytes (e.g., SPS/PPS, OpusHead). Format defined by codec.
52    pub extradata: Vec<u8>,
53
54    pub bit_rate: Option<u64>,
55}
56
57impl CodecParameters {
58    pub fn audio(codec_id: CodecId) -> Self {
59        Self {
60            codec_id,
61            media_type: MediaType::Audio,
62            sample_rate: None,
63            channels: None,
64            sample_format: None,
65            width: None,
66            height: None,
67            pixel_format: None,
68            frame_rate: None,
69            extradata: Vec::new(),
70            bit_rate: None,
71        }
72    }
73
74    /// True when `self` and `other` have the same codec_id and core
75    /// format parameters (sample_rate/channels/sample_format for audio,
76    /// width/height/pixel_format for video). Extradata and bitrate
77    /// differences are tolerated — many containers rewrite extradata
78    /// losslessly during a copy operation.
79    pub fn matches_core(&self, other: &CodecParameters) -> bool {
80        self.codec_id == other.codec_id
81            && self.sample_rate == other.sample_rate
82            && self.channels == other.channels
83            && self.sample_format == other.sample_format
84            && self.width == other.width
85            && self.height == other.height
86            && self.pixel_format == other.pixel_format
87    }
88
89    pub fn video(codec_id: CodecId) -> Self {
90        Self {
91            codec_id,
92            media_type: MediaType::Video,
93            sample_rate: None,
94            channels: None,
95            sample_format: None,
96            width: None,
97            height: None,
98            pixel_format: None,
99            frame_rate: None,
100            extradata: Vec::new(),
101            bit_rate: None,
102        }
103    }
104}
105
106/// Description of a single stream inside a container.
107#[derive(Clone, Debug)]
108pub struct StreamInfo {
109    pub index: u32,
110    pub time_base: TimeBase,
111    pub duration: Option<i64>,
112    pub start_time: Option<i64>,
113    pub params: CodecParameters,
114}