servo_media_gstreamer/
media_capture.rs1use crate::media_stream::GStreamerMediaStream;
2use gst;
3use gst::caps::NoFeature;
4use gst::prelude::*;
5use servo_media_streams::capture::*;
6use servo_media_streams::registry::MediaStreamId;
7use servo_media_streams::MediaStreamType;
8use std::i32;
9
10trait AddToCaps {
11 type Bound;
12 fn add_to_caps(
13 &self,
14 name: &str,
15 min: Self::Bound,
16 max: Self::Bound,
17 builder: gst::caps::Builder<NoFeature>,
18 ) -> Option<gst::caps::Builder<NoFeature>>;
19}
20
21impl AddToCaps for Constrain<u32> {
22 type Bound = u32;
23 fn add_to_caps(
24 &self,
25 name: &str,
26 min: u32,
27 max: u32,
28 builder: gst::caps::Builder<NoFeature>,
29 ) -> Option<gst::caps::Builder<NoFeature>> {
30 match self {
31 Constrain::Value(v) => Some(builder.field(name, v)),
32 Constrain::Range(r) => {
33 let min = into_i32(r.min.unwrap_or(min));
34 let max = into_i32(r.max.unwrap_or(max));
35 let range = gst::IntRange::<i32>::new(min, max);
36
37 Some(builder.field(name, range))
40 }
41 }
42 }
43}
44
45fn into_i32(x: u32) -> i32 {
46 if x > i32::MAX as u32 {
47 i32::MAX
48 } else {
49 x as i32
50 }
51}
52
53impl AddToCaps for Constrain<f64> {
54 type Bound = i32;
55 fn add_to_caps<'a>(
56 &self,
57 name: &str,
58 min: i32,
59 max: i32,
60 builder: gst::caps::Builder<NoFeature>,
61 ) -> Option<gst::caps::Builder<NoFeature>> {
62 match self {
63 Constrain::Value(v) => Some(builder.field("name", gst::Fraction::approximate_f64(*v)?)),
64 Constrain::Range(r) => {
65 let min = r
66 .min
67 .and_then(gst::Fraction::approximate_f64)
68 .unwrap_or(gst::Fraction::new(min, 1));
69 let max = r
70 .max
71 .and_then(gst::Fraction::approximate_f64)
72 .unwrap_or(gst::Fraction::new(max, 1));
73 let range = gst::FractionRange::new(min, max);
74 Some(builder.field(name, range))
77 }
78 }
79 }
80}
81
82fn into_caps(set: MediaTrackConstraintSet, format: &str) -> Option<gst::Caps> {
84 let mut builder = gst::Caps::builder(format);
85 if let Some(w) = set.width {
86 builder = w.add_to_caps("width", 0, 1000000, builder)?;
87 }
88 if let Some(h) = set.height {
89 builder = h.add_to_caps("height", 0, 1000000, builder)?;
90 }
91 if let Some(aspect) = set.aspect {
92 builder = aspect.add_to_caps("pixel-aspect-ratio", 0, 1000000, builder)?;
93 }
94 if let Some(fr) = set.frame_rate {
95 builder = fr.add_to_caps("framerate", 0, 1000000, builder)?;
96 }
97 if let Some(sr) = set.sample_rate {
98 builder = sr.add_to_caps("rate", 0, 1000000, builder)?;
99 }
100 Some(builder.build())
101}
102
103struct GstMediaDevices {
104 monitor: gst::DeviceMonitor,
105}
106
107impl GstMediaDevices {
108 pub fn new() -> Self {
109 Self {
110 monitor: gst::DeviceMonitor::new(),
111 }
112 }
113
114 pub fn get_track(
115 &self,
116 video: bool,
117 constraints: MediaTrackConstraintSet,
118 ) -> Option<GstMediaTrack> {
119 let (format, filter) = if video {
120 ("video/x-raw", "Video/Source")
121 } else {
122 ("audio/x-raw", "Audio/Source")
123 };
124 let caps = into_caps(constraints, format)?;
125 let f = self.monitor.add_filter(Some(filter), Some(&caps));
126 let devices = self.monitor.devices();
127 if let Some(f) = f {
128 let _ = self.monitor.remove_filter(f);
129 }
130 if let Some(d) = devices.front() {
131 let element = d.create_element(None).ok()?;
132 Some(GstMediaTrack { element })
133 } else {
134 None
135 }
136 }
137}
138
139pub struct GstMediaTrack {
140 element: gst::Element,
141}
142
143fn create_input_stream(
144 stream_type: MediaStreamType,
145 constraint_set: MediaTrackConstraintSet,
146) -> Option<MediaStreamId> {
147 let devices = GstMediaDevices::new();
148 devices
149 .get_track(stream_type == MediaStreamType::Video, constraint_set)
150 .map(|track| {
151 let f = match stream_type {
152 MediaStreamType::Audio => GStreamerMediaStream::create_audio_from,
153 MediaStreamType::Video => GStreamerMediaStream::create_video_from,
154 };
155 f(track.element)
156 })
157}
158
159pub fn create_audioinput_stream(constraint_set: MediaTrackConstraintSet) -> Option<MediaStreamId> {
160 create_input_stream(MediaStreamType::Audio, constraint_set)
161}
162
163pub fn create_videoinput_stream(constraint_set: MediaTrackConstraintSet) -> Option<MediaStreamId> {
164 create_input_stream(MediaStreamType::Video, constraint_set)
165}