/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2019-2021, Raspberry Pi (Trading) Ltd.
*
* rpi.cpp - Raspberry Pi Image Processing Algorithms
*/
#include <algorithm>
#include <array>
#include <fcntl.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include <libcamera/buffer.h>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
#include <libcamera/file_descriptor.h>
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/ipa_module_info.h>
#include <libcamera/ipa/raspberrypi.h>
#include <libcamera/ipa/raspberrypi_ipa_interface.h>
#include <libcamera/request.h>
#include <libcamera/span.h>
#include "libcamera/internal/buffer.h"
#include "libcamera/internal/log.h"
#include <linux/bcm2835-isp.h>
#include "agc_algorithm.hpp"
#include "agc_status.h"
#include "alsc_status.h"
#include "awb_algorithm.hpp"
#include "awb_status.h"
#include "black_level_status.h"
#include "cam_helper.hpp"
#include "ccm_algorithm.hpp"
#include "ccm_status.h"
#include "contrast_algorithm.hpp"
#include "contrast_status.h"
#include "controller.hpp"
#include "denoise_algorithm.hpp"
#include "denoise_status.h"
#include "dpc_status.h"
#include "focus_status.h"
#include "geq_status.h"
#include "lux_status.h"
#include "metadata.hpp"
#include "noise_status.h"
#include "sharpen_algorithm.hpp"
#include "sharpen_status.h"
namespace libcamera {
/* Configure the sensor with these values initially. */
constexpr double DefaultAnalogueGain = 1.0;
constexpr unsigned int DefaultExposureTime = 20000;
constexpr double defaultMinFrameDuration = 1e6 / 30.0;
constexpr double defaultMaxFrameDuration = 1e6 / 0.01;
/*
* Determine the minimum allowable inter-frame duration (in us) to run the
* controller algorithms. If the pipeline handler provider frames at a rate
* higher than this, we rate-limit the controller Prepare() and Process() calls
* to lower than or equal to this rate.
*/
constexpr double controllerMinFrameDuration = 1e6 / 60.0;
LOG_DEFINE_CATEGORY(IPARPI)
class IPARPi : public ipa::RPi::IPARPiInterface
{
public:
IPARPi()
: controller_(), frameCount_(0), checkCount_(0), mistrustCount_(0),
lastRunTimestamp_(0), lsTable_(nullptr), firstStart_(true)
{
}
~IPARPi()
{
if (lsTable_)
munmap(lsTable_, ipa::RPi::MaxLsGridSize);
}
int init(const IPASettings &settings, ipa::RPi::SensorConfig *sensorConfig) override;
void start(const ControlList &controls, ipa::RPi::StartConfig *startConfig) override;
void stop() override {}
int configure(const IPACameraSensorInfo &sensorInfo,
const std::map<unsigned int, IPAStream> &streamConfig,
const std::map<unsigned int, ControlInfoMap> &entityControls,
const ipa::RPi::IPAConfig &data,
ControlList *controls) override;
void mapBuffers(const std::vector<IPABuffer> &buffers) override;
void unmapBuffers(const std::vector<unsigned int> &ids) override;
void signalStatReady(const uint32_t bufferId) override;
void signalQueueRequest(const ControlList &controls) override;
void signalIspPrepare(const ipa::RPi::ISPConfig &data) override;
private:
void setMode(const IPACameraSensorInfo &sensorInfo);
bool validateSensorControls();
bool validateIspControls();
void queueRequest(const ControlList &controls);
void returnEmbeddedBuffer(unsigned int bufferId);
void prepareISP(const ipa::RPi::ISPConfig &data);
void reportMetadata();
void fillDeviceStatus(const ControlList &sensorControls);
void processStats(unsigned int bufferId);
void applyFrameDurations(double minFrameDuration, double maxFrameDuration);
void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);
void applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls);
void applyDG(const struct AgcStatus *dgStatus, ControlList &ctrls);
void applyCCM(const struct CcmStatus *ccmStatus, ControlList &ctrls);
void applyBlackLevel(const struct BlackLevelStatus *blackLevelStatus, ControlList &ctrls);
void applyGamma(const struct ContrastStatus *contrastStatus, ControlList &ctrls);
void applyGEQ(const struct GeqStatus *geqStatus, ControlList &ctrls);
void applyDenoise(const struct DenoiseStatus *denoiseStatus, ControlList &ctrls);
void applySharpen(const struct SharpenStatus *sharpenStatus, ControlList &ctrls);
void applyDPC(const struct DpcStatus *dpcStatus, ControlList &ctrls);
void applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls);
void resampleTable(uint16_t dest[], double const src[12][16], int destW, int destH);
std::map<unsigned int, MappedFrameBuffer> buffers_;
ControlInfoMap sensorCtrls_;
ControlInfoMap ispCtrls_;
ControlList libcameraMetadata_;
/* Camera sensor params. */
CameraMode mode_;
/* Raspberry Pi controller specific defines. */
std::unique_ptr<RPiController::CamHelper> helper_;
RPiController::Controller controller_;
RPiController::Metadata rpiMetadata_;
/*
* We count frames to decide if the frame must be hidden (e.g. from
* display) or mistrusted (i.e. not given to the control algos).
*/
uint64_t frameCount_;
/* For checking the sequencing of Prepare/Process calls. */
uint64_t checkCount_;
/* How many frames we should avoid running control algos on. */
unsigned int mistrustCount_;
/* Number of frames that need to be dropped on startup. */
unsigned int dropFrameCount_;
/* Frame timestamp for the last run of the controller. */
uint64_t lastRunTimestamp_;
/* Do we run a Controller::process() for this frame? */
bool processPending_;
/* LS table allocation passed in from the pipeline handler. */
FileDescriptor lsTableHandle_;
void *lsTable_;
/* Distinguish the first camera start from others. */
bool firstStart_;
/* Frame duration (1/fps) limits, given in microseconds. */
double minFrameDuration_;
double maxFrameDuration_;
};
int IPARPi::init(const IPASettings &settings, ipa::RPi::SensorConfig *sensorConfig)
{
/*
* Load the "helper" for this sensor. This tells us all the device specific stuff
* that the kernel driver doesn't. We only do this the first time; we don't need
* to re-parse the metadata after a simple mode-switch for no reason.
*/
|