Commit graph

13578 commits

Author SHA1 Message Date
Barnabás Pőcze
c80af0c2c0 spa: libcamera: source: remove impl::pendingRequests
The handling of `impl::pendingRequests` is a bit problematic because,
for example, during startup, if `spa_libcamera_buffer_recycle()` observes
that `impl::active == false`, then it will try to append to `impl::pendingRequests`,
which is being iterated in the main thread in `spa_libcamera_stream_on()`.
That is not allowed on an `std::deque`.

So instead remove it altogether, and simply queue all requests when starting.
After `libcamera::Camera::stop()` returns, every request is guaranteed not
to be used by libcamera, and they can be freely reused, so this is safe to do.

This also removes the need for calling `spa_libcamera_buffer_recycle()` when
the buffers are set/unset on a port since that function no longer changes
anything apart from updating `buffer::flags` but `spa_libcamera_alloc_buffers()`
is modified appropriately to take care of that. And in the case of
`spa_libcamera_clear_buffers()` clearing the flag is not required because the
next `spa_libcamera_alloc_buffers()` call will reset reset the flags.

(cherry picked from commit 68627c5563)
2025-09-27 13:22:59 +02:00
Barnabás Pőcze
ceb10964d3 spa: libcamera: source: persistent requests <-> buffer association
Currently only a single stream is used. This makes it easy to associate
each request with the appropriate frame buffer when it is created. In
turn, this makes reusing requests a bit simpler and a bit more efficient.

So do that: add buffers to requests when they are allocated in `allocBuffers()`.

(cherry picked from commit 475665d615)
2025-09-27 13:22:59 +02:00
Barnabás Pőcze
2dc1e2a5d3 spa: libcamera: source: allocBuffers(): more error checking
First, check if the request pool is empty, and signal an error if it
is not. Second, ensure that the number of allocated buffers matches.

(cherry picked from commit 29b0c87d71)
2025-09-27 13:22:58 +02:00
Barnabás Pőcze
98842d50cf spa: libcamera: source: allocBuffers(): restore on failure
Undo the allocation and clear the requests if a failure is encountered
in order to leave things in a known state.

(cherry picked from commit 348e703be0)
2025-09-27 13:22:58 +02:00
Barnabás Pőcze
b28eb20c1f spa: libcamera: source: freeBuffers(): call when format is unset
At the moment the libcamera buffer allocation is completely tied to format
negotiation. `freeBuffers()` undoes `allocBuffers()`. And `allocBuffers()`
is called as part of `spa_libcamera_set_format()`. Therefore `freeBuffers()`
should be called independent of the state of the buffers on any port.

Otherwise unsetting the format while there are no buffers on the port will
cause the libcamera requests and buffers not to be released correctly. Similarly,
removing the buffers from a port would clear the libcamera requests and buffers,
making the node unusable without setting a new format.

(cherry picked from commit b9b7c0ab05)
2025-09-27 13:22:58 +02:00
Barnabás Pőcze
a5cb888578 spa: libcamera: source: freeBuffers(): split pending request removal
`freeBuffers()` should undo exactly what `allocBuffers()` does. However,
it currently also clears `impl::pendingRequests`, but that is filled
by `spa_libcamera_buffer_recycle()` during `spa_libcamera_alloc_buffers()`.

So remove the clearing of `impl::pendingRequests` from `freeBuffers()` and
move it directly into `spa_libcamera_clear_buffers()`.

(cherry picked from commit 89545946fd)
2025-09-27 13:22:58 +02:00
Barnabás Pőcze
93426bca4b spa: libcamera: source: propagate error when setting format
If `spa_libcamera_set_format()` fails, propagate its return value
as is without rewriting it to `EINVAL`.

(cherry picked from commit 14e0a8f66f)
2025-09-27 13:22:58 +02:00
Barnabás Pőcze
ef09f436b3 spa: libcamera: source: port_set_format(): remove goto
Remove the `done` label by moving things into the `format != nullptr` branch.

(cherry picked from commit 47ee86938b)
2025-09-27 13:22:58 +02:00
Barnabás Pőcze
d76fee1353 spa: libcamera: source: use dynamic builder for controls
Use a dynamic spa pod builder when enumerating controls since previous
changes can report more information from any given control. Also increase
the stack buffer size to 4096 bytes.

(cherry picked from commit e6f767d41d)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
dbc376fc2f spa: libcamera: source: provide value labels if available
For enumerated controls of type `libcamera::ControlTypeInteger32`, libcamera
provides the names of the enumerators, so add them to `SPA_PROP_INFO_labels`.

(cherry picked from commit 8673f17c0a)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
9b638d37d1 spa: libcamera: source: handle enum controls better
If the `libcamera::ControlInfo` object explicitly lists the values of a
control, then use those values when adding `SPA_PROP_INFO_type` to
construct an enumerated choice object.

(cherry picked from commit e379267274)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
b8bbcfdb96 spa: libcamera: source: unify control range logic
If libcamera does not provide a default value, then the average of the
minimum and maximum values is taken. The same logic is duplicated for
`float` and `int32_t`, so move it into a function template.

(cherry picked from commit 8d9e469e09)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
337d3b3daf spa: libcamera: source: ignore array controls
Properly ignore array controls because they are not supported for now.

(cherry picked from commit e9367443ac)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
a1cc0f3d86 spa: libcamera: source: rework bool control type info
`SPA_POD_CHOICE_Bool()` assumes that both true and false are available,
which may not be the case for libcamera controls, so manualy construct
the enumerated choice object and only add the actually available options.

(cherry picked from commit 66cc01ee2d)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
f6d3db72a1 spa: libcamera: source: move control enumeration to loop
Remove the `goto`s and instead move everything into a loop.

(cherry picked from commit 44c05cfa7b)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
eb6b9a47fc spa: libcamera: source: separate type info generation
Add a new function `control_details_to_pod()` that builds a
`SPA_TYPE_OBJECT_PropInfo` object describing a libcamera control.

(cherry picked from commit cc187b035b)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
7b4713ec73 spa: libcamera: manager: keep libcamera::CameraManager
At the moment, the camera manager shared pointer is released when the last
listener is removed, and recreated when the first listener is added. This
is the same behaviour that the alsa and v4l2 monitors implement with their
respective udev, inotify monitors.

However, for `libcamera::CameraManager`, this is likely not the best way
for multiple reasons:

  (a) it is a complex object with significant construction and starting cost,
      which includes starting threads and usually loading shared libraries;
  (b) usually one listener is added right after creating, and it is removed
      right before destruction, in which there are real no advantages;
  (c) the camera manager, being a shared resource, might very well be kept
      alive by some other component, in which case there is again not much
      real benefit.

So simplify the code by getting a camera manager reference at the beginning
and keeping it until the libcamera monitor is destroyed.

This also fixes a race condition where a hot-plugged camera might not have
been detected if the libcamera event was emitted between these two:

  collect_existing_devices(impl);
  start_monitor(impl);

(cherry picked from commit 8614fc45f8)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
4847bb3faf spa: libcamera: manager: factor out hotplug event submission
The `impl::{add,remove}Camera` functions do the same thing except
for one value, the type of the hotplug event. Add a private method
to `impl` that implements the common parts.

(cherry picked from commit a36b8a273d)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
19d9bb7219 spa: libcamera: source: create eventfd before starting camera
An eventfd is used to signal the data loop from the libcamera request
completion event handler. Previously, this eventfd was created and
installed after the camera has been started and requests were queued.

This is problematic because it creates a small time frame where the
libcamera request completion handler will run in a state where the
eventfd is not fully set up.

Fix that by settup up the eventfd before the camera is started.

(cherry picked from commit e0e8bf083d)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
21a61b2194 spa: libcamera: source: generate camera config right away
Currently the plugin uses a single configuration during its entire lifetime.
So generate that configuration during initialization and hold on to it.

This makes the code a bit simpler, and also fixes issues stemming from missed
calls to `spa_libcamera_get_config()` as well as no error checking of
`libcamera::Camera::generateConfiguration()`.

(cherry picked from commit 49be2a1c52)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
1774249bdb spa: libcamera: source: remove SPA_PROP_device{,Name}
`SPA_PROP_deviceName` is an empty string and setting it does nothing.

`SPA_PROP_device` is always the libcamera identifier of the camera,
and setting it has no effect whatsoever in contrast to other plugins
such as v4l2.

So remove them both for now.

(cherry picked from commit 8c4f60af48)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
47aacb2a84 spa: libcamera: source: do not close fd
Currently the plugin does not support importing memory and uses
`libcamera::FrameBufferAllocator` to allocate memory. Every file
descriptor is managed by that object, so they must not be closed
manually.

(cherry picked from commit 429c0e03a3)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
192eab1fea spa: libcamera: source: remove unused enum_fmt member
This was introduced by b2c38a2b3b ("libcamera: work on rewrite"),
but it has never been used.

(cherry picked from commit c167b98ff2)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
a080a4a6f2 spa: libcamera: source: prop_id_to_control(): do range check first
If it is a custom spa property, it will not be found in the lookup
table, so we can return immediately.

(cherry picked from commit 30ce210c2a)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
b775acca60 spa: libcamera: source: fix mapping of libcamera::ColorSpace::TransferFunction::Linear
`SPA_VIDEO_TRANSFER_GAMMA10` should be used to represent a
linear transfer function.

Fixes: 7e202a3844 ("spa: libcamera: add colorimetry support")
(cherry picked from commit 07a4e593bb)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
db23d9fa04 spa: libcamera: source: simplify color space conversion
Instead of using an out parameter, just return the `spa_video_colorimetry`
object; and do the libcamera -> spa conversion in a single place, where
the data is actually added to the pod.

(cherry picked from commit 938195b19f)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
e770ed42c3 spa: libcamera: source: avoid iterator overrun when enumerating controls
Do not overrun the iterator when skipping the initial couple items.
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
c3fec9769c spa: libcamera: manager: fix id allocation
There is an issue in the id allocation mechanism which can result
in the different devices having the same id. Specifically, consider
the scenario where there are only two cameras, which have just been
added. In this case `impl::devices` looks like this:

   (0, camA) | (1, camB) | (?, nullptr) | ...

Now assume that `camA` is removed, after which the array appears
as follows:

  (1, camB) | (1, nullptr) | (?, nullptr) | ...

Then assume that a new camera appears. When `get_free_id()` runs,
when `i == 1`, it will observe that `devices[i].camera == nullptr`,
so it selects `1` as the id. Leading to the following:

  (1, camB) | (1, camC) | (?, nullptr) | ...

This is of course incorrect. The set of ids must be unique. When
wireplumber is faced with this situation it destroys the device
object for `camB` when `camC` is emitted.

Fix this by simply not moving elements in the `devices` array,
leaving everything where it is. In which case the array looks
like this:

  (nullptr) | (camB) | (nullptr) | ... // after `camA` removal
  (camC) | (camB) | (nullptr) | ... // after `camC` appearance

Note that `device::id` is removed, and the id is now derived from
the position in `impl::devices`.

(cherry picked from commit 2c2808fab1)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
0749851cfe spa: libcamera: use nullptr instead of NULL
(cherry picked from commit db3d91ebeb)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
a5ba04a8ba spa: libcamera: use C++ style casts
(cherry picked from commit 4fa11619a2)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
ea67bf1662 spa: libcamera: use anon ns instead of static
Move most things into anonymous namespaces for internal linkage
instead of using `static`. This shortes declarations and makes it
hard to forget.

(cherry picked from commit bb8223bff1)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
843dfe48b0 spa: libcamera: device: remove empty line
(cherry picked from commit cb71071d93)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
c22d9127e1 spa: libcamera: source: inline mmap_init()
The function has a single caller is essentially just a wrapper only
calling `mmap_init()`. So inline it into `spa_libcamera_alloc_buffers()`.

(cherry picked from commit e19a8bb5cd)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
5f77c729c2 spa: libcamera: source: set "corrupted" flag if applicable
If the libcamera `FrameMetadata` reports anything other than `FrameSuccess`,
then set `SPA_META_HEADER_FLAG_CORRUPTED`, notifying the application that
the frame may be unusable.

(cherry picked from commit 561a9d6ebb)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
7414d948ad spa: libcamera: source: use union for transferring control value
Use a union since only one member is active at a time, and use the
proper `libcamera::ControlType` enum to store the type instead of a
bare number. Also remove an unnecessary cast.

(cherry picked from commit 0022fc90b7)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
8181e2e051 spa: libcamera: source: simplify control mapping
Remove the `impl` parameter as it is not used, and use C++ range
based for loops.

(cherry picked from commit f94f4de6ff)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
bf1c57928b spa: libcamera: source: do not make expensive queries multiple times
`StreamFormats::pixelformats()` and `StreamFormats::sizes()` both
return newly created `std::vector`s, so do not call them multiple
times.

(cherry picked from commit 311b3cc37f)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
bdf904ebad spa: libcamera: source: simplify format lookup
Use range based for loops instead of indices.

(cherry picked from commit 489cc49937)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
d1eb5f6d20 spa: libcamera: source: use enum types
Use the appropriate enum types instead of bare `uint32_t`,
this provides better type safety in C++.

(cherry picked from commit 0ea7dc9f19)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
3dd413e131 spa: libcamera: source: handle camera acquire failure
Check the return value of `Camera::acquire()` and return the error
if that fails.

(cherry picked from commit f53ac8d57c)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
a233905f75 spa: libcamera: inline libcamera-utils.cpp
The file is not useful without `libcamera-source.cpp` because it
uses symbols only defined there. And being a non-self-contained
source file, it also breaks clangd. So move its contents directly
to `libcamera-source.cpp`. This makes the file about 2200 lines long,
but I feel that is still manageable (and it is by far not the longest).

(cherry picked from commit 1a1cf55efb)
2025-09-26 09:58:10 +02:00
Barnabás Pőcze
60d95e447a spa: libcamera: clean up includes
Remove some unnecessarily includes.

(cherry picked from commit 5a9cdd724f)
2025-09-19 05:35:47 +02:00
Barnabás Pőcze
de97a682f2 spa: libcamera: use lock when acquiring CameraManager
Make `libcamera_manager_acquire()` thread safe by locking a mutex
when the `CameraManager` instance is created and started.

(cherry picked from commit 5f4f4b5dd3)
2025-09-19 05:35:39 +02:00
Robert Mader
74bd520224 spa: libcamera: add colorimetry support
Libcamera equivalent to 41b831d0f ("spa: v4l2: add colorimetry support")

(cherry picked from commit 7e202a3844)
2025-09-19 05:35:23 +02:00
David Turner
8094cdf846 libcamera: Default to auto-focus & auto-exposure
libcamera says that cameras should default to manual focus mode.  This
means that unless pipewire clients specifically change this control,
users with an autofocus-capable camera are left with an out-of-focus
image.  This patch sets the autofocus mode to continuous and enables
auto-exposure (as the default for this is unspecified).

Testing with an imx708 on Raspberry Pi OS on a Raspberry Pi 4, before
this patch the image was generally out of focus in Firefox/webrtc, after
this patch autofocus works correctly.

(cherry picked from commit 3a0ffe21e6)
2025-09-19 05:34:37 +02:00
Wim Taymans
8f35e18d18 systemd: remove RestrictNamespaces from service file
Wireplumber loads the libcamera nodes into the pipewire server.
We need to remove the RestrictNamespaces option from the service file
to allow libcamera to load sandboxed IPA modules.
2025-09-17 10:29:35 +02:00
Wim Taymans
5212649ee1 control: fix event compare function
We can only compare UMP when both types are 2 or 4, so it must be
different from 2 *and* 4 to be rejected.

Fixes #4899
2025-09-17 10:29:15 +02:00
Wim Taymans
24ab601201 impl-node: only do unprepare once
There is not reason to do the unprepare logic twice and it might
actually interfere with the actions of the client.

See #4840
Fixes #4893
2025-09-15 10:33:14 +02:00
Wim Taymans
3e574b314a Revert "impl-node: improve the node unprepare function"
This reverts commit 839383d0dd.
2025-09-15 10:32:56 +02:00
Wim Taymans
8b43ed5c91 1.4.8 2025-09-11 10:12:34 +02:00