mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-25 04:51:26 +00:00
webrtc: allow resolution and framerate input changes
Some changes do not require a WebRTC renegotiation so we can allow those. Fix #515 Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1498>
This commit is contained in:
parent
eb49459937
commit
96337d5234
1 changed files with 68 additions and 24 deletions
|
@ -235,6 +235,8 @@ pub struct VideoEncoder {
|
||||||
session_id: String,
|
session_id: String,
|
||||||
mitigation_mode: WebRTCSinkMitigationMode,
|
mitigation_mode: WebRTCSinkMitigationMode,
|
||||||
pub transceiver: gst_webrtc::WebRTCRTPTransceiver,
|
pub transceiver: gst_webrtc::WebRTCRTPTransceiver,
|
||||||
|
/// name of the sink pad feeding this encoder
|
||||||
|
stream_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Session {
|
struct Session {
|
||||||
|
@ -920,6 +922,7 @@ impl VideoEncoder {
|
||||||
session_id: &str,
|
session_id: &str,
|
||||||
codec_name: &str,
|
codec_name: &str,
|
||||||
transceiver: gst_webrtc::WebRTCRTPTransceiver,
|
transceiver: gst_webrtc::WebRTCRTPTransceiver,
|
||||||
|
stream_name: String,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let halved_framerate = video_info.fps().mul(gst::Fraction::new(1, 2));
|
let halved_framerate = video_info.fps().mul(gst::Fraction::new(1, 2));
|
||||||
Some(Self {
|
Some(Self {
|
||||||
|
@ -938,6 +941,7 @@ impl VideoEncoder {
|
||||||
session_id: session_id.to_string(),
|
session_id: session_id.to_string(),
|
||||||
mitigation_mode: WebRTCSinkMitigationMode::NONE,
|
mitigation_mode: WebRTCSinkMitigationMode::NONE,
|
||||||
transceiver,
|
transceiver,
|
||||||
|
stream_name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1322,6 +1326,7 @@ impl Session {
|
||||||
&self.id,
|
&self.id,
|
||||||
codec.caps.structure(0).unwrap().name(),
|
codec.caps.structure(0).unwrap().name(),
|
||||||
transceiver,
|
transceiver,
|
||||||
|
stream_name.clone(),
|
||||||
) {
|
) {
|
||||||
match self.cc_info.heuristic {
|
match self.cc_info.heuristic {
|
||||||
WebRTCSinkCongestionControl::Disabled => {
|
WebRTCSinkCongestionControl::Disabled => {
|
||||||
|
@ -3459,6 +3464,37 @@ impl BaseWebRTCSink {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the caps of a sink pad can be changed from `current` to `new` without requiring a WebRTC renegotiation
|
||||||
|
fn input_caps_change_allowed(&self, current: &gst::CapsRef, new: &gst::CapsRef) -> bool {
|
||||||
|
let Some(current) = current.structure(0) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(new) = new.structure(0) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if current.name() != new.name() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut current = current.to_owned();
|
||||||
|
let mut new = new.to_owned();
|
||||||
|
|
||||||
|
// Allow changes of fields which should not be part of the SDP, and so can be updated without requiring
|
||||||
|
// a renegotiation.
|
||||||
|
let caps_type = current.name();
|
||||||
|
if caps_type.starts_with("video/") {
|
||||||
|
const VIDEO_ALLOWED_CHANGES: &[&str] = &["width", "height", "framerate"];
|
||||||
|
|
||||||
|
current.remove_fields(VIDEO_ALLOWED_CHANGES.iter().copied());
|
||||||
|
new.remove_fields(VIDEO_ALLOWED_CHANGES.iter().copied());
|
||||||
|
} else if caps_type.starts_with("audio/") {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
current == new
|
||||||
|
}
|
||||||
|
|
||||||
fn sink_event(
|
fn sink_event(
|
||||||
&self,
|
&self,
|
||||||
pad: &gst::Pad,
|
pad: &gst::Pad,
|
||||||
|
@ -3469,10 +3505,7 @@ impl BaseWebRTCSink {
|
||||||
|
|
||||||
if let EventView::Caps(e) = event.view() {
|
if let EventView::Caps(e) = event.view() {
|
||||||
if let Some(caps) = pad.current_caps() {
|
if let Some(caps) = pad.current_caps() {
|
||||||
if caps.is_strictly_equal(e.caps()) {
|
if !self.input_caps_change_allowed(&caps, e.caps()) {
|
||||||
// Nothing changed
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
gst::error!(
|
gst::error!(
|
||||||
CAT,
|
CAT,
|
||||||
obj: pad,
|
obj: pad,
|
||||||
|
@ -3482,29 +3515,40 @@ impl BaseWebRTCSink {
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
gst::info!(CAT, obj: pad, "Received caps event {:?}", e);
|
gst::info!(CAT, obj: pad, "Received caps event {:?}", e);
|
||||||
|
|
||||||
self.state
|
let mut state = self.state.lock().unwrap();
|
||||||
.lock()
|
|
||||||
.unwrap()
|
state.streams.iter_mut().for_each(|(_, stream)| {
|
||||||
.streams
|
if stream.sink_pad.upcast_ref::<gst::Pad>() == pad {
|
||||||
.iter_mut()
|
// We do not want VideoInfo to consider max-framerate
|
||||||
.for_each(|(_, stream)| {
|
// when computing fps, so we strip it away here
|
||||||
if stream.sink_pad.upcast_ref::<gst::Pad>() == pad {
|
let mut caps = e.caps().to_owned();
|
||||||
// We do not want VideoInfo to consider max-framerate
|
{
|
||||||
// when computing fps, so we strip it away here
|
let mut_caps = caps.get_mut().unwrap();
|
||||||
let mut caps = e.caps().to_owned();
|
if let Some(s) = mut_caps.structure_mut(0) {
|
||||||
{
|
if s.has_name("video/x-raw") {
|
||||||
let mut_caps = caps.get_mut().unwrap();
|
s.remove_field("max-framerate");
|
||||||
if let Some(s) = mut_caps.structure_mut(0) {
|
|
||||||
if s.has_name("video/x-raw") {
|
|
||||||
s.remove_field("max-framerate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stream.in_caps = Some(caps.to_owned());
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
stream.in_caps = Some(caps.to_owned());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Ok(video_info) = gst_video::VideoInfo::from_caps(e.caps()) {
|
||||||
|
// update video encoder info used when downscaling/downsampling the input
|
||||||
|
let stream_name = pad.name().to_string();
|
||||||
|
|
||||||
|
state
|
||||||
|
.sessions
|
||||||
|
.values_mut()
|
||||||
|
.flat_map(|session| session.unwrap_mut().encoders.iter_mut())
|
||||||
|
.filter(|encoder| encoder.stream_name == stream_name)
|
||||||
|
.for_each(|encoder| {
|
||||||
|
encoder.halved_framerate = video_info.fps().mul(gst::Fraction::new(1, 2));
|
||||||
|
encoder.video_info = video_info.clone();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue