Can't make webrtcbin connect to H.264 offering clients

Neil Young foreverneilyoung at googlemail.com
Sun Aug 22 10:41:34 UTC 2021


Finally giving up on this. Python, webrtcbin and H.264 offer - this does not work



> Am 21.08.2021 um 20:23 schrieb Neil Young <foreverneilyoung at googlemail.com>:
> 
> I'm hanging on this for a week now, and it seems so easy, but whatever I do, I can't make it work
> 
> My app is a Python GST app, running on 18.4. It supports two modes: "call" and "answer". In call mode the app immediately issues an H.264 or VP8 OFFER (depending on a setting). This works in 100 % of the cases. 
> 
> What also works is when the app ANSWERs a VP8 offer. Just H.264 OFFERS are not working, even though the SDP answer looks good. I just don't get the video to remote.
> 
> My app works like so:
> 
> 1) When the app has a connection to the signaling server it creates a webrtcbin object:
> 
>     def build_webrtcbin(self):
>         self.webrtcbin = Gst.ElementFactory.make("webrtcbin")
>         self.webrtcbin.set_property("bundle-policy", "max-bundle")
>         self.webrtcbin.set_property("stun-server", "stun://stun.l.google.com:19302 <stun://stun.l.google.com:19302>")
>         self.webrtcbin.connect('on-negotiation-needed', self.on_negotiation_needed)
>         self.webrtcbin.connect('on-ice-candidate', self.on_ice_candidate)
>         self.webrtcbin.connect('pad-added', self.on_pad_added)
>         self.webrtcbin.connect('notify::connection-state', self.on_connection_state)
>         self.webrtcbin.connect('notify::signaling-state', self.on_signaling_state)
>         self.webrtcbin.connect('notify::ice-connection-state', self.on_ice_connection_state)
>         self.webrtcbin.connect('notify::ice-gathering-state', self.on_ice_gathering_state)
> 
>         self.pipeline = Gst.Pipeline.new()
>         self.pipeline.add(self.webrtcbin)
> 
> Nothing special I guess.
> 
> 2) When the SDP OFFER comes in, the app does this:
> 
> 2a) It starts the H.264 pipeline with `start_pipeline`. 
> 2b) It emits the remote description to the local webrtcbin
> 
> self.webrtcbin.emit('set-remote-description', desc, promise)
> 
> 2c) It creates an answer calling `self.create_answer()`
> 
>     def create_answer(self):
>         promise = Gst.Promise.new_with_change_func(self.on_answer_created, self.webrtcbin, None)
>         self.webrtcbin.emit('create-answer', None, promise)
>     
>     def on_answer_created(self, promise, _, __):
>         ''' Local WebRTC stack has created an answer '''
>         promise.wait()
>         reply = promise.get_reply()
>         answer = reply.get_value('answer')
>         promise = Gst.Promise.new()
>         self.webrtcbin.emit('set-local-description', answer, promise)
>         promise.interrupt()
>         self.send_sdp_answer(answer) # Forwarding the answer to remote using the signaling server
> 
> Observations so far:
> 
> - It doesn't work if I don't set a payload-type which matches a payload type carried by the OFFERER or if I omit the payload-type. With ALL browsers it is sufficient to use the payload-type carried by the first H.264 element in the OFFER
> - It is not necessary to set the `profile-level-id`
> 
> The best result I can achieve with this flow is a spinning wheel in the browser. No video.
> 
> BUT: 
> 
> When I issue a call to `start_pipeline` somewhere shortly after the start (I use the moment, when I have a connection with the signaling server for this) with _exactly_the_same_payload_type_that_will_match_later_, I 100% have a video...
> 
> This MUST be a side effect, because the log complains about the second `start_pipeline` (warnings, it seems to ignore it).... But it works. Of course this is not a working solution, because
> 
> a) I would have to know the payload-type beforehand (it doesn't work if I use another payload-type in the first start)
> b) I would have to parse the incoming SDP for the first H.264 (which is doable)
> 
> What am I doing wrong?
> 
> 
> 
> 
>     def start_pipeline(self, payload_type):
>         videotestsrc = Gst.ElementFactory.make("videotestsrc", "videotestsrc")
>         videotestsrc.set_property("is-live", True)
>         videotestsrc.set_property("pattern", "smpte")
> 
>         videotestsrc_caps = Gst.caps_from_string("video/x-raw, width=1280, height=720")
>       
>         videotestsrc_caps_filter = Gst.ElementFactory.make("capsfilter")
>         videotestsrc_caps_filter.set_property("caps", videotestsrc_caps)
> 
>         videoconvert = Gst.ElementFactory.make("videoconvert", "videoconvert")
> 
>         x264enc = Gst.ElementFactory.make("x264enc", "x264enc")
>         x264enc.set_property("threads", 4)
>     
>         x264enc_caps = Gst.caps_from_string("video/x-h264, profile=constrained-baseline")
> 
>         x264enc_caps_filter = Gst.ElementFactory.make("capsfilter")
>         x264enc_caps_filter.set_property("caps", x264enc_caps)
> 
>         rtph264pay = Gst.ElementFactory.make("rtph264pay", "rtph264pay")
>         rtph264pay.set_property("config-interval", -1)
>         rtph264pay.set_property("aggregate-mode", "zero-latency")
> 
>         rtph264pay_caps = Gst.caps_from_string("application/x-rtp, media=video, encoding-name=H264")
>         rtph264pay_caps.set_value("payload", payload_type)
> 
>         rtph264pay_caps_filter = Gst.ElementFactory.make("capsfilter")
>         rtph264pay_caps_filter.set_property("caps", rtph264pay_caps)
> 
>         self.pipeline.add(videotestsrc)
>         self.pipeline.add(videotestsrc_caps_filter)
>         self.pipeline.add(videoconvert)
>         self.pipeline.add(x264enc)
>         self.pipeline.add(x264enc_caps_filter)
>         self.pipeline.add(rtph264pay)
>         self.pipeline.add(rtph264pay_caps_filter)
> 
>         Gst.Element.link <http://gst.element.link/>(videotestsrc, videotestsrc_caps_filter)
>         Gst.Element.link <http://gst.element.link/>(videotestsrc_caps_filter, videoconvert)
>         Gst.Element.link <http://gst.element.link/>(videoconvert, x264enc)
>         Gst.Element.link <http://gst.element.link/>(x264enc, x264enc_caps_filter)
>         Gst.Element.link <http://gst.element.link/>(x264enc_caps_filter, rtph264pay)
>         Gst.Element.link <http://gst.element.link/>(rtph264pay, rtph264pay_caps_filter)
>         Gst.Element.link <http://gst.element.link/>(rtph264pay_caps_filter, self.webrtcbin)
>         self.pipeline.set_state(Gst.State.PLAYING)
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20210822/20bd51bd/attachment-0001.htm>


More information about the gstreamer-devel mailing list