libcamera: android: Add face detection control support

Allow Android HAL adapter to pass the face detection metadata control to
the pipeline and also send face detection metadata to the camera client
if the pipeline generates it.

Signed-off-by: Yudhistira Erlandinata <yerlandinata@chromium.org>
Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>
Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Harvey Yang <chenghaoyang@chromium.org>
This commit is contained in:
Harvey Yang
2024-09-25 08:12:26 +00:00
committed by Jacopo Mondi
parent dada914339
commit 3088e14e81
2 changed files with 104 additions and 6 deletions

View File

@@ -11,6 +11,7 @@
#include <array>
#include <cmath>
#include <map>
#include <stdint.h>
#include <type_traits>
#include <hardware/camera3.h>
@@ -1176,11 +1177,46 @@ int CameraCapabilities::initializeStaticMetadata()
maxFrameDuration_);
/* Statistics static metadata. */
uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
faceDetectMode);
int32_t maxFaceCount = 0;
auto iter = camera_->controls().find(controls::draft::FaceDetectMode.id());
if (iter != camera_->controls().end()) {
const ControlInfo &faceDetectCtrlInfo = iter->second;
std::vector<uint8_t> faceDetectModes;
bool hasFaceDetection = false;
for (const auto &value : faceDetectCtrlInfo.values()) {
int32_t mode = value.get<int32_t>();
uint8_t androidMode = 0;
switch (mode) {
case controls::draft::FaceDetectModeOff:
androidMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
break;
case controls::draft::FaceDetectModeSimple:
androidMode = ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE;
hasFaceDetection = true;
break;
default:
LOG(HAL, Fatal) << "Received invalid face detect mode: " << mode;
}
faceDetectModes.push_back(androidMode);
}
if (hasFaceDetection) {
/*
* \todo Create new libcamera controls to query max
* possible faces detected.
*/
maxFaceCount = 10;
staticMetadata_->addEntry(
ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
faceDetectModes.data(), faceDetectModes.size());
}
} else {
uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
faceDetectMode);
}
staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
maxFaceCount);

View File

@@ -22,6 +22,7 @@
#include <libcamera/controls.h>
#include <libcamera/fence.h>
#include <libcamera/formats.h>
#include <libcamera/geometry.h>
#include <libcamera/property_ids.h>
#include "system/graphics.h"
@@ -813,6 +814,11 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
controls.set(controls::ScalerCrop, cropRegion);
}
if (settings.getEntry(ANDROID_STATISTICS_FACE_DETECT_MODE, &entry)) {
const uint8_t *data = entry.data.u8;
controls.set(controls::draft::FaceDetectMode, data[0]);
}
if (settings.getEntry(ANDROID_SENSOR_TEST_PATTERN_MODE, &entry)) {
const int32_t data = *entry.data.i32;
int32_t testPatternMode = controls::draft::TestPatternModeOff;
@@ -1540,8 +1546,9 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
value32 = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
resultMetadata->addEntry(ANDROID_SENSOR_TEST_PATTERN_MODE, value32);
value = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
resultMetadata->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE, value);
if (settings.getEntry(ANDROID_STATISTICS_FACE_DETECT_MODE, &entry))
resultMetadata->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,
entry.data.u8, 1);
value = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
resultMetadata->addEntry(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
@@ -1580,6 +1587,61 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
resultMetadata->addEntry(ANDROID_SENSOR_FRAME_DURATION,
*frameDuration * 1000);
const auto &faceDetectRectangles =
metadata.get(controls::draft::FaceDetectFaceRectangles);
if (faceDetectRectangles) {
std::vector<int32_t> flatRectangles;
for (const Rectangle &rect : *faceDetectRectangles) {
flatRectangles.push_back(rect.x);
flatRectangles.push_back(rect.y);
flatRectangles.push_back(rect.x + rect.width);
flatRectangles.push_back(rect.y + rect.height);
}
resultMetadata->addEntry(
ANDROID_STATISTICS_FACE_RECTANGLES, flatRectangles);
}
const auto &faceDetectFaceScores =
metadata.get(controls::draft::FaceDetectFaceScores);
if (faceDetectRectangles && faceDetectFaceScores) {
if (faceDetectFaceScores->size() != faceDetectRectangles->size()) {
LOG(HAL, Error) << "Pipeline returned wrong number of face scores; "
<< "Expected: " << faceDetectRectangles->size()
<< ", got: " << faceDetectFaceScores->size();
}
resultMetadata->addEntry(ANDROID_STATISTICS_FACE_SCORES,
*faceDetectFaceScores);
}
const auto &faceDetectFaceLandmarks =
metadata.get(controls::draft::FaceDetectFaceLandmarks);
if (faceDetectRectangles && faceDetectFaceLandmarks) {
size_t expectedLandmarks = faceDetectRectangles->size() * 3;
if (faceDetectFaceLandmarks->size() != expectedLandmarks) {
LOG(HAL, Error) << "Pipeline returned wrong number of face landmarks; "
<< "Expected: " << expectedLandmarks
<< ", got: " << faceDetectFaceLandmarks->size();
}
std::vector<int32_t> androidLandmarks;
for (const Point &landmark : *faceDetectFaceLandmarks) {
androidLandmarks.push_back(landmark.x);
androidLandmarks.push_back(landmark.y);
}
resultMetadata->addEntry(
ANDROID_STATISTICS_FACE_LANDMARKS, androidLandmarks);
}
const auto &faceDetectFaceIds = metadata.get(controls::draft::FaceDetectFaceIds);
if (faceDetectRectangles && faceDetectFaceIds) {
if (faceDetectFaceIds->size() != faceDetectRectangles->size()) {
LOG(HAL, Error) << "Pipeline returned wrong number of face ids; "
<< "Expected: " << faceDetectRectangles->size()
<< ", got: " << faceDetectFaceIds->size();
}
resultMetadata->addEntry(ANDROID_STATISTICS_FACE_IDS, *faceDetectFaceIds);
}
const auto &scalerCrop = metadata.get(controls::ScalerCrop);
if (scalerCrop) {
const Rectangle &crop = *scalerCrop;