/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2019-2020, Raspberry Pi (Trading) Ltd.
*
* raspberrypi.cpp - Pipeline handler for Raspberry Pi devices
*/
#include <algorithm>
#include <assert.h>
#include <fcntl.h>
#include <mutex>
#include <queue>
#include <sys/mman.h>
#include <libcamera/camera.h>
#include <libcamera/control_ids.h>
#include <libcamera/ipa/raspberrypi.h>
#include <libcamera/logging.h>
#include <libcamera/request.h>
#include <libcamera/stream.h>
#include <linux/drm_fourcc.h>
#include <linux/videodev2.h>
#include "libcamera/internal/camera_sensor.h"
#include "libcamera/internal/device_enumerator.h"
#include "libcamera/internal/ipa_manager.h"
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/utils.h"
#include "libcamera/internal/v4l2_controls.h"
#include "libcamera/internal/v4l2_videodevice.h"
#include "staggered_ctrl.h"
#include "vcsm.h"
namespace libcamera {
LOG_DEFINE_CATEGORY(RPI)
using V4L2PixFmtMap = std::map<V4L2PixelFormat, std::vector<SizeRange>>;
namespace {
bool isRaw(PixelFormat &pixFmt)
{
/*
* The isRaw test might be redundant right now the pipeline handler only
* supports RAW sensors. Leave it in for now, just as a sanity check.
*/
const PixelFormatInfo &info = PixelFormatInfo::info(pixFmt);
if (!info.isValid())
return false;
return info.colourEncoding == PixelFormatInfo::ColourEncodingRAW;
}
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;
}
V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
{
double bestScore = 9e9, score;
V4L2DeviceFormat bestMode = {};
#define PENALTY_AR 1500.0
#define PENALTY_8BIT 2000.0
#define PENALTY_10BIT 1000.0
#define PENALTY_12BIT 0.0
#define PENALTY_UNPACKED 500.0
/* Calculate the closest/best mode from the user requested size. */
for (const auto &iter : formatsMap) {
V4L2PixelFormat v4l2Format = iter.first;
PixelFormat pixelFormat = v4l2Format.toPixelFormat();
const PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat);
for (const SizeRange &sz : iter.second) {
double modeWidth = sz.contains(req) ? req.width : sz.max.width;
double modeHeight = sz.contains(req) ? req.height : sz.max.height;
double reqAr = static_cast<double>(req.width) / req.height;
double modeAr = modeWidth / modeHeight;
/* Score the dimensions for closeness. */
score = scoreFormat(req.width, modeWidth);
score += scoreFormat(req.height, modeHeight);
score += PENALTY_AR * scoreFormat(reqAr, modeAr);
/* Add any penalties... this is not an exact science! */
if (!info.packed)
score += PENALTY_UNPACKED;
if (info.bitsPerPixel == 12)
score += PENALTY_12BIT;
else if (info.bitsPerPixel == 10)
score += PENALTY_10BIT;
else if (info.bitsPerPixel == 8)
score += PENALTY_8BIT;
if (score <= bestScore) {
bestScore = score;
bestMode.fourcc = v4l2Format;
bestMode.size = Size(modeWidth, modeHeight);
}
LOG(RPI, Info) << "Mode: " << modeWidth << "x" << modeHeight
<< " fmt " << v4l2Format.toString()
<< " Score: " << score
<< " (best " << bestScore << ")";
}
}
return bestMode;
}
} /* namespace */
/*
* Device stream abstraction for either an internal or external stream.
* Used for both Unicam and the ISP.
*/
class RPiStream : public Stream
{
public:
RPiStream()
{
}
RPiStream(const char *name, MediaEntity *dev, bool importOnly = false)
|