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.
For enumerated controls of type `libcamera::ControlTypeInteger32`, libcamera
provides the names of the enumerators, so add them to `SPA_PROP_INFO_labels`.
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.
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.
`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.
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);
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.
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.
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()`.
`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.
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.
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.
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`.
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.
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.
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).
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.
When we simply need to change some state for the code executed in the
loop, we can use locked() instead of invoke(). This is more efficient
and avoids some context switches in the normal case.
Add an index offset when enumerating controls. We insert 2 properties
before enumerating the controls so the index of the first control needs
to have an offset of 2.
Some complex camera pipelines, like the IPU6 can involve many /dev/video#
nodes (32 in the IPU6 case) and the current size of 128 chars is not enough
to hold all /dev/video# nodes in this cases causing SPA_KEY_DEVICE_DEVIDS
to get truncated, which in turn breaks the filtering of V4L2 devices which
are used by a libcamera driven camera in wireplumber.
Fix this by increasing the size of devices_str[] to 256.
This fixes wireplumber adding a bunch of non-function V4L2 video sources,
e.g. before this "wpctl status" outputs the following video sources:
Video
├─ Devices:
...
├─ Sources:
│ 90. ov2740
│ * 115. ipu6 (V4L2)
...
│ 135. ipu6 (V4L2)
│
├─ Filters:
After this fix the output is:
Video
├─ Devices:
...
├─ Sources:
│ * 92. ov2740
│
├─ Filters:
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
When using Open Broadcaster Software with Pipewire and a libcamera
camera node, changing the ExposureTime doesn't work.
The commit introducing the camera control setting has commented out the
integer case: ef4b9745b2 ("libcamera: handle canceled requests")
But as it doesn't give a reson for the comment, it looks like an
oversight.
Therefore removing the comment to allow setting the ExposureTime integer.
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>