libcamera/src/android/camera_device.cpp
Jacopo Mondi d5473c9626 android: camera_device: Rename buffer fields
The buffers passed to the post processor are currently named 'buffer'
and 'mapped', names that do not convey their role.

Use 'src' and 'dest' instead.

Cosmetic change only.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
2021-03-03 09:50:13 +01:00

2143 lines
65 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 <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;
}
} /* 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. */
numBuffers_ = camera3Request->num_output_buffers;
buffers_ = new camera3_stream_buffer_t[numBuffers_];
for (unsigned int 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 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);
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()
{
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:
/*
* \todo Set this to EXTERNAL once we support
* HARDWARE_LEVEL_EXTERNAL
*/
facing_ = CAMERA_FACING_FRONT;
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)) {
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();
worker_.stop();
camera_->stop();
camera_->release();
running_ = false;
}
void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)
{
callbacks_ = callbacks;
}
std::tuple<uint32_t, uint32_t> CameraDevice::calculateStaticMetadataSize()
{
/*
* \todo Keep this in sync with the actual number of entries.
* Currently: 53 entries, 854 bytes of static metadata
*/
uint32_t numEntries = 53;
uint32_t byteSize = 854;
/*
* Calculate space occupation in bytes for dynamically built metadata
* entries.
*
* Each stream configuration entry requires 48 bytes:
* 4 32bits integers for ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
* 4 64bits integers for ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS
*/
byteSize += streamConfigurations_.size() * 48;
/*
* 2 32bits integers for each HAL_PIXEL_FORMAT_BLOB for thumbnail sizes
* 2 32bits integers for the (0, 0) thumbnail size
*
* This is a worst case estimates as different configurations with the
* same aspect ratio will generate the same size.
*/
for (const auto &entry : streamConfigurations_) {
if (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)
continue;
byteSize += 8;
}
byteSize += 8;
return std::make_tuple(numEntries, byteSize);
}
/*
* Return static information for the camera.
*/
const camera_metadata_t *CameraDevice::getStaticMetadata()
{
if (staticMetadata_)
return staticMetadata_->get();
/*
* The here reported metadata are enough to implement a basic capture
* example application, but a real camera implementation will require
* more.
*/
uint32_t numEntries;
uint32_t byteSize;
std::tie(numEntries, byteSize) = calculateStaticMetadataSize();
staticMetadata_ = new CameraMetadata(numEntries, byteSize);
if (!staticMetadata_->isValid()) {
LOG(HAL, Error) << "Failed to allocate static metadata";
delete staticMetadata_;
staticMetadata_ = nullptr;
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());
std::vector<int32_t> availableAeFpsTarget = {
15, 30,
};
staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
availableAeFpsTarget.data(),
availableAeFpsTarget.size());
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. */
{
const Size &size =
properties.get(properties::PixelArraySize);
std::vector<int32_t> data{
static_cast<int32_t>(size.width),
static_cast<int32_t>(size.height),
};
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
data.data(), data.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());
std::vector<float> physicalSize = {
2592, 1944,
};
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
physicalSize.data(),
physicalSize.size());
uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
staticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
&timestampSource, 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.
*/
const auto info = controlsInfo.find(&controls::ScalerCrop);
Rectangle min = info->second.min().get<Rectangle>();
Rectangle max = info->second.max().get<Rectangle>();
float 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());
/* \todo Collect the minimum frame duration from the camera. */
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(33333333);
}
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_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";
delete staticMetadata_;
staticMetadata_ = nullptr;
return nullptr;
}
return staticMetadata_->get();
}
CameraMetadata *CameraDevice::requestTemplatePreview()
{
/*
* \todo Keep this in sync with the actual number of entries.
* Currently: 20 entries, 35 bytes
*/
CameraMetadata *requestTemplate = new CameraMetadata(21, 36);
if (!requestTemplate->isValid()) {
delete requestTemplate;
return nullptr;
}
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);
std::vector<int32_t> aeFpsTarget = {
15, 30,
};
requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
aeFpsTarget.data(),
aeFpsTarget.size());
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;
}
/*
* 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. */
CameraMetadata *requestTemplate;
uint8_t captureIntent;
switch (type) {
case CAMERA3_TEMPLATE_PREVIEW:
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
break;
case CAMERA3_TEMPLATE_STILL_CAPTURE:
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
break;
case CAMERA3_TEMPLATE_VIDEO_RECORD:
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
break;
case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
break;
case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
break;
case CAMERA3_TEMPLATE_MANUAL:
captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;
break;
default:
LOG(HAL, Error) << "Invalid template request type: " << type;
return nullptr;
}
requestTemplate = requestTemplatePreview();
if (!requestTemplate || !requestTemplate->isValid()) {
LOG(HAL, Error) << "Failed to construct request template";
delete requestTemplate;
return nullptr;
}
requestTemplate->updateEntry(ANDROID_CONTROL_CAPTURE_INTENT,
&captureIntent, 1);
requestTemplates_[type] = requestTemplate;
return requestTemplate->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 if it's running. */
if (running_) {
worker_.stop();
camera_->stop();
running_ = false;
}
/*
* 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)
<< " (" << format.toString() << ")";
if (!format.isValid())
return -EINVAL;
/* 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));
}
/* 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) {
const auto &cfg = streamConfigs[i].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;
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;
}
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 (!camera3Request) {
LOG(HAL, Error) << "No capture request provided";
return -EINVAL;
}
if (!camera3Request->num_output_buffers) {
LOG(HAL, Error) << "No output buffers provided";
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 =
new Camera3RequestDescriptor(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->numBuffers_ << " streams";
for (unsigned int i = 0; i < descriptor->numBuffers_; ++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";
delete descriptor;
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());
return 0;
}
void CameraDevice::requestComplete(Request *request)
{
const Request::BufferMap &buffers = request->buffers();
camera3_buffer_status status = CAMERA3_BUFFER_STATUS_OK;
std::unique_ptr<CameraMetadata> resultMetadata;
Camera3RequestDescriptor *descriptor =
reinterpret_cast<Camera3RequestDescriptor *>(request->cookie());
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->numBuffers_ << " streams";
/*
* \todo The timestamp used for the metadata is currently always taken
* from the first buffer (which may be the first stream) in the Request.
* It might be appropriate to return a 'correct' (as determined by
* pipeline handlers) timestamp in the Request itself.
*/
uint64_t timestamp = buffers.begin()->second->metadata().timestamp;
resultMetadata = getResultMetadata(descriptor, timestamp);
/* Handle any JPEG compression. */
for (unsigned int i = 0; i < descriptor->numBuffers_; ++i) {
CameraStream *cameraStream =
static_cast<CameraStream *>(descriptor->buffers_[i].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;
}
/*
* \todo Buffer mapping and compression should be moved to a
* separate thread.
*/
CameraBuffer dest(*descriptor->buffers_[i].buffer,
PROT_READ | PROT_WRITE);
if (!dest.isValid()) {
LOG(HAL, Error) << "Failed to map android blob buffer";
continue;
}
int ret = cameraStream->process(*src, &dest,
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->numBuffers_;
for (unsigned int i = 0; i < descriptor->numBuffers_; ++i) {
descriptor->buffers_[i].acquire_fence = -1;
descriptor->buffers_[i].release_fence = -1;
descriptor->buffers_[i].status = status;
}
captureResult.output_buffers =
const_cast<const camera3_stream_buffer_t *>(descriptor->buffers_);
if (status == CAMERA3_BUFFER_STATUS_OK) {
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);
delete descriptor;
}
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_, &notify);
}
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_, &notify);
}
/*
* Produce a set of fixed result metadata.
*/
std::unique_ptr<CameraMetadata>
CameraDevice::getResultMetadata(Camera3RequestDescriptor *descriptor,
int64_t timestamp)
{
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 static 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);
std::vector<int32_t> aeFpsTarget = { 30, 30 };
resultMetadata->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
aeFpsTarget.data(), aeFpsTarget.size());
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);
resultMetadata->addEntry(ANDROID_SENSOR_TIMESTAMP, &timestamp, 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. */
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;
}