Counter-intuitive as it seems, when we are driving the clock, we can't
also provide a clock from PipeWire to the pipeline -- we need the
pipeline to drive the graph.
So we make the mode control whether we provide a clock or not.
In case of the video, if the buffer to be rendered is from upstream and
not from the pipewirepool, map the memory into video frames and copy the
frames instead of doing a buffer copy.
Avoid splitting of buffers in the case of video, because that might break
the frame layout, especially planar formats, for the applications which
use pipewiresink as a camera source to capture video.
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`
When we do any other blocking in the render function, we should unblock
and call _wait_preroll() when we go to PAUSED.
We can have this situation when all the buffers are queued in the
pw_stream and we get a new _render() call. We can't get more buffers
from the pool and so we must block and wait. When we go to PAUSED we
need to unlock and go to _wait_preroll(). Implement this by setting a
pool paused flag that is set when the sink goes to paused, we can then
return a special value that does the wait_preroll().
See !2248
Setting bufferpool to flushing state in PAUSED state is preventing the
buffer flow if there is a seek/flush event.
Instead, set the bufferpool to flushing during the `flush-start` event
and clear it during the `flush-stop`
Deactivate/activate the stream during flush event only if the sink is
in the PLAYING state. In the PAUSED or READY state, the stream would be
inactive and we do not want to alter that
flush the pw buffers to the stream's queue during a FLUSH_START event
and return the unqueued pw buffers, if they are dropped/released without
being rendered, so they can be available to be dequeued for the subsequent
`acquire` calls
For some streams, the buffer size is changed and may exceed
the acquired buffer size which is acquired from the pool of
pipewiresink. Need split buffer and send them in turn for
this case.
PipeWire expects the SPA_TYPE_OBJECT_ParamBuffers to be valid after
setting SPA_PARAM_Format. The pipewiresink knows the final buffer size
only after the pipewirepool has been activated.
There is a race between PipeWire asking the pipewiresink for the buffers
and GStreamer activating the buffer pool. If GStreamer has not activated
the buffer pool before PipeWire asks for the Buffer params, PipeWire
won't allocate buffers with the correct type and size.
The chance of hitting this window increases, if the upstream GStreamer
element doesn't use the buffer pool. In this case the buffer pool is
activated by the first buffer that arrives at the pipewiresink, which
may take some time.
Instead of not updating the Buffer params when the buffer pool is not
active, wait for the buffer pool to become active.
Add a helper function for updating the params instead of handling it in
the pool_activated callback. This allows to explicitly set the params
from the element.
Print the state of the stream not only as the numeric value, but also
print the name of the state to help the reader.
While at it, add the sink element to the log output to be able to
identify the sink that received the state change.
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
When the link on the pipewire side is destroyed, on video streams, buffers
are removed abruptly and there is no way this pipeline can be revived,
so let's post an element error to stop it.
On a normal shutdown, the pool is first set to flushing in change_state(),
so checking for the flushing state is a good indicator to know if this
is a normal shutdown or not.
See #1980
This is for readability and better control.
Make sure we clear out all pointers to anything related to the released
pw_buffer, including all the memories.
Both the GPtrArray and its contents are leaked in case of success.
`pw_stream_connect()` copies the params as needed, so use `g_autoptr()`
to free the array and with it, its contents.
Parse the audio rate from the caps and set this as the stream node.rate
property. This will try to switch the graph to this rate and avoids
resampling.
Rework some of the property handling.
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.
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.
GStreamer uses a time stamp for the decoding time, but PipeWire uses an
offset to the presentation time. Thus, the pipewiresink must not use the
DTS as dts_offset, but has to calculate the offset.
If the buffer's DTS is invalid, assume that dts is pts.
Tabs and spaces are mixed for indentation in the pipewiresink. Replace
all tabs with 8 spaces although indentation is 2 spaces, since that
looks like the intended indent.
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.
For encoded formats, buffer size is the size of the actual data in the
buffer and may change for each frame depending on the content. Thus,
configuring the buffer pool of the pipewiresrc with the size of the
first buffer may be insufficient for later buffers.
Configure the buffer pool to the maximum size of the first upstream
buffer and assume that the following buffers will be allocated with the
same size as the first buffer.
If the pipewiresink needs to copy the GStreamer buffers to the PipeWire
buffers, because the upstream element didn't use the pipewirepool, the
metadata must be copied, too. Otherwise the pipewire datas will be
filled with the metadata from the buffer during the initialization and
not the currently used buffer.
For example, without copying the metadata the buffer timestamp will be
missing on the pipewire buffers.
The offset in GstVideoMeta point to location of merge-mapped buffer memories (see "gst_buffer_find_memory()") instead of raw memory location for each plane, make adjustment to comply this rule.
Also some cleanups.
Fixes 023577e391