Commit graph

162 commits

Author SHA1 Message Date
Robert Mader
e8ae244b2b gst: src: Promote 'set format' log to info
Follow various other elements like glupload and gtk4paintablesink and
print the negotiated caps at a higher priority than debug. A small
quality of life improvement to facilitate debugging.
2025-08-13 22:41:38 +02:00
Wim Taymans
e317edcfb9 pod: rework the parser
Make a new body.h file with some functions to deal with pod and their
body. Make the iter.h functions use mostly this.

Rework the parser so that it only uses body.h functions. With the separation
of pod+body, we can read and verify the pod once and then use the
verified copy to handle the rest of the body safely.

We do this because iter.h only works in pods in memory that doesn't change
because it is vulnerable to modifications of the data after verifying it.

The new parser is not vulnerable to this and will not cause invalid
memory access when used on shared memory. There is however no need for
atomic operations to read the headers, whever is read is either valid
and useable of invalid and rejected.

See #4822
2025-07-29 15:15:02 +02:00
Arun Raghavan
51d4d5ec3c gst: pipewiresrc: Expose cursor position as a ROI meta 2025-07-11 11:57:59 -04:00
Elliot Chen
43441a4d69 pipewiresrc: fix sending last buffer failure if waiting operation exits in advance 2025-06-23 16:16:13 +00:00
Elliot Chen
72e0fe0479 pipewiresrc: add provide clock property 2025-06-13 08:10:20 +00:00
Robert Mader
e81fb77322 gst: src: Change DEFAULT_MIN_BUFFERS back to 1
The change from 1 to 8 was done without justification in the commit
message and possibly for debug purposes. Unfortunately it breaks
negotiation with the libcamera virtual pipeline, which defaults to
4 buffers.

Set the the value to 1 again as successful negotiation - even with an
unusually low number of buffers - is usually more desirable than an
error.

Fixes: 98b7dc7c0 ("gst: don't do set_caps from the pipewire callback")
2025-05-25 04:03:06 +02:00
Philippe Normand
2e409c0237 gst: src: Attach video meta when receiving DMABufs from PipeWire
Fixes getDisplayMedia() in WebKitGTK after regression introduced by:
https://gitlab.freedesktop.org/pipewire/pipewire/-/merge_requests/2330
2025-04-22 10:48:00 +01:00
Arun Raghavan
ebe9381236 gst: handle blocks and size allocation for encoded format
In case of encoded video we get n_planes as 0 from the video info so
passing that as n_datas is failing during the buffer negotiation. Make
sure to use an appropriate value based on whether we have raw video or
not.

Co-authored-by: Taruntej Kanakamalla <taruntej@asymptotic.io>
2025-04-17 15:21:38 -04:00
Sanchayan Maity
bb1bb07f6c gstpipewiresrc: Handle stream being disconnected
When PW source is used with something like Camera and the camera is
disconnected, all buffers are removed and stream will be paused.

When using PW sink with source, the sink side pipeline can go to EOS.
This again results in all the buffers being removed and stream being
paused on the source side. PW source side pipeline can also crash if
the sink was in the middle of frame copying a buffer to render which
got removed.

Handle this scenario by sending a flush-start event at the start of
buffer removal and flush-stop at the end followed by an end of stream
or pipeline error depending on user selection.
2025-04-09 07:45:27 +00:00
Sanchayan Maity
77143e54d9 gstpipewiresrc: Fix re-linking for audio
For a pipeline like below, we might want to dynamically switch the audio
source.

gst-launch-1.0 -e pipewiresrc autoconnect=false ! queue ! audioconvert ! autoaudiosink

On switching to a different audio source, any one of driver, quantum
or clock rate might change which changes the return `result` value of
gst_pipewire_clock_get_internal_time.

This can result in the basesrc create function incorrectly waiting in
gst_clock_id_wait. We post clock lost message to fix this. In the case
of gst-launch, it will set the pipeline to PAUSED and then PLAYING to
to force a new clock and a new base_time distribution.

Without the clock lost message, the following can be seen

before re-linking to a different source
0:00:30.887602864 79499 0x7fffe8000d40 DEBUG              GST_CLOCK gstsystemclock.c:1158:gst_system_clock_id_wait_jitter_unlocked:<pipewireclock0> entry 0x7fffd803fad0 time 0:00:17.024565416 now 0:00:17.024109144 diff (time-now) 456272

after re-linking to a different source
0:00:45.790843245 79499 0x7fffe8000d40 DEBUG              GST_CLOCK gstsystemclock.c:1158:gst_system_clock_id_wait_jitter_unlocked:<pipewireclock0> entry 0x7fffd803fad0 time 0:00:31.927694059 now 0:00:17.066883864 diff (time-now) 14860810195

With the clock lost message, the following can be seen

before re-linking to a different source
0:01:09.336533552 89461 0x7fffe8000d40 DEBUG              GST_CLOCK gstsystemclock.c:1158:gst_system_clock_id_wait_jitter_unlocked:<pipewireclock0> entry 0x7fffd803fad0 time 0:00:58.198536772 now 0:00:58.197444926 diff (time-now) 1091846

after re-linking to a different source
0:01:21.659827958 89461 0x7fffe8000d40 DEBUG              GST_CLOCK gstsystemclock.c:1158:gst_system_clock_id_wait_jitter_unlocked:<pipewireclock0> entry 0x7fffd803fad0 time 0:28:24.853517646 now 0:28:24.853527204 diff (time-now) -9558

Note the difference in `time` and `now` fields of the above log message.

This is easy to reproduce by using a pipewiresink as the audio source
with a pipeline like below, as one of the sources during switching.

gst-launch-1.0 -e audiotestsrc wave=ticks ! audioconvert ! audio/x-raw,format=F32LE,rate=48000,channels=1 !
pipewiresink stream-properties="props,media.class=Audio/Source,node.description=pwsink" client-name=pwsink

Applications need to handle the GST_MESSAGE_CLOCK_LOST message in their
bus handlers.
2025-04-03 19:20:34 +05:30
Wim Taymans
5f4c0cdd1e improve debug and error reporting a little 2025-03-28 16:08:57 +01:00
Wim Taymans
afb4a2f49c Revert "gst: src: Minor fix for offsets"
This reverts commit 4c200183b9.

The offset is already applied when we share/copy the memory in the
target buffer.
2025-03-26 17:56:14 +01:00
Arun Raghavan
4c200183b9 gst: src: Minor fix for offsets
I don't see any actual usage of left/top padding (yet), but we should
account for chunk offset in addition to the overall size.
2025-03-26 09:26:38 -04:00
Wim Taymans
cc6081b70d gst: fix video metadata offsets
The offsets in GStreamer are always offsets into the buffer memory where
the plane starts so set this to the accumulated plane sizes.
2025-03-26 12:30:41 +01:00
Wim Taymans
5fb9716ce7 gst: require a buffer size of at least 1
Setting the default size to 0 and outside of the min/max range now means
that there is no suggestion for the size and it should use the
suggestion of the peer.
2025-03-26 09:52:22 +01:00
Sanchayan Maity
3c62d29a55 gstpipewiresrc: Fix re-linking
When using PW source, one might want to dynamically link PW source to
a different source. Setting possible_caps to NULL prevents the caps
intersect from returning a successful result on format change. Do not
set possible_caps to NULL as we get that from peer caps which should
stay the same ideally for the duration of pipeline run. That allows
re-linking PW source any number of times with a pipeline like below.

gst-launch-1.0 pipewiresrc autoconnect=false ! queue ! video/x-raw,format=YUY2 ! videoconvert ! xvimagesink

The above pipeline can be made to switch between a camera source and a
screen capture source like wf-recorder.

Note that this fix only improves the status quo and won't work if the
peer caps change due to a re-negotiation.
2025-03-25 17:49:13 +00:00
Sanchayan Maity
eb534b4515 gst: pipewiresrc: Fixate caps if intersect did not return fixated caps
We might end up in a situation where depending on the pipeline,
intersect might not give us fixated caps.

Possible example of such a pipeline can be below.

gst-launch-1.0 -e pipewiresrc target-object=<path> ! audioconvert !
audio/x-raw,format=S16LE,rate=48000,channels=2 ! lamemp3enc !
filesink location=test.mp3

This results in non-fixated caps like below when intersecting caps from
format param and possible_caps which depends on what we have downstream
in the pipeline.

audio/x-raw, layout=(string)interleaved, format=(string)S16LE, rate=(int)48000, channels=(int)2, channel-mask=(bitmask)0x0000000000000003;
audio/x-raw, layout=(string)interleaved, format=(string)S16LE, rate=(int)48000, channels=(int)2

To fix this, fixate the caps explicitly.
2025-03-25 15:47:28 +00:00
Philippe Normand
e584cee066 gst: src: Fix buffer pool handling in case of caps renegotiation
In case negotiation is first attempted with unfixed caps, bufferpool support was
unconditionally disabled. Then at a second caps negotiation attempt it wasn't
restored according to the property value.
2025-03-25 12:50:42 +00:00
Sanchayan Maity
6c9ada270b gst: Fix handling of video planar formats
Tiled formats are not tested and supported yet.
2025-03-13 18:53:23 +05:30
Taruntej Kanakamalla
333b5aaa36 gst: don't use bufferpool for audio by default
Deprecate the `always-copy` property in pipewiresrc and use the new
property `use-bufferpool` in both pipewiresrc and pipewiresink to
specify whether to use the gstpipewirepool or not.

The gstpipewirepool is used for video by default unless `use-bufferpool`
is set to `false` and it is not used for audio by default unless
`use-bufferpool` is set to `true`
2025-02-03 17:22:34 +00:00
Olle Axelsson
1cc00923db gst: Ensure possible_caps exists before comparing caps
During negotiation, ensure that possible_caps exists before calling
gst_caps_intersect_full(). Sometimes possible_caps seem to be NULL which
cause the GST_IS_CAPS assert to fail.

The reason for the occasional NULL possible_caps during initial
negotiation is unknown, but this is also possible during renegotiation.
The handle_format_change() may be triggered before the next create(),
win which case we have not yet discovered in the streaming thread that
we are in the NOT_NEGOTIATED state. We should guard against this
possibility as well.
2025-01-30 13:38:55 -05:00
Arun Raghavan
85fa0aae40 gst: src: Set possible_caps before stream connect
The value is used when a the format changes in handle_format_change(),
and while it seems this was typically expected to happen async and thus
protected by the thread lock, there are cases (such as with
auto-port-config) where a param might be set within the
pw_stream_connect() call itself (in the case of auto-port-config, by the
impl_init() of the audioadapter).
2024-12-13 13:44:09 +00:00
Taruntej Kanakamalla
922efaf6ed gst: drop empty buffers in pipewiresrc
In case the dequeued buffer is empty or of size 0, skip the buffer
so that the downstream elements do not report an error
2024-12-02 14:15:23 +05:30
Wim Taymans
bebad7888f gst: take the thread lock before calling pw_stream functions 2024-11-08 12:22:35 +01:00
Robert Mader
226440382b gst: src: Reset transform on stream stop
When a stream is stopped, chances are high that downstream elements
change or get reset, i.e. don't remember a previously send rotation
event. Thus reset the transform value in order to ensure we create a new
one on the next stream start.

In order to not regress the case when downstream *does* remember the
orientation and the buffer orientation changes from e.g.
`TRANSFORMATION_90` to `TRANSFORMATION_None` between stream
stop and restart, initialize the remembered transform to an invalid
value and ensure we always send a rotation event, even for
`TRANSFORMATION_None`.
2024-07-02 15:15:05 +02:00
Robert Rosengren
3cbda26f07 gst: src: disable active state when only going to PAUSED
The pipewiresrc starts the stream in active state but should be inactive
if only going to PAUSED state. This patch sets the stream to inactive
when wait_started has returned in the GStreamer state tranistions.

Also resets internal started state when going PAUSED -> READY.

Fixes #4049
2024-06-17 15:11:48 +02:00
Michael Tretter
a9bf5fa24a gst: fix JPEG format
Since commit f400ff2050 ("gst: Check for video/ caps before parsing
for info") JPEG support in the GStreamer elements is broken as JPEG is
not recognized as a video format anymore.

gst_video_info_from_caps is able to handle "video/" and "image/"
formats. Therefore, the check needs to allow "image/" too.

While at it, cleanup the formatting to make the check more readable.
2024-06-12 06:56:03 +00:00
Michael Tretter
3b68b5088b gst: pipewiresrc: move correct brace under HAVE_GSTREAMER_DMA_DRM
The HAVE_GSTREAMER_DMA_DRM belongs to the inner brace, not the outer
brace, since the inner if statement is under HAVE_GSTREAMER_DMA_DRM.

While doesn't make a difference to the compiler, but confuses a reader.

Put the other brace under the HAVE_GSTREAMER_DMA_DRM.
2024-06-12 06:56:03 +00:00
George Kiagiadakis
0c40c01477 gst: factor out the stream management and some common variables in a new class
Construct this new class from both the src and sink to be able to share code

Consolidate the previous mess of open/close/start/stop into a single pair
of open/close functions in the new stream class
2024-06-11 12:51:51 +00:00
Robert Mader
e6f2aa6ce0 gst: src: Improve DMA_DRM caps selection
The translation between Pipewire parameters and Gstreamer caps is,
for compatibility reasons, ambiguous. Formats with linear modifier
are translated both in the legacy way as `format`, as well as
`drm-format`.

When finishing negotiation and setting caps, ensure that we:
1. set caps that the peer actually supports in order to prevent
   negotiation errors.
2. fixate caps to DMA_DRM if both options are supported, using the newly
   introduced helper, in order to prevent hangs.

While on it, add some small clean-ups that hopefully make the code
easier to follow, notably that `pwsrc->caps` and `pwsrc->possible_caps`
are only used during negotiation.
2024-05-29 19:29:02 +02:00
Robert Mader
adead74e8c gst: src: Indentation fix
Fixes: f400ff205 (gst: Check for video/ caps before parsing for info)
2024-05-29 18:52:06 +02:00
Arun Raghavan
1e3797512a gst/src: Check for 0 framerate before setting duration
This is possible if the source doesn't provide the framerate (as is the
case for libcamera), or if the framerate is variable (0/1).
2024-05-28 13:47:30 +03:00
Arun Raghavan
3cc5ca5a91 gst/src: Set buffer duration
We compute this from the clock quantum for audio and the negotiated
framerate for video.

Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1438
2024-05-28 08:18:47 +00:00
Arun Raghavan
f400ff2050 gst: Check for video/ caps before parsing for info
The gst_video_info_from_caps() API isn't really intended to be used as a
check-for-videoness function (it generates an error-level GStreamer
debug message when used this way).

We check the caps for a video/ name for this reason, which is
functionally equivalent.
2024-05-27 16:01:24 +03:00
Robert Rosengren
95127d8a18 gst/src: fix crash when current_caps is NULL
gst_pad_get_current_caps may return NULL and passing that into
gst_caps_is_equal may result in fatal critical log due to the
"g_return_val_if_fail (GST_IS_CAPS (caps1)" check. Fix by checking for
NULL to avoid this.
2024-04-10 09:17:14 +00:00
Robert Mader
e2e8cf7944 gst/src: Avoid unnecessary renegotiations during streaming
Some clients like many camera apps, including Cheese or Snapshot,
trigger a lot of unnessecary renegotiations. While arguably that should
be solved on a Gstreamer level, we can help out by checking if the
preferred new caps are the same that are already in use and skip the
renegotiation in this case.

This allows several apps to e.g. take pictures without a slow and heavy
stream restart.
2024-03-31 11:03:13 +00:00
Robert Mader
594e3fa09f gst/src: Cleanups for src_negotiate()
Using `g_autoptr` and related modern helpers more often makes
the code smaller, easier to follow and maintain.
No behavior changes intended.
2024-03-31 11:03:13 +00:00
Wim Taymans
2c0d73ab49 gst: handle latency in the pipewiresrc
Get the delay in the graph and subtract this from the cycle start time
to get the timestamp of the buffer.

Report this latency as well.

Fixes #30
2024-03-15 17:31:43 +01:00
Wim Taymans
1fe498560b gst: refactor some of the param handling
Clear the caps when the param is NULL.
2024-03-15 17:31:05 +01:00
Wim Taymans
a69e2ecda5 gst: fall back to buffer time when no header
This at least sets some form of timestamp on the buffers.
2024-03-15 12:10:40 +01:00
Robert Mader
1a6bb994a5 gst: Fix sanitization of non-writable caps
`gst_caps_make_writable()` may create a copy which we have to keep
using afterwards. The return value was meant to be used for that,
but was promptly forgotten for the initial user.
Avoid such errors in the future by using an in-out parameter instead.

While on it, add a type check and remove a check for an impossible
condition.

Fixes: 8a271a87b ("gst: Sanitize caps before translating")
2024-03-07 17:16:18 +00:00
Antonio Larrosa
2df931483d Specify "Audio" in gstreamer sink/src metadata to fix autodetect
gst-play uses autoaudiosink by default when playing audio, which
iterates over all sinks sorting them by rank. By default,
pipewiresink sets the rank to 0, but it can be overridden
by setting the GST_PLUGIN_FEATURE_RANK env. var. like this:

`GST_PLUGIN_FEATURE_RANK=pipewiresink:268 gst-play-1.0  /usr/share/sounds/alsa/test.wav`

But that doesn't work either because the autoaudiosink plugin also
filters the available options, testing for "Sink" and "Audio" to
appear in the classification metadata

(in the strstr comparison in
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/subprojects/gst-plugins-good/gst/autodetect/gstautodetect.c?ref_type=heads#L220
klass is what's set by pipewire as classification,
self->type_klass is "Sink" and self->media_klass is "Audio")

Just adding the word Audio to the classification metadata fixes
this and allows pipewiresink to be selected by autoaudiosink.

I also set it in the source plugin since looking at the code,
autoaudiosrc works exactly the same.
2024-03-07 17:15:20 +00:00
Robert Mader
8a271a87b7 gst: Sanitize caps before translating
DMABuf caps without concrete formats and modifiers don't map well to the
Pipewire negotiation process.
Introduce a new gst_caps_sanitize() helper function, where such cases
can be handled.
2024-03-05 12:08:32 +01:00
Robert Mader
f1b75fc6f8 gst: Add support for DMA_DRM / explicit modifiers
Gstreamer 1.24 added and largely switched to a new, modifier aware
DMABuf API. Unfortunately that breaks the existing DMABuf support in the
PW Gst element.

Add support for the new API.
2024-03-05 12:08:32 +01:00
Wim Taymans
0f14cc3b13 gst: remove timeouts when autoconnect=false
When we disable autoconnect, disable the timeouts as well. Otherwise the
user has to connect the stream within the 30 second timeout or get a
failure. With autoconnect we can reasonably assume there is a problem
when the stream is not connected after 30 seconds.

Fixes #3884
2024-03-01 10:29:18 +01:00
George Kiagiadakis
5a130ddd73 gstpipewiresrc: break out of wait_started() also on STATE_UNCONNECTED
When the session manager sends an error to the client, it typically
also destroys the node after the error, which causes the stream to go
to STATE_UNCONNECTED via proxy_removed(). In that case, make sure
we exit the loop early, otherwise it will take 30 seconds to unblock
gst_element_set_state()

This is a revised version of the fix that was commited via !1763
and then reverted, as it was problematic. Now the code ensures
that it breaks out only if the state was previously CONNECTING
or higher.
2023-12-26 16:01:44 +00:00
Wim Taymans
aef99f840f Revert "gstpipewiresrc: break out of wait_started() also on STATE_UNCONNECTED"
This reverts commit 7465175ad0.

wait_started() is called before the stream is connecting and so
exits with an error immediately, which then makes the stream start
too early and block.
2023-11-16 09:51:11 +01:00
George Kiagiadakis
7465175ad0 gstpipewiresrc: break out of wait_started() also on STATE_UNCONNECTED
When the session manager sends an error to the client, it typically
also destroys the node after the error, which causes the stream to go
to STATE_UNCONNECTED via proxy_removed(). In that case, make sure
we exit the loop early, otherwise it will take 30 seconds to unblock
gst_element_set_state()
2023-11-09 20:59:40 +00:00
George Kiagiadakis
a852b979b6 gst: avoid reporting error twice
First, make the error permanent by calling pw_stream_set_error()
and when this emits an error state again, report that to GStreamer.

Do the same in pipewiresink, which didn't even have the
pw_stream_set_error() call before, so the stream wasn't really going
into an error state at all.
2023-11-09 20:59:40 +00:00
Wim Taymans
bdb7f3adc8 gst: don't stop streaming when paused
We pause when we are unlinked, don't stop the streaming thread because
then we won't be able to resume when we are linked again.

Fixes #3620
2023-11-02 10:06:03 +01:00