From 1e205c842e6834de18e80c3d5136fb55d2e01174 Mon Sep 17 00:00:00 2001 From: Jakub Adam Date: Wed, 21 May 2025 23:31:25 +0200 Subject: [PATCH] webrtcsink: Don't require encoder element for pre-encoded streams When webrtcsink takes as an input a stream that is already encoded, it errors out when there is no encoder element available for the codec in question. This change makes it possible to stream an output from a camera that already produces e.g. video/x-h264 without bloating the GStreamer installation with a redundant H.264 encoder element. Part-of: --- net/webrtc/src/utils.rs | 27 ++++++++++++++++++++++----- net/webrtc/src/webrtcsink/imp.rs | 3 ++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/net/webrtc/src/utils.rs b/net/webrtc/src/utils.rs index 382f338ea..85e52bbaf 100644 --- a/net/webrtc/src/utils.rs +++ b/net/webrtc/src/utils.rs @@ -464,9 +464,9 @@ impl Codec { let encoder = Self::get_encoder_for_caps(caps, encoders); let payloader = Self::get_payloader_for_codec(name, payloaders); - let encoding_info = if let (Some(encoder), Some(payloader)) = (encoder, payloader) { + let encoding_info = if let (encoder, Some(payloader)) = (encoder, payloader) { Some(EncodingInfo { - encoder: Some(encoder), + encoder, payloader, output_filter: None, }) @@ -828,6 +828,20 @@ impl Codecs { Self(codecs.values().cloned().collect()) } + pub fn list_encoders(&self) -> Codecs { + Codecs( + self.iter() + .filter(|codec| { + codec + .encoding_info + .as_ref() + .is_some_and(|info| info.encoder.is_some()) + }) + .cloned() + .collect(), + ) + } + pub fn find_for_payloadable_caps(&self, caps: &gst::Caps) -> Option { self.iter() .find(|codec| codec.caps.can_intersect(caps) && codec.encoding_info.is_some()) @@ -938,9 +952,12 @@ impl Codecs { .filter(|codec| codec.stream_type == gst::StreamType::AUDIO) } - /// List all codecs that can be used for encoding the given caps and assign - /// a payload type to each of them. This is useful to initiate SDP negotiation. - pub fn list_encoders<'a>(caps: impl IntoIterator) -> Codecs { + /// List all codecs that can be used for encoding and/or payloading the given + /// caps and assign a payload type to each of them. This is useful to initiate + /// SDP negotiation. + pub fn list_encoders_and_payloaders<'a>( + caps: impl IntoIterator, + ) -> Codecs { let mut payload = 96..128; Codecs( diff --git a/net/webrtc/src/webrtcsink/imp.rs b/net/webrtc/src/webrtcsink/imp.rs index 8d98376d1..bae4ad760 100644 --- a/net/webrtc/src/webrtcsink/imp.rs +++ b/net/webrtc/src/webrtcsink/imp.rs @@ -4080,6 +4080,7 @@ impl BaseWebRTCSink { codecs: &Codecs, ) -> Result<(), Error> { let futs = if has_raw_caps(&discovery_info.caps) { + let codecs = codecs.list_encoders(); if codecs.is_empty() { return Err(anyhow!( "No codec available for encoding stream {}, \ @@ -4331,7 +4332,7 @@ impl BaseWebRTCSink { } else { drop(state); let settings = self.settings.lock().unwrap(); - let codecs = Codecs::list_encoders( + let codecs = Codecs::list_encoders_and_payloaders( settings.video_caps.iter().chain(settings.audio_caps.iter()), );