/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* camera_device.cpp - libcamera Android Camera Device
*/
#include "camera_device.h"
#include "camera_ops.h"
#include "post_processor.h"
#include <sys/mman.h>
#include <tuple>
#include <vector>
#include <libcamera/controls.h>
#include <libcamera/formats.h>
#include <libcamera/property_ids.h>
#include "libcamera/internal/formats.h"
#include "libcamera/internal/log.h"
#include "libcamera/internal/utils.h"
#include "camera_metadata.h"
#include "system/graphics.h"
using namespace libcamera;
namespace {
/*
* \var camera3Resolutions
* \brief The list of image resolutions defined as mandatory to be supported by
* the Android Camera3 specification
*/
const std::vector<Size> camera3Resolutions = {
{ 320, 240 },
{ 640, 480 },
{ 1280, 720 },
{ 1920, 1080 }
};
/*
* \struct Camera3Format
* \brief Data associated with an Android format identifier
* \var libcameraFormats List of libcamera pixel formats compatible with the
* Android format
* \var name The human-readable representation of the Android format code
*/
struct Camera3Format {
std::vector<PixelFormat> libcameraFormats;
bool mandatory;
const char *name;
};
/*
* \var camera3FormatsMap
* \brief Associate Android format code with ancillary data
*/
const std::map<int, const Camera3Format> camera3FormatsMap = {
{
HAL_PIXEL_FORMAT_BLOB, {
{ formats::MJPEG },
true,
"BLOB"
}
}, {
HAL_PIXEL_FORMAT_YCbCr_420_888, {
{ formats::NV12, formats::NV21 },
true,
"YCbCr_420_888"
}
}, {
/*
* \todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc
* usage flag. For now, copy the YCbCr_420 configuration.
*/
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {
{ formats::NV12, formats::NV21 },
true,
"IMPLEMENTATION_DEFINED"
}
}, {
HAL_PIXEL_FORMAT_RAW10, {
{
formats::SBGGR10_CSI2P,
formats::SGBRG10_CSI2P,
formats::SGRBG10_CSI2P,
formats::SRGGB10_CSI2P
},
false,
"RAW10"
}
}, {
HAL_PIXEL_FORMAT_RAW12, {
{
formats::SBGGR12_CSI2P,
formats::SGBRG12_CSI2P,
formats::SGRBG12_CSI2P,
formats::SRGGB12_CSI2P
},
false,
"RAW12"
}
}, {
HAL_PIXEL_FORMAT_RAW16, {
{
formats::SBGGR16,
formats::SGBRG16,
formats::SGRBG16,
formats::SRGGB16
},
false,
"RAW16"
}
}, {
HAL_PIXEL_FORMAT_RAW_OPAQUE, {
{
formats::SBGGR10_IPU3,
formats::SGBRG10_IPU3,
formats::SGRBG10_IPU3,
formats::SRGGB10_IPU3
},
false,
"RAW_OPAQUE"
}
},
};
} /* namespace */
LOG_DECLARE_CATEGORY(HAL)
MappedCamera3Buffer::MappedCamera3Buffer(const buffer_handle_t camera3buffer,
int flags)
{
maps_.reserve(camera3buffer->numFds);
error_ = 0;
for (int i = 0; i < camera3buffer->numFds; i++) {
if (camera3buffer->data[i] == -1)
continue;
off_t length = lseek(camera3buffer->data[i], 0, SEEK_END);
if (length < 0) {
error_ = -errno;
LOG(HAL, Error) << "Failed to query plane length";
break;
}
void *address = mmap(nullptr, length, flags, MAP_SHARED,
camera3buffer->data[i], 0);
if (address == MAP_FAILED) {
error_ = -errno;
LOG(HAL, Error) << "Failed to mmap plane";
break;
}
maps_.emplace_back(static_cast<uint8_t *>(address),
static_cast<size_t>(length));
}
}
/*
* \struct Camera3RequestDescriptor
*
* A utility structure that groups information about a capture request to be
* later re-used at request complete time to notify the framework.
*/
CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor(
Camera *camera, unsigned int frameNumber, unsigned int numBuffers)
: frameNumber(frameNumber), numBuffers(numBuffers)
{
buffers = new camera3_stream_buffer_t[numBuffers];
/*
* FrameBuffer instances created by wrapping a camera3 provided dmabuf
* are emplaced in this vector of unique_ptr<> for lifetime management.
*/
frameBuffers.reserve(numBuffers);
/*
* Create the libcamera::Request unique_ptr<> to tie its lifetime
* to the descriptor's one. Set the descriptor's address as the
* request's cookie to retrieve it at completion time.
*/
request = std::make_unique<CaptureRequest>(camera,
reinterpret_cast<uint64_t>(this));
}
CameraDevice::Camera3RequestDescriptor::~Camera3RequestDescriptor()
{
delete[] buffers;
}
/*
* \class CameraDevice
*
* The CameraDevice class wraps a libcamera::Camera instance, and implements
* the camera3_device_t interface, bridging calls received from the Android
* camera service to the CameraDevice.
*
* The class translates parameters and operations from the Camera HALv3 API to
* the libcamera API to provide static information for a Camera, create request
* templates for it, process capture requests and then deliver capture results
* back to the framework using the designated callbacks.
*/
CameraDevice::CameraDevice(unsigned int id, const std::shared_ptr<Camera> &camera)
: id_(id), running_(false), camera_(camera), staticMetadata_(nullptr),
facing_(CAMERA_FACING_FRONT), orientation_(0)
{
camera_->requestCompleted.connect(this, &CameraDevice::requestComplete);
/*
* \todo Determine a more accurate value for this during
* streamConfiguration.
*/
maxJpegBufferSize_ = 13 << 20; /* 13631488 from USB HAL */
}
CameraDevice::~CameraDevice()
{
if (staticMetadata_)
delete staticMetadata_;
for (auto &it : requestTemplates_)
delete it.second;
}
std::shared_ptr<CameraDevice> CameraDevice::create(unsigned int id,
const std::shared_ptr<Camera> &cam)
{
CameraDevice *camera = new CameraDevice(id, cam);
return std::shared_ptr<CameraDevice>(camera);
}
/*
* Initialize the camera static information.
* This method is called before the camera device is opened.
*/
int CameraDevice::initialize()
{
/* Initialize orientation and facing side of the camera. */
const ControlList &properties = camera_->properties();
if (properties.contains(properties::Location)) {
int32_t location = properties.get(properties::Location);
switch (location) {
case properties::CameraLocationFront:
facing_ = CAMERA_FACING_FRONT;
break;
case properties::CameraLocationBack:
facing_ = CAMERA_FACING_BACK;
break;
case properties::CameraLocationExternal:
facing_ = CAMERA_FACING_EXTERNAL;
break;
}
}
/*
* The Android orientation metadata specifies its rotation correction
* value in clockwise direction whereas libcamera specifies the
* rotation property in anticlockwise direction. Read the libcamera's
* rotation property (anticlockwise) and compute the corresponding
* value for clockwise direction as required by the Android orientation
* metadata.
*/
if (properties.contains(properties::Rotation)) {
|