mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-13 15:29:45 +03:00
Previously we had to manually declare the size of CameraMetadata on allocation, and its count could not be changed after construction. Change CameraMetadata's behavior so that the user can simply add or update entries, and the CameraMetadata will auto-resize (double the size) as necessary. Also remove everything involved with calculating the initial size for any CameraMetadata instances. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2304 lines
70 KiB
C++
2304 lines
70 KiB
C++
/* 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 <array>
|
|
#include <cmath>
|
|
#include <fstream>
|
|
#include <sys/mman.h>
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
#include <libcamera/control_ids.h>
|
|
#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 "system/graphics.h"
|
|
|
|
using namespace libcamera;
|
|
|
|
LOG_DECLARE_CATEGORY(HAL)
|
|
|
|
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"
|
|
}
|
|
},
|
|
};
|
|
|
|
/*
|
|
* \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;
|
|
}
|
|
|
|
bool isValidRequest(camera3_capture_request_t *camera3Request)
|
|
{
|
|
if (!camera3Request) {
|
|
LOG(HAL, Error) << "No capture request provided";
|
|
return false;
|
|
}
|
|
|
|
if (!camera3Request->num_output_buffers ||
|
|
!camera3Request->output_buffers) {
|
|
LOG(HAL, Error) << "No output buffers provided";
|
|
return false;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < camera3Request->num_output_buffers; i++) {
|
|
const camera3_stream_buffer_t &outputBuffer =
|
|
camera3Request->output_buffers[i];
|
|
if (!outputBuffer.buffer || !(*outputBuffer.buffer)) {
|
|
LOG(HAL, Error) << "Invalid native handle";
|
|
return false;
|
|
}
|
|
|
|
const native_handle_t *handle = *outputBuffer.buffer;
|
|
constexpr int kNativeHandleMaxFds = 1024;
|
|
if (handle->numFds < 0 || handle->numFds > kNativeHandleMaxFds) {
|
|
LOG(HAL, Error)
|
|
<< "Invalid number of fds (" << handle->numFds
|
|
<< ") in buffer " << i;
|
|
return false;
|
|
}
|
|
|
|
constexpr int kNativeHandleMaxInts = 1024;
|
|
if (handle->numInts < 0 || handle->numInts > kNativeHandleMaxInts) {
|
|
LOG(HAL, Error)
|
|
<< "Invalid number of ints (" << handle->numInts
|
|
<< ") in buffer " << i;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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), running_(false), 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.
|
|
* 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;
|
|
}
|
|
} else {
|
|
/*
|
|
* \todo Retrieve the camera location from configuration file
|
|
* if not available from the library.
|
|
*/
|
|
facing_ = CAMERA_FACING_FRONT;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
int ret = camera_->acquire();
|
|
if (ret) {
|
|
LOG(HAL, Error) << "Failed to temporarily acquire the camera";
|
|
return ret;
|
|
}
|
|
|
|
ret = initializeStreamConfigurations();
|
|
camera_->release();
|
|
return ret;
|
|
}
|
|
|
|
std::vector<Size> CameraDevice::getYUVResolutions(CameraConfiguration *cameraConfig,
|
|
const PixelFormat &pixelFormat,
|
|
const std::vector<Size> &resolutions)
|
|
{
|
|
std::vector<Size> supportedResolutions;
|
|
|
|
StreamConfiguration &cfg = cameraConfig->at(0);
|
|
for (const Size &res : resolutions) {
|
|
cfg.pixelFormat = pixelFormat;
|
|
cfg.size = res;
|
|
|
|
CameraConfiguration::Status status = cameraConfig->validate();
|
|
if (status != CameraConfiguration::Valid) {
|
|
LOG(HAL, Debug) << cfg.toString() << " not supported";
|
|
continue;
|
|
}
|
|
|
|
LOG(HAL, Debug) << cfg.toString() << " supported";
|
|
|
|
supportedResolutions.push_back(res);
|
|
}
|
|
|
|
return supportedResolutions;
|
|
}
|
|
|
|
std::vector<Size> CameraDevice::getRawResolutions(const libcamera::PixelFormat &pixelFormat)
|
|
{
|
|
std::unique_ptr<CameraConfiguration> cameraConfig =
|
|
camera_->generateConfiguration({ StreamRole::Raw });
|
|
StreamConfiguration &cfg = cameraConfig->at(0);
|
|
const StreamFormats &formats = cfg.formats();
|
|
std::vector<Size> supportedResolutions = formats.sizes(pixelFormat);
|
|
|
|
return supportedResolutions;
|
|
}
|
|
|
|
/*
|
|
* Initialize the format conversion map to translate from Android format
|
|
* identifier to libcamera pixel formats and fill in the list of supported
|
|
* stream configurations to be reported to the Android camera framework through
|
|
* the static stream configuration metadata.
|
|
*/
|
|
int CameraDevice::initializeStreamConfigurations()
|
|
{
|
|
/*
|
|
* Get the maximum output resolutions
|
|
* \todo Get this from the camera properties once defined
|
|
*/
|
|
std::unique_ptr<CameraConfiguration> cameraConfig =
|
|
camera_->generateConfiguration({ StillCapture });
|
|
if (!cameraConfig) {
|
|
LOG(HAL, Error) << "Failed to get maximum resolution";
|
|
return -EINVAL;
|
|
}
|
|
StreamConfiguration &cfg = cameraConfig->at(0);
|
|
|
|
/*
|
|
* \todo JPEG - Adjust the maximum available resolution by taking the
|
|
* JPEG encoder requirements into account (alignment and aspect ratio).
|
|
*/
|
|
const Size maxRes = cfg.size;
|
|
LOG(HAL, Debug) << "Maximum supported resolution: " << maxRes.toString();
|
|
|
|
/*
|
|
* Build the list of supported image resolutions.
|
|
*
|
|
* The resolutions listed in camera3Resolution are mandatory to be
|
|
* supported, up to the camera maximum resolution.
|
|
*
|
|
* Augment the list by adding resolutions calculated from the camera
|
|
* maximum one.
|
|
*/
|
|
std::vector<Size> cameraResolutions;
|
|
std::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),
|
|
std::back_inserter(cameraResolutions),
|
|
[&](const Size &res) { return res < maxRes; });
|
|
|
|
/*
|
|
* The Camera3 specification suggests adding 1/2 and 1/4 of the maximum
|
|
* resolution.
|
|
*/
|
|
for (unsigned int divider = 2;; divider <<= 1) {
|
|
Size derivedSize{
|
|
maxRes.width / divider,
|
|
maxRes.height / divider,
|
|
};
|
|
|
|
if (derivedSize.width < 320 ||
|
|
derivedSize.height < 240)
|
|
break;
|
|
|
|
cameraResolutions.push_back(derivedSize);
|
|
}
|
|
cameraResolutions.push_back(maxRes);
|
|
|
|
/* Remove duplicated entries from the list of supported resolutions. */
|
|
std::sort(cameraResolutions.begin(), cameraResolutions.end());
|
|
auto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());
|
|
cameraResolutions.erase(last, cameraResolutions.end());
|
|
|
|
/*
|
|
* Build the list of supported camera formats.
|
|
*
|
|
* To each Android format a list of compatible libcamera formats is
|
|
* associated. The first libcamera format that tests successful is added
|
|
* to the format translation map used when configuring the streams.
|
|
* It is then tested against the list of supported camera resolutions to
|
|
* build the stream configuration map reported through the camera static
|
|
* metadata.
|
|
*/
|
|
Size maxJpegSize;
|
|
for (const auto &format : camera3FormatsMap) {
|
|
int androidFormat = format.first;
|
|
const Camera3Format &camera3Format = format.second;
|
|
const std::vector<PixelFormat> &libcameraFormats =
|
|
camera3Format.libcameraFormats;
|
|
|
|
LOG(HAL, Debug) << "Trying to map Android format "
|
|
<< camera3Format.name;
|
|
|
|
/*
|
|
* JPEG is always supported, either produced directly by the
|
|
* camera, or encoded in the HAL.
|
|
*/
|
|
if (androidFormat == HAL_PIXEL_FORMAT_BLOB) {
|
|
formatsMap_[androidFormat] = formats::MJPEG;
|
|
LOG(HAL, Debug) << "Mapped Android format "
|
|
<< camera3Format.name << " to "
|
|
<< formats::MJPEG.toString()
|
|
<< " (fixed mapping)";
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Test the libcamera formats that can produce images
|
|
* compatible with the format defined by Android.
|
|
*/
|
|
PixelFormat mappedFormat;
|
|
for (const PixelFormat &pixelFormat : libcameraFormats) {
|
|
|
|
LOG(HAL, Debug) << "Testing " << pixelFormat.toString();
|
|
|
|
/*
|
|
* The stream configuration size can be adjusted,
|
|
* not the pixel format.
|
|
*
|
|
* \todo This could be simplified once all pipeline
|
|
* handlers will report the StreamFormats list of
|
|
* supported formats.
|
|
*/
|
|
cfg.pixelFormat = pixelFormat;
|
|
|
|
CameraConfiguration::Status status = cameraConfig->validate();
|
|
if (status != CameraConfiguration::Invalid &&
|
|
cfg.pixelFormat == pixelFormat) {
|
|
mappedFormat = pixelFormat;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!mappedFormat.isValid()) {
|
|
/* If the format is not mandatory, skip it. */
|
|
if (!camera3Format.mandatory)
|
|
continue;
|
|
|
|
LOG(HAL, Error)
|
|
<< "Failed to map mandatory Android format "
|
|
<< camera3Format.name << " ("
|
|
<< utils::hex(androidFormat) << "): aborting";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* Record the mapping and then proceed to generate the
|
|
* stream configurations map, by testing the image resolutions.
|
|
*/
|
|
formatsMap_[androidFormat] = mappedFormat;
|
|
LOG(HAL, Debug) << "Mapped Android format "
|
|
<< camera3Format.name << " to "
|
|
<< mappedFormat.toString();
|
|
|
|
std::vector<Size> resolutions;
|
|
const PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);
|
|
if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)
|
|
resolutions = getRawResolutions(mappedFormat);
|
|
else
|
|
resolutions = getYUVResolutions(cameraConfig.get(),
|
|
mappedFormat,
|
|
cameraResolutions);
|
|
|
|
for (const Size &res : resolutions) {
|
|
streamConfigurations_.push_back({ res, androidFormat });
|
|
|
|
/*
|
|
* If the format is HAL_PIXEL_FORMAT_YCbCr_420_888
|
|
* from which JPEG is produced, add an entry for
|
|
* the JPEG stream.
|
|
*
|
|
* \todo Wire the JPEG encoder to query the supported
|
|
* sizes provided a list of formats it can encode.
|
|
*
|
|
* \todo Support JPEG streams produced by the Camera
|
|
* natively.
|
|
*/
|
|
if (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
|
|
streamConfigurations_.push_back(
|
|
{ res, HAL_PIXEL_FORMAT_BLOB });
|
|
maxJpegSize = std::max(maxJpegSize, res);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* \todo Calculate the maximum JPEG buffer size by asking the
|
|
* encoder giving the maximum frame size required.
|
|
*/
|
|
maxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;
|
|
}
|
|
|
|
LOG(HAL, Debug) << "Collected stream configuration map: ";
|
|
for (const auto &entry : streamConfigurations_)
|
|
LOG(HAL, Debug) << "{ " << entry.resolution.toString() << " - "
|
|
<< utils::hex(entry.androidFormat) << " }";
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 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::stop()
|
|
{
|
|
if (!running_)
|
|
return;
|
|
|
|
worker_.stop();
|
|
camera_->stop();
|
|
|
|
descriptors_.clear();
|
|
running_ = false;
|
|
}
|
|
|
|
void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)
|
|
{
|
|
callbacks_ = callbacks;
|
|
}
|
|
|
|
/*
|
|
* Return static information for the camera.
|
|
*/
|
|
const camera_metadata_t *CameraDevice::getStaticMetadata()
|
|
{
|
|
if (staticMetadata_)
|
|
return staticMetadata_->get();
|
|
|
|
staticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);
|
|
if (!staticMetadata_->isValid()) {
|
|
LOG(HAL, Error) << "Failed to allocate static metadata";
|
|
staticMetadata_.reset();
|
|
return nullptr;
|
|
}
|
|
|
|
const ControlInfoMap &controlsInfo = camera_->controls();
|
|
const ControlList &properties = camera_->properties();
|
|
|
|
/* Color correction static metadata. */
|
|
{
|
|
std::vector<uint8_t> data;
|
|
data.reserve(3);
|
|
const auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);
|
|
if (infoMap != controlsInfo.end()) {
|
|
for (const auto &value : infoMap->second.values())
|
|
data.push_back(value.get<int32_t>());
|
|
} else {
|
|
data.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
|
|
data.data(), data.size());
|
|
}
|
|
|
|
/* Control static metadata. */
|
|
std::vector<uint8_t> aeAvailableAntiBandingModes = {
|
|
ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
|
|
ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,
|
|
ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,
|
|
ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
|
|
aeAvailableAntiBandingModes.data(),
|
|
aeAvailableAntiBandingModes.size());
|
|
|
|
std::vector<uint8_t> aeAvailableModes = {
|
|
ANDROID_CONTROL_AE_MODE_ON,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,
|
|
aeAvailableModes.data(),
|
|
aeAvailableModes.size());
|
|
|
|
int64_t minFrameDurationNsec = -1;
|
|
int64_t maxFrameDurationNsec = -1;
|
|
const auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurations);
|
|
if (frameDurationsInfo != controlsInfo.end()) {
|
|
minFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;
|
|
maxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;
|
|
|
|
/*
|
|
* Adjust the minimum frame duration to comply with Android
|
|
* requirements. The camera service mandates all preview/record
|
|
* streams to have a minimum frame duration < 33,366 milliseconds
|
|
* (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service
|
|
* implementation).
|
|
*
|
|
* If we're close enough (+ 500 useconds) to that value, round
|
|
* the minimum frame duration of the camera to an accepted
|
|
* value.
|
|
*/
|
|
static constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;
|
|
if (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&
|
|
minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)
|
|
minFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;
|
|
|
|
/*
|
|
* The AE routine frame rate limits are computed using the frame
|
|
* duration limits, as libcamera clips the AE routine to the
|
|
* frame durations.
|
|
*/
|
|
int32_t maxFps = std::round(1e9 / minFrameDurationNsec);
|
|
int32_t minFps = std::round(1e9 / maxFrameDurationNsec);
|
|
minFps = std::max(1, minFps);
|
|
|
|
/*
|
|
* Register to the camera service {min, max} and {max, max}
|
|
* intervals as requested by the metadata documentation.
|
|
*/
|
|
int32_t availableAeFpsTarget[] = {
|
|
minFps, maxFps, maxFps, maxFps
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
|
|
availableAeFpsTarget, 4);
|
|
}
|
|
|
|
std::vector<int32_t> aeCompensationRange = {
|
|
0, 0,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
|
|
aeCompensationRange.data(),
|
|
aeCompensationRange.size());
|
|
|
|
const camera_metadata_rational_t aeCompensationStep[] = {
|
|
{ 0, 1 }
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,
|
|
aeCompensationStep, 1);
|
|
|
|
std::vector<uint8_t> availableAfModes = {
|
|
ANDROID_CONTROL_AF_MODE_OFF,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,
|
|
availableAfModes.data(),
|
|
availableAfModes.size());
|
|
|
|
std::vector<uint8_t> availableEffects = {
|
|
ANDROID_CONTROL_EFFECT_MODE_OFF,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,
|
|
availableEffects.data(),
|
|
availableEffects.size());
|
|
|
|
std::vector<uint8_t> availableSceneModes = {
|
|
ANDROID_CONTROL_SCENE_MODE_DISABLED,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
|
|
availableSceneModes.data(),
|
|
availableSceneModes.size());
|
|
|
|
std::vector<uint8_t> availableStabilizationModes = {
|
|
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
|
|
availableStabilizationModes.data(),
|
|
availableStabilizationModes.size());
|
|
|
|
/*
|
|
* \todo Inspect the Camera capabilities to report the available
|
|
* AWB modes. Default to AUTO as CTS tests require it.
|
|
*/
|
|
std::vector<uint8_t> availableAwbModes = {
|
|
ANDROID_CONTROL_AWB_MODE_AUTO,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
|
|
availableAwbModes.data(),
|
|
availableAwbModes.size());
|
|
|
|
std::vector<int32_t> availableMaxRegions = {
|
|
0, 0, 0,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,
|
|
availableMaxRegions.data(),
|
|
availableMaxRegions.size());
|
|
|
|
std::vector<uint8_t> sceneModesOverride = {
|
|
ANDROID_CONTROL_AE_MODE_ON,
|
|
ANDROID_CONTROL_AWB_MODE_AUTO,
|
|
ANDROID_CONTROL_AF_MODE_OFF,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
|
|
sceneModesOverride.data(),
|
|
sceneModesOverride.size());
|
|
|
|
uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
|
|
&aeLockAvailable, 1);
|
|
|
|
uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
|
|
&awbLockAvailable, 1);
|
|
|
|
char availableControlModes = ANDROID_CONTROL_MODE_AUTO;
|
|
staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,
|
|
&availableControlModes, 1);
|
|
|
|
/* JPEG static metadata. */
|
|
|
|
/*
|
|
* Create the list of supported thumbnail sizes by inspecting the
|
|
* available JPEG resolutions collected in streamConfigurations_ and
|
|
* generate one entry for each aspect ratio.
|
|
*
|
|
* The JPEG thumbnailer can freely scale, so pick an arbitrary
|
|
* (160, 160) size as the bounding rectangle, which is then cropped to
|
|
* the different supported aspect ratios.
|
|
*/
|
|
constexpr Size maxJpegThumbnail(160, 160);
|
|
std::vector<Size> thumbnailSizes;
|
|
thumbnailSizes.push_back({ 0, 0 });
|
|
for (const auto &entry : streamConfigurations_) {
|
|
if (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)
|
|
continue;
|
|
|
|
Size thumbnailSize = maxJpegThumbnail
|
|
.boundedToAspectRatio({ entry.resolution.width,
|
|
entry.resolution.height });
|
|
thumbnailSizes.push_back(thumbnailSize);
|
|
}
|
|
|
|
std::sort(thumbnailSizes.begin(), thumbnailSizes.end());
|
|
auto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());
|
|
thumbnailSizes.erase(last, thumbnailSizes.end());
|
|
|
|
/* Transform sizes in to a list of integers that can be consumed. */
|
|
std::vector<int32_t> thumbnailEntries;
|
|
thumbnailEntries.reserve(thumbnailSizes.size() * 2);
|
|
for (const auto &size : thumbnailSizes) {
|
|
thumbnailEntries.push_back(size.width);
|
|
thumbnailEntries.push_back(size.height);
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
|
|
thumbnailEntries.data(), thumbnailEntries.size());
|
|
|
|
staticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, &maxJpegBufferSize_, 1);
|
|
|
|
/* Sensor static metadata. */
|
|
std::array<int32_t, 2> pixelArraySize;
|
|
{
|
|
const Size &size = properties.get(properties::PixelArraySize);
|
|
pixelArraySize[0] = size.width;
|
|
pixelArraySize[1] = size.height;
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
|
|
pixelArraySize.data(), pixelArraySize.size());
|
|
}
|
|
|
|
if (properties.contains(properties::UnitCellSize)) {
|
|
const Size &cellSize = properties.get<Size>(properties::UnitCellSize);
|
|
std::array<float, 2> physicalSize{
|
|
cellSize.width * pixelArraySize[0] / 1e6f,
|
|
cellSize.height * pixelArraySize[1] / 1e6f
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
|
|
physicalSize.data(), physicalSize.size());
|
|
}
|
|
|
|
{
|
|
const Span<const Rectangle> &rects =
|
|
properties.get(properties::PixelArrayActiveAreas);
|
|
std::vector<int32_t> data{
|
|
static_cast<int32_t>(rects[0].x),
|
|
static_cast<int32_t>(rects[0].y),
|
|
static_cast<int32_t>(rects[0].width),
|
|
static_cast<int32_t>(rects[0].height),
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
|
|
data.data(), data.size());
|
|
}
|
|
|
|
int32_t sensitivityRange[] = {
|
|
32, 2400,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
|
|
&sensitivityRange, 2);
|
|
|
|
/* Report the color filter arrangement if the camera reports it. */
|
|
if (properties.contains(properties::draft::ColorFilterArrangement)) {
|
|
uint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
|
|
&filterArr, 1);
|
|
}
|
|
|
|
const auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);
|
|
if (exposureInfo != controlsInfo.end()) {
|
|
int64_t exposureTimeRange[2] = {
|
|
exposureInfo->second.min().get<int32_t>() * 1000LL,
|
|
exposureInfo->second.max().get<int32_t>() * 1000LL,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
|
|
&exposureTimeRange, 2);
|
|
}
|
|
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, &orientation_, 1);
|
|
|
|
std::vector<int32_t> testPatterModes = {
|
|
ANDROID_SENSOR_TEST_PATTERN_MODE_OFF,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
|
|
testPatterModes.data(),
|
|
testPatterModes.size());
|
|
|
|
uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
|
|
×tampSource, 1);
|
|
|
|
if (maxFrameDurationNsec > 0)
|
|
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
|
|
&maxFrameDurationNsec, 1);
|
|
|
|
/* Statistics static metadata. */
|
|
uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
|
|
staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
|
|
&faceDetectMode, 1);
|
|
|
|
int32_t maxFaceCount = 0;
|
|
staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
|
|
&maxFaceCount, 1);
|
|
|
|
{
|
|
std::vector<uint8_t> data;
|
|
data.reserve(2);
|
|
const auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);
|
|
if (infoMap != controlsInfo.end()) {
|
|
for (const auto &value : infoMap->second.values())
|
|
data.push_back(value.get<int32_t>());
|
|
} else {
|
|
data.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
|
|
data.data(), data.size());
|
|
}
|
|
|
|
/* Sync static metadata. */
|
|
int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
|
|
staticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
|
|
|
|
/* Flash static metadata. */
|
|
char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
|
|
staticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,
|
|
&flashAvailable, 1);
|
|
|
|
/* Lens static metadata. */
|
|
std::vector<float> lensApertures = {
|
|
2.53 / 100,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,
|
|
lensApertures.data(),
|
|
lensApertures.size());
|
|
|
|
uint8_t lensFacing;
|
|
switch (facing_) {
|
|
default:
|
|
case CAMERA_FACING_FRONT:
|
|
lensFacing = ANDROID_LENS_FACING_FRONT;
|
|
break;
|
|
case CAMERA_FACING_BACK:
|
|
lensFacing = ANDROID_LENS_FACING_BACK;
|
|
break;
|
|
case CAMERA_FACING_EXTERNAL:
|
|
lensFacing = ANDROID_LENS_FACING_EXTERNAL;
|
|
break;
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_LENS_FACING, &lensFacing, 1);
|
|
|
|
std::vector<float> lensFocalLenghts = {
|
|
1,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
|
|
lensFocalLenghts.data(),
|
|
lensFocalLenghts.size());
|
|
|
|
std::vector<uint8_t> opticalStabilizations = {
|
|
ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
|
|
opticalStabilizations.data(),
|
|
opticalStabilizations.size());
|
|
|
|
float hypeFocalDistance = 0;
|
|
staticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
|
|
&hypeFocalDistance, 1);
|
|
|
|
float minFocusDistance = 0;
|
|
staticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
|
|
&minFocusDistance, 1);
|
|
|
|
/* Noise reduction modes. */
|
|
{
|
|
std::vector<uint8_t> data;
|
|
data.reserve(5);
|
|
const auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);
|
|
if (infoMap != controlsInfo.end()) {
|
|
for (const auto &value : infoMap->second.values())
|
|
data.push_back(value.get<int32_t>());
|
|
} else {
|
|
data.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
|
|
data.data(), data.size());
|
|
}
|
|
|
|
/* Scaler static metadata. */
|
|
|
|
/*
|
|
* \todo The digital zoom factor is a property that depends on the
|
|
* desired output configuration and the sensor frame size input to the
|
|
* ISP. This information is not available to the Android HAL, not at
|
|
* initialization time at least.
|
|
*
|
|
* As a workaround rely on pipeline handlers initializing the
|
|
* ScalerCrop control with the camera default configuration and use the
|
|
* maximum and minimum crop rectangles to calculate the digital zoom
|
|
* factor.
|
|
*/
|
|
float maxZoom = 1.0f;
|
|
const auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);
|
|
if (scalerCrop != controlsInfo.end()) {
|
|
Rectangle min = scalerCrop->second.min().get<Rectangle>();
|
|
Rectangle max = scalerCrop->second.max().get<Rectangle>();
|
|
maxZoom = std::min(1.0f * max.width / min.width,
|
|
1.0f * max.height / min.height);
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
|
|
&maxZoom, 1);
|
|
|
|
std::vector<uint32_t> availableStreamConfigurations;
|
|
availableStreamConfigurations.reserve(streamConfigurations_.size() * 4);
|
|
for (const auto &entry : streamConfigurations_) {
|
|
availableStreamConfigurations.push_back(entry.androidFormat);
|
|
availableStreamConfigurations.push_back(entry.resolution.width);
|
|
availableStreamConfigurations.push_back(entry.resolution.height);
|
|
availableStreamConfigurations.push_back(
|
|
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
|
|
availableStreamConfigurations.data(),
|
|
availableStreamConfigurations.size());
|
|
|
|
std::vector<int64_t> availableStallDurations = {
|
|
ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
|
|
availableStallDurations.data(),
|
|
availableStallDurations.size());
|
|
|
|
/* Use the minimum frame duration for all the YUV/RGB formats. */
|
|
if (minFrameDurationNsec > 0) {
|
|
std::vector<int64_t> minFrameDurations;
|
|
minFrameDurations.reserve(streamConfigurations_.size() * 4);
|
|
for (const auto &entry : streamConfigurations_) {
|
|
minFrameDurations.push_back(entry.androidFormat);
|
|
minFrameDurations.push_back(entry.resolution.width);
|
|
minFrameDurations.push_back(entry.resolution.height);
|
|
minFrameDurations.push_back(minFrameDurationNsec);
|
|
}
|
|
staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
|
|
minFrameDurations.data(),
|
|
minFrameDurations.size());
|
|
}
|
|
|
|
uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
|
|
staticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
|
|
|
|
/* Info static metadata. */
|
|
uint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
|
|
staticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
|
|
&supportedHWLevel, 1);
|
|
|
|
/* Request static metadata. */
|
|
int32_t partialResultCount = 1;
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
|
|
&partialResultCount, 1);
|
|
|
|
{
|
|
/* Default the value to 2 if not reported by the camera. */
|
|
uint8_t maxPipelineDepth = 2;
|
|
const auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);
|
|
if (infoMap != controlsInfo.end())
|
|
maxPipelineDepth = infoMap->second.max().get<int32_t>();
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
|
|
&maxPipelineDepth, 1);
|
|
}
|
|
|
|
/* LIMITED does not support reprocessing. */
|
|
uint32_t maxNumInputStreams = 0;
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
|
|
&maxNumInputStreams, 1);
|
|
|
|
std::vector<uint8_t> availableCapabilities = {
|
|
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
|
|
};
|
|
|
|
/* Report if camera supports RAW. */
|
|
bool rawStreamAvailable = false;
|
|
std::unique_ptr<CameraConfiguration> cameraConfig =
|
|
camera_->generateConfiguration({ StreamRole::Raw });
|
|
if (cameraConfig && !cameraConfig->empty()) {
|
|
const PixelFormatInfo &info =
|
|
PixelFormatInfo::info(cameraConfig->at(0).pixelFormat);
|
|
/* Only advertise RAW support if RAW16 is possible. */
|
|
if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&
|
|
info.bitsPerPixel == 16) {
|
|
rawStreamAvailable = true;
|
|
availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
|
|
}
|
|
}
|
|
|
|
/* Number of { RAW, YUV, JPEG } supported output streams */
|
|
int32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
|
|
&numOutStreams, 3);
|
|
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
|
|
availableCapabilities.data(),
|
|
availableCapabilities.size());
|
|
|
|
std::vector<int32_t> availableCharacteristicsKeys = {
|
|
ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
|
|
ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
|
|
ANDROID_CONTROL_AE_AVAILABLE_MODES,
|
|
ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
|
|
ANDROID_CONTROL_AE_COMPENSATION_RANGE,
|
|
ANDROID_CONTROL_AE_COMPENSATION_STEP,
|
|
ANDROID_CONTROL_AE_LOCK_AVAILABLE,
|
|
ANDROID_CONTROL_AF_AVAILABLE_MODES,
|
|
ANDROID_CONTROL_AVAILABLE_EFFECTS,
|
|
ANDROID_CONTROL_AVAILABLE_MODES,
|
|
ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
|
|
ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
|
|
ANDROID_CONTROL_AWB_AVAILABLE_MODES,
|
|
ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
|
|
ANDROID_CONTROL_MAX_REGIONS,
|
|
ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
|
|
ANDROID_FLASH_INFO_AVAILABLE,
|
|
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
|
|
ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
|
|
ANDROID_JPEG_MAX_SIZE,
|
|
ANDROID_LENS_FACING,
|
|
ANDROID_LENS_INFO_AVAILABLE_APERTURES,
|
|
ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
|
|
ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
|
|
ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
|
|
ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
|
|
ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
|
|
ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
|
|
ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
|
|
ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
|
|
ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
|
|
ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
|
|
ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
|
|
ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
|
|
ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
|
|
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
|
|
ANDROID_SCALER_CROPPING_TYPE,
|
|
ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
|
|
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
|
|
ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
|
|
ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
|
|
ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
|
|
ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
|
|
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
|
|
ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
|
|
ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
|
|
ANDROID_SENSOR_ORIENTATION,
|
|
ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
|
|
ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
|
|
ANDROID_SYNC_MAX_LATENCY,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
|
|
availableCharacteristicsKeys.data(),
|
|
availableCharacteristicsKeys.size());
|
|
|
|
std::vector<int32_t> availableRequestKeys = {
|
|
ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
|
|
ANDROID_CONTROL_AE_ANTIBANDING_MODE,
|
|
ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
|
|
ANDROID_CONTROL_AE_LOCK,
|
|
ANDROID_CONTROL_AE_MODE,
|
|
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
|
|
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
|
|
ANDROID_CONTROL_AF_MODE,
|
|
ANDROID_CONTROL_AF_TRIGGER,
|
|
ANDROID_CONTROL_AWB_LOCK,
|
|
ANDROID_CONTROL_AWB_MODE,
|
|
ANDROID_CONTROL_CAPTURE_INTENT,
|
|
ANDROID_CONTROL_EFFECT_MODE,
|
|
ANDROID_CONTROL_MODE,
|
|
ANDROID_CONTROL_SCENE_MODE,
|
|
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
|
|
ANDROID_FLASH_MODE,
|
|
ANDROID_JPEG_ORIENTATION,
|
|
ANDROID_JPEG_QUALITY,
|
|
ANDROID_JPEG_THUMBNAIL_QUALITY,
|
|
ANDROID_JPEG_THUMBNAIL_SIZE,
|
|
ANDROID_LENS_APERTURE,
|
|
ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
|
|
ANDROID_NOISE_REDUCTION_MODE,
|
|
ANDROID_SCALER_CROP_REGION,
|
|
ANDROID_STATISTICS_FACE_DETECT_MODE
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
|
|
availableRequestKeys.data(),
|
|
availableRequestKeys.size());
|
|
|
|
std::vector<int32_t> availableResultKeys = {
|
|
ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
|
|
ANDROID_CONTROL_AE_ANTIBANDING_MODE,
|
|
ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
|
|
ANDROID_CONTROL_AE_LOCK,
|
|
ANDROID_CONTROL_AE_MODE,
|
|
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
|
|
ANDROID_CONTROL_AE_STATE,
|
|
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
|
|
ANDROID_CONTROL_AF_MODE,
|
|
ANDROID_CONTROL_AF_STATE,
|
|
ANDROID_CONTROL_AF_TRIGGER,
|
|
ANDROID_CONTROL_AWB_LOCK,
|
|
ANDROID_CONTROL_AWB_MODE,
|
|
ANDROID_CONTROL_AWB_STATE,
|
|
ANDROID_CONTROL_CAPTURE_INTENT,
|
|
ANDROID_CONTROL_EFFECT_MODE,
|
|
ANDROID_CONTROL_MODE,
|
|
ANDROID_CONTROL_SCENE_MODE,
|
|
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
|
|
ANDROID_FLASH_MODE,
|
|
ANDROID_FLASH_STATE,
|
|
ANDROID_JPEG_GPS_COORDINATES,
|
|
ANDROID_JPEG_GPS_PROCESSING_METHOD,
|
|
ANDROID_JPEG_GPS_TIMESTAMP,
|
|
ANDROID_JPEG_ORIENTATION,
|
|
ANDROID_JPEG_QUALITY,
|
|
ANDROID_JPEG_SIZE,
|
|
ANDROID_JPEG_THUMBNAIL_QUALITY,
|
|
ANDROID_JPEG_THUMBNAIL_SIZE,
|
|
ANDROID_LENS_APERTURE,
|
|
ANDROID_LENS_FOCAL_LENGTH,
|
|
ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
|
|
ANDROID_LENS_STATE,
|
|
ANDROID_NOISE_REDUCTION_MODE,
|
|
ANDROID_REQUEST_PIPELINE_DEPTH,
|
|
ANDROID_SCALER_CROP_REGION,
|
|
ANDROID_SENSOR_EXPOSURE_TIME,
|
|
ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
|
|
ANDROID_SENSOR_TEST_PATTERN_MODE,
|
|
ANDROID_SENSOR_TIMESTAMP,
|
|
ANDROID_STATISTICS_FACE_DETECT_MODE,
|
|
ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
|
|
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
|
|
ANDROID_STATISTICS_SCENE_FLICKER,
|
|
};
|
|
staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
|
|
availableResultKeys.data(),
|
|
availableResultKeys.size());
|
|
|
|
if (!staticMetadata_->isValid()) {
|
|
LOG(HAL, Error) << "Failed to construct static metadata";
|
|
staticMetadata_.reset();
|
|
return nullptr;
|
|
}
|
|
|
|
return staticMetadata_->get();
|
|
}
|
|
|
|
std::unique_ptr<CameraMetadata> CameraDevice::requestTemplatePreview()
|
|
{
|
|
/*
|
|
* \todo Keep this in sync with the actual number of entries.
|
|
* Currently: 20 entries, 35 bytes
|
|
*/
|
|
auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);
|
|
if (!requestTemplate->isValid()) {
|
|
return nullptr;
|
|
}
|
|
|
|
/* Get the FPS range registered in the static metadata. */
|
|
camera_metadata_ro_entry_t entry;
|
|
bool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
|
|
&entry);
|
|
if (!found) {
|
|
LOG(HAL, Error) << "Cannot create capture template without FPS range";
|
|
return nullptr;
|
|
}
|
|
|
|
/*
|
|
* Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata
|
|
* has been assembled as {{min, max} {max, max}}.
|
|
*/
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
|
|
entry.data.i32, 2);
|
|
|
|
uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE,
|
|
&aeMode, 1);
|
|
|
|
int32_t aeExposureCompensation = 0;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
|
|
&aeExposureCompensation, 1);
|
|
|
|
uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
|
|
&aePrecaptureTrigger, 1);
|
|
|
|
uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK,
|
|
&aeLock, 1);
|
|
|
|
uint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
|
|
&aeAntibandingMode, 1);
|
|
|
|
uint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, &afMode, 1);
|
|
|
|
uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER,
|
|
&afTrigger, 1);
|
|
|
|
uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE,
|
|
&awbMode, 1);
|
|
|
|
uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK,
|
|
&awbLock, 1);
|
|
|
|
uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
|
|
requestTemplate->addEntry(ANDROID_FLASH_MODE,
|
|
&flashMode, 1);
|
|
|
|
uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
|
|
requestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,
|
|
&faceDetectMode, 1);
|
|
|
|
uint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;
|
|
requestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,
|
|
&noiseReduction, 1);
|
|
|
|
uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;
|
|
requestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
|
|
&aberrationMode, 1);
|
|
|
|
uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_MODE, &controlMode, 1);
|
|
|
|
float lensAperture = 2.53 / 100;
|
|
requestTemplate->addEntry(ANDROID_LENS_APERTURE, &lensAperture, 1);
|
|
|
|
uint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
|
|
requestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
|
|
&opticalStabilization, 1);
|
|
|
|
uint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
|
|
requestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,
|
|
&captureIntent, 1);
|
|
|
|
return requestTemplate;
|
|
}
|
|
|
|
std::unique_ptr<CameraMetadata> CameraDevice::requestTemplateVideo()
|
|
{
|
|
std::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();
|
|
if (!previewTemplate)
|
|
return nullptr;
|
|
|
|
/*
|
|
* The video template requires a fixed FPS range. Everything else
|
|
* stays the same as the preview template.
|
|
*/
|
|
camera_metadata_ro_entry_t entry;
|
|
staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
|
|
&entry);
|
|
|
|
/*
|
|
* Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata
|
|
* has been assembled as {{min, max} {max, max}}.
|
|
*/
|
|
previewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
|
|
entry.data.i32 + 2, 2);
|
|
|
|
return previewTemplate;
|
|
}
|
|
|
|
/*
|
|
* 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();
|
|
|
|
/* Use the capture intent matching the requested template type. */
|
|
std::unique_ptr<CameraMetadata> requestTemplate;
|
|
uint8_t captureIntent;
|
|
switch (type) {
|
|
case CAMERA3_TEMPLATE_PREVIEW:
|
|
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
|
|
requestTemplate = requestTemplatePreview();
|
|
break;
|
|
case CAMERA3_TEMPLATE_STILL_CAPTURE:
|
|
/*
|
|
* Use the preview template for still capture, they only differ
|
|
* for the torch mode we currently do not support.
|
|
*/
|
|
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
|
|
requestTemplate = requestTemplatePreview();
|
|
break;
|
|
case CAMERA3_TEMPLATE_VIDEO_RECORD:
|
|
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
|
|
requestTemplate = requestTemplateVideo();
|
|
break;
|
|
case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
|
|
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
|
|
requestTemplate = requestTemplateVideo();
|
|
break;
|
|
/* \todo Implement templates generation for the remaining use cases. */
|
|
case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
|
|
case CAMERA3_TEMPLATE_MANUAL:
|
|
default:
|
|
LOG(HAL, Error) << "Unsupported template request type: " << type;
|
|
return nullptr;
|
|
}
|
|
|
|
if (!requestTemplate || !requestTemplate->isValid()) {
|
|
LOG(HAL, Error) << "Failed to construct request template";
|
|
return nullptr;
|
|
}
|
|
|
|
requestTemplate->updateEntry(ANDROID_CONTROL_CAPTURE_INTENT,
|
|
&captureIntent, 1);
|
|
|
|
requestTemplates_[type] = std::move(requestTemplate);
|
|
return requestTemplates_[type]->get();
|
|
}
|
|
|
|
PixelFormat CameraDevice::toPixelFormat(int format) const
|
|
{
|
|
/* Translate Android format code to libcamera pixel format. */
|
|
auto it = formatsMap_.find(format);
|
|
if (it == formatsMap_.end()) {
|
|
LOG(HAL, Error) << "Requested format " << utils::hex(format)
|
|
<< " not supported";
|
|
return PixelFormat();
|
|
}
|
|
|
|
return it->second;
|
|
}
|
|
|
|
/*
|
|
* Inspect the stream_list to produce a list of StreamConfiguration to
|
|
* be use to configure the Camera.
|
|
*/
|
|
int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
|
|
{
|
|
/* Before any configuration attempt, stop the camera. */
|
|
stop();
|
|
|
|
if (stream_list->num_streams == 0) {
|
|
LOG(HAL, Error) << "No streams in configuration";
|
|
return -EINVAL;
|
|
}
|
|
|
|
#if defined(OS_CHROMEOS)
|
|
if (!validateCropRotate(*stream_list))
|
|
return -EINVAL;
|
|
#endif
|
|
|
|
/*
|
|
* Generate an empty configuration, and construct a StreamConfiguration
|
|
* for each camera3_stream to add to it.
|
|
*/
|
|
config_ = camera_->generateConfiguration();
|
|
if (!config_) {
|
|
LOG(HAL, Error) << "Failed to generate camera configuration";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* Clear and remove any existing configuration from previous calls, and
|
|
* ensure the required entries are available without further
|
|
* reallocation.
|
|
*/
|
|
streams_.clear();
|
|
streams_.reserve(stream_list->num_streams);
|
|
|
|
std::vector<Camera3StreamConfig> streamConfigs;
|
|
streamConfigs.reserve(stream_list->num_streams);
|
|
|
|
/* First handle all non-MJPEG streams. */
|
|
camera3_stream_t *jpegStream = nullptr;
|
|
for (unsigned int i = 0; i < stream_list->num_streams; ++i) {
|
|
camera3_stream_t *stream = stream_list->streams[i];
|
|
Size size(stream->width, stream->height);
|
|
|
|
PixelFormat format = toPixelFormat(stream->format);
|
|
|
|
LOG(HAL, Info) << "Stream #" << i
|
|
<< ", direction: " << stream->stream_type
|
|
<< ", width: " << stream->width
|
|
<< ", height: " << stream->height
|
|
<< ", format: " << utils::hex(stream->format)
|
|
<< ", rotation: " << rotationToString(stream->rotation)
|
|
#if defined(OS_CHROMEOS)
|
|
<< ", crop_rotate_scale_degrees: "
|
|
<< rotationToString(stream->crop_rotate_scale_degrees)
|
|
#endif
|
|
<< " (" << format.toString() << ")";
|
|
|
|
if (!format.isValid())
|
|
return -EINVAL;
|
|
|
|
/* \todo Support rotation. */
|
|
if (stream->rotation != CAMERA3_STREAM_ROTATION_0) {
|
|
LOG(HAL, Error) << "Rotation is not supported";
|
|
return -EINVAL;
|
|
}
|
|
#if defined(OS_CHROMEOS)
|
|
if (stream->crop_rotate_scale_degrees != CAMERA3_STREAM_ROTATION_0) {
|
|
LOG(HAL, Error) << "Rotation is not supported";
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
/* Defer handling of MJPEG streams until all others are known. */
|
|
if (stream->format == HAL_PIXEL_FORMAT_BLOB) {
|
|
if (jpegStream) {
|
|
LOG(HAL, Error)
|
|
<< "Multiple JPEG streams are not supported";
|
|
return -EINVAL;
|
|
}
|
|
|
|
jpegStream = stream;
|
|
continue;
|
|
}
|
|
|
|
Camera3StreamConfig streamConfig;
|
|
streamConfig.streams = { { stream, CameraStream::Type::Direct } };
|
|
streamConfig.config.size = size;
|
|
streamConfig.config.pixelFormat = format;
|
|
streamConfigs.push_back(std::move(streamConfig));
|
|
|
|
/* This stream will be produced by hardware. */
|
|
stream->usage |= GRALLOC_USAGE_HW_CAMERA_WRITE;
|
|
}
|
|
|
|
/* Now handle the MJPEG streams, adding a new stream if required. */
|
|
if (jpegStream) {
|
|
CameraStream::Type type;
|
|
int index = -1;
|
|
|
|
/* Search for a compatible stream in the non-JPEG ones. */
|
|
for (size_t i = 0; i < streamConfigs.size(); ++i) {
|
|
Camera3StreamConfig &streamConfig = streamConfigs[i];
|
|
const auto &cfg = streamConfig.config;
|
|
|
|
/*
|
|
* \todo The PixelFormat must also be compatible with
|
|
* the encoder.
|
|
*/
|
|
if (cfg.size.width != jpegStream->width ||
|
|
cfg.size.height != jpegStream->height)
|
|
continue;
|
|
|
|
LOG(HAL, Info)
|
|
<< "Android JPEG stream mapped to libcamera stream " << i;
|
|
|
|
type = CameraStream::Type::Mapped;
|
|
index = i;
|
|
|
|
/*
|
|
* The source stream will be read by software to
|
|
* produce the JPEG stream.
|
|
*/
|
|
camera3_stream_t *stream = streamConfig.streams[0].stream;
|
|
stream->usage |= GRALLOC_USAGE_SW_READ_OFTEN;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Without a compatible match for JPEG encoding we must
|
|
* introduce a new stream to satisfy the request requirements.
|
|
*/
|
|
if (index < 0) {
|
|
/*
|
|
* \todo The pixelFormat should be a 'best-fit' choice
|
|
* and may require a validation cycle. This is not yet
|
|
* handled, and should be considered as part of any
|
|
* stream configuration reworks.
|
|
*/
|
|
Camera3StreamConfig streamConfig;
|
|
streamConfig.config.size.width = jpegStream->width;
|
|
streamConfig.config.size.height = jpegStream->height;
|
|
streamConfig.config.pixelFormat = formats::NV12;
|
|
streamConfigs.push_back(std::move(streamConfig));
|
|
|
|
LOG(HAL, Info) << "Adding " << streamConfig.config.toString()
|
|
<< " for MJPEG support";
|
|
|
|
type = CameraStream::Type::Internal;
|
|
index = streamConfigs.size() - 1;
|
|
}
|
|
|
|
/* The JPEG stream will be produced by software. */
|
|
jpegStream->usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
|
|
|
|
streamConfigs[index].streams.push_back({ jpegStream, type });
|
|
}
|
|
|
|
sortCamera3StreamConfigs(streamConfigs, jpegStream);
|
|
for (const auto &streamConfig : streamConfigs) {
|
|
config_->addConfiguration(streamConfig.config);
|
|
|
|
for (auto &stream : streamConfig.streams) {
|
|
streams_.emplace_back(this, stream.type, stream.stream,
|
|
config_->size() - 1);
|
|
stream.stream->priv = static_cast<void *>(&streams_.back());
|
|
}
|
|
}
|
|
|
|
switch (config_->validate()) {
|
|
case CameraConfiguration::Valid:
|
|
break;
|
|
case CameraConfiguration::Adjusted:
|
|
LOG(HAL, Info) << "Camera configuration adjusted";
|
|
|
|
for (const StreamConfiguration &cfg : *config_)
|
|
LOG(HAL, Info) << " - " << cfg.toString();
|
|
|
|
config_.reset();
|
|
return -EINVAL;
|
|
case CameraConfiguration::Invalid:
|
|
LOG(HAL, Info) << "Camera configuration invalid";
|
|
config_.reset();
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* Once the CameraConfiguration has been adjusted/validated
|
|
* it can be applied to the camera.
|
|
*/
|
|
int ret = camera_->configure(config_.get());
|
|
if (ret) {
|
|
LOG(HAL, Error) << "Failed to configure camera '"
|
|
<< camera_->id() << "'";
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Configure the HAL CameraStream instances using the associated
|
|
* StreamConfiguration and set the number of required buffers in
|
|
* the Android camera3_stream_t.
|
|
*/
|
|
for (CameraStream &cameraStream : streams_) {
|
|
ret = cameraStream.configure();
|
|
if (ret) {
|
|
LOG(HAL, Error) << "Failed to configure camera stream";
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
FrameBuffer *CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer)
|
|
{
|
|
std::vector<FrameBuffer::Plane> planes;
|
|
for (int i = 0; i < camera3buffer->numFds; i++) {
|
|
/* Skip unused planes. */
|
|
if (camera3buffer->data[i] == -1)
|
|
break;
|
|
|
|
FrameBuffer::Plane plane;
|
|
plane.fd = FileDescriptor(camera3buffer->data[i]);
|
|
if (!plane.fd.isValid()) {
|
|
LOG(HAL, Error) << "Failed to obtain FileDescriptor ("
|
|
<< camera3buffer->data[i] << ") "
|
|
<< " on plane " << i;
|
|
return nullptr;
|
|
}
|
|
|
|
off_t length = lseek(plane.fd.fd(), 0, SEEK_END);
|
|
if (length == -1) {
|
|
LOG(HAL, Error) << "Failed to query plane length";
|
|
return nullptr;
|
|
}
|
|
|
|
plane.length = length;
|
|
planes.push_back(std::move(plane));
|
|
}
|
|
|
|
return new FrameBuffer(std::move(planes));
|
|
}
|
|
|
|
int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
|
|
{
|
|
const CameraMetadata &settings = descriptor->settings_;
|
|
if (!settings.isValid())
|
|
return 0;
|
|
|
|
/* Translate the Android request settings to libcamera controls. */
|
|
camera_metadata_ro_entry_t entry;
|
|
if (settings.getEntry(ANDROID_SCALER_CROP_REGION, &entry)) {
|
|
const int32_t *data = entry.data.i32;
|
|
Rectangle cropRegion{ data[0], data[1],
|
|
static_cast<unsigned int>(data[2]),
|
|
static_cast<unsigned int>(data[3]) };
|
|
ControlList &controls = descriptor->request_->controls();
|
|
controls.set(controls::ScalerCrop, cropRegion);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request)
|
|
{
|
|
if (!isValidRequest(camera3Request))
|
|
return -EINVAL;
|
|
|
|
/* Start the camera if that's the first request we handle. */
|
|
if (!running_) {
|
|
worker_.start();
|
|
|
|
int ret = camera_->start();
|
|
if (ret) {
|
|
LOG(HAL, Error) << "Failed to start camera";
|
|
return ret;
|
|
}
|
|
|
|
running_ = true;
|
|
}
|
|
|
|
/*
|
|
* Save the request descriptors for use at completion time.
|
|
* The descriptor and the associated memory reserved here are freed
|
|
* at request complete time.
|
|
*/
|
|
Camera3RequestDescriptor descriptor(camera_.get(), camera3Request);
|
|
|
|
/*
|
|
* \todo The Android request model is incremental, settings passed in
|
|
* previous requests are to be effective until overridden explicitly in
|
|
* a new request. Do we need to cache settings incrementally here, or is
|
|
* it handled by the Android camera service ?
|
|
*/
|
|
if (camera3Request->settings)
|
|
lastSettings_ = camera3Request->settings;
|
|
else
|
|
descriptor.settings_ = lastSettings_;
|
|
|
|
LOG(HAL, Debug) << "Queueing request " << descriptor.request_->cookie()
|
|
<< " with " << descriptor.buffers_.size() << " streams";
|
|
for (unsigned int i = 0; i < descriptor.buffers_.size(); ++i) {
|
|
const camera3_stream_buffer_t &camera3Buffer = descriptor.buffers_[i];
|
|
camera3_stream *camera3Stream = camera3Buffer.stream;
|
|
CameraStream *cameraStream = static_cast<CameraStream *>(camera3Stream->priv);
|
|
|
|
std::stringstream ss;
|
|
ss << i << " - (" << camera3Stream->width << "x"
|
|
<< camera3Stream->height << ")"
|
|
<< "[" << utils::hex(camera3Stream->format) << "] -> "
|
|
<< "(" << cameraStream->configuration().size.toString() << ")["
|
|
<< cameraStream->configuration().pixelFormat.toString() << "]";
|
|
|
|
/*
|
|
* Inspect the camera stream type, create buffers opportunely
|
|
* and add them to the Request if required.
|
|
*/
|
|
FrameBuffer *buffer = nullptr;
|
|
switch (cameraStream->type()) {
|
|
case CameraStream::Type::Mapped:
|
|
/*
|
|
* Mapped streams don't need buffers added to the
|
|
* Request.
|
|
*/
|
|
LOG(HAL, Debug) << ss.str() << " (mapped)";
|
|
continue;
|
|
|
|
case CameraStream::Type::Direct:
|
|
/*
|
|
* Create a libcamera buffer using the dmabuf
|
|
* descriptors of the camera3Buffer for each stream and
|
|
* associate it with the Camera3RequestDescriptor for
|
|
* lifetime management only.
|
|
*/
|
|
buffer = createFrameBuffer(*camera3Buffer.buffer);
|
|
descriptor.frameBuffers_.emplace_back(buffer);
|
|
LOG(HAL, Debug) << ss.str() << " (direct)";
|
|
break;
|
|
|
|
case CameraStream::Type::Internal:
|
|
/*
|
|
* Get the frame buffer from the CameraStream internal
|
|
* buffer pool.
|
|
*
|
|
* The buffer has to be returned to the CameraStream
|
|
* once it has been processed.
|
|
*/
|
|
buffer = cameraStream->getBuffer();
|
|
LOG(HAL, Debug) << ss.str() << " (internal)";
|
|
break;
|
|
}
|
|
|
|
if (!buffer) {
|
|
LOG(HAL, Error) << "Failed to create buffer";
|
|
return -ENOMEM;
|
|
}
|
|
|
|
descriptor.request_->addBuffer(cameraStream->stream(), buffer,
|
|
camera3Buffer.acquire_fence);
|
|
}
|
|
|
|
/*
|
|
* Translate controls from Android to libcamera and queue the request
|
|
* to the CameraWorker thread.
|
|
*/
|
|
int ret = processControls(&descriptor);
|
|
if (ret)
|
|
return ret;
|
|
|
|
worker_.queueRequest(descriptor.request_.get());
|
|
|
|
{
|
|
std::scoped_lock<std::mutex> lock(mutex_);
|
|
descriptors_[descriptor.request_->cookie()] = std::move(descriptor);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CameraDevice::requestComplete(Request *request)
|
|
{
|
|
camera3_buffer_status status = CAMERA3_BUFFER_STATUS_OK;
|
|
std::unique_ptr<CameraMetadata> resultMetadata;
|
|
|
|
decltype(descriptors_)::node_type node;
|
|
{
|
|
std::scoped_lock<std::mutex> lock(mutex_);
|
|
auto it = descriptors_.find(request->cookie());
|
|
if (it == descriptors_.end()) {
|
|
LOG(HAL, Fatal)
|
|
<< "Unknown request: " << request->cookie();
|
|
status = CAMERA3_BUFFER_STATUS_ERROR;
|
|
return;
|
|
}
|
|
|
|
node = descriptors_.extract(it);
|
|
}
|
|
Camera3RequestDescriptor &descriptor = node.mapped();
|
|
|
|
if (request->status() != Request::RequestComplete) {
|
|
LOG(HAL, Error) << "Request not successfully completed: "
|
|
<< request->status();
|
|
status = CAMERA3_BUFFER_STATUS_ERROR;
|
|
}
|
|
|
|
LOG(HAL, Debug) << "Request " << request->cookie() << " completed with "
|
|
<< descriptor.buffers_.size() << " streams";
|
|
|
|
resultMetadata = getResultMetadata(descriptor);
|
|
|
|
/* Handle any JPEG compression. */
|
|
for (camera3_stream_buffer_t &buffer : descriptor.buffers_) {
|
|
CameraStream *cameraStream =
|
|
static_cast<CameraStream *>(buffer.stream->priv);
|
|
|
|
if (cameraStream->camera3Stream().format != HAL_PIXEL_FORMAT_BLOB)
|
|
continue;
|
|
|
|
FrameBuffer *src = request->findBuffer(cameraStream->stream());
|
|
if (!src) {
|
|
LOG(HAL, Error) << "Failed to find a source stream buffer";
|
|
continue;
|
|
}
|
|
|
|
int ret = cameraStream->process(*src,
|
|
*buffer.buffer,
|
|
descriptor.settings_,
|
|
resultMetadata.get());
|
|
if (ret) {
|
|
status = CAMERA3_BUFFER_STATUS_ERROR;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Return the FrameBuffer to the CameraStream now that we're
|
|
* done processing it.
|
|
*/
|
|
if (cameraStream->type() == CameraStream::Type::Internal)
|
|
cameraStream->putBuffer(src);
|
|
}
|
|
|
|
/* Prepare to call back the Android camera stack. */
|
|
camera3_capture_result_t captureResult = {};
|
|
captureResult.frame_number = descriptor.frameNumber_;
|
|
captureResult.num_output_buffers = descriptor.buffers_.size();
|
|
for (camera3_stream_buffer_t &buffer : descriptor.buffers_) {
|
|
buffer.acquire_fence = -1;
|
|
buffer.release_fence = -1;
|
|
buffer.status = status;
|
|
}
|
|
captureResult.output_buffers = descriptor.buffers_.data();
|
|
|
|
if (status == CAMERA3_BUFFER_STATUS_OK) {
|
|
uint64_t timestamp =
|
|
static_cast<uint64_t>(request->metadata()
|
|
.get(controls::SensorTimestamp));
|
|
notifyShutter(descriptor.frameNumber_, timestamp);
|
|
|
|
captureResult.partial_result = 1;
|
|
captureResult.result = resultMetadata->get();
|
|
}
|
|
|
|
if (status == CAMERA3_BUFFER_STATUS_ERROR || !captureResult.result) {
|
|
/* \todo Improve error handling. In case we notify an error
|
|
* because the metadata generation fails, a shutter event has
|
|
* already been notified for this frame number before the error
|
|
* is here signalled. Make sure the error path plays well with
|
|
* the camera stack state machine.
|
|
*/
|
|
notifyError(descriptor.frameNumber_,
|
|
descriptor.buffers_[0].stream);
|
|
}
|
|
|
|
callbacks_->process_capture_result(callbacks_, &captureResult);
|
|
}
|
|
|
|
std::string CameraDevice::logPrefix() const
|
|
{
|
|
return "'" + camera_->id() + "'";
|
|
}
|
|
|
|
void CameraDevice::notifyShutter(uint32_t frameNumber, uint64_t timestamp)
|
|
{
|
|
camera3_notify_msg_t notify = {};
|
|
|
|
notify.type = CAMERA3_MSG_SHUTTER;
|
|
notify.message.shutter.frame_number = frameNumber;
|
|
notify.message.shutter.timestamp = timestamp;
|
|
|
|
callbacks_->notify(callbacks_, ¬ify);
|
|
}
|
|
|
|
void CameraDevice::notifyError(uint32_t frameNumber, camera3_stream_t *stream)
|
|
{
|
|
camera3_notify_msg_t notify = {};
|
|
|
|
/*
|
|
* \todo Report and identify the stream number or configuration to
|
|
* clarify the stream that failed.
|
|
*/
|
|
LOG(HAL, Error) << "Error occurred on frame " << frameNumber << " ("
|
|
<< toPixelFormat(stream->format).toString() << ")";
|
|
|
|
notify.type = CAMERA3_MSG_ERROR;
|
|
notify.message.error.error_stream = stream;
|
|
notify.message.error.frame_number = frameNumber;
|
|
notify.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
|
|
|
|
callbacks_->notify(callbacks_, ¬ify);
|
|
}
|
|
|
|
/*
|
|
* Produce a set of fixed result metadata.
|
|
*/
|
|
std::unique_ptr<CameraMetadata>
|
|
CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) const
|
|
{
|
|
const ControlList &metadata = descriptor.request_->metadata();
|
|
const CameraMetadata &settings = descriptor.settings_;
|
|
camera_metadata_ro_entry_t entry;
|
|
bool found;
|
|
|
|
/*
|
|
* \todo Keep this in sync with the actual number of entries.
|
|
* Currently: 40 entries, 156 bytes
|
|
*
|
|
* Reserve more space for the JPEG metadata set by the post-processor.
|
|
* Currently:
|
|
* ANDROID_JPEG_GPS_COORDINATES (double x 3) = 24 bytes
|
|
* ANDROID_JPEG_GPS_PROCESSING_METHOD (byte x 32) = 32 bytes
|
|
* ANDROID_JPEG_GPS_TIMESTAMP (int64) = 8 bytes
|
|
* ANDROID_JPEG_SIZE (int32_t) = 4 bytes
|
|
* ANDROID_JPEG_QUALITY (byte) = 1 byte
|
|
* ANDROID_JPEG_ORIENTATION (int32_t) = 4 bytes
|
|
* ANDROID_JPEG_THUMBNAIL_QUALITY (byte) = 1 byte
|
|
* ANDROID_JPEG_THUMBNAIL_SIZE (int32 x 2) = 8 bytes
|
|
* Total bytes for JPEG metadata: 82
|
|
*/
|
|
std::unique_ptr<CameraMetadata> resultMetadata =
|
|
std::make_unique<CameraMetadata>(44, 166);
|
|
if (!resultMetadata->isValid()) {
|
|
LOG(HAL, Error) << "Failed to allocate result metadata";
|
|
return nullptr;
|
|
}
|
|
|
|
/*
|
|
* \todo The value of the results metadata copied from the settings
|
|
* will have to be passed to the libcamera::Camera and extracted
|
|
* from libcamera::Request::metadata.
|
|
*/
|
|
|
|
uint8_t value = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
|
|
&value, 1);
|
|
|
|
value = ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE, &value, 1);
|
|
|
|
int32_t value32 = 0;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
|
|
&value32, 1);
|
|
|
|
value = ANDROID_CONTROL_AE_LOCK_OFF;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AE_LOCK, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AE_MODE_ON;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AE_MODE, &value, 1);
|
|
|
|
if (settings.getEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry))
|
|
/*
|
|
* \todo Retrieve the AE FPS range from the libcamera metadata.
|
|
* As libcamera does not support that control, as a temporary
|
|
* workaround return what the framework asked.
|
|
*/
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
|
|
entry.data.i32, 2);
|
|
|
|
value = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
|
|
found = settings.getEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &entry);
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
|
|
found ? entry.data.u8 : &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AE_STATE_CONVERGED;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AE_STATE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AF_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AF_MODE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AF_STATE_INACTIVE;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AF_STATE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AF_TRIGGER_IDLE;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AF_TRIGGER, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AWB_MODE_AUTO;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AWB_MODE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AWB_LOCK_OFF;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AWB_LOCK, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_AWB_STATE_CONVERGED;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_AWB_STATE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_CAPTURE_INTENT, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_EFFECT_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_EFFECT_MODE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_MODE_AUTO;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_MODE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_SCENE_MODE_DISABLED;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_SCENE_MODE, &value, 1);
|
|
|
|
value = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &value, 1);
|
|
|
|
value = ANDROID_FLASH_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_FLASH_MODE, &value, 1);
|
|
|
|
value = ANDROID_FLASH_STATE_UNAVAILABLE;
|
|
resultMetadata->addEntry(ANDROID_FLASH_STATE, &value, 1);
|
|
|
|
if (settings.getEntry(ANDROID_LENS_APERTURE, &entry))
|
|
resultMetadata->addEntry(ANDROID_LENS_APERTURE, entry.data.f, 1);
|
|
|
|
float focal_length = 1.0;
|
|
resultMetadata->addEntry(ANDROID_LENS_FOCAL_LENGTH, &focal_length, 1);
|
|
|
|
value = ANDROID_LENS_STATE_STATIONARY;
|
|
resultMetadata->addEntry(ANDROID_LENS_STATE, &value, 1);
|
|
|
|
value = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
|
|
&value, 1);
|
|
|
|
value32 = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_SENSOR_TEST_PATTERN_MODE,
|
|
&value32, 1);
|
|
|
|
value = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,
|
|
&value, 1);
|
|
|
|
value = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
|
|
&value, 1);
|
|
|
|
value = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
|
|
&value, 1);
|
|
|
|
value = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
|
|
resultMetadata->addEntry(ANDROID_STATISTICS_SCENE_FLICKER,
|
|
&value, 1);
|
|
|
|
value = ANDROID_NOISE_REDUCTION_MODE_OFF;
|
|
resultMetadata->addEntry(ANDROID_NOISE_REDUCTION_MODE, &value, 1);
|
|
|
|
/* 33.3 msec */
|
|
const int64_t rolling_shutter_skew = 33300000;
|
|
resultMetadata->addEntry(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
|
|
&rolling_shutter_skew, 1);
|
|
|
|
/* Add metadata tags reported by libcamera. */
|
|
const int64_t timestamp = metadata.get(controls::SensorTimestamp);
|
|
resultMetadata->addEntry(ANDROID_SENSOR_TIMESTAMP, ×tamp, 1);
|
|
|
|
if (metadata.contains(controls::draft::PipelineDepth)) {
|
|
uint8_t pipeline_depth =
|
|
metadata.get<int32_t>(controls::draft::PipelineDepth);
|
|
resultMetadata->addEntry(ANDROID_REQUEST_PIPELINE_DEPTH,
|
|
&pipeline_depth, 1);
|
|
}
|
|
|
|
if (metadata.contains(controls::ExposureTime)) {
|
|
int64_t exposure = metadata.get(controls::ExposureTime) * 1000ULL;
|
|
resultMetadata->addEntry(ANDROID_SENSOR_EXPOSURE_TIME,
|
|
&exposure, 1);
|
|
}
|
|
|
|
if (metadata.contains(controls::ScalerCrop)) {
|
|
Rectangle crop = metadata.get(controls::ScalerCrop);
|
|
int32_t cropRect[] = {
|
|
crop.x, crop.y, static_cast<int32_t>(crop.width),
|
|
static_cast<int32_t>(crop.height),
|
|
};
|
|
resultMetadata->addEntry(ANDROID_SCALER_CROP_REGION, cropRect, 4);
|
|
}
|
|
|
|
/*
|
|
* Return the result metadata pack even is not valid: get() will return
|
|
* nullptr.
|
|
*/
|
|
if (!resultMetadata->isValid()) {
|
|
LOG(HAL, Error) << "Failed to construct result metadata";
|
|
}
|
|
|
|
return resultMetadata;
|
|
}
|