Skip to main content

moq_ffi/
media.rs

1use std::collections::HashMap;
2
3#[derive(Clone, uniffi::Record)]
4pub struct MoqDimensions {
5	pub width: u32,
6	pub height: u32,
7}
8
9#[derive(Clone, uniffi::Enum)]
10pub enum Container {
11	Legacy,
12	Cmaf { init: Vec<u8> },
13	Loc,
14}
15
16impl From<hang::catalog::Container> for Container {
17	fn from(container: hang::catalog::Container) -> Self {
18		match container {
19			hang::catalog::Container::Legacy => Self::Legacy,
20			hang::catalog::Container::Cmaf { init, .. } => Self::Cmaf { init: init.to_vec() },
21			hang::catalog::Container::Loc => Self::Loc,
22		}
23	}
24}
25
26impl From<Container> for hang::catalog::Container {
27	fn from(container: Container) -> Self {
28		match container {
29			Container::Legacy => Self::Legacy,
30			Container::Cmaf { init } => Self::Cmaf {
31				init: init.into(),
32				timescale: None,
33				track_id: None,
34			},
35			Container::Loc => Self::Loc,
36		}
37	}
38}
39
40#[derive(uniffi::Record)]
41pub struct MoqCatalog {
42	pub video: HashMap<String, MoqVideo>,
43	pub audio: HashMap<String, MoqAudio>,
44	pub display: Option<MoqDimensions>,
45	pub rotation: Option<f64>,
46	pub flip: Option<bool>,
47}
48
49#[derive(Clone, uniffi::Record)]
50pub struct MoqVideo {
51	pub codec: String,
52	pub description: Option<Vec<u8>>,
53	pub coded: Option<MoqDimensions>,
54	pub display_ratio: Option<MoqDimensions>,
55	pub bitrate: Option<u64>,
56	pub framerate: Option<f64>,
57	pub container: Container,
58}
59
60#[derive(Clone, uniffi::Record)]
61pub struct MoqAudio {
62	pub codec: String,
63	pub description: Option<Vec<u8>>,
64	pub sample_rate: u32,
65	pub channel_count: u32,
66	pub bitrate: Option<u64>,
67	pub container: Container,
68}
69
70/// A media frame.
71#[derive(uniffi::Record)]
72pub struct MoqFrame {
73	pub payload: Vec<u8>,
74	pub timestamp_us: u64,
75	pub keyframe: bool,
76}
77
78pub(crate) fn convert_catalog(catalog: &moq_mux::catalog::hang::Catalog) -> MoqCatalog {
79	let video = catalog
80		.video
81		.renditions
82		.iter()
83		.map(|(name, config)| {
84			(
85				name.clone(),
86				MoqVideo {
87					codec: config.codec.to_string(),
88					description: config.description.as_ref().map(|d| d.to_vec()),
89					coded: match (config.coded_width, config.coded_height) {
90						(Some(w), Some(h)) => Some(MoqDimensions { width: w, height: h }),
91						_ => None,
92					},
93					display_ratio: match (config.display_ratio_width, config.display_ratio_height) {
94						(Some(w), Some(h)) => Some(MoqDimensions { width: w, height: h }),
95						_ => None,
96					},
97					bitrate: config.bitrate,
98					framerate: config.framerate,
99					container: config.container.clone().into(),
100				},
101			)
102		})
103		.collect();
104
105	let audio = catalog
106		.audio
107		.renditions
108		.iter()
109		.map(|(name, config)| {
110			(
111				name.clone(),
112				MoqAudio {
113					codec: config.codec.to_string(),
114					description: config.description.as_ref().map(|d| d.to_vec()),
115					sample_rate: config.sample_rate,
116					channel_count: config.channel_count,
117					bitrate: config.bitrate,
118					container: config.container.clone().into(),
119				},
120			)
121		})
122		.collect();
123
124	let display = catalog.video.display.as_ref().map(|d| MoqDimensions {
125		width: d.width,
126		height: d.height,
127	});
128
129	MoqCatalog {
130		video,
131		audio,
132		display,
133		rotation: catalog.video.rotation,
134		flip: catalog.video.flip,
135	}
136}