ipa: raspberrypi: Use CamHelpers to generalise sensor embedded data parsing

CamHelpers get virtual Prepare() and Process() methods, running just
before and just after the ISP, just like Raspberry Pi Algorithms.

The Prepare() method is able to parse the register dumps in embedded
data buffers, and can be specialised to perform custom processing when
necessary.

The IPA itself only needs to call the new Prepare() and Process()
methods. It must fill in the DeviceStatus from the controls first, in
case the Prepare() method does not supply its own values.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
David Plowman 2021-05-07 12:37:28 +01:00 committed by Laurent Pinchart
parent df36fb4abb
commit 5fda81e1f4
3 changed files with 90 additions and 55 deletions

View file

@ -17,6 +17,11 @@
#include "md_parser.hpp" #include "md_parser.hpp"
using namespace RPiController; using namespace RPiController;
using namespace libcamera;
namespace libcamera {
LOG_DECLARE_CATEGORY(IPARPI)
}
static std::map<std::string, CamHelperCreateFunc> cam_helpers; static std::map<std::string, CamHelperCreateFunc> cam_helpers;
@ -45,6 +50,17 @@ CamHelper::~CamHelper()
delete parser_; delete parser_;
} }
void CamHelper::Prepare(Span<const uint8_t> buffer,
Metadata &metadata)
{
parseEmbeddedData(buffer, metadata);
}
void CamHelper::Process([[maybe_unused]] StatisticsPtr &stats,
[[maybe_unused]] Metadata &metadata)
{
}
uint32_t CamHelper::ExposureLines(double exposure_us) const uint32_t CamHelper::ExposureLines(double exposure_us) const
{ {
assert(initialized_); assert(initialized_);
@ -139,6 +155,44 @@ unsigned int CamHelper::MistrustFramesModeSwitch() const
return 0; return 0;
} }
void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,
Metadata &metadata)
{
if (buffer.empty())
return;
uint32_t exposureLines, gainCode;
if (parser_->Parse(buffer) != MdParser::Status::OK ||
parser_->GetExposureLines(exposureLines) != MdParser::Status::OK ||
parser_->GetGainCode(gainCode) != MdParser::Status::OK) {
LOG(IPARPI, Error) << "Embedded data buffer parsing failed";
return;
}
/*
* Overwrite the exposure/gain values in the DeviceStatus, as
* we know better. Fetch it first in case any other fields were
* set meaningfully.
*/
DeviceStatus deviceStatus;
if (metadata.Get("device.status", deviceStatus) != 0) {
LOG(IPARPI, Error) << "DeviceStatus not found";
return;
}
deviceStatus.shutter_speed = Exposure(exposureLines);
deviceStatus.analogue_gain = Gain(gainCode);
LOG(IPARPI, Debug) << "Metadata updated - Exposure : "
<< deviceStatus.shutter_speed
<< " Gain : "
<< deviceStatus.analogue_gain;
metadata.Set("device.status", deviceStatus);
}
RegisterCamHelper::RegisterCamHelper(char const *cam_name, RegisterCamHelper::RegisterCamHelper(char const *cam_name,
CamHelperCreateFunc create_func) CamHelperCreateFunc create_func)
{ {

View file

@ -8,7 +8,11 @@
#include <string> #include <string>
#include <libcamera/span.h>
#include "camera_mode.h" #include "camera_mode.h"
#include "controller/controller.hpp"
#include "controller/metadata.hpp"
#include "md_parser.hpp" #include "md_parser.hpp"
#include "libcamera/internal/v4l2_videodevice.h" #include "libcamera/internal/v4l2_videodevice.h"
@ -65,7 +69,9 @@ public:
CamHelper(MdParser *parser, unsigned int frameIntegrationDiff); CamHelper(MdParser *parser, unsigned int frameIntegrationDiff);
virtual ~CamHelper(); virtual ~CamHelper();
void SetCameraMode(const CameraMode &mode); void SetCameraMode(const CameraMode &mode);
MdParser &Parser() const { return *parser_; } virtual void Prepare(libcamera::Span<const uint8_t> buffer,
Metadata &metadata);
virtual void Process(StatisticsPtr &stats, Metadata &metadata);
uint32_t ExposureLines(double exposure_us) const; uint32_t ExposureLines(double exposure_us) const;
double Exposure(uint32_t exposure_lines) const; // in us double Exposure(uint32_t exposure_lines) const; // in us
virtual uint32_t GetVBlanking(double &exposure_us, double minFrameDuration, virtual uint32_t GetVBlanking(double &exposure_us, double minFrameDuration,
@ -81,6 +87,9 @@ public:
virtual unsigned int MistrustFramesModeSwitch() const; virtual unsigned int MistrustFramesModeSwitch() const;
protected: protected:
void parseEmbeddedData(libcamera::Span<const uint8_t> buffer,
Metadata &metadata);
MdParser *parser_; MdParser *parser_;
CameraMode mode_; CameraMode mode_;

View file

@ -101,9 +101,7 @@ private:
void returnEmbeddedBuffer(unsigned int bufferId); void returnEmbeddedBuffer(unsigned int bufferId);
void prepareISP(const ipa::RPi::ISPConfig &data); void prepareISP(const ipa::RPi::ISPConfig &data);
void reportMetadata(); void reportMetadata();
bool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus); void fillDeviceStatus(const ControlList &sensorControls);
void fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,
struct DeviceStatus &deviceStatus);
void processStats(unsigned int bufferId); void processStats(unsigned int bufferId);
void applyFrameDurations(double minFrameDuration, double maxFrameDuration); void applyFrameDurations(double minFrameDuration, double maxFrameDuration);
void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls); void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);
@ -894,35 +892,34 @@ void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)
void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data) void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)
{ {
struct DeviceStatus deviceStatus = {}; Span<uint8_t> embeddedBuffer;
bool success = false;
rpiMetadata_.Clear();
fillDeviceStatus(data.controls);
if (data.embeddedBufferPresent) { if (data.embeddedBufferPresent) {
/* /*
* Pipeline handler has supplied us with an embedded data buffer, * Pipeline handler has supplied us with an embedded data buffer,
* so parse it and extract the exposure and gain. * we must pass it to the CamHelper for parsing.
*/ */
success = parseEmbeddedData(data.embeddedBufferId, deviceStatus); auto it = buffers_.find(data.embeddedBufferId);
ASSERT(it != buffers_.end());
embeddedBuffer = it->second.maps()[0];
}
/* Done with embedded data now, return to pipeline handler asap. */ /*
* This may overwrite the DeviceStatus using values from the sensor
* metadata, and may also do additional custom processing.
*/
helper_->Prepare(embeddedBuffer, rpiMetadata_);
/* Done with embedded data now, return to pipeline handler asap. */
if (data.embeddedBufferPresent)
returnEmbeddedBuffer(data.embeddedBufferId); returnEmbeddedBuffer(data.embeddedBufferId);
}
if (!success) {
/*
* Pipeline handler has not supplied an embedded data buffer,
* or embedded data buffer parsing has failed for some reason,
* so pull the exposure and gain values from the control list.
*/
int32_t exposureLines = data.controls.get(V4L2_CID_EXPOSURE).get<int32_t>();
int32_t gainCode = data.controls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
fillDeviceStatus(exposureLines, gainCode, deviceStatus);
}
ControlList ctrls(ispCtrls_); ControlList ctrls(ispCtrls_);
rpiMetadata_.Clear();
rpiMetadata_.Set("device.status", deviceStatus);
controller_.Prepare(&rpiMetadata_); controller_.Prepare(&rpiMetadata_);
/* Lock the metadata buffer to avoid constant locks/unlocks. */ /* Lock the metadata buffer to avoid constant locks/unlocks. */
@ -972,41 +969,13 @@ void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)
setIspControls.emit(ctrls); setIspControls.emit(ctrls);
} }
bool IPARPi::parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus) void IPARPi::fillDeviceStatus(const ControlList &sensorControls)
{ {
auto it = buffers_.find(bufferId); DeviceStatus deviceStatus = {};
if (it == buffers_.end()) {
LOG(IPARPI, Error) << "Could not find embedded buffer!";
return false;
}
Span<uint8_t> mem = it->second.maps()[0]; int32_t exposureLines = sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();
helper_->Parser().SetBufferSize(mem.size()); int32_t gainCode = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
RPiController::MdParser::Status status = helper_->Parser().Parse(mem.data());
if (status != RPiController::MdParser::Status::OK) {
LOG(IPARPI, Error) << "Embedded Buffer parsing failed, error " << status;
return false;
} else {
uint32_t exposureLines, gainCode;
if (helper_->Parser().GetExposureLines(exposureLines) != RPiController::MdParser::Status::OK) {
LOG(IPARPI, Error) << "Exposure time failed";
return false;
}
if (helper_->Parser().GetGainCode(gainCode) != RPiController::MdParser::Status::OK) {
LOG(IPARPI, Error) << "Gain failed";
return false;
}
fillDeviceStatus(exposureLines, gainCode, deviceStatus);
}
return true;
}
void IPARPi::fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,
struct DeviceStatus &deviceStatus)
{
deviceStatus.shutter_speed = helper_->Exposure(exposureLines); deviceStatus.shutter_speed = helper_->Exposure(exposureLines);
deviceStatus.analogue_gain = helper_->Gain(gainCode); deviceStatus.analogue_gain = helper_->Gain(gainCode);
@ -1014,6 +983,8 @@ void IPARPi::fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,
<< deviceStatus.shutter_speed << deviceStatus.shutter_speed
<< " Gain : " << " Gain : "
<< deviceStatus.analogue_gain; << deviceStatus.analogue_gain;
rpiMetadata_.Set("device.status", deviceStatus);
} }
void IPARPi::processStats(unsigned int bufferId) void IPARPi::processStats(unsigned int bufferId)
@ -1027,6 +998,7 @@ void IPARPi::processStats(unsigned int bufferId)
Span<uint8_t> mem = it->second.maps()[0]; Span<uint8_t> mem = it->second.maps()[0];
bcm2835_isp_stats *stats = reinterpret_cast<bcm2835_isp_stats *>(mem.data()); bcm2835_isp_stats *stats = reinterpret_cast<bcm2835_isp_stats *>(mem.data());
RPiController::StatisticsPtr statistics = std::make_shared<bcm2835_isp_stats>(*stats); RPiController::StatisticsPtr statistics = std::make_shared<bcm2835_isp_stats>(*stats);
helper_->Process(statistics, rpiMetadata_);
controller_.Process(statistics, &rpiMetadata_); controller_.Process(statistics, &rpiMetadata_);
struct AgcStatus agcStatus; struct AgcStatus agcStatus;