Skip to main content

webm/
lib.rs

1//! A crate for muxing one or more video/audio streams into a `WebM` file.
2//!
3//! Note that this crate is only for muxing media that has already been encoded with the appropriate codec.
4//! Consider a crate such as `vpx` if you need encoding as well.
5//!
6//! Actual writing of muxed data is done through a [`mux::Writer`], which lets you supply your own implementation.
7//! This makes it easy to support muxing to files, in-memory buffers, or whatever else you need. Once you have
8//! a [`mux::Writer`], you create a [`mux::SegmentBuilder`] and add the tracks you need. Finally, you create a
9//! [`mux::Segment`] with that builder, to which you can add media frames.
10//!
11//! In typical usage of this library, where you might mux to a `WebM` file, you would do:
12//! ```no_run
13//! use std::fs::File;
14//! use webm::mux::{Error, SegmentBuilder, SegmentMode, VideoCodecId, Writer};
15//!
16//! fn main() -> Result<(), Error> {
17//!     let file = File::create("./my-cool-file.webm").map_err(|_| Error::Unknown)?;
18//!     let writer = Writer::new(file);
19//!
20//!     // Build a segment with a single video track
21//!     let builder = SegmentBuilder::new(writer)?;
22//!     let builder = builder.set_mode(SegmentMode::Live)?; // Set live mode for streaming
23//!     let (builder, video_track) = builder.add_video_track(640, 480, VideoCodecId::VP8, None)?;
24//!     let mut segment = builder.build();
25//!
26//!     // Add some video frames
27//!     let encoded_video_frame: &[u8] = &[]; // TODO: Your video data here
28//!     let timestamp_ns = 0;
29//!     let is_keyframe = true;
30//!     segment.add_frame(video_track, encoded_video_frame, timestamp_ns, is_keyframe)?;
31//!     // TODO: More video frames
32//!
33//!     // Done writing frames, finish off the file
34//!     segment.finalize(None).map_err(|_| Error::Unknown)?;
35//!     Ok(())
36//! }
37//! ```
38
39use webm_sys as ffi;
40
41pub mod mux {
42    mod segment;
43    mod writer;
44
45    pub use crate::ffi::mux::TrackNum;
46    pub use segment::{Segment, SegmentBuilder};
47    pub use writer::Writer;
48
49    use crate::ffi;
50    use std::num::NonZeroU64;
51
52    /// This is a copyable handle equivalent to a track number
53    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54    pub struct VideoTrack(NonZeroU64);
55
56    impl From<VideoTrack> for TrackNum {
57        #[inline]
58        fn from(track: VideoTrack) -> Self {
59            track.0.get()
60        }
61    }
62
63    /// This is a copyable handle equivalent to a track number
64    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65    pub struct AudioTrack(NonZeroU64);
66
67    impl From<AudioTrack> for TrackNum {
68        #[inline]
69        fn from(track: AudioTrack) -> Self {
70            track.0.get()
71        }
72    }
73
74    pub trait Track {
75        #[must_use]
76        fn is_audio(&self) -> bool {
77            false
78        }
79
80        #[must_use]
81        fn is_video(&self) -> bool {
82            false
83        }
84
85        #[must_use]
86        fn track_number(&self) -> TrackNum;
87    }
88
89    impl Track for VideoTrack {
90        #[inline]
91        fn is_video(&self) -> bool {
92            true
93        }
94
95        #[inline]
96        fn track_number(&self) -> TrackNum {
97            self.0.get()
98        }
99    }
100
101    impl Track for AudioTrack {
102        #[inline]
103        fn is_audio(&self) -> bool {
104            true
105        }
106
107        #[inline]
108        fn track_number(&self) -> TrackNum {
109            self.0.get()
110        }
111    }
112
113    #[derive(Eq, PartialEq, Clone, Copy, Debug)]
114    #[repr(u32)]
115    pub enum AudioCodecId {
116        Opus = ffi::mux::OPUS_CODEC_ID,
117        Vorbis = ffi::mux::VORBIS_CODEC_ID,
118    }
119
120    impl AudioCodecId {
121        const fn get_id(self) -> u32 {
122            self as u32
123        }
124    }
125
126    #[derive(Eq, PartialEq, Clone, Copy, Debug)]
127    #[repr(u32)]
128    pub enum VideoCodecId {
129        VP8 = ffi::mux::VP8_CODEC_ID,
130        VP9 = ffi::mux::VP9_CODEC_ID,
131        AV1 = ffi::mux::AV1_CODEC_ID,
132    }
133
134    impl VideoCodecId {
135        const fn get_id(self) -> u32 {
136            self as u32
137        }
138    }
139
140    /// The error type for this entire crate. More specific error types will
141    /// be added in the future, hence the current marking as non-exhaustive.
142    #[derive(Debug)]
143    #[non_exhaustive]
144    pub enum Error {
145        /// An parameter with an invalid value was passed to a method.
146        BadParam,
147
148        /// An unknown error occurred. While this is typically the result of
149        /// incorrect parameters to methods, an internal error in libwebm is
150        /// also possible.
151        Unknown,
152    }
153
154    impl Error {
155        pub(crate) fn check_code(code: ffi::mux::ResultCode) -> Result<(), Self> {
156            match code {
157                ffi::mux::ResultCode::Ok => Ok(()),
158                ffi::mux::ResultCode::BadParam => Err(Self::BadParam),
159                ffi::mux::ResultCode::UnknownLibwebmError => Err(Self::Unknown),
160            }
161        }
162    }
163
164    impl std::fmt::Display for Error {
165        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166            match self {
167                Self::BadParam => f.write_str("Bad parameter"),
168                Self::Unknown => f.write_str("Unknown error"),
169            }
170        }
171    }
172
173    impl std::error::Error for Error {}
174
175    /// A specification for how pixels in written video frames are subsampled in chroma channels.
176    ///
177    /// Certain video frame formats (e.g. YUV 4:2:0) have a lower resolution in chroma (Cr/Cb) channels than the
178    /// luminance channel. This structure informs video players how that subsampling is done, using a number of
179    /// subsampling factors. A factor of zero means no subsampling, and a factor of one means that particular dimension
180    /// is half resolution.
181    ///
182    /// You may use [`ColorSubsampling::default()`] to get a specification of no subsampling in any dimension.
183    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
184    pub struct ColorSubsampling {
185        /// The subsampling factor for both chroma channels in the horizontal direction.
186        pub chroma_horizontal: u8,
187
188        /// The subsampling factor for both chroma channels in the vertical direction.
189        pub chroma_vertical: u8,
190    }
191
192    /// A specification of how the range of colors in the input video frames has been clipped.
193    ///
194    /// Certain screens struggle with the full range of available colors, and video content is thus sometimes tuned to
195    /// a restricted range.
196    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
197    pub enum ColorRange {
198        /// No claim is made as to how colors have been restricted.
199        #[default]
200        Unspecified = 0,
201
202        /// Color values are restricted to a "broadcast-safe" range.
203        Broadcast = 1,
204
205        /// No color clipping is performed.
206        Full = 2,
207    }
208
209    /// A specification for the segment writing mode.
210    ///
211    /// This controls how the segment is written and affects features like seeking.
212    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
213    pub enum SegmentMode {
214        /// Live mode - optimized for real-time streaming.
215        /// In this mode, seeking information may not be available.
216        Live,
217
218        /// File mode - optimized for file-based playback.
219        /// This enables full seeking and duration information.
220        File,
221    }
222
223    /// Transfer characteristics (EOTF - Electro-Optical Transfer Function).
224    ///
225    /// Specifies how the video signal values relate to light output.
226    /// See ITU-T H.273 / ISO/IEC 23091-2.
227    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
228    #[repr(u64)]
229    pub enum TransferCharacteristics {
230        /// Rec. ITU-R BT.709
231        Bt709 = 1,
232        /// Unspecified
233        Unspecified = 2,
234        /// Rec. ITU-R BT.470-6 System M
235        Bt470M = 4,
236        /// Rec. ITU-R BT.470-6 System B, G
237        Bt470Bg = 5,
238        /// Rec. ITU-R BT.601-7 525 or 625
239        Bt601 = 6,
240        /// SMPTE ST 240
241        Smpte240M = 7,
242        /// Linear transfer characteristics
243        Linear = 8,
244        /// Logarithmic transfer (100:1 range)
245        Log100 = 9,
246        /// Logarithmic transfer (316.22777:1 range)
247        Log316 = 10,
248        /// IEC 61966-2-4
249        Iec61966_2_4 = 11,
250        /// Rec. ITU-R BT.1361-0 extended colour gamut system
251        Bt1361 = 12,
252        /// IEC 61966-2-1 sRGB
253        Iec61966_2_1 = 13,
254        /// Rec. ITU-R BT.2020-2 (10-bit system)
255        Bt2020_10bit = 14,
256        /// Rec. ITU-R BT.2020-2 (12-bit system)
257        Bt2020_12bit = 15,
258        /// SMPTE ST 2084 - Perceptual Quantizer (PQ) for HDR10
259        Smpte2084 = 16,
260        /// SMPTE ST 428-1
261        Smpte428 = 17,
262        /// ARIB STD-B67 - Hybrid Log-Gamma (HLG)
263        AribStdB67 = 18,
264    }
265
266    /// Color primaries specification.
267    ///
268    /// Defines the chromaticity coordinates of the source primaries.
269    /// See ITU-T H.273 / ISO/IEC 23091-2.
270    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
271    #[repr(u64)]
272    pub enum ColorPrimaries {
273        /// Rec. ITU-R BT.709
274        Bt709 = 1,
275        /// Unspecified
276        Unspecified = 2,
277        /// Rec. ITU-R BT.470-6 System M
278        Bt470M = 4,
279        /// Rec. ITU-R BT.470-6 System B, G
280        Bt470Bg = 5,
281        /// Rec. ITU-R BT.601-7 525 or 625
282        Bt601 = 6,
283        /// SMPTE ST 240
284        Smpte240M = 7,
285        /// Generic film (colour filters using Illuminant C)
286        Film = 8,
287        /// Rec. ITU-R BT.2020 / BT.2100 - Wide color gamut for HDR
288        Bt2020 = 9,
289        /// SMPTE ST 428-1 (CIE 1931 XYZ)
290        Smpte428 = 10,
291        /// SMPTE RP 431-2 - DCI P3
292        Smpte431 = 11,
293        /// SMPTE EG 432-1 - Display P3
294        Smpte432 = 12,
295        /// EBU Tech. 3213-E
296        Ebu3213 = 22,
297    }
298
299    /// Matrix coefficients for deriving luma and chroma from RGB.
300    ///
301    /// See ITU-T H.273 / ISO/IEC 23091-2.
302    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
303    #[repr(u64)]
304    pub enum MatrixCoefficients {
305        /// Identity matrix (RGB)
306        Identity = 0,
307        /// Rec. ITU-R BT.709
308        Bt709 = 1,
309        /// Unspecified
310        Unspecified = 2,
311        /// FCC
312        Fcc = 4,
313        /// Rec. ITU-R BT.470-6 System B, G
314        Bt470Bg = 5,
315        /// Rec. ITU-R BT.601-7 525 or 625
316        Bt601 = 6,
317        /// SMPTE ST 240
318        Smpte240M = 7,
319        /// `YCgCo`
320        YCgCo = 8,
321        /// Rec. ITU-R BT.2020-2 non-constant luminance
322        Bt2020Ncl = 9,
323        /// Rec. ITU-R BT.2020-2 constant luminance
324        Bt2020Cl = 10,
325        /// SMPTE ST 2085
326        Smpte2085 = 11,
327        /// Chromaticity-derived non-constant luminance
328        ChromaNcl = 12,
329        /// Chromaticity-derived constant luminance
330        ChromaCl = 13,
331        /// `ICtCp` (Rec. ITU-R BT.2100-0)
332        ICtCp = 14,
333    }
334
335    /// Chromaticity coordinates (CIE 1931 xy).
336    ///
337    /// Values should be in the range 0.0 to 1.0.
338    #[derive(Debug, Clone, Copy, PartialEq)]
339    pub struct Chromaticity {
340        pub x: f32,
341        pub y: f32,
342    }
343
344    impl Chromaticity {
345        /// D65 white point (standard for BT.709, BT.2020)
346        pub const D65: Self = Self {
347            x: 0.3127,
348            y: 0.3290,
349        };
350    }
351
352    /// Display primaries for HDR mastering metadata.
353    #[derive(Debug, Clone, Copy, PartialEq)]
354    pub struct DisplayPrimaries {
355        pub red: Chromaticity,
356        pub green: Chromaticity,
357        pub blue: Chromaticity,
358    }
359
360    impl DisplayPrimaries {
361        /// Rec. ITU-R BT.709 primaries (SDR)
362        pub const BT_709: Self = Self {
363            red: Chromaticity { x: 0.64, y: 0.33 },
364            green: Chromaticity { x: 0.30, y: 0.60 },
365            blue: Chromaticity { x: 0.15, y: 0.06 },
366        };
367
368        /// Rec. ITU-R BT.2020 primaries (HDR/WCG)
369        pub const BT_2020: Self = Self {
370            red: Chromaticity { x: 0.708, y: 0.292 },
371            green: Chromaticity { x: 0.170, y: 0.797 },
372            blue: Chromaticity { x: 0.131, y: 0.046 },
373        };
374
375        /// DCI-P3 primaries
376        pub const DCI_P3: Self = Self {
377            red: Chromaticity { x: 0.680, y: 0.320 },
378            green: Chromaticity { x: 0.265, y: 0.690 },
379            blue: Chromaticity { x: 0.150, y: 0.060 },
380        };
381    }
382
383    /// SMPTE ST 2086 mastering display metadata.
384    ///
385    /// Specifies the color volume and luminance range of the display used for mastering HDR content.
386    #[derive(Debug, Clone, Copy, PartialEq)]
387    pub struct MasteringDisplayMetadata {
388        /// Maximum luminance in candelas per square meter (cd/m² or nits).
389        /// Typical values: 1000.0, 4000.0, 10000.0
390        pub luminance_max: f32,
391
392        /// Minimum luminance in candelas per square meter (cd/m² or nits).
393        /// Typical values: 0.0001, 0.001, 0.01, 0.05
394        pub luminance_min: f32,
395
396        /// Display primaries (red, green, blue chromaticity coordinates)
397        pub primaries: DisplayPrimaries,
398
399        /// White point chromaticity coordinates
400        pub white_point: Chromaticity,
401    }
402
403    /// HDR10 static metadata.
404    ///
405    /// Includes both content light level metadata and mastering display metadata.
406    #[derive(Debug, Clone, Copy, PartialEq)]
407    pub struct HdrMetadata {
408        /// Maximum Content Light Level in cd/m² (nits).
409        /// The maximum light level of any single pixel in the entire video.
410        /// Typical range: 1000-4000 nits.
411        pub max_cll: u64,
412
413        /// Maximum Frame-Average Light Level in cd/m² (nits).
414        /// The maximum average light level of any single frame in the video.
415        /// Typical range: 100-1000 nits.
416        pub max_fall: u64,
417
418        /// Optional SMPTE ST 2086 mastering metadata.
419        pub mastering_metadata: Option<MasteringDisplayMetadata>,
420    }
421}