diff options
Diffstat (limited to 'src/qcam/assets/feathericons/file-text.svg')
0 files changed, 0 insertions, 0 deletions
![]() |
index : libcamera/jmondi/libcamera.git | |
Jacopo Mondi's clone of libcamera | git repository hosting on libcamera.org |
summaryrefslogtreecommitdiff |
/* 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_hal_config.h"
#include "camera_ops.h"
#include "post_processor.h"
#include <algorithm>
#include <fstream>
#include <sys/mman.h>
#include <unistd.h>
#include <vector>
#include <libcamera/base/log.h>
#include <libcamera/base/thread.h>
#include <libcamera/base/utils.h>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
#include <libcamera/formats.h>
#include <libcamera/property_ids.h>
#include "system/graphics.h"
using namespace libcamera;
LOG_DECLARE_CATEGORY(HAL)
namespace {
/*
* \struct Camera3StreamConfig
* \brief Data to store StreamConfiguration associated with camera3_stream(s)
* \var streams List of the pairs of a stream requested by Android HAL client
* and CameraStream::Type associated with the stream
* \var config StreamConfiguration for streams
*/
struct Camera3StreamConfig {
struct Camera3Stream {
camera3_stream_t *stream;
CameraStream::Type type;
};
std::vector<Camera3Stream> streams;
StreamConfiguration config;
};
/*
* Reorder the configurations so that libcamera::Camera can accept them as much
* as possible. The sort rule is as follows.
* 1.) The configuration for NV12 request whose resolution is the largest.
* 2.) The configuration for JPEG request.
* 3.) Others. Larger resolutions and different formats are put earlier.
*/
void sortCamera3StreamConfigs(std::vector<Camera3StreamConfig> &unsortedConfigs,
const camera3_stream_t *jpegStream)
{
const Camera3StreamConfig *jpegConfig = nullptr;
std::map<PixelFormat, std::vector<const Camera3StreamConfig *>> formatToConfigs;
for (const auto &streamConfig : unsortedConfigs) {
if (jpegStream && !jpegConfig) {
const auto &streams = streamConfig.streams;
if (std::find_if(streams.begin(), streams.end(),
[jpegStream](const auto &stream) {
return stream.stream == jpegStream;
}) != streams.end()) {
jpegConfig = &streamConfig;
continue;
}
}
formatToConfigs[streamConfig.config.pixelFormat].push_back(&streamConfig);
}
if (jpegStream && !jpegConfig)
LOG(HAL, Fatal) << "No Camera3StreamConfig is found for JPEG";
for (auto &fmt : formatToConfigs) {
auto &streamConfigs = fmt.second;
/* Sorted by resolution. Smaller is put first. */
std::sort(streamConfigs.begin(), streamConfigs.end(),
[](const auto *streamConfigA, const auto *streamConfigB) {
const Size &sizeA = streamConfigA->config.size;
const Size &sizeB = streamConfigB->config.size;
return sizeA < sizeB;
});
}
std::vector<Camera3StreamConfig> sortedConfigs;
sortedConfigs.reserve(unsortedConfigs.size());
/*
* NV12 is the most prioritized format. Put the configuration with NV12
* and the largest resolution first.
*/
const auto nv12It = formatToConfigs.find(formats::NV12);
if (nv12It != formatToConfigs.end()) {
auto &nv12Configs = nv12It->second;
const Camera3StreamConfig *nv12Largest = nv12Configs.back();
/*
* If JPEG will be created from NV12 and the size is larger than
* the largest NV12 configurations, then put the NV12
* configuration for JPEG first.
*/
if (jpegConfig && jpegConfig->config.pixelFormat == formats::NV12) {
const Size &nv12SizeForJpeg = jpegConfig->config.size;
const Size &nv12LargestSize = nv12Largest->config.size;
if (nv12LargestSize < nv12SizeForJpeg) {
LOG(HAL, Debug) << "Insert " << jpegConfig->config.toString();
sortedConfigs.push_back(std::move(*jpegConfig));
jpegConfig = nullptr;
}
}
LOG(HAL, Debug) << "Insert " << nv12Largest->config.toString();
sortedConfigs.push_back(*nv12Largest);
nv12Configs.pop_back();
if (nv12Configs.empty())
formatToConfigs.erase(nv12It);
}
/* If the configuration for JPEG is there, then put it. */
if (jpegConfig) {
LOG(HAL, Debug) << "Insert " << jpegConfig->config.toString();
sortedConfigs.push_back(std::move(*jpegConfig));
jpegConfig = nullptr;
}
/*
* Put configurations with different formats and larger resolutions
* earlier.
*/
while (!formatToConfigs.empty()) {
for (auto it = formatToConfigs.begin(); it != formatToConfigs.end();) {
auto &configs = it->second;
LOG(HAL, Debug) << "Insert " << configs.back()->config.toString();
sortedConfigs.push_back(*configs.back());
configs.pop_back();
if (configs.empty())
it = formatToConfigs.erase(it);
else
it++;
}
}
ASSERT(sortedConfigs.size() == unsortedConfigs.size());
unsortedConfigs = sortedConfigs;
}
const char *rotationToString(int rotation)
{
switch (rotation) {
case CAMERA3_STREAM_ROTATION_0:
return "0";
case CAMERA3_STREAM_ROTATION_90:
return "90";
case CAMERA3_STREAM_ROTATION_180:
return "180";
case CAMERA3_STREAM_ROTATION_270:
return "270";
}
return "INVALID";
}
#if defined(OS_CHROMEOS)
/*
* Check whether the crop_rotate_scale_degrees values for all streams in
* the list are valid according to the Chrome OS camera HAL API.
*/
bool validateCropRotate(const camera3_stream_configuration_t &streamList)
{
ASSERT(streamList.num_streams > 0);
const int cropRotateScaleDegrees =
streamList.streams[0]->crop_rotate_scale_degrees;
for (unsigned int i = 0; i < streamList.num_streams; ++i) {
const camera3_stream_t &stream = *streamList.streams[i];
switch (stream.crop_rotate_scale_degrees) {
case CAMERA3_STREAM_ROTATION_0:
case CAMERA3_STREAM_ROTATION_90:
case CAMERA3_STREAM_ROTATION_270:
break;
/* 180° rotation is specified by Chrome OS as invalid. */
case CAMERA3_STREAM_ROTATION_180:
default:
LOG(HAL, Error) << "Invalid crop_rotate_scale_degrees: "
<< stream.crop_rotate_scale_degrees;
return false;
}
if (cropRotateScaleDegrees != stream.crop_rotate_scale_degrees) {
LOG(HAL, Error) << "crop_rotate_scale_degrees in all "
<< "streams are not identical";
return false;
}
}
return true;
}
#endif
} /* namespace */
/*
* \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, const camera3_capture_request_t *camera3Request)
{
frameNumber_ = camera3Request->frame_number;
/* Copy the camera3 request stream information for later access. */
const uint32_t numBuffers = camera3Request->num_output_buffers;
buffers_.resize(numBuffers);
for (uint32_t i = 0; i < numBuffers; i++)
buffers_[i] = camera3Request->output_buffers[i];
/*
* FrameBuffer instances created by wrapping a camera3 provided dmabuf
* are emplaced in this vector of unique_ptr<> for lifetime management.
*/
frameBuffers_.reserve(numBuffers);
/* Clone the controls associated with the camera3 request. */
settings_ = CameraMetadata(camera3Request->settings);
/*
* Create the CaptureRequest, stored as a unique_ptr<> to tie its
* lifetime to the descriptor.
*/
request_ = std::make_unique<CaptureRequest>(camera);
}
/*
* \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, std::shared_ptr<Camera> camera)
: id_(id), state_(State::Stopped), camera_(std::move(camera)),
facing_(CAMERA_FACING_FRONT), orientation_(0)
{
camera_->requestCompleted.connect(this, &CameraDevice::requestComplete);
maker_ = "libcamera";
model_ = "cameraModel";
/* \todo Support getting properties on Android */
std::ifstream fstream("/var/cache/camera/camera.prop");
if (!fstream.is_open())
return;
std::string line;
while (std::getline(fstream, line)) {
std::string::size_type delimPos = line.find("=");
if (delimPos == std::string::npos)
continue;
std::string key = line.substr(0, delimPos);
std::string val = line.substr(delimPos + 1);
if (!key.compare("ro.product.model"))
model_ = val;
else if (!key.compare("ro.product.manufacturer"))
maker_ = val;
}
}
CameraDevice::~CameraDevice() = default;
std::unique_ptr<CameraDevice> CameraDevice::create(unsigned int id,
std::shared_ptr<Camera> cam)
{
return std::unique_ptr<CameraDevice>(
new CameraDevice(id, std::move(cam)));
}
/*
* Initialize the camera static information retrieved from the
* Camera::properties or from the cameraConfigData.
*
* cameraConfigData is optional for external camera devices and can be
* nullptr.
*
* This method is called before the camera device is opened.
*/
int CameraDevice::initialize(const CameraConfigData *cameraConfigData)
{
/*
* Initialize orientation and facing side of the camera.
*
* If the libcamera::Camera provides those information as retrieved
* from firmware use them, otherwise fallback to values parsed from
* the configuration file. If the configuration file is not available
* the camera is external so its location and rotation can be safely
* defaulted.
*/
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;
}
if (cameraConfigData && cameraConfigData->facing != -1 &&
facing_ != cameraConfigData->facing) {
LOG(HAL, Warning)
<< "Camera location does not match"
<< " configuration file. Using " << facing_;
}
} else if (cameraConfigData) {
if (cameraConfigData->facing == -1) {
LOG(HAL, Error)
<< "Camera facing not in configuration file";
return -EINVAL;
}
facing_ = cameraConfigData->facing;
} else {
facing_ = CAMERA_FACING_EXTERNAL;
}
/*
* 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)) {
int rotation = properties.get(properties::Rotation);
orientation_ = (360 - rotation) % 360;
if (cameraConfigData && cameraConfigData->rotation != -1 &&
orientation_ != cameraConfigData->rotation) {
LOG(HAL, Warning)
<< "Camera orientation does not match"
<< " configuration file. Using " << orientation_;
}
} else if (cameraConfigData) {
if (cameraConfigData->rotation == -1) {
LOG(HAL, Error)
<< "Camera rotation not in configuration file";
return -EINVAL;
}
orientation_ = cameraConfigData->rotation;
} else {
orientation_ = 0;
}
return capabilities_.initialize(camera_, orientation_, facing_);
}
/*
* Open a camera device. The static information on the camera shall have been
* initialized with a call to CameraDevice::initialize().
*/
int CameraDevice::open(const hw_module_t *hardwareModule)
{
int ret = camera_->acquire();
if (ret) {
LOG(HAL, Error) << "Failed to acquire the camera";
return ret;
}
/* Initialize the hw_device_t in the instance camera3_module_t. */
camera3Device_.common.tag = HARDWARE_DEVICE_TAG;
camera3Device_.common.version = CAMERA_DEVICE_API_VERSION_3_3;
camera3Device_.common.module = (hw_module_t *)hardwareModule;
camera3Device_.common.close = hal_dev_close;
/*
* The camera device operations. These actually implement
* the Android Camera HALv3 interface.
*/
camera3Device_.ops = &hal_dev_ops;
camera3Device_.priv = this;
return 0;
}
void CameraDevice::close()
{
streams_.clear();
stop();
camera_->release();
}
void CameraDevice::flush()
{
{
MutexLocker stateLock(stateMutex_);
if (state_ != State::Running)
return;
state_ = State::Flushing;
}
worker_.stop();
camera_->stop();
MutexLocker stateLock(stateMutex_);
state_ = State::Stopped;
}
void CameraDevice::stop()
{
MutexLocker stateLock(stateMutex_);
if (state_ == State::Stopped)
return;
worker_.stop();
camera_->stop();
descriptors_.clear();
state_ = State::Stopped;
}
unsigned int CameraDevice::maxJpegBufferSize() const
{
return capabilities_.maxJpegBufferSize();
}
void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)
{
callbacks_ = callbacks;
}
const camera_metadata_t *CameraDevice::getStaticMetadata()
{
return capabilities_.staticMetadata()->get();
}
/*
* Produce a metadata pack to be used as template for a capture request.
*/
const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)
{
auto it = requestTemplates_.find(type);
if (it != requestTemplates_.end())
return it->second->get();