blob: 6d060e0c40e5d313fe219a75f8adf598680ccaa6 [file] [log] [blame]
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001/* SPDX-License-Identifier: LGPL-2.1-or-later */
2/*
3 * Copyright (C) 2019, Google Inc.
4 *
5 * camera_device.cpp - libcamera Android Camera Device
6 */
7
8#include "camera_device.h"
Laurent Pinchartda3f50e2020-01-20 01:09:34 +02009#include "camera_ops.h"
Jacopo Mondi667d8ea2019-05-10 17:40:02 +020010
Jacopo Mondia80d3812020-05-26 12:31:35 +020011#include <tuple>
Jacopo Mondi117588b2020-05-23 18:53:54 +020012#include <vector>
13
Jacopo Mondi857a2162019-11-20 17:00:49 +010014#include <libcamera/controls.h>
Laurent Pinchart8b7e0732020-05-22 04:02:06 +030015#include <libcamera/formats.h>
Jacopo Mondi857a2162019-11-20 17:00:49 +010016#include <libcamera/property_ids.h>
17
Laurent Pinchart93e72b62020-05-12 00:58:34 +030018#include "libcamera/internal/log.h"
19#include "libcamera/internal/utils.h"
Jacopo Mondi667d8ea2019-05-10 17:40:02 +020020
Laurent Pinchart39860092019-09-05 03:12:34 +030021#include "camera_metadata.h"
Jacopo Mondi117588b2020-05-23 18:53:54 +020022#include "system/graphics.h"
Jacopo Mondi667d8ea2019-05-10 17:40:02 +020023
24using namespace libcamera;
25
Jacopo Mondi117588b2020-05-23 18:53:54 +020026namespace {
27
28/*
29 * \var camera3Resolutions
30 * \brief The list of image resolutions defined as mandatory to be supported by
31 * the Android Camera3 specification
32 */
33const std::vector<Size> camera3Resolutions = {
34 { 320, 240 },
35 { 640, 480 },
36 { 1280, 720 },
37 { 1920, 1080 }
38};
39
40/*
41 * \struct Camera3Format
42 * \brief Data associated with an Android format identifier
43 * \var libcameraFormats List of libcamera pixel formats compatible with the
44 * Android format
45 * \var scalerFormat The format identifier to be reported to the android
46 * framework through the static format configuration map
47 * \var name The human-readable representation of the Android format code
48 */
49struct Camera3Format {
50 std::vector<PixelFormat> libcameraFormats;
51 camera_metadata_enum_android_scaler_available_formats_t scalerFormat;
52 const char *name;
53};
54
55/*
56 * \var camera3FormatsMap
57 * \brief Associate Android format code with ancillary data
58 */
59const std::map<int, const Camera3Format> camera3FormatsMap = {
60 {
61 HAL_PIXEL_FORMAT_BLOB, {
Laurent Pinchart8b7e0732020-05-22 04:02:06 +030062 { formats::MJPEG },
Jacopo Mondi117588b2020-05-23 18:53:54 +020063 ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
64 "BLOB"
65 }
66 }, {
67 HAL_PIXEL_FORMAT_YCbCr_420_888, {
Laurent Pinchart8b7e0732020-05-22 04:02:06 +030068 { formats::NV12, formats::NV21 },
Jacopo Mondi117588b2020-05-23 18:53:54 +020069 ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
70 "YCbCr_420_888"
71 }
72 }, {
73 /*
74 * \todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc
75 * usage flag. For now, copy the YCbCr_420 configuration.
76 */
77 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {
Laurent Pinchart8b7e0732020-05-22 04:02:06 +030078 { formats::NV12, formats::NV21 },
Jacopo Mondi117588b2020-05-23 18:53:54 +020079 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
80 "IMPLEMENTATION_DEFINED"
81 }
82 },
83};
84
85} /* namespace */
86
Jacopo Mondi667d8ea2019-05-10 17:40:02 +020087LOG_DECLARE_CATEGORY(HAL);
88
89/*
90 * \struct Camera3RequestDescriptor
91 *
92 * A utility structure that groups information about a capture request to be
93 * later re-used at request complete time to notify the framework.
94 */
95
96CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor(
97 unsigned int frameNumber, unsigned int numBuffers)
98 : frameNumber(frameNumber), numBuffers(numBuffers)
99{
100 buffers = new camera3_stream_buffer_t[numBuffers];
101}
102
103CameraDevice::Camera3RequestDescriptor::~Camera3RequestDescriptor()
104{
105 delete[] buffers;
106}
107
108/*
109 * \class CameraDevice
110 *
111 * The CameraDevice class wraps a libcamera::Camera instance, and implements
Laurent Pinchartda3f50e2020-01-20 01:09:34 +0200112 * the camera3_device_t interface, bridging calls received from the Android
113 * camera service to the CameraDevice.
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200114 *
Laurent Pinchartda3f50e2020-01-20 01:09:34 +0200115 * The class translates parameters and operations from the Camera HALv3 API to
116 * the libcamera API to provide static information for a Camera, create request
117 * templates for it, process capture requests and then deliver capture results
118 * back to the framework using the designated callbacks.
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200119 */
120
Laurent Pinchart0ed40d22019-08-18 01:45:01 +0300121CameraDevice::CameraDevice(unsigned int id, const std::shared_ptr<Camera> &camera)
Jacopo Mondi64f4f662020-05-25 16:08:22 +0200122 : running_(false), camera_(camera), staticMetadata_(nullptr),
123 facing_(CAMERA_FACING_FRONT), orientation_(0)
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200124{
125 camera_->requestCompleted.connect(this, &CameraDevice::requestComplete);
126}
127
128CameraDevice::~CameraDevice()
129{
130 if (staticMetadata_)
Laurent Pinchart39860092019-09-05 03:12:34 +0300131 delete staticMetadata_;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200132
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200133 for (auto &it : requestTemplates_)
134 delete it.second;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200135}
136
Jacopo Mondi64f4f662020-05-25 16:08:22 +0200137/*
138 * Initialize the camera static information.
139 * This method is called before the camera device is opened.
140 */
141int CameraDevice::initialize()
142{
143 /* Initialize orientation and facing side of the camera. */
144 const ControlList &properties = camera_->properties();
145
146 if (properties.contains(properties::Location)) {
147 int32_t location = properties.get(properties::Location);
148 switch (location) {
149 case properties::CameraLocationFront:
150 facing_ = CAMERA_FACING_FRONT;
151 break;
152 case properties::CameraLocationBack:
153 facing_ = CAMERA_FACING_BACK;
154 break;
155 case properties::CameraLocationExternal:
156 facing_ = CAMERA_FACING_EXTERNAL;
157 break;
158 }
159 }
160
161 /*
162 * The Android orientation metadata and libcamera rotation property are
163 * defined differently but have identical numerical values for Android
164 * devices such as phones and tablets.
165 */
166 if (properties.contains(properties::Rotation))
167 orientation_ = properties.get(properties::Rotation);
168
Jacopo Mondi117588b2020-05-23 18:53:54 +0200169 int ret = camera_->acquire();
170 if (ret) {
171 LOG(HAL, Error) << "Failed to temporarily acquire the camera";
172 return ret;
173 }
174
175 ret = initializeStreamConfigurations();
176 camera_->release();
177 return ret;
178}
179
180/*
181 * Initialize the format conversion map to translate from Android format
182 * identifier to libcamera pixel formats and fill in the list of supported
183 * stream configurations to be reported to the Android camera framework through
184 * the static stream configuration metadata.
185 */
186int CameraDevice::initializeStreamConfigurations()
187{
188 /*
189 * Get the maximum output resolutions
190 * \todo Get this from the camera properties once defined
191 */
192 std::unique_ptr<CameraConfiguration> cameraConfig =
193 camera_->generateConfiguration({ StillCapture });
194 if (!cameraConfig) {
195 LOG(HAL, Error) << "Failed to get maximum resolution";
196 return -EINVAL;
197 }
198 StreamConfiguration &cfg = cameraConfig->at(0);
199
200 /*
201 * \todo JPEG - Adjust the maximum available resolution by taking the
202 * JPEG encoder requirements into account (alignment and aspect ratio).
203 */
204 const Size maxRes = cfg.size;
205 LOG(HAL, Debug) << "Maximum supported resolution: " << maxRes.toString();
206
207 /*
208 * Build the list of supported image resolutions.
209 *
210 * The resolutions listed in camera3Resolution are mandatory to be
211 * supported, up to the camera maximum resolution.
212 *
213 * Augment the list by adding resolutions calculated from the camera
214 * maximum one.
215 */
216 std::vector<Size> cameraResolutions;
217 std::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),
218 std::back_inserter(cameraResolutions),
219 [&](const Size &res) { return res < maxRes; });
220
221 /*
222 * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum
223 * resolution.
224 */
225 for (unsigned int divider = 2;; divider <<= 1) {
226 Size derivedSize{
227 maxRes.width / divider,
228 maxRes.height / divider,
229 };
230
231 if (derivedSize.width < 320 ||
232 derivedSize.height < 240)
233 break;
234
235 cameraResolutions.push_back(derivedSize);
236 }
237 cameraResolutions.push_back(maxRes);
238
239 /* Remove duplicated entries from the list of supported resolutions. */
240 std::sort(cameraResolutions.begin(), cameraResolutions.end());
241 auto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());
242 cameraResolutions.erase(last, cameraResolutions.end());
243
244 /*
245 * Build the list of supported camera formats.
246 *
247 * To each Android format a list of compatible libcamera formats is
248 * associated. The first libcamera format that tests successful is added
249 * to the format translation map used when configuring the streams.
250 * It is then tested against the list of supported camera resolutions to
251 * build the stream configuration map reported through the camera static
252 * metadata.
253 */
254 for (const auto &format : camera3FormatsMap) {
255 int androidFormat = format.first;
256 const Camera3Format &camera3Format = format.second;
257 const std::vector<PixelFormat> &libcameraFormats =
258 camera3Format.libcameraFormats;
259
260 /*
261 * Test the libcamera formats that can produce images
262 * compatible with the format defined by Android.
263 */
264 PixelFormat mappedFormat;
265 for (const PixelFormat &pixelFormat : libcameraFormats) {
266 /* \todo Fixed mapping for JPEG. */
267 if (androidFormat == HAL_PIXEL_FORMAT_BLOB) {
Laurent Pinchart8b7e0732020-05-22 04:02:06 +0300268 mappedFormat = formats::MJPEG;
Jacopo Mondi117588b2020-05-23 18:53:54 +0200269 break;
270 }
271
272 /*
273 * The stream configuration size can be adjusted,
274 * not the pixel format.
275 *
276 * \todo This could be simplified once all pipeline
277 * handlers will report the StreamFormats list of
278 * supported formats.
279 */
280 cfg.pixelFormat = pixelFormat;
281
282 CameraConfiguration::Status status = cameraConfig->validate();
283 if (status != CameraConfiguration::Invalid &&
284 cfg.pixelFormat == pixelFormat) {
285 mappedFormat = pixelFormat;
286 break;
287 }
288 }
289 if (!mappedFormat.isValid()) {
290 LOG(HAL, Error) << "Failed to map Android format "
291 << camera3Format.name << " ("
292 << utils::hex(androidFormat) << ")";
293 return -EINVAL;
294 }
295
296 /*
297 * Record the mapping and then proceed to generate the
298 * stream configurations map, by testing the image resolutions.
299 */
300 formatsMap_[androidFormat] = mappedFormat;
301
302 for (const Size &res : cameraResolutions) {
303 cfg.pixelFormat = mappedFormat;
304 cfg.size = res;
305
306 CameraConfiguration::Status status = cameraConfig->validate();
307 /*
308 * Unconditionally report we can produce JPEG.
309 *
310 * \todo The JPEG stream will be implemented as an
311 * HAL-only stream, but some cameras can produce it
312 * directly. As of now, claim support for JPEG without
313 * inspecting where the JPEG stream is produced.
314 */
315 if (androidFormat != HAL_PIXEL_FORMAT_BLOB &&
316 status != CameraConfiguration::Valid)
317 continue;
318
319 streamConfigurations_.push_back({ res, camera3Format.scalerFormat });
320 }
321 }
322
323 LOG(HAL, Debug) << "Collected stream configuration map: ";
324 for (const auto &entry : streamConfigurations_)
325 LOG(HAL, Debug) << "{ " << entry.resolution.toString() << " - "
326 << utils::hex(entry.androidScalerCode) << " }";
327
Jacopo Mondi64f4f662020-05-25 16:08:22 +0200328 return 0;
329}
330
331/*
332 * Open a camera device. The static information on the camera shall have been
333 * initialized with a call to CameraDevice::initialize().
334 */
Laurent Pinchartda3f50e2020-01-20 01:09:34 +0200335int CameraDevice::open(const hw_module_t *hardwareModule)
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200336{
337 int ret = camera_->acquire();
338 if (ret) {
339 LOG(HAL, Error) << "Failed to acquire the camera";
340 return ret;
341 }
342
Laurent Pinchartda3f50e2020-01-20 01:09:34 +0200343 /* Initialize the hw_device_t in the instance camera3_module_t. */
344 camera3Device_.common.tag = HARDWARE_DEVICE_TAG;
345 camera3Device_.common.version = CAMERA_DEVICE_API_VERSION_3_3;
346 camera3Device_.common.module = (hw_module_t *)hardwareModule;
347 camera3Device_.common.close = hal_dev_close;
348
349 /*
350 * The camera device operations. These actually implement
351 * the Android Camera HALv3 interface.
352 */
353 camera3Device_.ops = &hal_dev_ops;
354 camera3Device_.priv = this;
355
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200356 return 0;
357}
358
359void CameraDevice::close()
360{
361 camera_->stop();
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200362 camera_->release();
363
364 running_ = false;
365}
366
367void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)
368{
369 callbacks_ = callbacks;
370}
371
Jacopo Mondia80d3812020-05-26 12:31:35 +0200372std::tuple<uint32_t, uint32_t> CameraDevice::calculateStaticMetadataSize()
373{
374 /*
375 * \todo Keep this in sync with the actual number of entries.
376 * Currently: 50 entries, 647 bytes of static metadata
377 */
378 uint32_t numEntries = 50;
379 uint32_t byteSize = 647;
380
381 /*
382 * Calculate space occupation in bytes for dynamically built metadata
383 * entries.
384 *
385 * Each stream configuration entry requires 52 bytes:
386 * 4 32bits integers for ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
387 * 1 32bits integer for ANDROID_SCALER_AVAILABLE_FORMATS
388 * 4 64bits integers for ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS
389 */
390 byteSize += streamConfigurations_.size() * 52;
391
Laurent Pinchart7a88b212020-06-10 00:07:59 +0300392 return std::make_tuple(numEntries, byteSize);
Jacopo Mondia80d3812020-05-26 12:31:35 +0200393}
394
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200395/*
396 * Return static information for the camera.
397 */
Laurent Pinchartda3f50e2020-01-20 01:09:34 +0200398const camera_metadata_t *CameraDevice::getStaticMetadata()
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200399{
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200400 if (staticMetadata_)
Laurent Pinchart39860092019-09-05 03:12:34 +0300401 return staticMetadata_->get();
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200402
403 /*
404 * The here reported metadata are enough to implement a basic capture
405 * example application, but a real camera implementation will require
406 * more.
407 */
Jacopo Mondia80d3812020-05-26 12:31:35 +0200408 uint32_t numEntries;
409 uint32_t byteSize;
410 std::tie(numEntries, byteSize) = calculateStaticMetadataSize();
411 staticMetadata_ = new CameraMetadata(numEntries, byteSize);
Laurent Pinchart39860092019-09-05 03:12:34 +0300412 if (!staticMetadata_->isValid()) {
413 LOG(HAL, Error) << "Failed to allocate static metadata";
414 delete staticMetadata_;
415 staticMetadata_ = nullptr;
416 return nullptr;
417 }
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200418
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200419 /* Color correction static metadata. */
420 std::vector<uint8_t> aberrationModes = {
421 ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF,
422 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300423 staticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
424 aberrationModes.data(),
425 aberrationModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200426
427 /* Control static metadata. */
428 std::vector<uint8_t> aeAvailableAntiBandingModes = {
429 ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
430 ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,
431 ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,
432 ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,
433 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300434 staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
435 aeAvailableAntiBandingModes.data(),
436 aeAvailableAntiBandingModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200437
438 std::vector<uint8_t> aeAvailableModes = {
439 ANDROID_CONTROL_AE_MODE_ON,
440 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300441 staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,
442 aeAvailableModes.data(),
443 aeAvailableModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200444
445 std::vector<int32_t> availableAeFpsTarget = {
446 15, 30,
447 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300448 staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
449 availableAeFpsTarget.data(),
450 availableAeFpsTarget.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200451
452 std::vector<int32_t> aeCompensationRange = {
453 0, 0,
454 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300455 staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
456 aeCompensationRange.data(),
457 aeCompensationRange.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200458
459 const camera_metadata_rational_t aeCompensationStep[] = {
460 { 0, 1 }
461 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300462 staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,
463 aeCompensationStep, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200464
465 std::vector<uint8_t> availableAfModes = {
466 ANDROID_CONTROL_AF_MODE_OFF,
467 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300468 staticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,
469 availableAfModes.data(),
470 availableAfModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200471
472 std::vector<uint8_t> availableEffects = {
473 ANDROID_CONTROL_EFFECT_MODE_OFF,
474 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300475 staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,
476 availableEffects.data(),
477 availableEffects.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200478
479 std::vector<uint8_t> availableSceneModes = {
480 ANDROID_CONTROL_SCENE_MODE_DISABLED,
481 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300482 staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
483 availableSceneModes.data(),
484 availableSceneModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200485
486 std::vector<uint8_t> availableStabilizationModes = {
487 ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,
488 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300489 staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
490 availableStabilizationModes.data(),
491 availableStabilizationModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200492
493 std::vector<uint8_t> availableAwbModes = {
494 ANDROID_CONTROL_AWB_MODE_OFF,
495 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300496 staticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
497 availableAwbModes.data(),
498 availableAwbModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200499
500 std::vector<int32_t> availableMaxRegions = {
501 0, 0, 0,
502 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300503 staticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,
504 availableMaxRegions.data(),
505 availableMaxRegions.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200506
507 std::vector<uint8_t> sceneModesOverride = {
508 ANDROID_CONTROL_AE_MODE_ON,
509 ANDROID_CONTROL_AWB_MODE_AUTO,
510 ANDROID_CONTROL_AF_MODE_AUTO,
511 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300512 staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
513 sceneModesOverride.data(),
514 sceneModesOverride.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200515
516 uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
Laurent Pinchart39860092019-09-05 03:12:34 +0300517 staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
518 &aeLockAvailable, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200519
520 uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
Laurent Pinchart39860092019-09-05 03:12:34 +0300521 staticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
522 &awbLockAvailable, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200523
524 char availableControlModes = ANDROID_CONTROL_MODE_AUTO;
Laurent Pinchart39860092019-09-05 03:12:34 +0300525 staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,
526 &availableControlModes, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200527
528 /* JPEG static metadata. */
529 std::vector<int32_t> availableThumbnailSizes = {
530 0, 0,
531 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300532 staticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
533 availableThumbnailSizes.data(),
534 availableThumbnailSizes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200535
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200536 /* Sensor static metadata. */
537 int32_t pixelArraySize[] = {
538 2592, 1944,
539 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300540 staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
541 &pixelArraySize, 2);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200542
543 int32_t sensorSizes[] = {
544 0, 0, 2560, 1920,
545 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300546 staticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
547 &sensorSizes, 4);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200548
549 int32_t sensitivityRange[] = {
550 32, 2400,
551 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300552 staticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
553 &sensitivityRange, 2);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200554
555 uint16_t filterArr = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG;
Laurent Pinchart39860092019-09-05 03:12:34 +0300556 staticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
557 &filterArr, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200558
559 int64_t exposureTimeRange[] = {
560 100000, 200000000,
561 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300562 staticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
563 &exposureTimeRange, 2);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200564
Jacopo Mondi64f4f662020-05-25 16:08:22 +0200565 staticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, &orientation_, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200566
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200567 std::vector<int32_t> testPatterModes = {
568 ANDROID_SENSOR_TEST_PATTERN_MODE_OFF,
569 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300570 staticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
571 testPatterModes.data(),
572 testPatterModes.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200573
574 std::vector<float> physicalSize = {
575 2592, 1944,
576 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300577 staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
578 physicalSize.data(),
579 physicalSize.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200580
581 uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
Laurent Pinchart39860092019-09-05 03:12:34 +0300582 staticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
583 &timestampSource, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200584
585 /* Statistics static metadata. */
586 uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
Laurent Pinchart39860092019-09-05 03:12:34 +0300587 staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
588 &faceDetectMode, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200589
590 int32_t maxFaceCount = 0;
Laurent Pinchart39860092019-09-05 03:12:34 +0300591 staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
592 &maxFaceCount, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200593
594 /* Sync static metadata. */
595 int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
Laurent Pinchart39860092019-09-05 03:12:34 +0300596 staticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200597
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200598 /* Flash static metadata. */
599 char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
Laurent Pinchart39860092019-09-05 03:12:34 +0300600 staticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,
601 &flashAvailable, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200602
603 /* Lens static metadata. */
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200604 std::vector<float> lensApertures = {
605 2.53 / 100,
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200606 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300607 staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,
608 lensApertures.data(),
609 lensApertures.size());
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200610
Jacopo Mondi64f4f662020-05-25 16:08:22 +0200611 uint8_t lensFacing;
612 switch (facing_) {
613 default:
614 case CAMERA_FACING_FRONT:
615 lensFacing = ANDROID_LENS_FACING_FRONT;
616 break;
617 case CAMERA_FACING_BACK:
618 lensFacing = ANDROID_LENS_FACING_BACK;
619 break;
620 case CAMERA_FACING_EXTERNAL:
621 lensFacing = ANDROID_LENS_FACING_EXTERNAL;
622 break;
Jacopo Mondi857a2162019-11-20 17:00:49 +0100623 }
Laurent Pinchart39860092019-09-05 03:12:34 +0300624 staticMetadata_->addEntry(ANDROID_LENS_FACING, &lensFacing, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200625
626 std::vector<float> lensFocalLenghts = {
627 1,
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200628 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300629 staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
630 lensFocalLenghts.data(),
631 lensFocalLenghts.size());
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200632
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200633 std::vector<uint8_t> opticalStabilizations = {
634 ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,
635 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300636 staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
637 opticalStabilizations.data(),
638 opticalStabilizations.size());
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200639
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200640 float hypeFocalDistance = 0;
Laurent Pinchart39860092019-09-05 03:12:34 +0300641 staticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
642 &hypeFocalDistance, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200643
644 float minFocusDistance = 0;
Laurent Pinchart39860092019-09-05 03:12:34 +0300645 staticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
646 &minFocusDistance, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200647
648 /* Noise reduction modes. */
649 uint8_t noiseReductionModes = ANDROID_NOISE_REDUCTION_MODE_OFF;
Laurent Pinchart39860092019-09-05 03:12:34 +0300650 staticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
651 &noiseReductionModes, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200652
653 /* Scaler static metadata. */
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200654 float maxDigitalZoom = 1;
Laurent Pinchart39860092019-09-05 03:12:34 +0300655 staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
656 &maxDigitalZoom, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200657
Jacopo Mondibde7b982020-05-25 17:18:28 +0200658 std::vector<uint32_t> availableStreamFormats;
659 availableStreamFormats.reserve(streamConfigurations_.size());
660 std::transform(streamConfigurations_.begin(), streamConfigurations_.end(),
661 std::back_inserter(availableStreamFormats),
662 [](const auto &entry) { return entry.androidScalerCode; });
Laurent Pinchart39860092019-09-05 03:12:34 +0300663 staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_FORMATS,
664 availableStreamFormats.data(),
665 availableStreamFormats.size());
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200666
Jacopo Mondibde7b982020-05-25 17:18:28 +0200667 std::vector<uint32_t> availableStreamConfigurations;
668 availableStreamConfigurations.reserve(streamConfigurations_.size() * 4);
669 for (const auto &entry : streamConfigurations_) {
670 availableStreamConfigurations.push_back(entry.androidScalerCode);
671 availableStreamConfigurations.push_back(entry.resolution.width);
672 availableStreamConfigurations.push_back(entry.resolution.height);
673 availableStreamConfigurations.push_back(
674 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
675 }
Laurent Pinchart39860092019-09-05 03:12:34 +0300676 staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
677 availableStreamConfigurations.data(),
678 availableStreamConfigurations.size());
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200679
680 std::vector<int64_t> availableStallDurations = {
681 ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,
682 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300683 staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
684 availableStallDurations.data(),
685 availableStallDurations.size());
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200686
Jacopo Mondibde7b982020-05-25 17:18:28 +0200687 /* \todo Collect the minimum frame duration from the camera. */
688 std::vector<int64_t> minFrameDurations;
689 minFrameDurations.reserve(streamConfigurations_.size() * 4);
690 for (const auto &entry : streamConfigurations_) {
691 minFrameDurations.push_back(entry.androidScalerCode);
692 minFrameDurations.push_back(entry.resolution.width);
693 minFrameDurations.push_back(entry.resolution.height);
694 minFrameDurations.push_back(33333333);
695 }
Laurent Pinchart39860092019-09-05 03:12:34 +0300696 staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
697 minFrameDurations.data(),
698 minFrameDurations.size());
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200699
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200700 uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
Laurent Pinchart39860092019-09-05 03:12:34 +0300701 staticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200702
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200703 /* Info static metadata. */
704 uint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
Laurent Pinchart39860092019-09-05 03:12:34 +0300705 staticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
706 &supportedHWLevel, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200707
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200708 /* Request static metadata. */
709 int32_t partialResultCount = 1;
Laurent Pinchart39860092019-09-05 03:12:34 +0300710 staticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
711 &partialResultCount, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200712
713 uint8_t maxPipelineDepth = 2;
Laurent Pinchart39860092019-09-05 03:12:34 +0300714 staticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
715 &maxPipelineDepth, 1);
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200716
717 std::vector<uint8_t> availableCapabilities = {
718 ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
719 };
Laurent Pinchart39860092019-09-05 03:12:34 +0300720 staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
721 availableCapabilities.data(),
722 availableCapabilities.size());
Jacopo Mondib4893fc2019-09-04 16:18:18 +0200723
Jacopo Mondi19f85f42019-09-04 16:18:25 +0200724 std::vector<int32_t> availableCharacteristicsKeys = {
725 ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
726 ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
727 ANDROID_CONTROL_AE_AVAILABLE_MODES,
728 ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
729 ANDROID_CONTROL_AE_COMPENSATION_RANGE,
730 ANDROID_CONTROL_AE_COMPENSATION_STEP,
731 ANDROID_CONTROL_AF_AVAILABLE_MODES,
732 ANDROID_CONTROL_AVAILABLE_EFFECTS,
733 ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
734 ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
735 ANDROID_CONTROL_AWB_AVAILABLE_MODES,
736 ANDROID_CONTROL_MAX_REGIONS,
737 ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
738 ANDROID_CONTROL_AE_LOCK_AVAILABLE,
739 ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
740 ANDROID_CONTROL_AVAILABLE_MODES,
741 ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
742 ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
743 ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
744 ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
745 ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
746 ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
747 ANDROID_SENSOR_ORIENTATION,
748 ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
749 ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
750 ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
751 ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
752 ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
753 ANDROID_SYNC_MAX_LATENCY,
754 ANDROID_FLASH_INFO_AVAILABLE,
755 ANDROID_LENS_INFO_AVAILABLE_APERTURES,
756 ANDROID_LENS_FACING,
757 ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
758 ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
759 ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
760 ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
761 ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
762 ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
763 ANDROID_SCALER_AVAILABLE_FORMATS,
764 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
765 ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
766 ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
767 ANDROID_SCALER_CROPPING_TYPE,
768 ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
769 ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
770 ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
771 ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
772 };
773 staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
774 availableCharacteristicsKeys.data(),
775 availableCharacteristicsKeys.size());
776
777 std::vector<int32_t> availableRequestKeys = {
778 ANDROID_CONTROL_AE_MODE,
779 ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
780 ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
781 ANDROID_CONTROL_AE_LOCK,
782 ANDROID_CONTROL_AF_TRIGGER,
783 ANDROID_CONTROL_AWB_MODE,
784 ANDROID_CONTROL_AWB_LOCK,
785 ANDROID_FLASH_MODE,
786 ANDROID_STATISTICS_FACE_DETECT_MODE,
787 ANDROID_NOISE_REDUCTION_MODE,
788 ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
789 ANDROID_CONTROL_CAPTURE_INTENT,
790 };
791 staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
792 availableRequestKeys.data(),
793 availableRequestKeys.size());
794
795 std::vector<int32_t> availableResultKeys = {
796 ANDROID_CONTROL_AE_STATE,
797 ANDROID_CONTROL_AE_LOCK,
798 ANDROID_CONTROL_AF_STATE,
799 ANDROID_CONTROL_AWB_STATE,
800 ANDROID_CONTROL_AWB_LOCK,
801 ANDROID_LENS_STATE,
802 ANDROID_SCALER_CROP_REGION,
803 ANDROID_SENSOR_TIMESTAMP,
804 ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
805 ANDROID_SENSOR_EXPOSURE_TIME,
806 ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
807 ANDROID_STATISTICS_SCENE_FLICKER,
808 };
809 staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
810 availableResultKeys.data(),
811 availableResultKeys.size());
812
Laurent Pinchart39860092019-09-05 03:12:34 +0300813 if (!staticMetadata_->isValid()) {
814 LOG(HAL, Error) << "Failed to construct static metadata";
815 delete staticMetadata_;
816 staticMetadata_ = nullptr;
817 return nullptr;
818 }
819
820 return staticMetadata_->get();
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200821}
822
823/*
824 * Produce a metadata pack to be used as template for a capture request.
825 */
826const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)
827{
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200828 auto it = requestTemplates_.find(type);
829 if (it != requestTemplates_.end())
830 return it->second->get();
831
832 /* Use the capture intent matching the requested template type. */
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200833 uint8_t captureIntent;
834 switch (type) {
835 case CAMERA3_TEMPLATE_PREVIEW:
836 captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
837 break;
838 case CAMERA3_TEMPLATE_STILL_CAPTURE:
839 captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
840 break;
841 case CAMERA3_TEMPLATE_VIDEO_RECORD:
842 captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
843 break;
844 case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
845 captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
846 break;
847 case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
848 captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
849 break;
850 case CAMERA3_TEMPLATE_MANUAL:
851 captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;
852 break;
853 default:
854 LOG(HAL, Error) << "Invalid template request type: " << type;
855 return nullptr;
856 }
857
Jacopo Mondi63703472019-09-04 16:18:22 +0200858 /*
859 * \todo Keep this in sync with the actual number of entries.
860 * Currently: 12 entries, 15 bytes
861 */
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200862 CameraMetadata *requestTemplate = new CameraMetadata(15, 20);
863 if (!requestTemplate->isValid()) {
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200864 LOG(HAL, Error) << "Failed to allocate template metadata";
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200865 delete requestTemplate;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200866 return nullptr;
867 }
868
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200869 uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200870 requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE,
871 &aeMode, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200872
873 int32_t aeExposureCompensation = 0;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200874 requestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
875 &aeExposureCompensation, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200876
877 uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200878 requestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
879 &aePrecaptureTrigger, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200880
881 uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200882 requestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK,
883 &aeLock, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200884
885 uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200886 requestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER,
887 &afTrigger, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200888
889 uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200890 requestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE,
891 &awbMode, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200892
893 uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200894 requestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK,
895 &awbLock, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200896
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200897 uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200898 requestTemplate->addEntry(ANDROID_FLASH_MODE,
899 &flashMode, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200900
901 uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200902 requestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,
903 &faceDetectMode, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200904
Jacopo Mondi9b361dc2019-09-04 16:18:21 +0200905 uint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200906 requestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,
907 &noiseReduction, 1);
Jacopo Mondi9b361dc2019-09-04 16:18:21 +0200908
909 uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200910 requestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
911 &aberrationMode, 1);
Jacopo Mondi9b361dc2019-09-04 16:18:21 +0200912
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200913 requestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,
914 &captureIntent, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200915
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200916 if (!requestTemplate->isValid()) {
Laurent Pinchart39860092019-09-05 03:12:34 +0300917 LOG(HAL, Error) << "Failed to construct request template";
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200918 delete requestTemplate;
Laurent Pinchart39860092019-09-05 03:12:34 +0300919 return nullptr;
920 }
921
Jacopo Mondifcd5a4f2019-09-04 16:18:23 +0200922 requestTemplates_[type] = requestTemplate;
923 return requestTemplate->get();
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200924}
925
Kieran Bingham43e3b802020-06-26 09:58:49 +0100926PixelFormat CameraDevice::toPixelFormat(int format)
927{
928 /* Translate Android format code to libcamera pixel format. */
929 auto it = formatsMap_.find(format);
930 if (it == formatsMap_.end()) {
931 LOG(HAL, Error) << "Requested format " << utils::hex(format)
932 << " not supported";
933 return PixelFormat();
934 }
935
936 return it->second;
937}
938
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200939/*
940 * Inspect the stream_list to produce a list of StreamConfiguration to
941 * be use to configure the Camera.
942 */
943int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
944{
Kieran Bingham0a9244e2020-06-26 20:19:10 +0100945 /*
946 * Generate an empty configuration, and construct a StreamConfiguration
947 * for each camera3_stream to add to it.
948 */
949 config_ = camera_->generateConfiguration();
950 if (!config_) {
951 LOG(HAL, Error) << "Failed to generate camera configuration";
952 return -EINVAL;
953 }
954
Kieran Bingham2f34f5e2020-07-01 16:42:13 +0100955 /*
956 * Clear and remove any existing configuration from previous calls, and
957 * ensure the required entries are available without further
958 * re-allcoation.
959 */
960 streams_.clear();
961 streams_.reserve(stream_list->num_streams);
962
963 /*
964 * Track actually created streams, as there may not be a 1:1 mapping of
965 * camera3 streams to libcamera streams.
966 */
967 unsigned int streamIndex = 0;
968
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200969 for (unsigned int i = 0; i < stream_list->num_streams; ++i) {
970 camera3_stream_t *stream = stream_list->streams[i];
971
Kieran Bingham43e3b802020-06-26 09:58:49 +0100972 PixelFormat format = toPixelFormat(stream->format);
973
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200974 LOG(HAL, Info) << "Stream #" << i
975 << ", direction: " << stream->stream_type
976 << ", width: " << stream->width
977 << ", height: " << stream->height
Kieran Bingham43e3b802020-06-26 09:58:49 +0100978 << ", format: " << utils::hex(stream->format)
979 << " (" << format.toString() << ")";
Kieran Bingham0a9244e2020-06-26 20:19:10 +0100980
981 if (!format.isValid())
982 return -EINVAL;
983
984 StreamConfiguration streamConfiguration;
985
986 streamConfiguration.size.width = stream->width;
987 streamConfiguration.size.height = stream->height;
988 streamConfiguration.pixelFormat = format;
989
990 config_->addConfiguration(streamConfiguration);
Kieran Bingham2f34f5e2020-07-01 16:42:13 +0100991
992 streams_[i].index = streamIndex++;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200993 }
994
Jacopo Mondi667d8ea2019-05-10 17:40:02 +0200995 switch (config_->validate()) {
996 case CameraConfiguration::Valid:
997 break;
998 case CameraConfiguration::Adjusted:
999 LOG(HAL, Info) << "Camera configuration adjusted";
1000 config_.reset();
1001 return -EINVAL;
1002 case CameraConfiguration::Invalid:
1003 LOG(HAL, Info) << "Camera configuration invalid";
1004 config_.reset();
1005 return -EINVAL;
1006 }
1007
Kieran Bingham0a9244e2020-06-26 20:19:10 +01001008 for (unsigned int i = 0; i < stream_list->num_streams; ++i) {
1009 camera3_stream_t *stream = stream_list->streams[i];
Kieran Bingham2f34f5e2020-07-01 16:42:13 +01001010 CameraStream *cameraStream = &streams_[i];
1011 StreamConfiguration &cfg = config_->at(cameraStream->index);
Kieran Bingham0a9244e2020-06-26 20:19:10 +01001012
1013 /* Use the bufferCount confirmed by the validation process. */
Kieran Bingham2f34f5e2020-07-01 16:42:13 +01001014 stream->max_buffers = cfg.bufferCount;
Kieran Bingham0a9244e2020-06-26 20:19:10 +01001015 }
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001016
1017 /*
1018 * Once the CameraConfiguration has been adjusted/validated
1019 * it can be applied to the camera.
1020 */
1021 int ret = camera_->configure(config_.get());
1022 if (ret) {
1023 LOG(HAL, Error) << "Failed to configure camera '"
1024 << camera_->name() << "'";
1025 return ret;
1026 }
1027
1028 return 0;
1029}
1030
Kieran Bingham74ab4422020-07-01 13:25:38 +01001031FrameBuffer *CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer)
1032{
1033 std::vector<FrameBuffer::Plane> planes;
1034 for (unsigned int i = 0; i < 3; i++) {
1035 FrameBuffer::Plane plane;
1036 plane.fd = FileDescriptor(camera3buffer->data[i]);
1037 /*
1038 * Setting length to zero here is OK as the length is only used
1039 * to map the memory of the plane. Libcamera do not need to poke
1040 * at the memory content queued by the HAL.
1041 */
1042 plane.length = 0;
1043 planes.push_back(std::move(plane));
1044 }
1045
1046 return new FrameBuffer(std::move(planes));
1047}
1048
Laurent Pinchartda3f50e2020-01-20 01:09:34 +02001049int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request)
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001050{
1051 StreamConfiguration *streamConfiguration = &config_->at(0);
1052 Stream *stream = streamConfiguration->stream();
1053
1054 if (camera3Request->num_output_buffers != 1) {
1055 LOG(HAL, Error) << "Invalid number of output buffers: "
1056 << camera3Request->num_output_buffers;
Laurent Pinchartda3f50e2020-01-20 01:09:34 +02001057 return -EINVAL;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001058 }
1059
1060 /* Start the camera if that's the first request we handle. */
1061 if (!running_) {
Niklas Söderlunda1c54502019-11-25 17:51:06 +01001062 int ret = camera_->start();
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001063 if (ret) {
1064 LOG(HAL, Error) << "Failed to start camera";
Laurent Pinchartda3f50e2020-01-20 01:09:34 +02001065 return ret;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001066 }
1067
1068 running_ = true;
1069 }
1070
1071 /*
1072 * Queue a request for the Camera with the provided dmabuf file
1073 * descriptors.
1074 */
1075 const camera3_stream_buffer_t *camera3Buffers =
1076 camera3Request->output_buffers;
1077
1078 /*
1079 * Save the request descriptors for use at completion time.
1080 * The descriptor and the associated memory reserved here are freed
1081 * at request complete time.
1082 */
1083 Camera3RequestDescriptor *descriptor =
1084 new Camera3RequestDescriptor(camera3Request->frame_number,
1085 camera3Request->num_output_buffers);
Kieran Binghameac05422020-07-01 13:28:16 +01001086
1087 Request *request =
1088 camera_->createRequest(reinterpret_cast<uint64_t>(descriptor));
1089
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001090 for (unsigned int i = 0; i < descriptor->numBuffers; ++i) {
1091 /*
1092 * Keep track of which stream the request belongs to and store
1093 * the native buffer handles.
1094 *
1095 * \todo Currently we only support one capture buffer. Copy
1096 * all of them to be ready once we'll support more.
1097 */
1098 descriptor->buffers[i].stream = camera3Buffers[i].stream;
1099 descriptor->buffers[i].buffer = camera3Buffers[i].buffer;
1100 }
1101
1102 /*
1103 * Create a libcamera buffer using the dmabuf descriptors of the first
1104 * and (currently) only supported request buffer.
1105 */
Kieran Bingham74ab4422020-07-01 13:25:38 +01001106 FrameBuffer *buffer = createFrameBuffer(*camera3Buffers[0].buffer);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001107 if (!buffer) {
1108 LOG(HAL, Error) << "Failed to create buffer";
Kieran Binghameac05422020-07-01 13:28:16 +01001109 delete request;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001110 delete descriptor;
Laurent Pinchartda3f50e2020-01-20 01:09:34 +02001111 return -ENOMEM;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001112 }
1113
Niklas Söderlund9217f272019-11-22 16:22:56 +01001114 request->addBuffer(stream, buffer);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001115
1116 int ret = camera_->queueRequest(request);
1117 if (ret) {
1118 LOG(HAL, Error) << "Failed to queue request";
Laurent Pinchartda3f50e2020-01-20 01:09:34 +02001119 delete request;
1120 delete descriptor;
1121 return ret;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001122 }
1123
Laurent Pinchartda3f50e2020-01-20 01:09:34 +02001124 return 0;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001125}
1126
Niklas Söderlundf7ddfd42019-10-21 20:01:19 +02001127void CameraDevice::requestComplete(Request *request)
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001128{
Niklas Söderlund9217f272019-11-22 16:22:56 +01001129 const std::map<Stream *, FrameBuffer *> &buffers = request->buffers();
1130 FrameBuffer *buffer = buffers.begin()->second;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001131 camera3_buffer_status status = CAMERA3_BUFFER_STATUS_OK;
Laurent Pinchart39860092019-09-05 03:12:34 +03001132 std::unique_ptr<CameraMetadata> resultMetadata;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001133
1134 if (request->status() != Request::RequestComplete) {
1135 LOG(HAL, Error) << "Request not succesfully completed: "
1136 << request->status();
1137 status = CAMERA3_BUFFER_STATUS_ERROR;
1138 }
1139
1140 /* Prepare to call back the Android camera stack. */
1141 Camera3RequestDescriptor *descriptor =
1142 reinterpret_cast<Camera3RequestDescriptor *>(request->cookie());
1143
1144 camera3_capture_result_t captureResult = {};
1145 captureResult.frame_number = descriptor->frameNumber;
1146 captureResult.num_output_buffers = descriptor->numBuffers;
1147 for (unsigned int i = 0; i < descriptor->numBuffers; ++i) {
1148 /*
1149 * \todo Currently we only support one capture buffer. Prepare
1150 * all of them to be ready once we'll support more.
1151 */
1152 descriptor->buffers[i].acquire_fence = -1;
1153 descriptor->buffers[i].release_fence = -1;
1154 descriptor->buffers[i].status = status;
1155 }
1156 captureResult.output_buffers =
1157 const_cast<const camera3_stream_buffer_t *>(descriptor->buffers);
1158
Laurent Pinchart39860092019-09-05 03:12:34 +03001159 if (status == CAMERA3_BUFFER_STATUS_OK) {
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001160 notifyShutter(descriptor->frameNumber,
Niklas Söderlund9217f272019-11-22 16:22:56 +01001161 buffer->metadata().timestamp);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001162
1163 captureResult.partial_result = 1;
1164 resultMetadata = getResultMetadata(descriptor->frameNumber,
Niklas Söderlund9217f272019-11-22 16:22:56 +01001165 buffer->metadata().timestamp);
Laurent Pinchart39860092019-09-05 03:12:34 +03001166 captureResult.result = resultMetadata->get();
1167 }
1168
1169 if (status == CAMERA3_BUFFER_STATUS_ERROR || !captureResult.result) {
1170 /* \todo Improve error handling. In case we notify an error
1171 * because the metadata generation fails, a shutter event has
1172 * already been notified for this frame number before the error
1173 * is here signalled. Make sure the error path plays well with
1174 * the camera stack state machine.
1175 */
1176 notifyError(descriptor->frameNumber,
1177 descriptor->buffers[0].stream);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001178 }
1179
1180 callbacks_->process_capture_result(callbacks_, &captureResult);
1181
1182 delete descriptor;
Niklas Söderlund9217f272019-11-22 16:22:56 +01001183 delete buffer;
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001184}
1185
Jacopo Mondia7b92772020-05-26 15:41:41 +02001186std::string CameraDevice::logPrefix() const
1187{
1188 return "'" + camera_->name() + "'";
1189}
1190
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001191void CameraDevice::notifyShutter(uint32_t frameNumber, uint64_t timestamp)
1192{
1193 camera3_notify_msg_t notify = {};
1194
1195 notify.type = CAMERA3_MSG_SHUTTER;
1196 notify.message.shutter.frame_number = frameNumber;
1197 notify.message.shutter.timestamp = timestamp;
1198
1199 callbacks_->notify(callbacks_, &notify);
1200}
1201
1202void CameraDevice::notifyError(uint32_t frameNumber, camera3_stream_t *stream)
1203{
1204 camera3_notify_msg_t notify = {};
1205
1206 notify.type = CAMERA3_MSG_ERROR;
1207 notify.message.error.error_stream = stream;
1208 notify.message.error.frame_number = frameNumber;
1209 notify.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
1210
1211 callbacks_->notify(callbacks_, &notify);
1212}
1213
1214/*
1215 * Produce a set of fixed result metadata.
1216 */
Laurent Pinchart39860092019-09-05 03:12:34 +03001217std::unique_ptr<CameraMetadata> CameraDevice::getResultMetadata(int frame_number,
1218 int64_t timestamp)
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001219{
Jacopo Mondi48504ba2019-09-04 16:18:19 +02001220 /*
1221 * \todo Keep this in sync with the actual number of entries.
Laurent Pinchart39860092019-09-05 03:12:34 +03001222 * Currently: 12 entries, 36 bytes
Jacopo Mondi48504ba2019-09-04 16:18:19 +02001223 */
Laurent Pinchart39860092019-09-05 03:12:34 +03001224 std::unique_ptr<CameraMetadata> resultMetadata =
Laurent Pinchartacf18e42020-01-14 01:35:22 +02001225 std::make_unique<CameraMetadata>(15, 50);
Laurent Pinchart39860092019-09-05 03:12:34 +03001226 if (!resultMetadata->isValid()) {
1227 LOG(HAL, Error) << "Failed to allocate static metadata";
1228 return nullptr;
1229 }
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001230
1231 const uint8_t ae_state = ANDROID_CONTROL_AE_STATE_CONVERGED;
Laurent Pinchart39860092019-09-05 03:12:34 +03001232 resultMetadata->addEntry(ANDROID_CONTROL_AE_STATE, &ae_state, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001233
1234 const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
Laurent Pinchart39860092019-09-05 03:12:34 +03001235 resultMetadata->addEntry(ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001236
1237 uint8_t af_state = ANDROID_CONTROL_AF_STATE_INACTIVE;
Laurent Pinchart39860092019-09-05 03:12:34 +03001238 resultMetadata->addEntry(ANDROID_CONTROL_AF_STATE, &af_state, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001239
1240 const uint8_t awb_state = ANDROID_CONTROL_AWB_STATE_CONVERGED;
Laurent Pinchart39860092019-09-05 03:12:34 +03001241 resultMetadata->addEntry(ANDROID_CONTROL_AWB_STATE, &awb_state, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001242
1243 const uint8_t awb_lock = ANDROID_CONTROL_AWB_LOCK_OFF;
Laurent Pinchart39860092019-09-05 03:12:34 +03001244 resultMetadata->addEntry(ANDROID_CONTROL_AWB_LOCK, &awb_lock, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001245
1246 const uint8_t lens_state = ANDROID_LENS_STATE_STATIONARY;
Laurent Pinchart39860092019-09-05 03:12:34 +03001247 resultMetadata->addEntry(ANDROID_LENS_STATE, &lens_state, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001248
1249 int32_t sensorSizes[] = {
1250 0, 0, 2560, 1920,
1251 };
Laurent Pinchart39860092019-09-05 03:12:34 +03001252 resultMetadata->addEntry(ANDROID_SCALER_CROP_REGION, sensorSizes, 4);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001253
Laurent Pinchart39860092019-09-05 03:12:34 +03001254 resultMetadata->addEntry(ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001255
1256 /* 33.3 msec */
1257 const int64_t rolling_shutter_skew = 33300000;
Laurent Pinchart39860092019-09-05 03:12:34 +03001258 resultMetadata->addEntry(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
1259 &rolling_shutter_skew, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001260
1261 /* 16.6 msec */
1262 const int64_t exposure_time = 16600000;
Laurent Pinchart39860092019-09-05 03:12:34 +03001263 resultMetadata->addEntry(ANDROID_SENSOR_EXPOSURE_TIME,
1264 &exposure_time, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001265
1266 const uint8_t lens_shading_map_mode =
1267 ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
Laurent Pinchart39860092019-09-05 03:12:34 +03001268 resultMetadata->addEntry(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
1269 &lens_shading_map_mode, 1);
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001270
1271 const uint8_t scene_flicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
Laurent Pinchart39860092019-09-05 03:12:34 +03001272 resultMetadata->addEntry(ANDROID_STATISTICS_SCENE_FLICKER,
1273 &scene_flicker, 1);
1274
1275 /*
1276 * Return the result metadata pack even is not valid: get() will return
1277 * nullptr.
1278 */
1279 if (!resultMetadata->isValid()) {
1280 LOG(HAL, Error) << "Failed to construct result metadata";
1281 }
Jacopo Mondi667d8ea2019-05-10 17:40:02 +02001282
1283 return resultMetadata;
1284}