diff options
Diffstat (limited to 'src/android/mm')
-rw-r--r-- | src/android/mm/cros_camera_buffer.cpp | 134 | ||||
-rw-r--r-- | src/android/mm/generic_camera_buffer.cpp | 91 | ||||
-rw-r--r-- | src/android/mm/meson.build | 9 |
3 files changed, 234 insertions, 0 deletions
diff --git a/src/android/mm/cros_camera_buffer.cpp b/src/android/mm/cros_camera_buffer.cpp new file mode 100644 index 00000000..bb55b95e --- /dev/null +++ b/src/android/mm/cros_camera_buffer.cpp @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * cros_camera_buffer.cpp - Chromium OS buffer backend using CameraBufferManager + */ + +#include "../camera_buffer.h" + +#include <libcamera/base/log.h> + +#include "cros-camera/camera_buffer_manager.h" + +using namespace libcamera; + +LOG_DECLARE_CATEGORY(HAL) + +class CameraBuffer::Private : public Extensible::Private +{ + LIBCAMERA_DECLARE_PUBLIC(CameraBuffer) + +public: + Private(CameraBuffer *cameraBuffer, + buffer_handle_t camera3Buffer, int flags); + ~Private(); + + bool isValid() const { return valid_; } + + unsigned int numPlanes() const; + + Span<uint8_t> plane(unsigned int plane); + + size_t jpegBufferSize(size_t maxJpegBufferSize) const; + +private: + cros::CameraBufferManager *bufferManager_; + buffer_handle_t handle_; + unsigned int numPlanes_; + bool valid_; + bool registered_; + union { + void *addr; + android_ycbcr ycbcr; + } mem; +}; + +CameraBuffer::Private::Private(CameraBuffer *cameraBuffer, + buffer_handle_t camera3Buffer, + [[maybe_unused]] int flags) + : Extensible::Private(cameraBuffer), handle_(camera3Buffer), + numPlanes_(0), valid_(false), registered_(false) +{ + bufferManager_ = cros::CameraBufferManager::GetInstance(); + + int ret = bufferManager_->Register(camera3Buffer); + if (ret) { + LOG(HAL, Error) << "Failed registering a buffer: " << ret; + return; + } + + registered_ = true; + numPlanes_ = bufferManager_->GetNumPlanes(camera3Buffer); + switch (numPlanes_) { + case 1: { + ret = bufferManager_->Lock(handle_, 0, 0, 0, 0, 0, &mem.addr); + if (ret) { + LOG(HAL, Error) << "Single plane buffer mapping failed"; + return; + } + break; + } + case 2: + case 3: { + ret = bufferManager_->LockYCbCr(handle_, 0, 0, 0, 0, 0, + &mem.ycbcr); + if (ret) { + LOG(HAL, Error) << "YCbCr buffer mapping failed"; + return; + } + break; + } + default: + LOG(HAL, Error) << "Invalid number of planes: " << numPlanes_; + return; + } + + valid_ = true; +} + +CameraBuffer::Private::~Private() +{ + if (valid_) + bufferManager_->Unlock(handle_); + if (registered_) + bufferManager_->Deregister(handle_); +} + +unsigned int CameraBuffer::Private::numPlanes() const +{ + return bufferManager_->GetNumPlanes(handle_); +} + +Span<uint8_t> CameraBuffer::Private::plane(unsigned int plane) +{ + void *addr; + + switch (numPlanes()) { + case 1: + addr = mem.addr; + break; + default: + switch (plane) { + case 0: + addr = mem.ycbcr.y; + break; + case 1: + addr = mem.ycbcr.cb; + break; + case 2: + addr = mem.ycbcr.cr; + break; + } + } + + return { static_cast<uint8_t *>(addr), + bufferManager_->GetPlaneSize(handle_, plane) }; +} + +size_t CameraBuffer::Private::jpegBufferSize([[maybe_unused]] size_t maxJpegBufferSize) const +{ + return bufferManager_->GetPlaneSize(handle_, 0); +} + +PUBLIC_CAMERA_BUFFER_IMPLEMENTATION diff --git a/src/android/mm/generic_camera_buffer.cpp b/src/android/mm/generic_camera_buffer.cpp new file mode 100644 index 00000000..166be36e --- /dev/null +++ b/src/android/mm/generic_camera_buffer.cpp @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * generic_camera_buffer.cpp - Generic Android frame buffer backend + */ + +#include "../camera_buffer.h" + +#include <unistd.h> + +#include <libcamera/base/log.h> + +#include "libcamera/internal/framebuffer.h" + +using namespace libcamera; + +LOG_DECLARE_CATEGORY(HAL) + +class CameraBuffer::Private : public Extensible::Private, + public libcamera::MappedBuffer +{ + LIBCAMERA_DECLARE_PUBLIC(CameraBuffer) + +public: + Private(CameraBuffer *cameraBuffer, + buffer_handle_t camera3Buffer, int flags); + ~Private(); + + unsigned int numPlanes() const; + + Span<uint8_t> plane(unsigned int plane); + + size_t jpegBufferSize(size_t maxJpegBufferSize) const; +}; + +CameraBuffer::Private::Private(CameraBuffer *cameraBuffer, + buffer_handle_t camera3Buffer, int flags) + : Extensible::Private(cameraBuffer) +{ + maps_.reserve(camera3Buffer->numFds); + error_ = 0; + + for (int i = 0; i < camera3Buffer->numFds; i++) { + if (camera3Buffer->data[i] == -1) + continue; + + off_t length = lseek(camera3Buffer->data[i], 0, SEEK_END); + if (length < 0) { + error_ = -errno; + LOG(HAL, Error) << "Failed to query plane length"; + break; + } + + void *address = mmap(nullptr, length, flags, MAP_SHARED, + camera3Buffer->data[i], 0); + if (address == MAP_FAILED) { + error_ = -errno; + LOG(HAL, Error) << "Failed to mmap plane"; + break; + } + + maps_.emplace_back(static_cast<uint8_t *>(address), + static_cast<size_t>(length)); + } +} + +CameraBuffer::Private::~Private() +{ +} + +unsigned int CameraBuffer::Private::numPlanes() const +{ + return maps_.size(); +} + +Span<uint8_t> CameraBuffer::Private::plane(unsigned int plane) +{ + if (plane >= maps_.size()) + return {}; + + return maps_[plane]; +} + +size_t CameraBuffer::Private::jpegBufferSize(size_t maxJpegBufferSize) const +{ + return std::min<unsigned int>(maps_[0].size(), + maxJpegBufferSize); +} + +PUBLIC_CAMERA_BUFFER_IMPLEMENTATION diff --git a/src/android/mm/meson.build b/src/android/mm/meson.build new file mode 100644 index 00000000..eeb5cc2e --- /dev/null +++ b/src/android/mm/meson.build @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: CC0-1.0 + +platform = get_option('android_platform') +if platform == 'generic' + android_hal_sources += files(['generic_camera_buffer.cpp']) +elif platform == 'cros' + android_hal_sources += files(['cros_camera_buffer.cpp']) + android_deps += [dependency('libcros_camera')] +endif |