This is a first step where we try to replicate encoding conditions from
the input stream into the discovery pipeline. A second patch will
implement using input buffers in the discovery pipelines.
This moves discovery to using input buffers directly. Instead of trying
to replicate buffers that `webrtcsink` is getting as input with testsrc,
directly run discovery based on the real buffers. This way we are sure
we work with the exact right stream type and we don't need encoders to
support encoding streams inputs.
We use the same logic for both encoded and raw input to avoid having
several code paths and makes it all more correct in any case.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1194>
In `webrtcsink`, we terminate a session by setting the session's pipeline to
`Null` like this:
```rust
pipeline.call_async(|pipeline| {
[...]
pipeline.set_state(gst::State::Null);
[...]
// the following cvar is awaited in unprepare()
cvar.notify_one();
});
```
However, `pipeline.call_async` keeps a ref on the pipeline until it's done,
which means the `cvar` is notified before `pipeline` is actually 'disposed',
which happens in a different thread than `unprepare`'s. [`gst_rtp_bin_dispose`]
releases some resources when the pipeline is unrefed. In some cases, those
resources are actually released after the main thread has returned, leading
various issues.
This commit uses tokio runtime's `spawn_blocking` instead, which allows owning
and disposing of the pipeline before the `cvar` is notified.
[`gst_rtp_bin_dispose`]: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.c#L3108
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1225>
This signal is emitted as soon as the pipeline for each consumer
is created, and can be used by applications that require a greater
level of control over webrtcsink's internals.
An example is also provided to demonstrate usage
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1220>
Adapt a commit [1] that was introduced as part of the forward port of the MR
'add signal "request-encoded-filter"' [2].
The deadlock said commit was fixing doesn't happen on main branch due to
changes in the element design: the Sessions are no longer aborted with the
element `State` held. However, we want to ensure the stats collection task
is terminated when the `webrtcbin` element returns from the Ready to Null
transition, meaning that the related resources are released.
[1]: gstreamer/gst-plugins-rs!1176 (0e6b9df9)
[2]: gstreamer/gst-plugins-rs!1176
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1222>
First off, we just created the session, we know stats_sigid is None
at this point.
Second, don't first assign the result of connecting on-new-ssrc to the
field, then the result of connection twcc-stats, that simply doesn't
make sense.
Finally, actually check that stats_sigid *is* None before connecting
twcc-stats, as I understand it this must have been the original
intention / behavior.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1217>
`State::finalize_session()` asynchronously sets the Session pipeline to Null.
In some cases, sessions `webrtcbin` could terminate their transition to Null
after `webrtcsink` had reached Null.
This commit adds a set of `finalizing_sessions`. When the finalization process
starts, the session is added to the set. After `webrtcbin` has reached the Null
state, the session is removed from the set and a condvar is notified.
In `unprepare`, `webrtcsink` loops until the `finalizing_sessions` set is
empty, awaiting for the condvar to be notified when it's not.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1221>
In certain cases, roundedcorners would negotiate to I420 even when user
supplied a non-zero border radius.
For example, the below pipeline leads to I420 being negotiated even
though a non-zero border radius was given. Ideally, this pipeline
should have failed at the negotiation stage.
```bash
gst-launch-1.0 -v \
videotestsrc num-buffers=1000 pattern=white ! \
video/x-raw,width=320,height=180 ! \
roundedcorners border-radius-px=10 ! videobox border-alpha=0 top=-10 left=-10 right=-10 bottom=-10 fill=yellow ! \
compositor name=comp sink_0::xpos=960 sink_0::ypos=0 sink_0::width=320 sink_0::height=180 sink_0::alpha=1.0 sink_1::xpos=960 sink_1::ypos=180 sink_1::width=320 sink_1::height=180 sink_1::alpha=1.0 \
sink_2::xpos=960 sink_2::ypos=360 sink_2::width=320 sink_2::height=180 sink_2::alpha=1.0 sink_3::xpos=0 sink_3::ypos=0 sink_3::width=960 sink_3::height=720 sink_3::alpha=1.0 ! \
video/x-raw,width=1280,height=720! x264enc ! mp4mux ! filesink location=test.mp4 \
videotestsrc num-buffers=1000 pattern=red ! \
video/x-raw,width=320,height=180 ! roundedcorners border-radius-px=10 ! comp. \
videotestsrc num-buffers=1000 pattern=blue ! \
video/x-raw,width=320,height=180 ! roundedcorners border-radius-px=10 ! comp. \
videotestsrc num-buffers=1000 pattern=green ! \
video/x-raw,width=960,height=720 ! roundedcorners border-radius-px=10 ! comp.
```
If border radius is non-zero, we should not really allow negotiation
to select I420. Fix this by returning only A420 for border-radius > 0
in `transform_caps` instead of returning both like earlier.
Another example of a simpler pipeline like below which would earlier work
```bash
gst-launch-1.0 videotestsrc pattern=red ! videoconvert ! video/x-raw,width=1923,height=1087,format=I420 ! roundedcorners border-radius-px=40 ! video/x-raw,format=I420 ! videoconvert ! gtksink
```
now fails with
```bash
WARNING: erroneous pipeline: could not link roundedcorners0 to videoconvert1, roundedcorners0 can't handle caps video/x-raw, format=(string)I420
```
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1211>
After calculating the earliest pts, the fragment_start_pts and
chunk_start_pts in State are updated. However, when checking if the
stream is filled, the previous start_pts (set to None) is used instead.
This means that chunk_filled and fragment_filled will be false the first
time aggregate() is called, assuming timeout is false, all_eos is false,
and the sinkpad is not EOS. This requires aggregate() having to be
called a second time before the first fragment is sent.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1207>
In some rare cases, the webrtc-test entered a deadlock while executing
`WebRTCSink::unprepare`. Attaching gdb to a blocked instance showed:
* `gstrswebrtc::signaller:👿:Signaller::stop()` parked, waiting for a
`Condvar` in `Signaller::stop()`. This was most likely awaiting for the
receive task to complete while it was locked in `element.end_session()`.
This code path is triggered from `unprepare` with the `State` `Mutex` locked.
* `webrtcsink:👿:WebRtcSink::process_stats` waiting for a contended `Mutex`,
which is also the `State` `Mutex`. This prevented completion of the signal
`gst_webrtc_bin_get_stats`.
This commit aborts the task in charge of periodically collecting stats and
ensures any remaining iteration completes before requesting the Signaller to
stop.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1202>