[libcamera-devel] [PATCH 4/8] android: camera_device: Build stream configuration
Jacopo Mondi
jacopo at jmondi.org
Tue May 26 16:22:33 CEST 2020
Build the stream configuration map by applying the Android Camera3
requested resolutions and formats to the libcamera Camera device.
For each required format test a list of required and optional
resolutions, construct a map to translate from Android format to the
libcamera formats and store the available stream configuration to
be provided to the Android framework through static metadata.
Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
src/android/camera_device.cpp | 184 ++++++++++++++++++++++++++++++++++
src/android/camera_device.h | 13 +++
2 files changed, 197 insertions(+)
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index 69b25ed2f11f..534bfb1df1ef 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -8,6 +8,8 @@
#include "camera_device.h"
#include "camera_ops.h"
+#include <set>
+
#include <libcamera/controls.h>
#include <libcamera/property_ids.h>
@@ -15,9 +17,37 @@
#include "libcamera/internal/utils.h"
#include "camera_metadata.h"
+#include "system/graphics.h"
using namespace libcamera;
+namespace {
+
+std::set<Size> camera3Resolutions = {
+ { 320, 240 },
+ { 640, 480 },
+ { 1280, 720 },
+ { 1920, 1080 }
+};
+
+std::map<int, std::forward_list<uint32_t>> camera3FormatsMap = {
+ { HAL_PIXEL_FORMAT_BLOB, { DRM_FORMAT_MJPEG } },
+ { HAL_PIXEL_FORMAT_YCbCr_420_888, { DRM_FORMAT_NV12, DRM_FORMAT_NV21 } },
+ /*
+ * \todo Translate IMPLEMENTATION_DEFINED inspecting the
+ * gralloc usage flag. For now, copy the YCbCr_420 configuration.
+ */
+ { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, { DRM_FORMAT_NV12, DRM_FORMAT_NV21 } },
+};
+
+std::map<int32_t, int32_t> camera3ScalerFormatMap = {
+ { HAL_PIXEL_FORMAT_BLOB, ANDROID_SCALER_AVAILABLE_FORMATS_BLOB },
+ { HAL_PIXEL_FORMAT_YCbCr_420_888, ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 },
+ { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED },
+};
+
+} /* namespace */
+
LOG_DECLARE_CATEGORY(HAL);
/*
@@ -100,6 +130,160 @@ int CameraDevice::initialize()
if (properties.contains(properties::Rotation))
orientation_ = properties.get(properties::Rotation);
+ int ret = camera_->acquire();
+ if (ret) {
+ LOG(HAL, Error) << "Failed to temporary acquire the camera";
+ return ret;
+ }
+
+ ret = initializeFormats();
+ camera_->release();
+ return ret;
+}
+
+int CameraDevice::initializeFormats()
+{
+ /*
+ * 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 (alignement
+ * 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::set<Size> cameraResolutions;
+ for (const Size &res : camera3Resolutions) {
+ if (res > maxRes)
+ continue;
+
+ cameraResolutions.insert(res);
+ }
+
+ /* Camera3 specification suggest to add 1/2 and 1/4 max resolution. */
+ for (unsigned int divider = 2;; divider <<= 1) {
+ Size derivedSize{};
+ derivedSize.width = maxRes.width / divider;
+ derivedSize.height = maxRes.height / divider;
+
+ if (derivedSize.width < 320 ||
+ derivedSize.height < 240)
+ break;
+
+ /* std::set::insert() guarantees the entry is unique. */
+ cameraResolutions.insert(derivedSize);
+ }
+ cameraResolutions.insert(maxRes);
+
+ /*
+ * Build the list of supported camera format.
+ *
+ * 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 in the camera static
+ * metadata.
+ */
+ for (const auto &format : camera3FormatsMap) {
+ int androidFormatCode = format.first;
+ const std::forward_list<uint32_t> testFormats = format.second;
+
+ /*
+ * Test the libcamera formats that can produce images
+ * compatible with the Android's defined format
+ */
+ uint32_t mappedFormatCode = 0;
+ for (int32_t formatCode : testFormats) {
+ /*
+ * \todo Fixed mapping for JPEG
+ */
+ if (androidFormatCode == HAL_PIXEL_FORMAT_BLOB) {
+ mappedFormatCode = DRM_FORMAT_MJPEG;
+ break;
+ }
+
+ /*
+ * The stream configuration size can be adjusted,
+ * not the pixel format.
+ */
+ PixelFormat pixelFormat = PixelFormat(formatCode);
+ cfg.pixelFormat = pixelFormat;
+
+ CameraConfiguration::Status status = cameraConfig->validate();
+ if (status != CameraConfiguration::Invalid &&
+ cfg.pixelFormat == pixelFormat) {
+ mappedFormatCode = pixelFormat.fourcc();
+ break;
+ }
+ }
+ if (!mappedFormatCode) {
+ LOG(HAL, Error) << "Failed to get map Android format "
+ << utils::hex(androidFormatCode);
+ return -EINVAL;
+ }
+
+ /*
+ * Record the mapping and then proceed to generate the
+ * stream configuration map, by testing the image resolutions.
+ */
+ formatsMap_[androidFormatCode] = mappedFormatCode;
+
+ for (const Size &res : cameraResolutions) {
+ PixelFormat pixelFormat = PixelFormat(mappedFormatCode);
+ cfg.pixelFormat = pixelFormat;
+ cfg.size = res;
+
+ CameraConfiguration::Status status = cameraConfig->validate();
+ /* \todo Assume we the camera can produce JPEG */
+ if (androidFormatCode != HAL_PIXEL_FORMAT_BLOB &&
+ status != CameraConfiguration::Valid)
+ continue;
+
+ auto it = camera3ScalerFormatMap.find(androidFormatCode);
+ if (it == camera3ScalerFormatMap.end()) {
+ LOG(HAL, Error) << "Format " << utils::hex(androidFormatCode)
+ << " has no scaler format associated";
+ return -EINVAL;
+ }
+ int32_t androidScalerCode = it->second;
+
+ /*
+ * \todo Add support for input streams. At the moment
+ * register all stream configurations as output-only.
+ */
+ streamConfigurations_.push_front(
+ { res, androidScalerCode, false });
+ }
+ }
+
+ LOG(HAL, Debug) << "Collected stream configuration map: ";
+ for (const auto &entry : streamConfigurations_) {
+ LOG(HAL, Debug) << "{ " << entry.resolution.toString() << " - "
+ << utils::hex(entry.androidScalerCode) << ": "
+ << (entry.input ? "input" : "output") << " }";
+ }
+
return 0;
}
diff --git a/src/android/camera_device.h b/src/android/camera_device.h
index ace9c1b7c929..95bd39f590ab 100644
--- a/src/android/camera_device.h
+++ b/src/android/camera_device.h
@@ -7,12 +7,15 @@
#ifndef __ANDROID_CAMERA_DEVICE_H__
#define __ANDROID_CAMERA_DEVICE_H__
+#include <forward_list>
+#include <map>
#include <memory>
#include <hardware/camera3.h>
#include <libcamera/buffer.h>
#include <libcamera/camera.h>
+#include <libcamera/geometry.h>
#include <libcamera/request.h>
#include <libcamera/stream.h>
@@ -59,6 +62,13 @@ private:
camera3_stream_buffer_t *buffers;
};
+ struct Camera3StreamConfiguration {
+ libcamera::Size resolution;
+ int androidScalerCode;
+ bool input;
+ };
+
+ int initializeFormats();
void notifyShutter(uint32_t frameNumber, uint64_t timestamp);
void notifyError(uint32_t frameNumber, camera3_stream_t *stream);
std::unique_ptr<CameraMetadata> getResultMetadata(int frame_number,
@@ -75,6 +85,9 @@ private:
std::map<unsigned int, CameraMetadata *> requestTemplates_;
const camera3_callback_ops_t *callbacks_;
+ std::forward_list<Camera3StreamConfiguration> streamConfigurations_;
+ std::map<int, uint32_t> formatsMap_;
+
int facing_;
int orientation_;
};
--
2.26.2
More information about the libcamera-devel
mailing list