mp4_emsg/version.rs
1//! The `emsg` `FullBox` version field — DASH-IF IOP Part 10 §6.1 / Table 6-2.
2//!
3//! Per Table 6-2 (`emsg.version`): "version 0 is used for segment relative
4//! timing, version 1 for representation relative timing." The two versions
5//! carry the same logical field set except for the presentation-time field:
6//!
7//! - **version 0** — `presentation_time_delta` (u32), relative to the
8//! segment's earliest presentation time;
9//! - **version 1** — `presentation_time` (u64), relative to `Period@start`.
10//!
11//! The box body field *ordering* also differs between the two versions — see
12//! the crate root caveat and [`crate::EmsgBox`].
13
14/// The `version` byte of the `'emsg'` `FullBox` (DASH-IF Part 10 Table 6-2).
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize))]
17#[non_exhaustive]
18pub enum EmsgVersion {
19 /// Version 0 — segment-relative timing; carries `presentation_time_delta`
20 /// (u32). Strings precede the integer fields on the wire.
21 SegmentRelative,
22 /// Version 1 — representation/`Period@start`-relative timing; carries
23 /// `presentation_time` (u64). Integer fields precede the strings on the
24 /// wire.
25 RepresentationRelative,
26}
27
28/// The wire value of `version` for [`EmsgVersion::SegmentRelative`].
29pub const VERSION_0: u8 = 0;
30/// The wire value of `version` for [`EmsgVersion::RepresentationRelative`].
31pub const VERSION_1: u8 = 1;
32
33impl EmsgVersion {
34 /// Decode the `FullBox` `version` byte; only 0 and 1 are defined.
35 pub fn from_u8(v: u8) -> Option<Self> {
36 match v {
37 VERSION_0 => Some(EmsgVersion::SegmentRelative),
38 VERSION_1 => Some(EmsgVersion::RepresentationRelative),
39 _ => None,
40 }
41 }
42
43 /// The `version` byte as it appears on the wire.
44 pub fn to_u8(self) -> u8 {
45 match self {
46 EmsgVersion::SegmentRelative => VERSION_0,
47 EmsgVersion::RepresentationRelative => VERSION_1,
48 }
49 }
50
51 /// Spec label for this version.
52 pub fn name(&self) -> &'static str {
53 match self {
54 EmsgVersion::SegmentRelative => "segment relative (v0)",
55 EmsgVersion::RepresentationRelative => "representation relative (v1)",
56 }
57 }
58}
59
60dvb_common::impl_spec_display!(EmsgVersion);
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use alloc::string::ToString;
66
67 #[test]
68 fn round_trips() {
69 assert_eq!(EmsgVersion::from_u8(0), Some(EmsgVersion::SegmentRelative));
70 assert_eq!(
71 EmsgVersion::from_u8(1),
72 Some(EmsgVersion::RepresentationRelative)
73 );
74 assert_eq!(EmsgVersion::from_u8(2), None);
75 assert_eq!(EmsgVersion::SegmentRelative.to_u8(), 0);
76 assert_eq!(EmsgVersion::RepresentationRelative.to_u8(), 1);
77 }
78
79 #[test]
80 fn display_uses_name() {
81 assert_eq!(
82 EmsgVersion::SegmentRelative.to_string(),
83 "segment relative (v0)"
84 );
85 }
86}