Message ID | 20250912-flash_reco-v2-2-d5bb80a2e619@emfend.at |
---|---|
State | New |
Headers | show |
Series |
|
Related | show |
Hi Matthias, Thank you for the patch! Quoting Matthias Fend (2025-09-12 08:13:21) > 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 | 72 ++++++++ > include/libcamera/internal/camera_sensor.h | 2 + > src/libcamera/camera_flash.cpp | 249 ++++++++++++++++++++++++++ > src/libcamera/meson.build | 1 + > src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ > src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ > 6 files changed, 350 insertions(+) > > diff --git a/include/libcamera/internal/camera_flash.h b/include/libcamera/internal/camera_flash.h > new file mode 100644 > index 0000000000000000000000000000000000000000..70234ca96d98dd88a084e2c6804a66e455d87ef8 > --- /dev/null > +++ b/include/libcamera/internal/camera_flash.h > @@ -0,0 +1,72 @@ > +/* 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 class Mode { > + None, > + Flash, > + Torch, > + }; > + > + enum class StrobeSource { > + Software, > + External, > + }; > + > + explicit CameraFlash(const MediaEntity *entity); > + ~CameraFlash(); > + int init(); > + std::optional<Mode> getMode() const; > + int setMode(Mode mode); > + const ControlInfo &getFlashIntensityInfo() const; > + std::optional<int32_t> getFlashIntensity() const; > + int setFlashIntensity(int32_t intensity); > + const ControlInfo &getFlashTimeoutInfo() const; > + std::optional<int32_t> getFlashTimeout() const; > + int setFlashTimeout(int32_t timeout_us); > + std::optional<StrobeSource> getStrobeSource() const; > + int setStrobeSource(StrobeSource source); > + int startStrobe(); > + int stopStrobe(); > + const ControlInfo &getTorchIntensityInfo() const; > + std::optional<int32_t> getTorchIntensity() const; > + int setTorchIntensity(int32_t intensity); > + > +protected: > + std::string logPrefix() const override; > + > +private: > + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash) > + > + std::optional<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..d3b9fbf78f063ae0cb67635c4cda667508479534 > --- /dev/null > +++ b/src/libcamera/camera_flash.cpp > @@ -0,0 +1,249 @@ > +/* 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; > +} > + > +std::optional<CameraFlash::Mode> CameraFlash::getMode() const > +{ > + Mode mode; > + > + auto v4l2Mode = getSubdevControl(V4L2_CID_FLASH_LED_MODE); > + if (!v4l2Mode) > + return std::nullopt; > + > + switch (*v4l2Mode) { > + case V4L2_FLASH_LED_MODE_FLASH: > + mode = Mode::Flash; > + break; > + case V4L2_FLASH_LED_MODE_TORCH: > + mode = Mode::Torch; > + break; > + case V4L2_FLASH_LED_MODE_NONE: > + default: > + mode = Mode::None; > + break; > + } > + > + return mode; > +} > + > +int CameraFlash::setMode(Mode mode) > +{ > + int32_t v4l2Mode; > + > + switch (mode) { > + case Mode::Flash: > + v4l2Mode = V4L2_FLASH_LED_MODE_FLASH; > + break; > + case Mode::Torch: > + v4l2Mode = V4L2_FLASH_LED_MODE_TORCH; > + break; > + case Mode::None: > + v4l2Mode = V4L2_FLASH_LED_MODE_NONE; > + break; > + default: > + return -EINVAL; > + } > + > + return setSubdevControl(V4L2_CID_FLASH_LED_MODE, v4l2Mode); > +} > + > +const ControlInfo &CameraFlash::getFlashIntensityInfo() const > +{ > + return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second; > +} > + > +std::optional<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; > +} > + > +std::optional<int32_t> CameraFlash::getFlashTimeout() const > +{ > + return getSubdevControl(V4L2_CID_FLASH_TIMEOUT); > +} > + > +int CameraFlash::setFlashTimeout(int32_t timeout) > +{ > + return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout); > +} > + > +std::optional<CameraFlash::StrobeSource> CameraFlash::getStrobeSource() const > +{ > + StrobeSource source; > + > + auto v4l2Source = getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE); > + if (!v4l2Source) > + return std::nullopt; > + > + switch (*v4l2Source) { > + case V4L2_FLASH_STROBE_SOURCE_EXTERNAL: > + source = StrobeSource::External; > + break; > + case V4L2_FLASH_STROBE_SOURCE_SOFTWARE: > + default: > + source = StrobeSource::Software; > + break; > + } > + > + return source; > +} > + > +int CameraFlash::setStrobeSource(StrobeSource source) > +{ > + int32_t v4l2Source; > + > + switch (source) { > + case StrobeSource::External: > + v4l2Source = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; > + break; > + case StrobeSource::Software: > + v4l2Source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; > + break; > + default: > + return -EINVAL; > + } > + > + return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, v4l2Source); > +} > + > +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; > +} > + > +std::optional<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); > +} > + > +std::string CameraFlash::logPrefix() const > +{ > + return "'" + entity_->name() + "'"; > +} > + > +std::optional<int32_t> CameraFlash::getSubdevControl(uint32_t id) const > +{ > + ControlList controlList = subdev_->getControls(std::array{ id }); > + > + if (controlList.contains(id)) > + return std::nullopt; > + > + return controlList.get(id).get<int32_t>(); > +} > + > +int CameraFlash::setSubdevControl(uint32_t id, int32_t value) > +{ > + ControlList flashCtrls(*controlInfoMap_); > + > + 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, > + }; This all looks good to me. The thoughts I have are relating to whether STROBE controls should be mandatory in general; If a torch device only serves as a torch, I don't think it should have to implement strobe controls. When I've used v4l2_flash for torches in the past I have implemented the strobe functionality as a function that just returns 0 so I can register the v4l2_flash in the first place. But that's a discussion for the maintainers of v4l2_flash in the kernel. Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com> > + > + 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 " > > -- > 2.34.1 > Best wishes, Isaac
diff --git a/include/libcamera/internal/camera_flash.h b/include/libcamera/internal/camera_flash.h new file mode 100644 index 0000000000000000000000000000000000000000..70234ca96d98dd88a084e2c6804a66e455d87ef8 --- /dev/null +++ b/include/libcamera/internal/camera_flash.h @@ -0,0 +1,72 @@ +/* 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 class Mode { + None, + Flash, + Torch, + }; + + enum class StrobeSource { + Software, + External, + }; + + explicit CameraFlash(const MediaEntity *entity); + ~CameraFlash(); + int init(); + std::optional<Mode> getMode() const; + int setMode(Mode mode); + const ControlInfo &getFlashIntensityInfo() const; + std::optional<int32_t> getFlashIntensity() const; + int setFlashIntensity(int32_t intensity); + const ControlInfo &getFlashTimeoutInfo() const; + std::optional<int32_t> getFlashTimeout() const; + int setFlashTimeout(int32_t timeout_us); + std::optional<StrobeSource> getStrobeSource() const; + int setStrobeSource(StrobeSource source); + int startStrobe(); + int stopStrobe(); + const ControlInfo &getTorchIntensityInfo() const; + std::optional<int32_t> getTorchIntensity() const; + int setTorchIntensity(int32_t intensity); + +protected: + std::string logPrefix() const override; + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash) + + std::optional<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..d3b9fbf78f063ae0cb67635c4cda667508479534 --- /dev/null +++ b/src/libcamera/camera_flash.cpp @@ -0,0 +1,249 @@ +/* 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; +} + +std::optional<CameraFlash::Mode> CameraFlash::getMode() const +{ + Mode mode; + + auto v4l2Mode = getSubdevControl(V4L2_CID_FLASH_LED_MODE); + if (!v4l2Mode) + return std::nullopt; + + switch (*v4l2Mode) { + case V4L2_FLASH_LED_MODE_FLASH: + mode = Mode::Flash; + break; + case V4L2_FLASH_LED_MODE_TORCH: + mode = Mode::Torch; + break; + case V4L2_FLASH_LED_MODE_NONE: + default: + mode = Mode::None; + break; + } + + return mode; +} + +int CameraFlash::setMode(Mode mode) +{ + int32_t v4l2Mode; + + switch (mode) { + case Mode::Flash: + v4l2Mode = V4L2_FLASH_LED_MODE_FLASH; + break; + case Mode::Torch: + v4l2Mode = V4L2_FLASH_LED_MODE_TORCH; + break; + case Mode::None: + v4l2Mode = V4L2_FLASH_LED_MODE_NONE; + break; + default: + return -EINVAL; + } + + return setSubdevControl(V4L2_CID_FLASH_LED_MODE, v4l2Mode); +} + +const ControlInfo &CameraFlash::getFlashIntensityInfo() const +{ + return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second; +} + +std::optional<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; +} + +std::optional<int32_t> CameraFlash::getFlashTimeout() const +{ + return getSubdevControl(V4L2_CID_FLASH_TIMEOUT); +} + +int CameraFlash::setFlashTimeout(int32_t timeout) +{ + return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout); +} + +std::optional<CameraFlash::StrobeSource> CameraFlash::getStrobeSource() const +{ + StrobeSource source; + + auto v4l2Source = getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE); + if (!v4l2Source) + return std::nullopt; + + switch (*v4l2Source) { + case V4L2_FLASH_STROBE_SOURCE_EXTERNAL: + source = StrobeSource::External; + break; + case V4L2_FLASH_STROBE_SOURCE_SOFTWARE: + default: + source = StrobeSource::Software; + break; + } + + return source; +} + +int CameraFlash::setStrobeSource(StrobeSource source) +{ + int32_t v4l2Source; + + switch (source) { + case StrobeSource::External: + v4l2Source = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; + break; + case StrobeSource::Software: + v4l2Source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; + break; + default: + return -EINVAL; + } + + return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, v4l2Source); +} + +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; +} + +std::optional<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); +} + +std::string CameraFlash::logPrefix() const +{ + return "'" + entity_->name() + "'"; +} + +std::optional<int32_t> CameraFlash::getSubdevControl(uint32_t id) const +{ + ControlList controlList = subdev_->getControls(std::array{ id }); + + if (controlList.contains(id)) + return std::nullopt; + + return controlList.get(id).get<int32_t>(); +} + +int CameraFlash::setSubdevControl(uint32_t id, int32_t value) +{ + ControlList flashCtrls(*controlInfoMap_); + + 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 | 72 ++++++++ include/libcamera/internal/camera_sensor.h | 2 + src/libcamera/camera_flash.cpp | 249 ++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ 6 files changed, 350 insertions(+)