servo_media_gstreamer/
registry_scanner.rs1use std::collections::HashSet;
6use std::str::FromStr;
7use std::sync::LazyLock;
8
9pub static GSTREAMER_REGISTRY_SCANNER: LazyLock<GStreamerRegistryScanner> =
13 LazyLock::new(GStreamerRegistryScanner::new);
14
15pub struct GStreamerRegistryScanner {
16 supported_mime_types: HashSet<&'static str>,
17 supported_codecs: HashSet<&'static str>,
18}
19
20impl GStreamerRegistryScanner {
21 fn new() -> GStreamerRegistryScanner {
22 let mut registry_scanner = GStreamerRegistryScanner {
23 supported_mime_types: HashSet::new(),
24 supported_codecs: HashSet::new(),
25 };
26 registry_scanner.initialize();
27 registry_scanner
28 }
29
30 pub fn is_container_type_supported(&self, container_type: &str) -> bool {
31 self.supported_mime_types.contains(container_type)
32 }
33
34 fn is_codec_supported(&self, codec: &str) -> bool {
35 self.supported_codecs.contains(codec)
36 }
37
38 pub fn are_all_codecs_supported(&self, codecs: &Vec<&str>) -> bool {
39 codecs.iter().all(|&codec| self.is_codec_supported(codec))
40 }
41
42 fn initialize(&mut self) {
43 let audio_decoder_factories = gstreamer::ElementFactory::factories_with_type(
44 gstreamer::ElementFactoryType::DECODER | gstreamer::ElementFactoryType::MEDIA_AUDIO,
45 gstreamer::Rank::MARGINAL,
46 );
47 let audio_parser_factories = gstreamer::ElementFactory::factories_with_type(
48 gstreamer::ElementFactoryType::PARSER | gstreamer::ElementFactoryType::MEDIA_AUDIO,
49 gstreamer::Rank::NONE,
50 );
51 let video_decoder_factories = gstreamer::ElementFactory::factories_with_type(
52 gstreamer::ElementFactoryType::DECODER | gstreamer::ElementFactoryType::MEDIA_VIDEO,
53 gstreamer::Rank::MARGINAL,
54 );
55 let video_parser_factories = gstreamer::ElementFactory::factories_with_type(
56 gstreamer::ElementFactoryType::PARSER | gstreamer::ElementFactoryType::MEDIA_VIDEO,
57 gstreamer::Rank::MARGINAL,
58 );
59 let demux_factories = gstreamer::ElementFactory::factories_with_type(
60 gstreamer::ElementFactoryType::DEMUXER,
61 gstreamer::Rank::MARGINAL,
62 );
63
64 if has_element_for_media_type(&audio_decoder_factories, "audio/mpeg, mpegversion=(int)4") {
65 self.supported_mime_types.insert("audio/aac");
66 self.supported_mime_types.insert("audio/mp4");
67 self.supported_mime_types.insert("audio/x-m4a");
68 self.supported_codecs.insert("mpeg");
69 self.supported_codecs.insert("mp4a*");
70 }
71
72 let is_opus_supported =
73 has_element_for_media_type(&audio_decoder_factories, "audio/x-opus");
74 if is_opus_supported && has_element_for_media_type(&audio_parser_factories, "audio/x-opus")
75 {
76 self.supported_mime_types.insert("audio/opus");
77 self.supported_codecs.insert("opus");
78 self.supported_codecs.insert("x-opus");
79 }
80
81 let is_vorbis_supported =
82 has_element_for_media_type(&audio_decoder_factories, "audio/x-vorbis");
83 if is_vorbis_supported &&
84 has_element_for_media_type(&audio_parser_factories, "audio/x-vorbis")
85 {
86 self.supported_codecs.insert("vorbis");
87 self.supported_codecs.insert("x-vorbis");
88 }
89
90 if has_element_for_media_type(&demux_factories, "video/x-matroska") {
91 let is_vp8_decoder_available =
92 has_element_for_media_type(&video_decoder_factories, "video/x-vp8");
93 let is_vp9_decoder_available =
94 has_element_for_media_type(&video_decoder_factories, "video/x-vp9");
95
96 if is_vp8_decoder_available || is_vp9_decoder_available {
97 self.supported_mime_types.insert("video/webm");
98 }
99
100 if is_vp8_decoder_available {
101 self.supported_codecs.insert("vp8");
102 self.supported_codecs.insert("x-vp8");
103 self.supported_codecs.insert("vp8.0");
104 }
105
106 if is_vp9_decoder_available {
107 self.supported_codecs.insert("vp9");
108 self.supported_codecs.insert("x-vp9");
109 self.supported_codecs.insert("vp9.0");
110 }
111
112 if is_opus_supported {
113 self.supported_mime_types.insert("audio/webm");
114 }
115 }
116
117 let is_h264_decoder_available = has_element_for_media_type(
118 &video_decoder_factories,
119 "video/x-h264, profile=(string){ constrained-baseline, baseline, high }",
120 );
121 if is_h264_decoder_available &&
122 has_element_for_media_type(&video_parser_factories, "video/x-h264")
123 {
124 self.supported_mime_types.insert("video/mp4");
125 self.supported_mime_types.insert("video/x-m4v");
126 self.supported_codecs.insert("x-h264");
127 self.supported_codecs.insert("avc*");
128 self.supported_codecs.insert("mp4v*");
129 }
130
131 if has_element_for_media_type(&audio_decoder_factories, "audio/midi") {
132 self.supported_mime_types.insert("audio/midi");
133 self.supported_mime_types.insert("audio/riff-midi");
134 }
135
136 if has_element_for_media_type(&audio_decoder_factories, "audio/x-ac3") {
137 self.supported_mime_types.insert("audio/x-ac3");
138 }
139
140 if has_element_for_media_type(&audio_decoder_factories, "audio/x-flac") {
141 self.supported_mime_types.insert("audio/flac");
142 self.supported_mime_types.insert("audio/x-flac");
143 }
144
145 if has_element_for_media_type(&audio_decoder_factories, "audio/x-speex") {
146 self.supported_mime_types.insert("audio/speex");
147 self.supported_mime_types.insert("audio/x-speex");
148 }
149
150 if has_element_for_media_type(&audio_decoder_factories, "audio/x-wavpack") {
151 self.supported_mime_types.insert("audio/x-wavpack");
152 }
153
154 if has_element_for_media_type(
155 &video_decoder_factories,
156 "video/mpeg, mpegversion=(int){1,2}, systemstream=(boolean)false",
157 ) {
158 self.supported_mime_types.insert("video/mpeg");
159 self.supported_codecs.insert("mpeg");
160 }
161
162 if has_element_for_media_type(&video_decoder_factories, "video/x-flash-video") {
163 self.supported_mime_types.insert("video/flv");
164 self.supported_mime_types.insert("video/x-flv");
165 }
166
167 if has_element_for_media_type(&video_decoder_factories, "video/x-msvideocodec") {
168 self.supported_mime_types.insert("video/x-msvideo");
169 }
170
171 if has_element_for_media_type(&demux_factories, "application/x-hls") {
172 self.supported_mime_types
173 .insert("application/vnd.apple.mpegurl");
174 self.supported_mime_types.insert("application/x-mpegurl");
175 }
176
177 if has_element_for_media_type(&demux_factories, "application/x-wav") ||
178 has_element_for_media_type(&demux_factories, "audio/x-wav")
179 {
180 self.supported_mime_types.insert("audio/wav");
181 self.supported_mime_types.insert("audio/vnd.wav");
182 self.supported_mime_types.insert("audio/x-wav");
183 self.supported_codecs.insert("1");
184 }
185
186 if has_element_for_media_type(&demux_factories, "video/quicktime, variant=(string)3gpp") {
187 self.supported_mime_types.insert("video/3gpp");
188 }
189
190 if has_element_for_media_type(&demux_factories, "application/ogg") {
191 self.supported_mime_types.insert("application/ogg");
192
193 if is_vorbis_supported {
194 self.supported_mime_types.insert("audio/ogg");
195 self.supported_mime_types.insert("audio/x-vorbis+ogg");
196 }
197
198 if has_element_for_media_type(&audio_decoder_factories, "audio/x-speex") {
199 self.supported_mime_types.insert("audio/ogg");
200 self.supported_codecs.insert("speex");
201 }
202
203 if has_element_for_media_type(&video_decoder_factories, "video/x-theora") {
204 self.supported_mime_types.insert("video/ogg");
205 self.supported_codecs.insert("theora");
206 }
207 }
208
209 let mut is_audio_mpeg_supported = false;
210 if has_element_for_media_type(
211 &audio_decoder_factories,
212 "audio/mpeg, mpegversion=(int)1, layer=(int)[1, 3]",
213 ) {
214 is_audio_mpeg_supported = true;
215 self.supported_mime_types.insert("audio/mp1");
216 self.supported_mime_types.insert("audio/mp3");
217 self.supported_mime_types.insert("audio/x-mp3");
218 self.supported_codecs.insert("audio/mp3");
219 }
220
221 if has_element_for_media_type(&audio_decoder_factories, "audio/mpeg, mpegversion=(int)2") {
222 is_audio_mpeg_supported = true;
223 self.supported_mime_types.insert("audio/mp2");
224 }
225
226 is_audio_mpeg_supported |= self.is_container_type_supported("video/mp4");
227 if is_audio_mpeg_supported {
228 self.supported_mime_types.insert("audio/mpeg");
229 self.supported_mime_types.insert("audio/x-mpeg");
230 }
231
232 let is_matroska_supported =
233 has_element_for_media_type(&demux_factories, "video/x-matroska");
234 if is_matroska_supported {
235 self.supported_mime_types.insert("video/x-matroska");
236
237 if has_element_for_media_type(&video_decoder_factories, "video/x-vp10") {
238 self.supported_mime_types.insert("video/webm");
239 }
240 }
241
242 if (is_matroska_supported || self.is_container_type_supported("video/mp4")) &&
243 has_element_for_media_type(&video_decoder_factories, "video/x-av1")
244 {
245 self.supported_codecs.insert("av01*");
246 }
247 }
248}
249
250fn has_element_for_media_type(
251 factories: &glib::List<gstreamer::ElementFactory>,
252 media_type: &str,
253) -> bool {
254 match gstreamer::caps::Caps::from_str(media_type) {
255 Ok(caps) => {
256 for factory in factories {
257 if factory.can_sink_all_caps(&caps) {
258 return true;
259 }
260 }
261 false
262 },
263 _ => false,
264 }
265}