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