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.
This commit is contained in:
David Turner 2025-06-09 13:22:35 +01:00 committed by Wim Taymans
parent 82229b3d87
commit 3a0ffe21e6
2 changed files with 29 additions and 1 deletions

View file

@ -163,6 +163,7 @@ struct impl {
struct spa_source source = {}; struct spa_source source = {};
ControlList ctrls; ControlList ctrls;
ControlList initial_controls;
bool active = false; bool active = false;
bool acquired = false; bool acquired = false;

View file

@ -16,6 +16,30 @@
#include <linux/media.h> #include <linux/media.h>
#include <libcamera/control_ids.h> #include <libcamera/control_ids.h>
static void setup_initial_controls(const ControlInfoMap& ctrl_infos, ControlList& ctrls)
{
/* Libcamera recommends cameras default to manual focus mode, but we don't
* expose any focus controls. So, specifically enable autofocus on
* cameras which support it. */
auto af_it = ctrl_infos.find(libcamera::controls::AF_MODE);
if (af_it != ctrl_infos.end()) {
const ControlInfo &ctrl_info = af_it->second;
auto is_af_continuous = [](const ControlValue &value) {
return value.get<int32_t>() == libcamera::controls::AfModeContinuous;
};
if (std::any_of(ctrl_info.values().begin(),
ctrl_info.values().end(), is_af_continuous)) {
ctrls.set(libcamera::controls::AF_MODE,
libcamera::controls::AfModeContinuous);
}
}
auto ae_it = ctrl_infos.find(libcamera::controls::AE_ENABLE);
if (ae_it != ctrl_infos.end()) {
ctrls.set(libcamera::controls::AE_ENABLE, true);
}
}
int spa_libcamera_open(struct impl *impl) int spa_libcamera_open(struct impl *impl)
{ {
if (impl->acquired) if (impl->acquired)
@ -26,6 +50,9 @@ int spa_libcamera_open(struct impl *impl)
impl->allocator = new FrameBufferAllocator(impl->camera); impl->allocator = new FrameBufferAllocator(impl->camera);
const ControlInfoMap &controls = impl->camera->controls();
setup_initial_controls(controls, impl->initial_controls);
impl->acquired = true; impl->acquired = true;
return 0; return 0;
} }
@ -990,7 +1017,7 @@ static int spa_libcamera_stream_on(struct impl *impl)
impl->camera->requestCompleted.connect(impl, &impl::requestComplete); impl->camera->requestCompleted.connect(impl, &impl::requestComplete);
spa_log_info(impl->log, "starting camera %s", impl->device_id.c_str()); spa_log_info(impl->log, "starting camera %s", impl->device_id.c_str());
if ((res = impl->camera->start()) < 0) if ((res = impl->camera->start(&impl->initial_controls)) < 0)
goto error; goto error;
for (Request *req : impl->pendingRequests) { for (Request *req : impl->pendingRequests) {