Message ID | 20250828-flash-support-v1-2-4c5dc674a05b@emfend.at |
---|---|
State | New |
Headers | show |
Series |
|
Related | show |
Hi 2025. 08. 28. 15:09 keltezéssel, Matthias Fend írta: > Add a class to model camera flash devices. Currently, only v4l2 flash > devices are supported. The v4l2 flash devices are implemented similar to > the camera lenses. > > Signed-off-by: Matthias Fend <matthias.fend@emfend.at> > --- > include/libcamera/internal/camera_flash.h | 75 ++++++++ > include/libcamera/internal/camera_sensor.h | 2 + > src/libcamera/camera_flash.cpp | 248 ++++++++++++++++++++++++++ > src/libcamera/meson.build | 1 + > src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ > src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ > 6 files changed, 352 insertions(+) > > diff --git a/include/libcamera/internal/camera_flash.h b/include/libcamera/internal/camera_flash.h > new file mode 100644 > index 0000000000000000000000000000000000000000..e41afef2ab84852a340a12a012e3994f00cac27a > --- /dev/null > +++ b/include/libcamera/internal/camera_flash.h > @@ -0,0 +1,75 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2025, matthias.fend@emfend.at > + * > + * Camera flash support > + */ > +#pragma once > + > +#include <memory> > +#include <stdint.h> > +#include <string> > + > +#include <libcamera/base/class.h> > +#include <libcamera/base/log.h> > + > +#include <libcamera/controls.h> > + > +namespace libcamera { > + > +class MediaEntity; > +class V4L2Subdevice; > + > +class CameraFlash : protected Loggable > +{ > +public: > + enum Mode { > + None, > + Flash, > + Torch, > + }; > + > + enum StrobeSource { > + Software, > + External, > + }; I think instead of defining these again, you should use the generated enums from `control_ids.h` since the return values of `getMode()` and `getStrobeSource()` are directly set as the value for `controls::draft::Flash{Mode,StrobeSource}`. Or at the very least some `static_assert()`s would be good. But I think using the generated enumerators would be preferable. > + > + explicit CameraFlash(const MediaEntity *entity); > + ~CameraFlash(); > + int init(); > + Mode getMode() const; > + int setMode(Mode mode); > + const ControlInfo &getFlashIntensityInfo() const; > + int32_t getFlashIntensity() const; > + int setFlashIntensity(int32_t intensity); > + const ControlInfo &getFlashTimeoutInfo() const; > + int32_t getFlashTimeout() const; > + int setFlashTimeout(int32_t timeout_us); > + StrobeSource getStrobeSource() const; > + int setStrobeSource(StrobeSource source); > + int startStrobe(); > + int stopStrobe(); > + const ControlInfo &getTorchIntensityInfo() const; > + int32_t getTorchIntensity() const; > + int setTorchIntensity(int32_t intensity); > + > + const std::string &model() const; > + const ControlInfoMap &controls() const; > + > +protected: > + std::string logPrefix() const override; > + > +private: > + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash) > + > + int32_t getSubdevControl(uint32_t id) const; > + int setSubdevControl(uint32_t id, int32_t value); > + int validateDriver(); > + > + const MediaEntity *entity_; > + std::unique_ptr<V4L2Subdevice> subdev_; > + std::string model_; > + const ControlInfoMap *controlInfoMap_ = nullptr; What is the motivation for caching this value? > +}; > + > +} /* namespace libcamera */ > diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h > index f6ef4df170d43500bc652762e9a575010a6c1cbd..faeecf244c8d42a43eca52ae04813e0c2f80e516 100644 > --- a/include/libcamera/internal/camera_sensor.h > +++ b/include/libcamera/internal/camera_sensor.h > @@ -28,6 +28,7 @@ > > namespace libcamera { > > +class CameraFlash; > class CameraLens; > class MediaEntity; > class SensorConfiguration; > @@ -48,6 +49,7 @@ public: > virtual V4L2Subdevice *device() = 0; > > virtual CameraLens *focusLens() = 0; > + virtual CameraFlash *flash() = 0; > > virtual const std::vector<unsigned int> &mbusCodes() const = 0; > virtual std::vector<Size> sizes(unsigned int mbusCode) const = 0; > diff --git a/src/libcamera/camera_flash.cpp b/src/libcamera/camera_flash.cpp > new file mode 100644 > index 0000000000000000000000000000000000000000..4702c590c91e0bcb20d173e7ce03608e1ae6ecfd > --- /dev/null > +++ b/src/libcamera/camera_flash.cpp > @@ -0,0 +1,248 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2025, matthias.fend@emfend.at > + * > + * Camera flash support > + */ > + > +#include "libcamera/internal/camera_flash.h" > + > +#include <libcamera/base/utils.h> > + > +#include "libcamera/internal/v4l2_subdevice.h" > + > +namespace libcamera { > + > +LOG_DEFINE_CATEGORY(CameraFlash) > + > +CameraFlash::CameraFlash(const MediaEntity *entity) > + : entity_(entity) > +{ > +} > + > +CameraFlash::~CameraFlash() = default; > + > +int CameraFlash::init() > +{ > + if (entity_->function() != MEDIA_ENT_F_FLASH) { > + LOG(CameraFlash, Error) > + << "Invalid flash function " > + << utils::hex(entity_->function()); > + return -EINVAL; > + } > + > + subdev_ = std::make_unique<V4L2Subdevice>(entity_); > + int ret = subdev_->open(); > + if (ret < 0) > + return ret; > + > + controlInfoMap_ = &subdev_->controls(); > + > + ret = validateDriver(); > + if (ret) > + return ret; > + > + model_ = subdev_->model(); > + > + return 0; > +} > + > +CameraFlash::Mode CameraFlash::getMode() const > +{ > + Mode m; > + > + switch (getSubdevControl(V4L2_CID_FLASH_LED_MODE)) { > + case V4L2_FLASH_LED_MODE_FLASH: > + m = Flash; > + break; > + case V4L2_FLASH_LED_MODE_TORCH: > + m = Torch; > + break; > + case V4L2_FLASH_LED_MODE_NONE: > + default: > + m = None; > + break; > + } > + > + return m; > +} > + > +int CameraFlash::setMode(Mode mode) > +{ > + int32_t m; > + > + switch (mode) { > + case Flash: > + m = V4L2_FLASH_LED_MODE_FLASH; > + break; > + case Torch: > + m = V4L2_FLASH_LED_MODE_TORCH; > + break; > + case None: > + m = V4L2_FLASH_LED_MODE_NONE; > + break; > + default: > + return -EINVAL; > + } > + > + return setSubdevControl(V4L2_CID_FLASH_LED_MODE, m); > +} > + > +const ControlInfo &CameraFlash::getFlashIntensityInfo() const > +{ > + return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second; > +} > + > +int32_t CameraFlash::getFlashIntensity() const > +{ > + return getSubdevControl(V4L2_CID_FLASH_INTENSITY); > +} > + > +int CameraFlash::setFlashIntensity(int32_t intensity) > +{ > + return setSubdevControl(V4L2_CID_FLASH_INTENSITY, intensity); > +} > + > +const ControlInfo &CameraFlash::getFlashTimeoutInfo() const > +{ > + return controlInfoMap_->find(V4L2_CID_FLASH_TIMEOUT)->second; > +} > + > +int32_t CameraFlash::getFlashTimeout() const > +{ > + return getSubdevControl(V4L2_CID_FLASH_TIMEOUT); > +} > + > +int CameraFlash::setFlashTimeout(int32_t timeout) > +{ > + return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout); > +} > + > +CameraFlash::StrobeSource CameraFlash::getStrobeSource() const > +{ > + StrobeSource s; > + > + switch (getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE)) { > + case V4L2_FLASH_STROBE_SOURCE_EXTERNAL: > + s = External; > + break; > + case V4L2_FLASH_STROBE_SOURCE_SOFTWARE: > + default: > + s = Software; > + break; > + } > + > + return s; > +} > + > +int CameraFlash::setStrobeSource(StrobeSource source) > +{ > + int32_t s; > + > + switch (source) { > + case External: > + s = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; > + break; > + case Software: > + s = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; > + break; > + default: > + return -EINVAL; > + } > + > + return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, s); > +} > + > +int CameraFlash::startStrobe() > +{ > + return setSubdevControl(V4L2_CID_FLASH_STROBE, 1); > +} > + > +int CameraFlash::stopStrobe() > +{ > + return setSubdevControl(V4L2_CID_FLASH_STROBE_STOP, 1); > +} > + > +const ControlInfo &CameraFlash::getTorchIntensityInfo() const > +{ > + return controlInfoMap_->find(V4L2_CID_FLASH_TORCH_INTENSITY)->second; > +} > + > +int32_t CameraFlash::getTorchIntensity() const > +{ > + return getSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY); > +} > + > +int CameraFlash::setTorchIntensity(int32_t intensity) > +{ > + return setSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY, intensity); > +} > + > +const std::string &CameraFlash::model() const > +{ > + return model_; > +} > + > +const ControlInfoMap &CameraFlash::controls() const > +{ > + return subdev_->controls(); Why not `controlInfoMap_` here? > +} > + > +std::string CameraFlash::logPrefix() const > +{ > + return "'" + entity_->name() + "'"; > +} > + > +int32_t CameraFlash::getSubdevControl(uint32_t id) const > +{ > + ControlList controlList = subdev_->getControls(std::vector<uint32_t>{ id }); getControls(std::array{ id }) should work. > + > + return controlList.get(id).get<int32_t>(); I think some level of error checking would be useful when querying the device. Regards, Barnabás Pőcze > +} > + > +int CameraFlash::setSubdevControl(uint32_t id, int32_t value) > +{ > + ControlList flashCtrls(subdev_->controls()); > + > + flashCtrls.set(id, value); > + > + if (subdev_->setControls(&flashCtrls)) > + return -EINVAL; > + > + return 0; > +} > + > +int CameraFlash::validateDriver() > +{ > + int ret = 0; > + static constexpr uint32_t mandatoryControls[] = { > + V4L2_CID_FLASH_LED_MODE, > + V4L2_CID_FLASH_STROBE_SOURCE, > + V4L2_CID_FLASH_STROBE, > + V4L2_CID_FLASH_TIMEOUT, > + V4L2_CID_FLASH_INTENSITY, > + V4L2_CID_FLASH_TORCH_INTENSITY, > + }; > + > + for (uint32_t ctrl : mandatoryControls) { > + if (!controlInfoMap_->count(ctrl)) { > + LOG(CameraFlash, Error) > + << "Mandatory V4L2 control " << utils::hex(ctrl) > + << " not available"; > + ret = -EINVAL; > + } > + } > + > + if (ret) { > + LOG(CameraFlash, Error) > + << "The flash kernel driver needs to be fixed"; > + LOG(CameraFlash, Error) > + << "See Documentation/flash_driver_requirements.rst in" > + << " the libcamera sources for more information"; > + return ret; > + } > + > + return ret; > +} > + > +} /* namespace libcamera */ > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build > index b3ca27f217da4ba3a896ef7cbfb5502fa82a4907..0f125661a51e2431c1febc353cef30a1219f9ce7 100644 > --- a/src/libcamera/meson.build > +++ b/src/libcamera/meson.build > @@ -20,6 +20,7 @@ libcamera_internal_sources = files([ > 'bayer_format.cpp', > 'byte_stream_buffer.cpp', > 'camera_controls.cpp', > + 'camera_flash.cpp', > 'camera_lens.cpp', > 'clock_recovery.cpp', > 'control_serializer.cpp', > diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/libcamera/sensor/camera_sensor_legacy.cpp > index f9e685a9acc499fc91d51ed1d66780a0ad2d2a8f..632b66ea0aa15fcd654e7f0efb50c24cb9b973bf 100644 > --- a/src/libcamera/sensor/camera_sensor_legacy.cpp > +++ b/src/libcamera/sensor/camera_sensor_legacy.cpp > @@ -31,6 +31,7 @@ > #include <libcamera/ipa/core_ipa_interface.h> > > #include "libcamera/internal/bayer_format.h" > +#include "libcamera/internal/camera_flash.h" > #include "libcamera/internal/camera_lens.h" > #include "libcamera/internal/camera_sensor.h" > #include "libcamera/internal/camera_sensor_properties.h" > @@ -68,6 +69,7 @@ public: > V4L2Subdevice *device() override { return subdev_.get(); } > > CameraLens *focusLens() override { return focusLens_.get(); } > + CameraFlash *flash() override { return flash_.get(); } > > const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; } > std::vector<Size> sizes(unsigned int mbusCode) const override; > @@ -139,6 +141,7 @@ private: > ControlList properties_; > > std::unique_ptr<CameraLens> focusLens_; > + std::unique_ptr<CameraFlash> flash_; > }; > > /** > @@ -665,6 +668,16 @@ int CameraSensorLegacy::discoverAncillaryDevices() > } > break; > > + case MEDIA_ENT_F_FLASH: > + flash_ = std::make_unique<CameraFlash>(ancillary); > + ret = flash_->init(); > + if (ret) { > + LOG(CameraSensor, Error) > + << "Flash initialisation failed, flash disabled"; > + flash_.reset(); > + } > + break; > + > default: > LOG(CameraSensor, Warning) > << "Unsupported ancillary entity function " > diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp > index 8ea4423698cd8c1eaae43eb5ba8b5d524b94d515..9d533d814b9df453aa4009a87818c1558bcbd665 100644 > --- a/src/libcamera/sensor/camera_sensor_raw.cpp > +++ b/src/libcamera/sensor/camera_sensor_raw.cpp > @@ -32,6 +32,7 @@ > #include <libcamera/ipa/core_ipa_interface.h> > > #include "libcamera/internal/bayer_format.h" > +#include "libcamera/internal/camera_flash.h" > #include "libcamera/internal/camera_lens.h" > #include "libcamera/internal/camera_sensor.h" > #include "libcamera/internal/camera_sensor_properties.h" > @@ -69,6 +70,7 @@ public: > V4L2Subdevice *device() override { return subdev_.get(); } > > CameraLens *focusLens() override { return focusLens_.get(); } > + CameraFlash *flash() override { return flash_.get(); } > > const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; } > std::vector<Size> sizes(unsigned int mbusCode) const override; > @@ -150,6 +152,7 @@ private: > ControlList properties_; > > std::unique_ptr<CameraLens> focusLens_; > + std::unique_ptr<CameraFlash> flash_; > }; > > /** > @@ -513,6 +516,16 @@ std::optional<int> CameraSensorRaw::init() > } > break; > > + case MEDIA_ENT_F_FLASH: > + flash_ = std::make_unique<CameraFlash>(ancillary); > + ret = flash_->init(); > + if (ret) { > + LOG(CameraSensor, Error) > + << "Flash initialisation failed, flash disabled"; > + flash_.reset(); > + } > + break; > + > default: > LOG(CameraSensor, Warning) > << "Unsupported ancillary entity function " >
Hi Barnabás, thanks a lot for your feedback! Am 28.08.2025 um 15:44 schrieb Barnabás Pőcze: > Hi > > 2025. 08. 28. 15:09 keltezéssel, Matthias Fend írta: >> Add a class to model camera flash devices. Currently, only v4l2 flash >> devices are supported. The v4l2 flash devices are implemented similar to >> the camera lenses. >> >> Signed-off-by: Matthias Fend <matthias.fend@emfend.at> >> --- >> include/libcamera/internal/camera_flash.h | 75 ++++++++ >> include/libcamera/internal/camera_sensor.h | 2 + >> src/libcamera/camera_flash.cpp | 248 ++++++++++++++++ >> ++++++++++ >> src/libcamera/meson.build | 1 + >> src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ >> src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ >> 6 files changed, 352 insertions(+) >> >> diff --git a/include/libcamera/internal/camera_flash.h b/include/ >> libcamera/internal/camera_flash.h >> new file mode 100644 >> index >> 0000000000000000000000000000000000000000..e41afef2ab84852a340a12a012e3994f00cac27a >> --- /dev/null >> +++ b/include/libcamera/internal/camera_flash.h >> @@ -0,0 +1,75 @@ >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >> +/* >> + * Copyright (C) 2025, matthias.fend@emfend.at >> + * >> + * Camera flash support >> + */ >> +#pragma once >> + >> +#include <memory> >> +#include <stdint.h> >> +#include <string> >> + >> +#include <libcamera/base/class.h> >> +#include <libcamera/base/log.h> >> + >> +#include <libcamera/controls.h> >> + >> +namespace libcamera { >> + >> +class MediaEntity; >> +class V4L2Subdevice; >> + >> +class CameraFlash : protected Loggable >> +{ >> +public: >> + enum Mode { >> + None, >> + Flash, >> + Torch, >> + }; >> + >> + enum StrobeSource { >> + Software, >> + External, >> + }; > > I think instead of defining these again, you should use the generated > enums from > `control_ids.h` since the return values of `getMode()` and > `getStrobeSource()` are > directly set as the value for `controls::draft::Flash{Mode,StrobeSource} > `. Or at the > very least some `static_assert()`s would be good. But I think using the > generated > enumerators would be preferable. I wanted to have a dedicated internal API here and not mix it with the external control API. But you're right, for the controls in the metadata, the return values of getMode() and getStrobeSource() should also be mapped (as is already done for the incoming controls). > > >> + >> + explicit CameraFlash(const MediaEntity *entity); >> + ~CameraFlash(); >> + int init(); >> + Mode getMode() const; >> + int setMode(Mode mode); >> + const ControlInfo &getFlashIntensityInfo() const; >> + int32_t getFlashIntensity() const; >> + int setFlashIntensity(int32_t intensity); >> + const ControlInfo &getFlashTimeoutInfo() const; >> + int32_t getFlashTimeout() const; >> + int setFlashTimeout(int32_t timeout_us); >> + StrobeSource getStrobeSource() const; >> + int setStrobeSource(StrobeSource source); >> + int startStrobe(); >> + int stopStrobe(); >> + const ControlInfo &getTorchIntensityInfo() const; >> + int32_t getTorchIntensity() const; >> + int setTorchIntensity(int32_t intensity); >> + >> + const std::string &model() const; >> + const ControlInfoMap &controls() const; >> + >> +protected: >> + std::string logPrefix() const override; >> + >> +private: >> + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash) >> + >> + int32_t getSubdevControl(uint32_t id) const; >> + int setSubdevControl(uint32_t id, int32_t value); >> + int validateDriver(); >> + >> + const MediaEntity *entity_; >> + std::unique_ptr<V4L2Subdevice> subdev_; >> + std::string model_; >> + const ControlInfoMap *controlInfoMap_ = nullptr; > > What is the motivation for caching this value? Just to make it a little easier to read and to avoid constructs like this: subdev_->controls().find(V4L2_CID_FLASH_TORCH_INTENSITY)->second; > > >> +}; >> + >> +} /* namespace libcamera */ >> diff --git a/include/libcamera/internal/camera_sensor.h b/include/ >> libcamera/internal/camera_sensor.h >> index >> f6ef4df170d43500bc652762e9a575010a6c1cbd..faeecf244c8d42a43eca52ae04813e0c2f80e516 100644 >> --- a/include/libcamera/internal/camera_sensor.h >> +++ b/include/libcamera/internal/camera_sensor.h >> @@ -28,6 +28,7 @@ >> namespace libcamera { >> +class CameraFlash; >> class CameraLens; >> class MediaEntity; >> class SensorConfiguration; >> @@ -48,6 +49,7 @@ public: >> virtual V4L2Subdevice *device() = 0; >> virtual CameraLens *focusLens() = 0; >> + virtual CameraFlash *flash() = 0; >> virtual const std::vector<unsigned int> &mbusCodes() const = 0; >> virtual std::vector<Size> sizes(unsigned int mbusCode) const = 0; >> diff --git a/src/libcamera/camera_flash.cpp b/src/libcamera/ >> camera_flash.cpp >> new file mode 100644 >> index >> 0000000000000000000000000000000000000000..4702c590c91e0bcb20d173e7ce03608e1ae6ecfd >> --- /dev/null >> +++ b/src/libcamera/camera_flash.cpp >> @@ -0,0 +1,248 @@ >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >> +/* >> + * Copyright (C) 2025, matthias.fend@emfend.at >> + * >> + * Camera flash support >> + */ >> + >> +#include "libcamera/internal/camera_flash.h" >> + >> +#include <libcamera/base/utils.h> >> + >> +#include "libcamera/internal/v4l2_subdevice.h" >> + >> +namespace libcamera { >> + >> +LOG_DEFINE_CATEGORY(CameraFlash) >> + >> +CameraFlash::CameraFlash(const MediaEntity *entity) >> + : entity_(entity) >> +{ >> +} >> + >> +CameraFlash::~CameraFlash() = default; >> + >> +int CameraFlash::init() >> +{ >> + if (entity_->function() != MEDIA_ENT_F_FLASH) { >> + LOG(CameraFlash, Error) >> + << "Invalid flash function " >> + << utils::hex(entity_->function()); >> + return -EINVAL; >> + } >> + >> + subdev_ = std::make_unique<V4L2Subdevice>(entity_); >> + int ret = subdev_->open(); >> + if (ret < 0) >> + return ret; >> + >> + controlInfoMap_ = &subdev_->controls(); >> + >> + ret = validateDriver(); >> + if (ret) >> + return ret; >> + >> + model_ = subdev_->model(); >> + >> + return 0; >> +} >> + >> +CameraFlash::Mode CameraFlash::getMode() const >> +{ >> + Mode m; >> + >> + switch (getSubdevControl(V4L2_CID_FLASH_LED_MODE)) { >> + case V4L2_FLASH_LED_MODE_FLASH: >> + m = Flash; >> + break; >> + case V4L2_FLASH_LED_MODE_TORCH: >> + m = Torch; >> + break; >> + case V4L2_FLASH_LED_MODE_NONE: >> + default: >> + m = None; >> + break; >> + } >> + >> + return m; >> +} >> + >> +int CameraFlash::setMode(Mode mode) >> +{ >> + int32_t m; >> + >> + switch (mode) { >> + case Flash: >> + m = V4L2_FLASH_LED_MODE_FLASH; >> + break; >> + case Torch: >> + m = V4L2_FLASH_LED_MODE_TORCH; >> + break; >> + case None: >> + m = V4L2_FLASH_LED_MODE_NONE; >> + break; >> + default: >> + return -EINVAL; >> + } >> + >> + return setSubdevControl(V4L2_CID_FLASH_LED_MODE, m); >> +} >> + >> +const ControlInfo &CameraFlash::getFlashIntensityInfo() const >> +{ >> + return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second; >> +} >> + >> +int32_t CameraFlash::getFlashIntensity() const >> +{ >> + return getSubdevControl(V4L2_CID_FLASH_INTENSITY); >> +} >> + >> +int CameraFlash::setFlashIntensity(int32_t intensity) >> +{ >> + return setSubdevControl(V4L2_CID_FLASH_INTENSITY, intensity); >> +} >> + >> +const ControlInfo &CameraFlash::getFlashTimeoutInfo() const >> +{ >> + return controlInfoMap_->find(V4L2_CID_FLASH_TIMEOUT)->second; >> +} >> + >> +int32_t CameraFlash::getFlashTimeout() const >> +{ >> + return getSubdevControl(V4L2_CID_FLASH_TIMEOUT); >> +} >> + >> +int CameraFlash::setFlashTimeout(int32_t timeout) >> +{ >> + return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout); >> +} >> + >> +CameraFlash::StrobeSource CameraFlash::getStrobeSource() const >> +{ >> + StrobeSource s; >> + >> + switch (getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE)) { >> + case V4L2_FLASH_STROBE_SOURCE_EXTERNAL: >> + s = External; >> + break; >> + case V4L2_FLASH_STROBE_SOURCE_SOFTWARE: >> + default: >> + s = Software; >> + break; >> + } >> + >> + return s; >> +} >> + >> +int CameraFlash::setStrobeSource(StrobeSource source) >> +{ >> + int32_t s; >> + >> + switch (source) { >> + case External: >> + s = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; >> + break; >> + case Software: >> + s = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; >> + break; >> + default: >> + return -EINVAL; >> + } >> + >> + return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, s); >> +} >> + >> +int CameraFlash::startStrobe() >> +{ >> + return setSubdevControl(V4L2_CID_FLASH_STROBE, 1); >> +} >> + >> +int CameraFlash::stopStrobe() >> +{ >> + return setSubdevControl(V4L2_CID_FLASH_STROBE_STOP, 1); >> +} >> + >> +const ControlInfo &CameraFlash::getTorchIntensityInfo() const >> +{ >> + return controlInfoMap_->find(V4L2_CID_FLASH_TORCH_INTENSITY)- >> >second; >> +} >> + >> +int32_t CameraFlash::getTorchIntensity() const >> +{ >> + return getSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY); >> +} >> + >> +int CameraFlash::setTorchIntensity(int32_t intensity) >> +{ >> + return setSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY, intensity); >> +} >> + >> +const std::string &CameraFlash::model() const >> +{ >> + return model_; >> +} >> + >> +const ControlInfoMap &CameraFlash::controls() const >> +{ >> + return subdev_->controls(); > > Why not `controlInfoMap_` here? True, if the variable already exists, it should probably always be used. > > >> +} >> + >> +std::string CameraFlash::logPrefix() const >> +{ >> + return "'" + entity_->name() + "'"; >> +} >> + >> +int32_t CameraFlash::getSubdevControl(uint32_t id) const >> +{ >> + ControlList controlList = subdev_- >> >getControls(std::vector<uint32_t>{ id }); > > getControls(std::array{ id }) > > should work. ACK. > > >> + >> + return controlList.get(id).get<int32_t>(); > > I think some level of error checking would be useful when > querying the device. Okay. Do you have anything specific in mind that could go wrong here that should be checked? Thanks, ~Matthias > > > Regards, > Barnabás Pőcze > > >> +} >> + >> +int CameraFlash::setSubdevControl(uint32_t id, int32_t value) >> +{ >> + ControlList flashCtrls(subdev_->controls()); >> + >> + flashCtrls.set(id, value); >> + >> + if (subdev_->setControls(&flashCtrls)) >> + return -EINVAL; >> + >> + return 0; >> +} >> + >> +int CameraFlash::validateDriver() >> +{ >> + int ret = 0; >> + static constexpr uint32_t mandatoryControls[] = { >> + V4L2_CID_FLASH_LED_MODE, >> + V4L2_CID_FLASH_STROBE_SOURCE, >> + V4L2_CID_FLASH_STROBE, >> + V4L2_CID_FLASH_TIMEOUT, >> + V4L2_CID_FLASH_INTENSITY, >> + V4L2_CID_FLASH_TORCH_INTENSITY, >> + }; >> + >> + for (uint32_t ctrl : mandatoryControls) { >> + if (!controlInfoMap_->count(ctrl)) { >> + LOG(CameraFlash, Error) >> + << "Mandatory V4L2 control " << utils::hex(ctrl) >> + << " not available"; >> + ret = -EINVAL; >> + } >> + } >> + >> + if (ret) { >> + LOG(CameraFlash, Error) >> + << "The flash kernel driver needs to be fixed"; >> + LOG(CameraFlash, Error) >> + << "See Documentation/flash_driver_requirements.rst in" >> + << " the libcamera sources for more information"; >> + return ret; >> + } >> + >> + return ret; >> +} >> + >> +} /* namespace libcamera */ >> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build >> index >> b3ca27f217da4ba3a896ef7cbfb5502fa82a4907..0f125661a51e2431c1febc353cef30a1219f9ce7 100644 >> --- a/src/libcamera/meson.build >> +++ b/src/libcamera/meson.build >> @@ -20,6 +20,7 @@ libcamera_internal_sources = files([ >> 'bayer_format.cpp', >> 'byte_stream_buffer.cpp', >> 'camera_controls.cpp', >> + 'camera_flash.cpp', >> 'camera_lens.cpp', >> 'clock_recovery.cpp', >> 'control_serializer.cpp', >> diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/ >> libcamera/sensor/camera_sensor_legacy.cpp >> index >> f9e685a9acc499fc91d51ed1d66780a0ad2d2a8f..632b66ea0aa15fcd654e7f0efb50c24cb9b973bf 100644 >> --- a/src/libcamera/sensor/camera_sensor_legacy.cpp >> +++ b/src/libcamera/sensor/camera_sensor_legacy.cpp >> @@ -31,6 +31,7 @@ >> #include <libcamera/ipa/core_ipa_interface.h> >> #include "libcamera/internal/bayer_format.h" >> +#include "libcamera/internal/camera_flash.h" >> #include "libcamera/internal/camera_lens.h" >> #include "libcamera/internal/camera_sensor.h" >> #include "libcamera/internal/camera_sensor_properties.h" >> @@ -68,6 +69,7 @@ public: >> V4L2Subdevice *device() override { return subdev_.get(); } >> CameraLens *focusLens() override { return focusLens_.get(); } >> + CameraFlash *flash() override { return flash_.get(); } >> const std::vector<unsigned int> &mbusCodes() const override >> { return mbusCodes_; } >> std::vector<Size> sizes(unsigned int mbusCode) const override; >> @@ -139,6 +141,7 @@ private: >> ControlList properties_; >> std::unique_ptr<CameraLens> focusLens_; >> + std::unique_ptr<CameraFlash> flash_; >> }; >> /** >> @@ -665,6 +668,16 @@ int CameraSensorLegacy::discoverAncillaryDevices() >> } >> break; >> + case MEDIA_ENT_F_FLASH: >> + flash_ = std::make_unique<CameraFlash>(ancillary); >> + ret = flash_->init(); >> + if (ret) { >> + LOG(CameraSensor, Error) >> + << "Flash initialisation failed, flash disabled"; >> + flash_.reset(); >> + } >> + break; >> + >> default: >> LOG(CameraSensor, Warning) >> << "Unsupported ancillary entity function " >> diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/ >> libcamera/sensor/camera_sensor_raw.cpp >> index >> 8ea4423698cd8c1eaae43eb5ba8b5d524b94d515..9d533d814b9df453aa4009a87818c1558bcbd665 100644 >> --- a/src/libcamera/sensor/camera_sensor_raw.cpp >> +++ b/src/libcamera/sensor/camera_sensor_raw.cpp >> @@ -32,6 +32,7 @@ >> #include <libcamera/ipa/core_ipa_interface.h> >> #include "libcamera/internal/bayer_format.h" >> +#include "libcamera/internal/camera_flash.h" >> #include "libcamera/internal/camera_lens.h" >> #include "libcamera/internal/camera_sensor.h" >> #include "libcamera/internal/camera_sensor_properties.h" >> @@ -69,6 +70,7 @@ public: >> V4L2Subdevice *device() override { return subdev_.get(); } >> CameraLens *focusLens() override { return focusLens_.get(); } >> + CameraFlash *flash() override { return flash_.get(); } >> const std::vector<unsigned int> &mbusCodes() const override >> { return mbusCodes_; } >> std::vector<Size> sizes(unsigned int mbusCode) const override; >> @@ -150,6 +152,7 @@ private: >> ControlList properties_; >> std::unique_ptr<CameraLens> focusLens_; >> + std::unique_ptr<CameraFlash> flash_; >> }; >> /** >> @@ -513,6 +516,16 @@ std::optional<int> CameraSensorRaw::init() >> } >> break; >> + case MEDIA_ENT_F_FLASH: >> + flash_ = std::make_unique<CameraFlash>(ancillary); >> + ret = flash_->init(); >> + if (ret) { >> + LOG(CameraSensor, Error) >> + << "Flash initialisation failed, flash disabled"; >> + flash_.reset(); >> + } >> + break; >> + >> default: >> LOG(CameraSensor, Warning) >> << "Unsupported ancillary entity function " >> >
2025. 08. 28. 16:30 keltezéssel, Matthias Fend írta: > Hi Barnabás, > > thanks a lot for your feedback! > > Am 28.08.2025 um 15:44 schrieb Barnabás Pőcze: >> Hi >> >> 2025. 08. 28. 15:09 keltezéssel, Matthias Fend írta: >>> Add a class to model camera flash devices. Currently, only v4l2 flash >>> devices are supported. The v4l2 flash devices are implemented similar to >>> the camera lenses. >>> >>> Signed-off-by: Matthias Fend <matthias.fend@emfend.at> >>> --- >>> include/libcamera/internal/camera_flash.h | 75 ++++++++ >>> include/libcamera/internal/camera_sensor.h | 2 + >>> src/libcamera/camera_flash.cpp | 248 ++++++++++++++++ ++++++++++ >>> src/libcamera/meson.build | 1 + >>> src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ >>> src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ >>> 6 files changed, 352 insertions(+) >>> >>> diff --git a/include/libcamera/internal/camera_flash.h b/include/ libcamera/internal/camera_flash.h >>> new file mode 100644 >>> index 0000000000000000000000000000000000000000..e41afef2ab84852a340a12a012e3994f00cac27a >>> --- /dev/null >>> +++ b/include/libcamera/internal/camera_flash.h >>> @@ -0,0 +1,75 @@ >>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >>> +/* >>> + * Copyright (C) 2025, matthias.fend@emfend.at >>> + * >>> + * Camera flash support >>> + */ >>> +#pragma once >>> + >>> +#include <memory> >>> +#include <stdint.h> >>> +#include <string> >>> + >>> +#include <libcamera/base/class.h> >>> +#include <libcamera/base/log.h> >>> + >>> +#include <libcamera/controls.h> >>> + >>> +namespace libcamera { >>> + >>> +class MediaEntity; >>> +class V4L2Subdevice; >>> + >>> +class CameraFlash : protected Loggable >>> +{ >>> +public: >>> + enum Mode { >>> + None, >>> + Flash, >>> + Torch, >>> + }; >>> + >>> + enum StrobeSource { >>> + Software, >>> + External, >>> + }; >> >> I think instead of defining these again, you should use the generated enums from >> `control_ids.h` since the return values of `getMode()` and `getStrobeSource()` are >> directly set as the value for `controls::draft::Flash{Mode,StrobeSource} `. Or at the >> very least some `static_assert()`s would be good. But I think using the generated >> enumerators would be preferable. > > I wanted to have a dedicated internal API here and not mix it with the external control API. > But you're right, for the controls in the metadata, the return values of getMode() and getStrobeSource() should also be mapped (as is already done for the incoming controls). > The `CameraSensor*` types also reuse `controls::draft::TestPatternModeEnum`, I don't see any issues with it if you just end up duplicating the values. In any case, if you want the separate enumerators, please try to make them `enum class`. >> >> >>> + >>> + explicit CameraFlash(const MediaEntity *entity); >>> + ~CameraFlash(); >>> + int init(); >>> + Mode getMode() const; >>> + int setMode(Mode mode); >>> + const ControlInfo &getFlashIntensityInfo() const; >>> + int32_t getFlashIntensity() const; >>> + int setFlashIntensity(int32_t intensity); >>> + const ControlInfo &getFlashTimeoutInfo() const; >>> + int32_t getFlashTimeout() const; >>> + int setFlashTimeout(int32_t timeout_us); >>> + StrobeSource getStrobeSource() const; >>> + int setStrobeSource(StrobeSource source); >>> + int startStrobe(); >>> + int stopStrobe(); >>> + const ControlInfo &getTorchIntensityInfo() const; >>> + int32_t getTorchIntensity() const; >>> + int setTorchIntensity(int32_t intensity); >>> + >>> + const std::string &model() const; >>> + const ControlInfoMap &controls() const; Are these two used? In any case, I'd make the inline, they are quite trivial. >>> + >>> +protected: >>> + std::string logPrefix() const override; >>> + >>> +private: >>> + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash) >>> + >>> + int32_t getSubdevControl(uint32_t id) const; >>> + int setSubdevControl(uint32_t id, int32_t value); >>> + int validateDriver(); >>> + >>> + const MediaEntity *entity_; >>> + std::unique_ptr<V4L2Subdevice> subdev_; >>> + std::string model_; >>> + const ControlInfoMap *controlInfoMap_ = nullptr; >> >> What is the motivation for caching this value? > > Just to make it a little easier to read and to avoid constructs like this: > subdev_->controls().find(V4L2_CID_FLASH_TORCH_INTENSITY)->second; ACK. In any case, I think what you wrote or even just `controls().find(...)` is fine. > >> >> >>> +}; >>> + >>> +} /* namespace libcamera */ >>> diff --git a/include/libcamera/internal/camera_sensor.h b/include/ libcamera/internal/camera_sensor.h >>> index f6ef4df170d43500bc652762e9a575010a6c1cbd..faeecf244c8d42a43eca52ae04813e0c2f80e516 100644 >>> --- a/include/libcamera/internal/camera_sensor.h >>> +++ b/include/libcamera/internal/camera_sensor.h >>> @@ -28,6 +28,7 @@ >>> namespace libcamera { >>> +class CameraFlash; >>> class CameraLens; >>> class MediaEntity; >>> class SensorConfiguration; >>> @@ -48,6 +49,7 @@ public: >>> virtual V4L2Subdevice *device() = 0; >>> virtual CameraLens *focusLens() = 0; >>> + virtual CameraFlash *flash() = 0; >>> virtual const std::vector<unsigned int> &mbusCodes() const = 0; >>> virtual std::vector<Size> sizes(unsigned int mbusCode) const = 0; >>> diff --git a/src/libcamera/camera_flash.cpp b/src/libcamera/ camera_flash.cpp >>> new file mode 100644 >>> index 0000000000000000000000000000000000000000..4702c590c91e0bcb20d173e7ce03608e1ae6ecfd >>> --- /dev/null >>> +++ b/src/libcamera/camera_flash.cpp >>> @@ -0,0 +1,248 @@ >>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >>> +/* >>> + * Copyright (C) 2025, matthias.fend@emfend.at >>> + * >>> + * Camera flash support >>> + */ >>> + >>> +#include "libcamera/internal/camera_flash.h" >>> + >>> +#include <libcamera/base/utils.h> >>> + >>> +#include "libcamera/internal/v4l2_subdevice.h" >>> + >>> +namespace libcamera { >>> + >>> +LOG_DEFINE_CATEGORY(CameraFlash) >>> + >>> +CameraFlash::CameraFlash(const MediaEntity *entity) >>> + : entity_(entity) >>> +{ >>> +} >>> + >>> +CameraFlash::~CameraFlash() = default; >>> + >>> +int CameraFlash::init() >>> +{ >>> + if (entity_->function() != MEDIA_ENT_F_FLASH) { >>> + LOG(CameraFlash, Error) >>> + << "Invalid flash function " >>> + << utils::hex(entity_->function()); >>> + return -EINVAL; >>> + } >>> + >>> + subdev_ = std::make_unique<V4L2Subdevice>(entity_); >>> + int ret = subdev_->open(); >>> + if (ret < 0) >>> + return ret; >>> + >>> + controlInfoMap_ = &subdev_->controls(); >>> + >>> + ret = validateDriver(); >>> + if (ret) >>> + return ret; >>> + >>> + model_ = subdev_->model(); >>> + >>> + return 0; >>> +} >>> + >>> +CameraFlash::Mode CameraFlash::getMode() const >>> +{ >>> + Mode m; >>> + >>> + switch (getSubdevControl(V4L2_CID_FLASH_LED_MODE)) { >>> + case V4L2_FLASH_LED_MODE_FLASH: >>> + m = Flash; >>> + break; >>> + case V4L2_FLASH_LED_MODE_TORCH: >>> + m = Torch; >>> + break; >>> + case V4L2_FLASH_LED_MODE_NONE: >>> + default: >>> + m = None; >>> + break; >>> + } >>> + >>> + return m; >>> +} >>> + >>> +int CameraFlash::setMode(Mode mode) >>> +{ >>> + int32_t m; >>> + >>> + switch (mode) { >>> + case Flash: >>> + m = V4L2_FLASH_LED_MODE_FLASH; >>> + break; >>> + case Torch: >>> + m = V4L2_FLASH_LED_MODE_TORCH; >>> + break; >>> + case None: >>> + m = V4L2_FLASH_LED_MODE_NONE; >>> + break; >>> + default: >>> + return -EINVAL; >>> + } >>> + >>> + return setSubdevControl(V4L2_CID_FLASH_LED_MODE, m); >>> +} >>> + >>> +const ControlInfo &CameraFlash::getFlashIntensityInfo() const >>> +{ >>> + return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second; >>> +} >>> + >>> +int32_t CameraFlash::getFlashIntensity() const >>> +{ >>> + return getSubdevControl(V4L2_CID_FLASH_INTENSITY); >>> +} >>> + >>> +int CameraFlash::setFlashIntensity(int32_t intensity) >>> +{ >>> + return setSubdevControl(V4L2_CID_FLASH_INTENSITY, intensity); >>> +} >>> + >>> +const ControlInfo &CameraFlash::getFlashTimeoutInfo() const >>> +{ >>> + return controlInfoMap_->find(V4L2_CID_FLASH_TIMEOUT)->second; >>> +} >>> + >>> +int32_t CameraFlash::getFlashTimeout() const >>> +{ >>> + return getSubdevControl(V4L2_CID_FLASH_TIMEOUT); >>> +} >>> + >>> +int CameraFlash::setFlashTimeout(int32_t timeout) >>> +{ >>> + return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout); >>> +} >>> + >>> +CameraFlash::StrobeSource CameraFlash::getStrobeSource() const >>> +{ >>> + StrobeSource s; >>> + >>> + switch (getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE)) { >>> + case V4L2_FLASH_STROBE_SOURCE_EXTERNAL: >>> + s = External; >>> + break; >>> + case V4L2_FLASH_STROBE_SOURCE_SOFTWARE: >>> + default: >>> + s = Software; >>> + break; >>> + } >>> + >>> + return s; >>> +} >>> + >>> +int CameraFlash::setStrobeSource(StrobeSource source) >>> +{ >>> + int32_t s; >>> + >>> + switch (source) { >>> + case External: >>> + s = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; >>> + break; >>> + case Software: >>> + s = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; >>> + break; >>> + default: >>> + return -EINVAL; >>> + } >>> + >>> + return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, s); >>> +} >>> + >>> +int CameraFlash::startStrobe() >>> +{ >>> + return setSubdevControl(V4L2_CID_FLASH_STROBE, 1); >>> +} >>> + >>> +int CameraFlash::stopStrobe() >>> +{ >>> + return setSubdevControl(V4L2_CID_FLASH_STROBE_STOP, 1); >>> +} >>> + >>> +const ControlInfo &CameraFlash::getTorchIntensityInfo() const >>> +{ >>> + return controlInfoMap_->find(V4L2_CID_FLASH_TORCH_INTENSITY)- >second; >>> +} >>> + >>> +int32_t CameraFlash::getTorchIntensity() const >>> +{ >>> + return getSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY); >>> +} >>> + >>> +int CameraFlash::setTorchIntensity(int32_t intensity) >>> +{ >>> + return setSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY, intensity); >>> +} >>> + >>> +const std::string &CameraFlash::model() const >>> +{ >>> + return model_; >>> +} >>> + >>> +const ControlInfoMap &CameraFlash::controls() const >>> +{ >>> + return subdev_->controls(); >> >> Why not `controlInfoMap_` here? > > True, if the variable already exists, it should probably always be used. > >> >> >>> +} >>> + >>> +std::string CameraFlash::logPrefix() const >>> +{ >>> + return "'" + entity_->name() + "'"; >>> +} >>> + >>> +int32_t CameraFlash::getSubdevControl(uint32_t id) const >>> +{ >>> + ControlList controlList = subdev_- >getControls(std::vector<uint32_t>{ id }); >> >> getControls(std::array{ id }) >> >> should work. > > ACK. > >> >> >>> + >>> + return controlList.get(id).get<int32_t>(); >> >> I think some level of error checking would be useful when >> querying the device. > > Okay. Do you have anything specific in mind that could go wrong here that should be checked? Something like `controlList.empty()` or `controlList.contains(id)` at least. Possibly making it return `std::optional`. Regards, Barnabás Pőcze > > Thanks, > ~Matthias > >> >> >> Regards, >> Barnabás Pőcze >> >> >>> +} >>> + >>> +int CameraFlash::setSubdevControl(uint32_t id, int32_t value) >>> +{ >>> + ControlList flashCtrls(subdev_->controls()); >>> + >>> + flashCtrls.set(id, value); >>> + >>> + if (subdev_->setControls(&flashCtrls)) >>> + return -EINVAL; >>> + >>> + return 0; >>> +} >>> + >>> +int CameraFlash::validateDriver() >>> +{ >>> + int ret = 0; >>> + static constexpr uint32_t mandatoryControls[] = { >>> + V4L2_CID_FLASH_LED_MODE, >>> + V4L2_CID_FLASH_STROBE_SOURCE, >>> + V4L2_CID_FLASH_STROBE, >>> + V4L2_CID_FLASH_TIMEOUT, >>> + V4L2_CID_FLASH_INTENSITY, >>> + V4L2_CID_FLASH_TORCH_INTENSITY, >>> + }; >>> + >>> + for (uint32_t ctrl : mandatoryControls) { >>> + if (!controlInfoMap_->count(ctrl)) { >>> + LOG(CameraFlash, Error) >>> + << "Mandatory V4L2 control " << utils::hex(ctrl) >>> + << " not available"; >>> + ret = -EINVAL; >>> + } >>> + } >>> + >>> + if (ret) { >>> + LOG(CameraFlash, Error) >>> + << "The flash kernel driver needs to be fixed"; >>> + LOG(CameraFlash, Error) >>> + << "See Documentation/flash_driver_requirements.rst in" >>> + << " the libcamera sources for more information"; >>> + return ret; >>> + } >>> + >>> + return ret; >>> +} >>> + >>> +} /* namespace libcamera */ >>> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build >>> index b3ca27f217da4ba3a896ef7cbfb5502fa82a4907..0f125661a51e2431c1febc353cef30a1219f9ce7 100644 >>> --- a/src/libcamera/meson.build >>> +++ b/src/libcamera/meson.build >>> @@ -20,6 +20,7 @@ libcamera_internal_sources = files([ >>> 'bayer_format.cpp', >>> 'byte_stream_buffer.cpp', >>> 'camera_controls.cpp', >>> + 'camera_flash.cpp', >>> 'camera_lens.cpp', >>> 'clock_recovery.cpp', >>> 'control_serializer.cpp', >>> diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/ libcamera/sensor/camera_sensor_legacy.cpp >>> index f9e685a9acc499fc91d51ed1d66780a0ad2d2a8f..632b66ea0aa15fcd654e7f0efb50c24cb9b973bf 100644 >>> --- a/src/libcamera/sensor/camera_sensor_legacy.cpp >>> +++ b/src/libcamera/sensor/camera_sensor_legacy.cpp >>> @@ -31,6 +31,7 @@ >>> #include <libcamera/ipa/core_ipa_interface.h> >>> #include "libcamera/internal/bayer_format.h" >>> +#include "libcamera/internal/camera_flash.h" >>> #include "libcamera/internal/camera_lens.h" >>> #include "libcamera/internal/camera_sensor.h" >>> #include "libcamera/internal/camera_sensor_properties.h" >>> @@ -68,6 +69,7 @@ public: >>> V4L2Subdevice *device() override { return subdev_.get(); } >>> CameraLens *focusLens() override { return focusLens_.get(); } >>> + CameraFlash *flash() override { return flash_.get(); } >>> const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; } >>> std::vector<Size> sizes(unsigned int mbusCode) const override; >>> @@ -139,6 +141,7 @@ private: >>> ControlList properties_; >>> std::unique_ptr<CameraLens> focusLens_; >>> + std::unique_ptr<CameraFlash> flash_; >>> }; >>> /** >>> @@ -665,6 +668,16 @@ int CameraSensorLegacy::discoverAncillaryDevices() >>> } >>> break; >>> + case MEDIA_ENT_F_FLASH: >>> + flash_ = std::make_unique<CameraFlash>(ancillary); >>> + ret = flash_->init(); >>> + if (ret) { >>> + LOG(CameraSensor, Error) >>> + << "Flash initialisation failed, flash disabled"; >>> + flash_.reset(); >>> + } >>> + break; >>> + >>> default: >>> LOG(CameraSensor, Warning) >>> << "Unsupported ancillary entity function " >>> diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/ libcamera/sensor/camera_sensor_raw.cpp >>> index 8ea4423698cd8c1eaae43eb5ba8b5d524b94d515..9d533d814b9df453aa4009a87818c1558bcbd665 100644 >>> --- a/src/libcamera/sensor/camera_sensor_raw.cpp >>> +++ b/src/libcamera/sensor/camera_sensor_raw.cpp >>> @@ -32,6 +32,7 @@ >>> #include <libcamera/ipa/core_ipa_interface.h> >>> #include "libcamera/internal/bayer_format.h" >>> +#include "libcamera/internal/camera_flash.h" >>> #include "libcamera/internal/camera_lens.h" >>> #include "libcamera/internal/camera_sensor.h" >>> #include "libcamera/internal/camera_sensor_properties.h" >>> @@ -69,6 +70,7 @@ public: >>> V4L2Subdevice *device() override { return subdev_.get(); } >>> CameraLens *focusLens() override { return focusLens_.get(); } >>> + CameraFlash *flash() override { return flash_.get(); } >>> const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; } >>> std::vector<Size> sizes(unsigned int mbusCode) const override; >>> @@ -150,6 +152,7 @@ private: >>> ControlList properties_; >>> std::unique_ptr<CameraLens> focusLens_; >>> + std::unique_ptr<CameraFlash> flash_; >>> }; >>> /** >>> @@ -513,6 +516,16 @@ std::optional<int> CameraSensorRaw::init() >>> } >>> break; >>> + case MEDIA_ENT_F_FLASH: >>> + flash_ = std::make_unique<CameraFlash>(ancillary); >>> + ret = flash_->init(); >>> + if (ret) { >>> + LOG(CameraSensor, Error) >>> + << "Flash initialisation failed, flash disabled"; >>> + flash_.reset(); >>> + } >>> + break; >>> + >>> default: >>> LOG(CameraSensor, Warning) >>> << "Unsupported ancillary entity function " >>> >> >
diff --git a/include/libcamera/internal/camera_flash.h b/include/libcamera/internal/camera_flash.h new file mode 100644 index 0000000000000000000000000000000000000000..e41afef2ab84852a340a12a012e3994f00cac27a --- /dev/null +++ b/include/libcamera/internal/camera_flash.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, matthias.fend@emfend.at + * + * Camera flash support + */ +#pragma once + +#include <memory> +#include <stdint.h> +#include <string> + +#include <libcamera/base/class.h> +#include <libcamera/base/log.h> + +#include <libcamera/controls.h> + +namespace libcamera { + +class MediaEntity; +class V4L2Subdevice; + +class CameraFlash : protected Loggable +{ +public: + enum Mode { + None, + Flash, + Torch, + }; + + enum StrobeSource { + Software, + External, + }; + + explicit CameraFlash(const MediaEntity *entity); + ~CameraFlash(); + int init(); + Mode getMode() const; + int setMode(Mode mode); + const ControlInfo &getFlashIntensityInfo() const; + int32_t getFlashIntensity() const; + int setFlashIntensity(int32_t intensity); + const ControlInfo &getFlashTimeoutInfo() const; + int32_t getFlashTimeout() const; + int setFlashTimeout(int32_t timeout_us); + StrobeSource getStrobeSource() const; + int setStrobeSource(StrobeSource source); + int startStrobe(); + int stopStrobe(); + const ControlInfo &getTorchIntensityInfo() const; + int32_t getTorchIntensity() const; + int setTorchIntensity(int32_t intensity); + + const std::string &model() const; + const ControlInfoMap &controls() const; + +protected: + std::string logPrefix() const override; + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash) + + int32_t getSubdevControl(uint32_t id) const; + int setSubdevControl(uint32_t id, int32_t value); + int validateDriver(); + + const MediaEntity *entity_; + std::unique_ptr<V4L2Subdevice> subdev_; + std::string model_; + const ControlInfoMap *controlInfoMap_ = nullptr; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index f6ef4df170d43500bc652762e9a575010a6c1cbd..faeecf244c8d42a43eca52ae04813e0c2f80e516 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -28,6 +28,7 @@ namespace libcamera { +class CameraFlash; class CameraLens; class MediaEntity; class SensorConfiguration; @@ -48,6 +49,7 @@ public: virtual V4L2Subdevice *device() = 0; virtual CameraLens *focusLens() = 0; + virtual CameraFlash *flash() = 0; virtual const std::vector<unsigned int> &mbusCodes() const = 0; virtual std::vector<Size> sizes(unsigned int mbusCode) const = 0; diff --git a/src/libcamera/camera_flash.cpp b/src/libcamera/camera_flash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4702c590c91e0bcb20d173e7ce03608e1ae6ecfd --- /dev/null +++ b/src/libcamera/camera_flash.cpp @@ -0,0 +1,248 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, matthias.fend@emfend.at + * + * Camera flash support + */ + +#include "libcamera/internal/camera_flash.h" + +#include <libcamera/base/utils.h> + +#include "libcamera/internal/v4l2_subdevice.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(CameraFlash) + +CameraFlash::CameraFlash(const MediaEntity *entity) + : entity_(entity) +{ +} + +CameraFlash::~CameraFlash() = default; + +int CameraFlash::init() +{ + if (entity_->function() != MEDIA_ENT_F_FLASH) { + LOG(CameraFlash, Error) + << "Invalid flash function " + << utils::hex(entity_->function()); + return -EINVAL; + } + + subdev_ = std::make_unique<V4L2Subdevice>(entity_); + int ret = subdev_->open(); + if (ret < 0) + return ret; + + controlInfoMap_ = &subdev_->controls(); + + ret = validateDriver(); + if (ret) + return ret; + + model_ = subdev_->model(); + + return 0; +} + +CameraFlash::Mode CameraFlash::getMode() const +{ + Mode m; + + switch (getSubdevControl(V4L2_CID_FLASH_LED_MODE)) { + case V4L2_FLASH_LED_MODE_FLASH: + m = Flash; + break; + case V4L2_FLASH_LED_MODE_TORCH: + m = Torch; + break; + case V4L2_FLASH_LED_MODE_NONE: + default: + m = None; + break; + } + + return m; +} + +int CameraFlash::setMode(Mode mode) +{ + int32_t m; + + switch (mode) { + case Flash: + m = V4L2_FLASH_LED_MODE_FLASH; + break; + case Torch: + m = V4L2_FLASH_LED_MODE_TORCH; + break; + case None: + m = V4L2_FLASH_LED_MODE_NONE; + break; + default: + return -EINVAL; + } + + return setSubdevControl(V4L2_CID_FLASH_LED_MODE, m); +} + +const ControlInfo &CameraFlash::getFlashIntensityInfo() const +{ + return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second; +} + +int32_t CameraFlash::getFlashIntensity() const +{ + return getSubdevControl(V4L2_CID_FLASH_INTENSITY); +} + +int CameraFlash::setFlashIntensity(int32_t intensity) +{ + return setSubdevControl(V4L2_CID_FLASH_INTENSITY, intensity); +} + +const ControlInfo &CameraFlash::getFlashTimeoutInfo() const +{ + return controlInfoMap_->find(V4L2_CID_FLASH_TIMEOUT)->second; +} + +int32_t CameraFlash::getFlashTimeout() const +{ + return getSubdevControl(V4L2_CID_FLASH_TIMEOUT); +} + +int CameraFlash::setFlashTimeout(int32_t timeout) +{ + return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout); +} + +CameraFlash::StrobeSource CameraFlash::getStrobeSource() const +{ + StrobeSource s; + + switch (getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE)) { + case V4L2_FLASH_STROBE_SOURCE_EXTERNAL: + s = External; + break; + case V4L2_FLASH_STROBE_SOURCE_SOFTWARE: + default: + s = Software; + break; + } + + return s; +} + +int CameraFlash::setStrobeSource(StrobeSource source) +{ + int32_t s; + + switch (source) { + case External: + s = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; + break; + case Software: + s = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; + break; + default: + return -EINVAL; + } + + return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, s); +} + +int CameraFlash::startStrobe() +{ + return setSubdevControl(V4L2_CID_FLASH_STROBE, 1); +} + +int CameraFlash::stopStrobe() +{ + return setSubdevControl(V4L2_CID_FLASH_STROBE_STOP, 1); +} + +const ControlInfo &CameraFlash::getTorchIntensityInfo() const +{ + return controlInfoMap_->find(V4L2_CID_FLASH_TORCH_INTENSITY)->second; +} + +int32_t CameraFlash::getTorchIntensity() const +{ + return getSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY); +} + +int CameraFlash::setTorchIntensity(int32_t intensity) +{ + return setSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY, intensity); +} + +const std::string &CameraFlash::model() const +{ + return model_; +} + +const ControlInfoMap &CameraFlash::controls() const +{ + return subdev_->controls(); +} + +std::string CameraFlash::logPrefix() const +{ + return "'" + entity_->name() + "'"; +} + +int32_t CameraFlash::getSubdevControl(uint32_t id) const +{ + ControlList controlList = subdev_->getControls(std::vector<uint32_t>{ id }); + + return controlList.get(id).get<int32_t>(); +} + +int CameraFlash::setSubdevControl(uint32_t id, int32_t value) +{ + ControlList flashCtrls(subdev_->controls()); + + flashCtrls.set(id, value); + + if (subdev_->setControls(&flashCtrls)) + return -EINVAL; + + return 0; +} + +int CameraFlash::validateDriver() +{ + int ret = 0; + static constexpr uint32_t mandatoryControls[] = { + V4L2_CID_FLASH_LED_MODE, + V4L2_CID_FLASH_STROBE_SOURCE, + V4L2_CID_FLASH_STROBE, + V4L2_CID_FLASH_TIMEOUT, + V4L2_CID_FLASH_INTENSITY, + V4L2_CID_FLASH_TORCH_INTENSITY, + }; + + for (uint32_t ctrl : mandatoryControls) { + if (!controlInfoMap_->count(ctrl)) { + LOG(CameraFlash, Error) + << "Mandatory V4L2 control " << utils::hex(ctrl) + << " not available"; + ret = -EINVAL; + } + } + + if (ret) { + LOG(CameraFlash, Error) + << "The flash kernel driver needs to be fixed"; + LOG(CameraFlash, Error) + << "See Documentation/flash_driver_requirements.rst in" + << " the libcamera sources for more information"; + return ret; + } + + return ret; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index b3ca27f217da4ba3a896ef7cbfb5502fa82a4907..0f125661a51e2431c1febc353cef30a1219f9ce7 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -20,6 +20,7 @@ libcamera_internal_sources = files([ 'bayer_format.cpp', 'byte_stream_buffer.cpp', 'camera_controls.cpp', + 'camera_flash.cpp', 'camera_lens.cpp', 'clock_recovery.cpp', 'control_serializer.cpp', diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/libcamera/sensor/camera_sensor_legacy.cpp index f9e685a9acc499fc91d51ed1d66780a0ad2d2a8f..632b66ea0aa15fcd654e7f0efb50c24cb9b973bf 100644 --- a/src/libcamera/sensor/camera_sensor_legacy.cpp +++ b/src/libcamera/sensor/camera_sensor_legacy.cpp @@ -31,6 +31,7 @@ #include <libcamera/ipa/core_ipa_interface.h> #include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_flash.h" #include "libcamera/internal/camera_lens.h" #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/camera_sensor_properties.h" @@ -68,6 +69,7 @@ public: V4L2Subdevice *device() override { return subdev_.get(); } CameraLens *focusLens() override { return focusLens_.get(); } + CameraFlash *flash() override { return flash_.get(); } const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; } std::vector<Size> sizes(unsigned int mbusCode) const override; @@ -139,6 +141,7 @@ private: ControlList properties_; std::unique_ptr<CameraLens> focusLens_; + std::unique_ptr<CameraFlash> flash_; }; /** @@ -665,6 +668,16 @@ int CameraSensorLegacy::discoverAncillaryDevices() } break; + case MEDIA_ENT_F_FLASH: + flash_ = std::make_unique<CameraFlash>(ancillary); + ret = flash_->init(); + if (ret) { + LOG(CameraSensor, Error) + << "Flash initialisation failed, flash disabled"; + flash_.reset(); + } + break; + default: LOG(CameraSensor, Warning) << "Unsupported ancillary entity function " diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp index 8ea4423698cd8c1eaae43eb5ba8b5d524b94d515..9d533d814b9df453aa4009a87818c1558bcbd665 100644 --- a/src/libcamera/sensor/camera_sensor_raw.cpp +++ b/src/libcamera/sensor/camera_sensor_raw.cpp @@ -32,6 +32,7 @@ #include <libcamera/ipa/core_ipa_interface.h> #include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_flash.h" #include "libcamera/internal/camera_lens.h" #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/camera_sensor_properties.h" @@ -69,6 +70,7 @@ public: V4L2Subdevice *device() override { return subdev_.get(); } CameraLens *focusLens() override { return focusLens_.get(); } + CameraFlash *flash() override { return flash_.get(); } const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; } std::vector<Size> sizes(unsigned int mbusCode) const override; @@ -150,6 +152,7 @@ private: ControlList properties_; std::unique_ptr<CameraLens> focusLens_; + std::unique_ptr<CameraFlash> flash_; }; /** @@ -513,6 +516,16 @@ std::optional<int> CameraSensorRaw::init() } break; + case MEDIA_ENT_F_FLASH: + flash_ = std::make_unique<CameraFlash>(ancillary); + ret = flash_->init(); + if (ret) { + LOG(CameraSensor, Error) + << "Flash initialisation failed, flash disabled"; + flash_.reset(); + } + break; + default: LOG(CameraSensor, Warning) << "Unsupported ancillary entity function "
Add a class to model camera flash devices. Currently, only v4l2 flash devices are supported. The v4l2 flash devices are implemented similar to the camera lenses. Signed-off-by: Matthias Fend <matthias.fend@emfend.at> --- include/libcamera/internal/camera_flash.h | 75 ++++++++ include/libcamera/internal/camera_sensor.h | 2 + src/libcamera/camera_flash.cpp | 248 ++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ 6 files changed, 352 insertions(+)