From patchwork Tue May 26 14:22:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 3863 X-Patchwork-Delegate: jacopo@jmondi.org Return-Path: Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E097B61075 for ; Tue, 26 May 2020 16:19:26 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from localhost.localdomain (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay2-d.mail.gandi.net (Postfix) with ESMTPSA id 676BB40002; Tue, 26 May 2020 14:19:26 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 26 May 2020 16:22:33 +0200 Message-Id: <20200526142237.407557-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200526142237.407557-1-jacopo@jmondi.org> References: <20200526142237.407557-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 4/8] android: camera_device: Build stream configuration X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 May 2020 14:19:27 -0000 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 --- 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 + #include #include @@ -15,9 +17,37 @@ #include "libcamera/internal/utils.h" #include "camera_metadata.h" +#include "system/graphics.h" using namespace libcamera; +namespace { + +std::set camera3Resolutions = { + { 320, 240 }, + { 640, 480 }, + { 1280, 720 }, + { 1920, 1080 } +}; + +std::map> 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 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 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 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 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 +#include #include #include #include #include +#include #include #include @@ -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 getResultMetadata(int frame_number, @@ -75,6 +85,9 @@ private: std::map requestTemplates_; const camera3_callback_ops_t *callbacks_; + std::forward_list streamConfigurations_; + std::map formatsMap_; + int facing_; int orientation_; };