libcamera: software_isp: Add focus control
Signed-off-by: Vasiliy Doylov <nekocwd@mainlining.org>
This commit is contained in:
parent
30e17d48c7
commit
7d19533589
10 changed files with 169 additions and 12 deletions
|
@ -86,11 +86,11 @@ public:
|
||||||
Signal<FrameBuffer *> outputBufferReady;
|
Signal<FrameBuffer *> outputBufferReady;
|
||||||
Signal<uint32_t, uint32_t> ispStatsReady;
|
Signal<uint32_t, uint32_t> ispStatsReady;
|
||||||
Signal<uint32_t, const ControlList &> metadataReady;
|
Signal<uint32_t, const ControlList &> metadataReady;
|
||||||
Signal<const ControlList &> setSensorControls;
|
Signal<const ControlList &, const ControlList &> setSensorControls;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void saveIspParams();
|
void saveIspParams();
|
||||||
void setSensorCtrls(const ControlList &sensorControls);
|
void setSensorCtrls(const ControlList &sensorControls, const ControlList &lensControls);
|
||||||
void statsReady(uint32_t frame, uint32_t bufferId);
|
void statsReady(uint32_t frame, uint32_t bufferId);
|
||||||
void inputReady(FrameBuffer *input);
|
void inputReady(FrameBuffer *input);
|
||||||
void outputReady(FrameBuffer *output);
|
void outputReady(FrameBuffer *output);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import "include/libcamera/ipa/core.mojom";
|
||||||
|
|
||||||
struct IPAConfigInfo {
|
struct IPAConfigInfo {
|
||||||
libcamera.ControlInfoMap sensorControls;
|
libcamera.ControlInfoMap sensorControls;
|
||||||
|
libcamera.ControlInfoMap lensControls;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IPASoftInterface {
|
interface IPASoftInterface {
|
||||||
|
@ -32,7 +33,7 @@ interface IPASoftInterface {
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IPASoftEventInterface {
|
interface IPASoftEventInterface {
|
||||||
setSensorControls(libcamera.ControlList sensorControls);
|
setSensorControls(libcamera.ControlList sensorControls, libcamera.ControlList lensControls);
|
||||||
setIspParams();
|
setIspParams();
|
||||||
metadataReady(uint32 frame, libcamera.ControlList metadata);
|
metadataReady(uint32 frame, libcamera.ControlList metadata);
|
||||||
};
|
};
|
||||||
|
|
71
src/ipa/simple/algorithms/af.cpp
Normal file
71
src/ipa/simple/algorithms/af.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Vasiliy Doylov <nekodevelopper@gmail.com>
|
||||||
|
*
|
||||||
|
* Auto focus
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "af.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libcamera/base/log.h>
|
||||||
|
|
||||||
|
#include "control_ids.h"
|
||||||
|
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
LOG_DEFINE_CATEGORY(IPASoftAutoFocus)
|
||||||
|
|
||||||
|
namespace ipa::soft::algorithms {
|
||||||
|
|
||||||
|
Af::Af()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int Af::init(IPAContext &context,
|
||||||
|
[[maybe_unused]] const YamlObject &tuningData)
|
||||||
|
{
|
||||||
|
context.ctrlMap[&controls::LensPosition] = ControlInfo(0.0f, 100.0f, 50.0f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Af::configure(IPAContext &context,
|
||||||
|
[[maybe_unused]] const IPAConfigInfo &configInfo)
|
||||||
|
{
|
||||||
|
context.activeState.knobs.focus_pos = std::optional<double>();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Af::queueRequest([[maybe_unused]] typename Module::Context &context,
|
||||||
|
[[maybe_unused]] const uint32_t frame,
|
||||||
|
[[maybe_unused]] typename Module::FrameContext &frameContext,
|
||||||
|
const ControlList &controls)
|
||||||
|
{
|
||||||
|
const auto &focus_pos = controls.get(controls::LensPosition);
|
||||||
|
if (focus_pos.has_value()) {
|
||||||
|
context.activeState.knobs.focus_pos = focus_pos;
|
||||||
|
LOG(IPASoftAutoFocus, Debug) << "Setting focus position to " << focus_pos.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Af::updateFocus([[maybe_unused]] IPAContext &context, [[maybe_unused]] IPAFrameContext &frameContext, [[maybe_unused]] double exposureMSV)
|
||||||
|
{
|
||||||
|
frameContext.lens.focus_pos = context.activeState.knobs.focus_pos.value_or(50.0) / 100.0 * (context.configuration.focus.focus_max - context.configuration.focus.focus_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Af::process([[maybe_unused]] IPAContext &context,
|
||||||
|
[[maybe_unused]] const uint32_t frame,
|
||||||
|
[[maybe_unused]] IPAFrameContext &frameContext,
|
||||||
|
[[maybe_unused]] const SwIspStats *stats,
|
||||||
|
[[maybe_unused]] ControlList &metadata)
|
||||||
|
{
|
||||||
|
updateFocus(context, frameContext, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_IPA_ALGORITHM(Af, "Af")
|
||||||
|
|
||||||
|
} /* namespace ipa::soft::algorithms */
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
40
src/ipa/simple/algorithms/af.h
Normal file
40
src/ipa/simple/algorithms/af.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Vasiliy Doylov <nekodevelopper@gmail.com>
|
||||||
|
*
|
||||||
|
* Auto focus
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "algorithm.h"
|
||||||
|
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
namespace ipa::soft::algorithms {
|
||||||
|
|
||||||
|
class Af : public Algorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Af();
|
||||||
|
~Af() = default;
|
||||||
|
|
||||||
|
int init(IPAContext &context, const YamlObject &tuningData) override;
|
||||||
|
int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
|
||||||
|
void queueRequest(typename Module::Context &context,
|
||||||
|
const uint32_t frame,
|
||||||
|
typename Module::FrameContext &frameContext,
|
||||||
|
const ControlList &controls)
|
||||||
|
override;
|
||||||
|
void process(IPAContext &context, const uint32_t frame,
|
||||||
|
IPAFrameContext &frameContext,
|
||||||
|
const SwIspStats *stats,
|
||||||
|
ControlList &metadata) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateFocus(IPAContext &context, IPAFrameContext &frameContext, double focus);
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace ipa::soft::algorithms */
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
|
@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([
|
||||||
'blc.cpp',
|
'blc.cpp',
|
||||||
'ccm.cpp',
|
'ccm.cpp',
|
||||||
'lut.cpp',
|
'lut.cpp',
|
||||||
|
'af.cpp',
|
||||||
])
|
])
|
||||||
|
|
|
@ -16,4 +16,5 @@ algorithms:
|
||||||
# 0, 0, 1]
|
# 0, 0, 1]
|
||||||
- Lut:
|
- Lut:
|
||||||
- Agc:
|
- Agc:
|
||||||
|
- Af:
|
||||||
...
|
...
|
||||||
|
|
|
@ -34,6 +34,9 @@ struct IPASessionConfiguration {
|
||||||
struct {
|
struct {
|
||||||
std::optional<uint8_t> level;
|
std::optional<uint8_t> level;
|
||||||
} black;
|
} black;
|
||||||
|
struct {
|
||||||
|
int32_t focus_min, focus_max;
|
||||||
|
} focus;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IPAActiveState {
|
struct IPAActiveState {
|
||||||
|
@ -68,6 +71,8 @@ struct IPAActiveState {
|
||||||
std::optional<double> brightness;
|
std::optional<double> brightness;
|
||||||
/* 0..1 range, 1 = normal */
|
/* 0..1 range, 1 = normal */
|
||||||
std::optional<bool> ae_enabled;
|
std::optional<bool> ae_enabled;
|
||||||
|
/* 0..100 range, 50.0 = normal */
|
||||||
|
std::optional<double> focus_pos;
|
||||||
} knobs;
|
} knobs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,6 +86,10 @@ struct IPAFrameContext : public FrameContext {
|
||||||
double gain;
|
double gain;
|
||||||
} sensor;
|
} sensor;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int32_t focus_pos;
|
||||||
|
} lens;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
double red;
|
double red;
|
||||||
double blue;
|
double blue;
|
||||||
|
|
|
@ -77,6 +77,7 @@ private:
|
||||||
SwIspStats *stats_;
|
SwIspStats *stats_;
|
||||||
std::unique_ptr<CameraSensorHelper> camHelper_;
|
std::unique_ptr<CameraSensorHelper> camHelper_;
|
||||||
ControlInfoMap sensorInfoMap_;
|
ControlInfoMap sensorInfoMap_;
|
||||||
|
ControlInfoMap lensInfoMap_;
|
||||||
|
|
||||||
/* Local parameter storage */
|
/* Local parameter storage */
|
||||||
struct IPAContext context_;
|
struct IPAContext context_;
|
||||||
|
@ -196,6 +197,7 @@ int IPASoftSimple::init(const IPASettings &settings,
|
||||||
int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
|
int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
|
||||||
{
|
{
|
||||||
sensorInfoMap_ = configInfo.sensorControls;
|
sensorInfoMap_ = configInfo.sensorControls;
|
||||||
|
lensInfoMap_ = configInfo.lensControls;
|
||||||
|
|
||||||
const ControlInfo &exposureInfo = sensorInfoMap_.find(V4L2_CID_EXPOSURE)->second;
|
const ControlInfo &exposureInfo = sensorInfoMap_.find(V4L2_CID_EXPOSURE)->second;
|
||||||
const ControlInfo &gainInfo = sensorInfoMap_.find(V4L2_CID_ANALOGUE_GAIN)->second;
|
const ControlInfo &gainInfo = sensorInfoMap_.find(V4L2_CID_ANALOGUE_GAIN)->second;
|
||||||
|
@ -205,6 +207,17 @@ int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
|
||||||
context_.activeState = {};
|
context_.activeState = {};
|
||||||
context_.frameContexts.clear();
|
context_.frameContexts.clear();
|
||||||
|
|
||||||
|
if (lensInfoMap_.empty()) {
|
||||||
|
LOG(IPASoft, Warning) << "No camera leans found! Focus control disabled.";
|
||||||
|
context_.configuration.focus.focus_min = 0;
|
||||||
|
context_.configuration.focus.focus_max = 0;
|
||||||
|
} else {
|
||||||
|
const ControlInfo &lensInfo = lensInfoMap_.find(V4L2_CID_FOCUS_ABSOLUTE)->second;
|
||||||
|
context_.configuration.focus.focus_min = lensInfo.min().get<int32_t>();
|
||||||
|
context_.configuration.focus.focus_max = lensInfo.max().get<int32_t>();
|
||||||
|
LOG(IPASoft, Warning) << "Camera leans found! Focus: " << context_.configuration.focus.focus_min << "-" << context_.configuration.focus.focus_max;
|
||||||
|
}
|
||||||
|
|
||||||
context_.configuration.agc.lineDuration =
|
context_.configuration.agc.lineDuration =
|
||||||
context_.sensorInfo.minLineLength * 1.0s / context_.sensorInfo.pixelRate;
|
context_.sensorInfo.minLineLength * 1.0s / context_.sensorInfo.pixelRate;
|
||||||
context_.configuration.agc.exposureMin = exposureInfo.min().get<int32_t>();
|
context_.configuration.agc.exposureMin = exposureInfo.min().get<int32_t>();
|
||||||
|
@ -327,7 +340,10 @@ void IPASoftSimple::processStats(const uint32_t frame,
|
||||||
ctrls.set(V4L2_CID_ANALOGUE_GAIN,
|
ctrls.set(V4L2_CID_ANALOGUE_GAIN,
|
||||||
static_cast<int32_t>(camHelper_ ? camHelper_->gainCode(againNew) : againNew));
|
static_cast<int32_t>(camHelper_ ? camHelper_->gainCode(againNew) : againNew));
|
||||||
|
|
||||||
setSensorControls.emit(ctrls);
|
ControlList lens_ctrls(lensInfoMap_);
|
||||||
|
lens_ctrls.set(V4L2_CID_FOCUS_ABSOLUTE, frameContext.lens.focus_pos);
|
||||||
|
|
||||||
|
setSensorControls.emit(ctrls, lens_ctrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string IPASoftSimple::logPrefix() const
|
std::string IPASoftSimple::logPrefix() const
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <libcamera/stream.h>
|
#include <libcamera/stream.h>
|
||||||
|
|
||||||
#include "libcamera/internal/camera.h"
|
#include "libcamera/internal/camera.h"
|
||||||
|
#include "libcamera/internal/camera_lens.h"
|
||||||
#include "libcamera/internal/camera_sensor.h"
|
#include "libcamera/internal/camera_sensor.h"
|
||||||
#include "libcamera/internal/camera_sensor_properties.h"
|
#include "libcamera/internal/camera_sensor_properties.h"
|
||||||
#include "libcamera/internal/converter.h"
|
#include "libcamera/internal/converter.h"
|
||||||
|
@ -41,6 +42,8 @@
|
||||||
#include "libcamera/internal/v4l2_subdevice.h"
|
#include "libcamera/internal/v4l2_subdevice.h"
|
||||||
#include "libcamera/internal/v4l2_videodevice.h"
|
#include "libcamera/internal/v4l2_videodevice.h"
|
||||||
|
|
||||||
|
#include "libcamera/controls.h"
|
||||||
|
|
||||||
namespace libcamera {
|
namespace libcamera {
|
||||||
|
|
||||||
LOG_DEFINE_CATEGORY(SimplePipeline)
|
LOG_DEFINE_CATEGORY(SimplePipeline)
|
||||||
|
@ -356,7 +359,7 @@ private:
|
||||||
|
|
||||||
void ispStatsReady(uint32_t frame, uint32_t bufferId);
|
void ispStatsReady(uint32_t frame, uint32_t bufferId);
|
||||||
void metadataReady(uint32_t frame, const ControlList &metadata);
|
void metadataReady(uint32_t frame, const ControlList &metadata);
|
||||||
void setSensorControls(const ControlList &sensorControls);
|
void setSensorControls(const ControlList &sensorControls, const ControlList &lensControls);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleCameraConfiguration : public CameraConfiguration
|
class SimpleCameraConfiguration : public CameraConfiguration
|
||||||
|
@ -1002,7 +1005,7 @@ void SimpleCameraData::metadataReady(uint32_t frame, const ControlList &metadata
|
||||||
tryCompleteRequest(info->request);
|
tryCompleteRequest(info->request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleCameraData::setSensorControls(const ControlList &sensorControls)
|
void SimpleCameraData::setSensorControls(const ControlList &sensorControls, const ControlList &lensControls)
|
||||||
{
|
{
|
||||||
delayedCtrls_->push(sensorControls);
|
delayedCtrls_->push(sensorControls);
|
||||||
/*
|
/*
|
||||||
|
@ -1013,10 +1016,21 @@ void SimpleCameraData::setSensorControls(const ControlList &sensorControls)
|
||||||
* but it also bypasses delayedCtrls_, creating AGC regulation issues.
|
* but it also bypasses delayedCtrls_, creating AGC regulation issues.
|
||||||
* Both problems should be fixed.
|
* Both problems should be fixed.
|
||||||
*/
|
*/
|
||||||
if (!frameStartEmitter_) {
|
if (frameStartEmitter_)
|
||||||
ControlList ctrls(sensorControls);
|
return;
|
||||||
sensor_->setControls(&ctrls);
|
|
||||||
}
|
ControlList ctrls(sensorControls);
|
||||||
|
sensor_->setControls(&ctrls);
|
||||||
|
|
||||||
|
CameraLens *focusLens = sensor_->focusLens();
|
||||||
|
if (!focusLens)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!lensControls.contains(V4L2_CID_FOCUS_ABSOLUTE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const ControlValue &focusValue = lensControls.get(V4L2_CID_FOCUS_ABSOLUTE);
|
||||||
|
focusLens->setFocusPosition(focusValue.get<int32_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve all source pads connected to a sink pad through active routes. */
|
/* Retrieve all source pads connected to a sink pad through active routes. */
|
||||||
|
@ -1406,6 +1420,10 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
|
||||||
} else {
|
} else {
|
||||||
ipa::soft::IPAConfigInfo configInfo;
|
ipa::soft::IPAConfigInfo configInfo;
|
||||||
configInfo.sensorControls = data->sensor_->controls();
|
configInfo.sensorControls = data->sensor_->controls();
|
||||||
|
if (data->sensor_->focusLens() != nullptr)
|
||||||
|
configInfo.lensControls = data->sensor_->focusLens()->controls();
|
||||||
|
else
|
||||||
|
configInfo.lensControls = ControlInfoMap();
|
||||||
return data->swIsp_->configure(inputCfg, outputCfgs, configInfo);
|
return data->swIsp_->configure(inputCfg, outputCfgs, configInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,9 +395,9 @@ void SoftwareIsp::saveIspParams()
|
||||||
debayerParams_ = *sharedParams_;
|
debayerParams_ = *sharedParams_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareIsp::setSensorCtrls(const ControlList &sensorControls)
|
void SoftwareIsp::setSensorCtrls(const ControlList &sensorControls, const ControlList &lensControls)
|
||||||
{
|
{
|
||||||
setSensorControls.emit(sensorControls);
|
setSensorControls.emit(sensorControls, lensControls);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareIsp::statsReady(uint32_t frame, uint32_t bufferId)
|
void SoftwareIsp::statsReady(uint32_t frame, uint32_t bufferId)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue