/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019-2021, Raspberry Pi Ltd
*
* raspberrypi.cpp - Pipeline handler for Raspberry Pi devices
*/
#include <algorithm>
#include <assert.h>
#include <cmath>
#include <fcntl.h>
#include <memory>
#include <mutex>
#include <queue>
#include <unordered_set>
#include <utility>
#include <libcamera/base/file.h>
#include <libcamera/base/shared_fd.h>
#include <libcamera/base/utils.h>
#include <libcamera/camera.h>
#include <libcamera/control_ids.h>
#include <libcamera/formats.h>
#include <libcamera/ipa/raspberrypi_ipa_interface.h>
#include <libcamera/ipa/raspberrypi_ipa_proxy.h>
#include <libcamera/logging.h>
#include <libcamera/property_ids.h>
#include <libcamera/request.h>
#include <linux/bcm2835-isp.h>
#include <linux/media-bus-format.h>
#include <linux/videodev2.h>
#include "libcamera/internal/bayer_format.h"
#include "libcamera/internal/camera.h"
#include "libcamera/internal/camera_lens.h"
#include "libcamera/internal/camera_sensor.h"
#include "libcamera/internal/device_enumerator.h"
#include "libcamera/internal/framebuffer.h"
#include "libcamera/internal/ipa_manager.h"
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/v4l2_videodevice.h"
#include "libcamera/internal/yaml_parser.h"
#include "delayed_controls.h"
#include "dma_heaps.h"
#include "rpi_stream.h"
using namespace std::chrono_literals;
namespace libcamera {
LOG_DEFINE_CATEGORY(RPI)
namespace {
constexpr unsigned int defaultRawBitDepth = 12;
/* Map of mbus codes to supported sizes reported by the sensor. */
using SensorFormats = std::map<unsigned int, std::vector<Size>>;
SensorFormats populateSensorFormats(std::unique_ptr<CameraSensor> &sensor)
{
SensorFormats formats;
for (auto const mbusCode : sensor->mbusCodes())
formats.emplace(mbusCode, sensor->sizes(mbusCode));
return formats;
}
bool isMonoSensor(std::unique_ptr<CameraSensor> &sensor)
{
unsigned int mbusCode = sensor->mbusCodes()[0];
const BayerFormat &bayer = BayerFormat::fromMbusCode(mbusCode);
return bayer.order == BayerFormat::Order::MONO;
}
PixelFormat mbusCodeToPixelFormat(unsigned int mbus_code,
BayerFormat::Packing packingReq)
{
BayerFormat bayer = BayerFormat::fromMbusCode(mbus_code);
ASSERT(bayer.isValid());
bayer.packing = packingReq;
PixelFormat pix = bayer.toPixelFormat();
/*
* Not all formats (e.g. 8-bit or 16-bit Bayer formats) can have packed
* variants. So if the PixelFormat returns as invalid, use the non-packed
* conversion instead.
*/
if (!pix.isValid()) {
bayer.packing = BayerFormat::Packing::None;
pix = bayer.toPixelFormat();
}
return pix;
}
V4L2DeviceFormat toV4L2DeviceFormat(const V4L2VideoDevice *dev,
const V4L2SubdeviceFormat &format,
BayerFormat::Packing packingReq)
{
const PixelFormat pix = mbusCodeToPixelFormat(format.mbus_code, packingReq);
V4L2DeviceFormat deviceFormat;
deviceFormat.fourcc = dev->toV4L2PixelFormat(pix);
deviceFormat.size = format.size;
deviceFormat.colorSpace = format.colorSpace;
return deviceFormat;
}
bool isRaw(const PixelFormat &pixFmt)
{
/* This test works for both Bayer and raw mono formats. */
return BayerFormat::fromPixelFormat(pixFmt).isValid();
}
double scoreFormat(double desired, double actual)
{
double score = desired - actual;
/* Smaller desired dimensions are preferred. */
if (score < 0.0)
score = (-score) / 8;
/* Penalise non-exact matches. */
if (actual != desired)
score *= 2;
return score;
}
V4L2SubdeviceFormat findBestFormat(const SensorFormats &formatsMap, const Size &req, unsigned int bitDepth)
{
double bestScore = std::numeric_limits<double>::max(), score;
V4L2SubdeviceFormat bestFormat;
bestFormat.colorSpace = ColorSpace::Raw;
constexpr float penaltyAr = 1500.0;
constexpr float penaltyBitDepth = 500.0;
/* Calculate the closest/best mode from the user requested size. */
for (const auto &iter : formatsMap) {
const unsigned int mbusCode = iter.first;
const PixelFormat format = mbusCodeToPixelFormat(mbusCode,
BayerFormat::Packing::None);
const PixelFormatInfo &info = PixelFormatInfo::info(format);
for (const Size &size : iter.second) {
double reqAr = static_cast<double>(req.width) / req.height;
double fmtAr = static_cast<double>(size.width) / size.height;
/* Score the dimensions for closeness. */
score = scoreFormat(req.width, size.width);
score += scoreFormat(req.height, size.height);
score += penaltyAr * scoreFormat(reqAr, fmtAr);
/* Add any penalties... this is not an exact science! */
score += utils::abs_diff(info.bitsPerPixel, bitDepth) * penaltyBitDepth;
if (score <= bestScore) {
bestScore = score;
bestFormat.mbus_code = mbusCode;
bestFormat.size = size;
}
LOG(RPI, Debug) << "Format: " << size
<< " fmt " << format
<< " Score: " << score
<< " (best " << bestScore << ")";
}
}
return bestFormat;
}
enum class Unicam : unsigned int { Image, Embedded };
enum class Isp : unsigned int { Input, Output0, Output1, Stats };
} /* namespace */
class RPiCameraData : public Camera::Private
{
public:
RPiCameraData(PipelineHandler *pipe)
: Camera::Private(pipe), state_(State::Stopped),
supportsFlips_(false), flipsAlterBayerOrder_(false),
dropFrameCount_(0), buffersAllocated_(false), ispOutputCount_(0)
{
}
~RPiCameraData()
{
freeBuffers();
}
void freeBuffers();
void frameStarted(uint32_t sequence);
int loadIPA(ipa::RPi::IPAInitResult *result);
int configureIPA(const CameraConfiguration *config, ipa::RPi::IPAConfigResult *result);
int loadPipelineConfiguration();
void enumerateVideoDevices(MediaLink *link);
void statsMetadataComplete(uint32_t bufferId, const ControlList &controls);
void runIsp(uint32_t bufferId);
void embeddedComplete(uint32_t bufferId);
void setIspControls(const ControlList &controls);
void setDelayedControls(const ControlList &controls, uint32_t delayContext);
void setLensControls(const ControlList &controls);
void setSensorControls(ControlList &controls);
void unicamTimeout();
/* bufferComplete signal handlers. */
void unicamBufferDequeue(FrameBuffer *buffer);
void ispInputDequeue(FrameBuffer *buffer);
void ispOutputDequeue(FrameBuffer *buffer);
void clearIncompleteRequests();
void handleStreamBuffer(FrameBuffer *buffer, RPi::Stream *stream);
void handleExternalBuffer(FrameBuffer *buffer, RPi::Stream *stream);
void handleState();
Rectangle scaleIspCrop(const Rectangle &ispCrop) const;
void applyScalerCrop(const ControlList &controls);
std::unique_ptr<ipa::RPi::IPAProxyRPi> ipa_;
std::unique_ptr<CameraSensor> sensor_;
SensorFormats sensorFormats_;
/* Array of Unicam and ISP device streams and associated buffers/streams. */
RPi::Device<Unicam, 2> unicam_;
RPi::Device<Isp, 4> isp_;
/* The vector below is just for convenience when iterating over all streams. */
|