Message ID | 20220406094130.189862-2-chenghaoyang@chromium.org |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi Harvey, Thank you for the patch, and sorry for the late reply. Catching up with e-mail after travel is painful. Next time I'll try to get the whole world to travel at the same time, maybe I'll get less e-mails :-) On Wed, Apr 06, 2022 at 05:41:30PM +0800, Harvey Yang via libcamera-devel wrote: > This CL uses CrOS JpegCompressor with potential HW accelerator to do > JPEG encoding. > > As CrOS JpegCompressor might need file descriptors to get the source > data and pass the jpeg result, this CL extends FrameBuffer in the > android source code as Android_FrameBuffer, which stores the > buffer_handle_t when constructing the frame buffer, and adds a > getter function to access it. > > This CL also redefines src/android/jpeg/encoder interfaces and adds > Encoder::generateThumbnail, which might also be accelerated by CrOS > HW. It simplifies PostProcessorJpeg's logic when generating the > thumbnail. The original implementation is then moved into the > EncoderLibJpeg::generateThumbnail. This is missing a Signed-off-by line, see Documentation/contributing.rst. > --- > include/libcamera/framebuffer.h | 3 +- > src/android/android_framebuffer.cpp | 32 ++++++++ > src/android/android_framebuffer.h | 28 +++++++ > src/android/camera_device.cpp | 3 +- > src/android/cros/camera3_hal.cpp | 3 + > src/android/frame_buffer_allocator.h | 37 +++++---- > src/android/jpeg/cros_post_processor_jpeg.cpp | 14 ++++ > src/android/jpeg/encoder.h | 9 +- > src/android/jpeg/encoder_jea.cpp | 82 +++++++++++++++++++ > src/android/jpeg/encoder_jea.h | 35 ++++++++ > src/android/jpeg/encoder_libjpeg.cpp | 70 ++++++++++++++++ > src/android/jpeg/encoder_libjpeg.h | 21 ++++- > .../jpeg/generic_post_processor_jpeg.cpp | 14 ++++ > src/android/jpeg/meson.build | 16 ++++ > src/android/jpeg/post_processor_jpeg.cpp | 60 ++------------ > src/android/jpeg/post_processor_jpeg.h | 11 +-- > src/android/meson.build | 6 +- > .../mm/cros_frame_buffer_allocator.cpp | 13 +-- > .../mm/generic_frame_buffer_allocator.cpp | 11 +-- There are lots of changes here, making this hard to review. Could you please split this patch in pieces, with one logical change by patch, and bundle them as a series ? Candidates are - Drop the final keyword from FrameBuffer and make the destructor virtual - Add AndroidFrameBuffer and use it in the HAL (you could even split that in two if desired, but bundling a new class with its user(s) can make review easier, if the result isn't too big) - Rework the JPEG encoder API and implementation to prepare for the needs of JEA - Add the JEA implementation > 19 files changed, 367 insertions(+), 101 deletions(-) > create mode 100644 src/android/android_framebuffer.cpp > create mode 100644 src/android/android_framebuffer.h > create mode 100644 src/android/jpeg/cros_post_processor_jpeg.cpp > create mode 100644 src/android/jpeg/encoder_jea.cpp > create mode 100644 src/android/jpeg/encoder_jea.h > create mode 100644 src/android/jpeg/generic_post_processor_jpeg.cpp > create mode 100644 src/android/jpeg/meson.build > > diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h > index de172d97..c902cc18 100644 > --- a/include/libcamera/framebuffer.h > +++ b/include/libcamera/framebuffer.h > @@ -46,7 +46,7 @@ private: > std::vector<Plane> planes_; > }; > > -class FrameBuffer final : public Extensible > +class FrameBuffer : public Extensible > { > LIBCAMERA_DECLARE_PRIVATE() > > @@ -61,6 +61,7 @@ public: > FrameBuffer(const std::vector<Plane> &planes, unsigned int cookie = 0); > FrameBuffer(std::unique_ptr<Private> d, > const std::vector<Plane> &planes, unsigned int cookie = 0); > + virtual ~FrameBuffer() {} > > const std::vector<Plane> &planes() const { return planes_; } > Request *request() const; > diff --git a/src/android/android_framebuffer.cpp b/src/android/android_framebuffer.cpp > new file mode 100644 > index 00000000..1ff7018e > --- /dev/null > +++ b/src/android/android_framebuffer.cpp > @@ -0,0 +1,32 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * > + * android_framebuffer.cpp - Android Frame buffer handling > + */ > + > +#include "android_framebuffer.h" > + > +#include <hardware/camera3.h> > + > +AndroidFrameBuffer::AndroidFrameBuffer( > + buffer_handle_t handle, > + std::unique_ptr<Private> d, > + const std::vector<Plane> &planes, > + unsigned int cookie) > + : FrameBuffer(std::move(d), planes, cookie), handle_(handle) > +{ > +} > + > +AndroidFrameBuffer::AndroidFrameBuffer( > + buffer_handle_t handle, > + const std::vector<Plane> &planes, > + unsigned int cookie) > + : FrameBuffer(planes, cookie), handle_(handle) > +{ > +} > + > +buffer_handle_t AndroidFrameBuffer::getHandle() const > +{ > + return handle_; > +} > diff --git a/src/android/android_framebuffer.h b/src/android/android_framebuffer.h > new file mode 100644 > index 00000000..49df9756 > --- /dev/null > +++ b/src/android/android_framebuffer.h > @@ -0,0 +1,28 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * > + * android_framebuffer.h - Android Frame buffer handling > + */ > + > +#pragma once > + > +#include "libcamera/internal/framebuffer.h" > + > +#include <hardware/camera3.h> > + > +class AndroidFrameBuffer final : public libcamera::FrameBuffer > +{ > +public: > + AndroidFrameBuffer( > + buffer_handle_t handle, std::unique_ptr<Private> d, > + const std::vector<Plane> &planes, > + unsigned int cookie = 0); > + AndroidFrameBuffer(buffer_handle_t handle, > + const std::vector<Plane> &planes, > + unsigned int cookie = 0); > + buffer_handle_t getHandle() const; > + > +private: > + buffer_handle_t handle_ = nullptr; > +}; > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp > index 00d48471..643b4dee 100644 > --- a/src/android/camera_device.cpp > +++ b/src/android/camera_device.cpp > @@ -25,6 +25,7 @@ > > #include "system/graphics.h" > > +#include "android_framebuffer.h" > #include "camera_buffer.h" > #include "camera_hal_config.h" > #include "camera_ops.h" > @@ -754,7 +755,7 @@ CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer, > planes[i].length = buf.size(i); > } > > - return std::make_unique<FrameBuffer>(planes); > + return std::make_unique<AndroidFrameBuffer>(camera3buffer, planes); > } > > int CameraDevice::processControls(Camera3RequestDescriptor *descriptor) > diff --git a/src/android/cros/camera3_hal.cpp b/src/android/cros/camera3_hal.cpp > index fb863b5f..ea5577f0 100644 > --- a/src/android/cros/camera3_hal.cpp > +++ b/src/android/cros/camera3_hal.cpp > @@ -9,8 +9,11 @@ > > #include "../camera_hal_manager.h" > > +cros::CameraMojoChannelManagerToken *g_cros_camera_token = nullptr; > + > static void set_up([[maybe_unused]] cros::CameraMojoChannelManagerToken *token) > { > + g_cros_camera_token = token; > } > > static void tear_down() > diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h > index 5d2eeda1..e26422a3 100644 > --- a/src/android/frame_buffer_allocator.h > +++ b/src/android/frame_buffer_allocator.h > @@ -13,9 +13,10 @@ > #include <libcamera/base/class.h> > > #include <libcamera/camera.h> > -#include <libcamera/framebuffer.h> > #include <libcamera/geometry.h> > > +#include "android_framebuffer.h" > + > class CameraDevice; > > class PlatformFrameBufferAllocator : libcamera::Extensible > @@ -31,25 +32,25 @@ public: > * Note: The returned FrameBuffer needs to be destroyed before > * PlatformFrameBufferAllocator is destroyed. > */ > - std::unique_ptr<libcamera::FrameBuffer> allocate( > + std::unique_ptr<AndroidFrameBuffer> allocate( > int halPixelFormat, const libcamera::Size &size, uint32_t usage); > }; > > -#define PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION \ > -PlatformFrameBufferAllocator::PlatformFrameBufferAllocator( \ > - CameraDevice *const cameraDevice) \ > - : Extensible(std::make_unique<Private>(cameraDevice)) \ > -{ \ > -} \ > -PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator() \ > -{ \ > -} \ > -std::unique_ptr<libcamera::FrameBuffer> \ > -PlatformFrameBufferAllocator::allocate(int halPixelFormat, \ > - const libcamera::Size &size, \ > - uint32_t usage) \ > -{ \ > - return _d()->allocate(halPixelFormat, size, usage); \ > -} > +#define PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION \ > + PlatformFrameBufferAllocator::PlatformFrameBufferAllocator( \ > + CameraDevice *const cameraDevice) \ > + : Extensible(std::make_unique<Private>(cameraDevice)) \ > + { \ > + } \ > + PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator() \ > + { \ > + } \ > + std::unique_ptr<AndroidFrameBuffer> \ > + PlatformFrameBufferAllocator::allocate(int halPixelFormat, \ > + const libcamera::Size &size, \ > + uint32_t usage) \ > + { \ > + return _d()->allocate(halPixelFormat, size, usage); \ > + } > > #endif /* __ANDROID_FRAME_BUFFER_ALLOCATOR_H__ */ > diff --git a/src/android/jpeg/cros_post_processor_jpeg.cpp b/src/android/jpeg/cros_post_processor_jpeg.cpp > new file mode 100644 > index 00000000..7020f0d0 > --- /dev/null > +++ b/src/android/jpeg/cros_post_processor_jpeg.cpp > @@ -0,0 +1,14 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * > + * cros_post_processor_jpeg.cpp - CrOS JPEG Post Processor > + */ > + > +#include "encoder_jea.h" > +#include "post_processor_jpeg.h" > + > +void PostProcessorJpeg::SetEncoder() > +{ > + encoder_ = std::make_unique<EncoderJea>(); > +} > diff --git a/src/android/jpeg/encoder.h b/src/android/jpeg/encoder.h > index b974d367..6d527d91 100644 > --- a/src/android/jpeg/encoder.h > +++ b/src/android/jpeg/encoder.h > @@ -12,14 +12,19 @@ > #include <libcamera/framebuffer.h> > #include <libcamera/stream.h> > > +#include "../camera_request.h" > + > class Encoder > { > public: > virtual ~Encoder() = default; > > virtual int configure(const libcamera::StreamConfiguration &cfg) = 0; > - virtual int encode(const libcamera::FrameBuffer &source, > - libcamera::Span<uint8_t> destination, > + virtual int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, > libcamera::Span<const uint8_t> exifData, > unsigned int quality) = 0; > + virtual int generateThumbnail(const libcamera::FrameBuffer &source, > + const libcamera::Size &targetSize, > + unsigned int quality, > + std::vector<unsigned char> *thumbnail) = 0; > }; > diff --git a/src/android/jpeg/encoder_jea.cpp b/src/android/jpeg/encoder_jea.cpp > new file mode 100644 > index 00000000..838e8647 > --- /dev/null > +++ b/src/android/jpeg/encoder_jea.cpp > @@ -0,0 +1,82 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * > + * encoder_jea.cpp - JPEG encoding using CrOS JEA > + */ > + > +#include "encoder_jea.h" > + > +#include <libcamera/base/log.h> > + > +#include "libcamera/internal/mapped_framebuffer.h" > + > +#include <cros-camera/camera_mojo_channel_manager_token.h> > + > +#include "../android_framebuffer.h" > + > +extern cros::CameraMojoChannelManagerToken *g_cros_camera_token; > + > +EncoderJea::EncoderJea() = default; > + > +EncoderJea::~EncoderJea() = default; > + > +int EncoderJea::configure(const libcamera::StreamConfiguration &cfg) > +{ > + size_ = cfg.size; > + > + if (jpeg_compressor_.get()) > + return 0; > + > + if (g_cros_camera_token == nullptr) > + return -ENOTSUP; > + > + jpeg_compressor_ = cros::JpegCompressor::GetInstance(g_cros_camera_token); > + > + return 0; > +} > + > +int EncoderJea::encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, > + libcamera::Span<const uint8_t> exifData, > + unsigned int quality) > +{ > + if (!jpeg_compressor_.get()) > + return -1; > + > + uint32_t out_data_size = 0; > + > + if (!jpeg_compressor_->CompressImageFromHandle( > + dynamic_cast<const AndroidFrameBuffer *>( > + streamBuffer->srcBuffer) > + ->getHandle(), > + *streamBuffer->camera3Buffer, size_.width, size_.height, quality, > + exifData.data(), exifData.size(), &out_data_size)) { > + return -1; > + } > + > + return out_data_size; > +} > + > +int EncoderJea::generateThumbnail(const libcamera::FrameBuffer &source, > + const libcamera::Size &targetSize, > + unsigned int quality, > + std::vector<unsigned char> *thumbnail) > +{ > + if (!jpeg_compressor_.get()) > + return -1; > + > + libcamera::MappedFrameBuffer frame(&source, libcamera::MappedFrameBuffer::MapFlag::Read); > + > + if (frame.planes().empty()) > + return 0; > + > + uint32_t out_data_size = 0; > + > + if (!jpeg_compressor_->GenerateThumbnail(frame.planes()[0].data(), > + size_.width, size_.height, targetSize.width, targetSize.height, > + quality, thumbnail->size(), thumbnail->data(), &out_data_size)) { > + return -1; > + } > + > + return out_data_size; > +} > diff --git a/src/android/jpeg/encoder_jea.h b/src/android/jpeg/encoder_jea.h > new file mode 100644 > index 00000000..d5c9f1f7 > --- /dev/null > +++ b/src/android/jpeg/encoder_jea.h > @@ -0,0 +1,35 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * > + * encoder_jea.h - JPEG encoding using CrOS JEA > + */ > + > +#pragma once > + > +#include <libcamera/geometry.h> > + > +#include <cros-camera/jpeg_compressor.h> > + > +#include "encoder.h" > + > +class EncoderJea : public Encoder > +{ > +public: > + EncoderJea(); > + ~EncoderJea(); > + > + int configure(const libcamera::StreamConfiguration &cfg) override; > + int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, > + libcamera::Span<const uint8_t> exifData, > + unsigned int quality) override; > + int generateThumbnail(const libcamera::FrameBuffer &source, > + const libcamera::Size &targetSize, > + unsigned int quality, > + std::vector<unsigned char> *thumbnail) override; > + > +private: > + libcamera::Size size_; > + > + std::unique_ptr<cros::JpegCompressor> jpeg_compressor_; > +}; > diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp > index 21a3b33d..b5591e33 100644 > --- a/src/android/jpeg/encoder_libjpeg.cpp > +++ b/src/android/jpeg/encoder_libjpeg.cpp > @@ -24,6 +24,8 @@ > #include "libcamera/internal/formats.h" > #include "libcamera/internal/mapped_framebuffer.h" > > +#include "../camera_buffer.h" > + > using namespace libcamera; > > LOG_DECLARE_CATEGORY(JPEG) > @@ -82,8 +84,17 @@ EncoderLibJpeg::~EncoderLibJpeg() > } > > int EncoderLibJpeg::configure(const StreamConfiguration &cfg) > +{ > + thumbnailer_.configure(cfg.size, cfg.pixelFormat); > + cfg_ = cfg; > + > + return internalConfigure(cfg); > +} > + > +int EncoderLibJpeg::internalConfigure(const StreamConfiguration &cfg) > { > const struct JPEGPixelFormatInfo info = findPixelInfo(cfg.pixelFormat); > + > if (info.colorSpace == JCS_UNKNOWN) > return -ENOTSUP; > > @@ -178,6 +189,65 @@ void EncoderLibJpeg::compressNV(const std::vector<Span<uint8_t>> &planes) > } > } > > +int EncoderLibJpeg::encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, > + libcamera::Span<const uint8_t> exifData, > + unsigned int quality) > +{ > + internalConfigure(cfg_); > + return encode(*streamBuffer->srcBuffer, streamBuffer->dstBuffer.get()->plane(0), exifData, quality); > +} > + > +int EncoderLibJpeg::generateThumbnail( > + const libcamera::FrameBuffer &source, > + const libcamera::Size &targetSize, > + unsigned int quality, > + std::vector<unsigned char> *thumbnail) > +{ > + /* Stores the raw scaled-down thumbnail bytes. */ > + std::vector<unsigned char> rawThumbnail; > + > + thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); > + > + StreamConfiguration thCfg; > + thCfg.size = targetSize; > + thCfg.pixelFormat = thumbnailer_.pixelFormat(); > + int ret = internalConfigure(thCfg); > + > + if (!rawThumbnail.empty() && !ret) { > + /* > + * \todo Avoid value-initialization of all elements of the > + * vector. > + */ > + thumbnail->resize(rawThumbnail.size()); > + > + /* > + * Split planes manually as the encoder expects a vector of > + * planes. > + * > + * \todo Pass a vector of planes directly to > + * Thumbnailer::createThumbnailer above and remove the manual > + * planes split from here. > + */ > + std::vector<Span<uint8_t>> thumbnailPlanes; > + const PixelFormatInfo &formatNV12 = PixelFormatInfo::info(formats::NV12); > + size_t yPlaneSize = formatNV12.planeSize(targetSize, 0); > + size_t uvPlaneSize = formatNV12.planeSize(targetSize, 1); > + thumbnailPlanes.push_back({ rawThumbnail.data(), yPlaneSize }); > + thumbnailPlanes.push_back({ rawThumbnail.data() + yPlaneSize, uvPlaneSize }); > + > + int jpeg_size = encode(thumbnailPlanes, *thumbnail, {}, quality); > + thumbnail->resize(jpeg_size); > + > + LOG(JPEG, Debug) > + << "Thumbnail compress returned " > + << jpeg_size << " bytes"; > + > + return jpeg_size; > + } > + > + return -1; > +} > + > int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> dest, > Span<const uint8_t> exifData, unsigned int quality) > { > diff --git a/src/android/jpeg/encoder_libjpeg.h b/src/android/jpeg/encoder_libjpeg.h > index 1b3ac067..56b27bae 100644 > --- a/src/android/jpeg/encoder_libjpeg.h > +++ b/src/android/jpeg/encoder_libjpeg.h > @@ -15,6 +15,8 @@ > > #include <jpeglib.h> > > +#include "thumbnailer.h" > + > class EncoderLibJpeg : public Encoder > { > public: > @@ -22,19 +24,32 @@ public: > ~EncoderLibJpeg(); > > int configure(const libcamera::StreamConfiguration &cfg) override; > + int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, > + libcamera::Span<const uint8_t> exifData, > + unsigned int quality) override; > + int generateThumbnail( > + const libcamera::FrameBuffer &source, > + const libcamera::Size &targetSize, > + unsigned int quality, > + std::vector<unsigned char> *thumbnail) override; > + > +private: > + int internalConfigure(const libcamera::StreamConfiguration &cfg); > + > int encode(const libcamera::FrameBuffer &source, > libcamera::Span<uint8_t> destination, > libcamera::Span<const uint8_t> exifData, > - unsigned int quality) override; > + unsigned int quality); > int encode(const std::vector<libcamera::Span<uint8_t>> &planes, > libcamera::Span<uint8_t> destination, > libcamera::Span<const uint8_t> exifData, > unsigned int quality); > > -private: > void compressRGB(const std::vector<libcamera::Span<uint8_t>> &planes); > void compressNV(const std::vector<libcamera::Span<uint8_t>> &planes); > > + libcamera::StreamConfiguration cfg_; > + > struct jpeg_compress_struct compress_; > struct jpeg_error_mgr jerr_; > > @@ -42,4 +57,6 @@ private: > > bool nv_; > bool nvSwap_; > + > + Thumbnailer thumbnailer_; > }; > diff --git a/src/android/jpeg/generic_post_processor_jpeg.cpp b/src/android/jpeg/generic_post_processor_jpeg.cpp > new file mode 100644 > index 00000000..890f6972 > --- /dev/null > +++ b/src/android/jpeg/generic_post_processor_jpeg.cpp > @@ -0,0 +1,14 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2022, Google Inc. > + * > + * generic_post_processor_jpeg.cpp - Generic JPEG Post Processor > + */ > + > +#include "encoder_libjpeg.h" > +#include "post_processor_jpeg.h" > + > +void PostProcessorJpeg::SetEncoder() > +{ > + encoder_ = std::make_unique<EncoderLibJpeg>(); > +} > diff --git a/src/android/jpeg/meson.build b/src/android/jpeg/meson.build > new file mode 100644 > index 00000000..8606acc4 > --- /dev/null > +++ b/src/android/jpeg/meson.build > @@ -0,0 +1,16 @@ > +# SPDX-License-Identifier: CC0-1.0 > + > +android_hal_sources += files([ > + 'exif.cpp', > + 'post_processor_jpeg.cpp']) > + > +platform = get_option('android_platform') > +if platform == 'generic' > + android_hal_sources += files(['encoder_libjpeg.cpp', > + 'generic_post_processor_jpeg.cpp', > + 'thumbnailer.cpp']) > +elif platform == 'cros' > + android_hal_sources += files(['cros_post_processor_jpeg.cpp', > + 'encoder_jea.cpp']) > + android_deps += [dependency('libcros_camera')] > +endif > diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp > index d72ebc3c..7ceba60e 100644 > --- a/src/android/jpeg/post_processor_jpeg.cpp > +++ b/src/android/jpeg/post_processor_jpeg.cpp > @@ -9,10 +9,10 @@ > > #include <chrono> > > +#include "../android_framebuffer.h" > #include "../camera_device.h" > #include "../camera_metadata.h" > #include "../camera_request.h" > -#include "encoder_libjpeg.h" > #include "exif.h" > > #include <libcamera/base/log.h> > @@ -44,60 +44,11 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg, > > streamSize_ = outCfg.size; > > - thumbnailer_.configure(inCfg.size, inCfg.pixelFormat); > - > - encoder_ = std::make_unique<EncoderLibJpeg>(); > + SetEncoder(); > > return encoder_->configure(inCfg); > } > > -void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, > - const Size &targetSize, > - unsigned int quality, > - std::vector<unsigned char> *thumbnail) > -{ > - /* Stores the raw scaled-down thumbnail bytes. */ > - std::vector<unsigned char> rawThumbnail; > - > - thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); > - > - StreamConfiguration thCfg; > - thCfg.size = targetSize; > - thCfg.pixelFormat = thumbnailer_.pixelFormat(); > - int ret = thumbnailEncoder_.configure(thCfg); > - > - if (!rawThumbnail.empty() && !ret) { > - /* > - * \todo Avoid value-initialization of all elements of the > - * vector. > - */ > - thumbnail->resize(rawThumbnail.size()); > - > - /* > - * Split planes manually as the encoder expects a vector of > - * planes. > - * > - * \todo Pass a vector of planes directly to > - * Thumbnailer::createThumbnailer above and remove the manual > - * planes split from here. > - */ > - std::vector<Span<uint8_t>> thumbnailPlanes; > - const PixelFormatInfo &formatNV12 = PixelFormatInfo::info(formats::NV12); > - size_t yPlaneSize = formatNV12.planeSize(targetSize, 0); > - size_t uvPlaneSize = formatNV12.planeSize(targetSize, 1); > - thumbnailPlanes.push_back({ rawThumbnail.data(), yPlaneSize }); > - thumbnailPlanes.push_back({ rawThumbnail.data() + yPlaneSize, uvPlaneSize }); > - > - int jpeg_size = thumbnailEncoder_.encode(thumbnailPlanes, > - *thumbnail, {}, quality); > - thumbnail->resize(jpeg_size); > - > - LOG(JPEG, Debug) > - << "Thumbnail compress returned " > - << jpeg_size << " bytes"; > - } > -} > - > void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBuffer) > { > ASSERT(encoder_); > @@ -164,8 +115,8 @@ void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBu > > if (thumbnailSize != Size(0, 0)) { > std::vector<unsigned char> thumbnail; > - generateThumbnail(source, thumbnailSize, quality, &thumbnail); > - if (!thumbnail.empty()) > + ret = encoder_->generateThumbnail(source, thumbnailSize, quality, &thumbnail); > + if (ret > 0 && !thumbnail.empty()) > exif.setThumbnail(thumbnail, Exif::Compression::JPEG); > } > > @@ -194,8 +145,7 @@ void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBu > const uint8_t quality = ret ? *entry.data.u8 : 95; > resultMetadata->addEntry(ANDROID_JPEG_QUALITY, quality); > > - int jpeg_size = encoder_->encode(source, destination->plane(0), > - exif.data(), quality); > + int jpeg_size = encoder_->encode(streamBuffer, exif.data(), quality); > if (jpeg_size < 0) { > LOG(JPEG, Error) << "Failed to encode stream image"; > processComplete.emit(streamBuffer, PostProcessor::Status::Error); > diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h > index 98309b01..a09f8798 100644 > --- a/src/android/jpeg/post_processor_jpeg.h > +++ b/src/android/jpeg/post_processor_jpeg.h > @@ -8,11 +8,11 @@ > #pragma once > > #include "../post_processor.h" > -#include "encoder_libjpeg.h" > -#include "thumbnailer.h" > > #include <libcamera/geometry.h> > > +#include "encoder.h" > + > class CameraDevice; > > class PostProcessorJpeg : public PostProcessor > @@ -25,14 +25,9 @@ public: > void process(Camera3RequestDescriptor::StreamBuffer *streamBuffer) override; > > private: > - void generateThumbnail(const libcamera::FrameBuffer &source, > - const libcamera::Size &targetSize, > - unsigned int quality, > - std::vector<unsigned char> *thumbnail); > + void SetEncoder(); > > CameraDevice *const cameraDevice_; > std::unique_ptr<Encoder> encoder_; > libcamera::Size streamSize_; > - EncoderLibJpeg thumbnailEncoder_; > - Thumbnailer thumbnailer_; > }; > diff --git a/src/android/meson.build b/src/android/meson.build > index 75b4bf20..026b8b3c 100644 > --- a/src/android/meson.build > +++ b/src/android/meson.build > @@ -38,6 +38,7 @@ endif > android_deps += [libyuv_dep] > > android_hal_sources = files([ > + 'android_framebuffer.cpp', > 'camera3_hal.cpp', > 'camera_capabilities.cpp', > 'camera_device.cpp', > @@ -47,10 +48,6 @@ android_hal_sources = files([ > 'camera_ops.cpp', > 'camera_request.cpp', > 'camera_stream.cpp', > - 'jpeg/encoder_libjpeg.cpp', > - 'jpeg/exif.cpp', > - 'jpeg/post_processor_jpeg.cpp', > - 'jpeg/thumbnailer.cpp', > 'yuv/post_processor_yuv.cpp' > ]) > > @@ -58,6 +55,7 @@ android_cpp_args = [] > > subdir('cros') > subdir('mm') > +subdir('jpeg') > > android_camera_metadata_sources = files([ > 'metadata/camera_metadata.c', > diff --git a/src/android/mm/cros_frame_buffer_allocator.cpp b/src/android/mm/cros_frame_buffer_allocator.cpp > index 52e8c180..163c5d75 100644 > --- a/src/android/mm/cros_frame_buffer_allocator.cpp > +++ b/src/android/mm/cros_frame_buffer_allocator.cpp > @@ -14,6 +14,7 @@ > > #include "libcamera/internal/framebuffer.h" > > +#include "../android_framebuffer.h" > #include "../camera_device.h" > #include "../frame_buffer_allocator.h" > #include "cros-camera/camera_buffer_manager.h" > @@ -47,11 +48,11 @@ public: > { > } > > - std::unique_ptr<libcamera::FrameBuffer> > + std::unique_ptr<AndroidFrameBuffer> > allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage); > }; > > -std::unique_ptr<libcamera::FrameBuffer> > +std::unique_ptr<AndroidFrameBuffer> > PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, > const libcamera::Size &size, > uint32_t usage) > @@ -80,9 +81,11 @@ PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, > plane.length = cros::CameraBufferManager::GetPlaneSize(handle, i); > } > > - return std::make_unique<FrameBuffer>( > - std::make_unique<CrosFrameBufferData>(std::move(scopedHandle)), > - planes); > + auto fb = std::make_unique<AndroidFrameBuffer>(handle, > + std::make_unique<CrosFrameBufferData>(std::move(scopedHandle)), > + planes); > + > + return fb; > } > > PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION > diff --git a/src/android/mm/generic_frame_buffer_allocator.cpp b/src/android/mm/generic_frame_buffer_allocator.cpp > index acb2fa2b..c79b7b10 100644 > --- a/src/android/mm/generic_frame_buffer_allocator.cpp > +++ b/src/android/mm/generic_frame_buffer_allocator.cpp > @@ -18,6 +18,7 @@ > #include <hardware/gralloc.h> > #include <hardware/hardware.h> > > +#include "../android_framebuffer.h" > #include "../camera_device.h" > #include "../frame_buffer_allocator.h" > > @@ -77,7 +78,7 @@ public: > > ~Private() override; > > - std::unique_ptr<libcamera::FrameBuffer> > + std::unique_ptr<AndroidFrameBuffer> > allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage); > > private: > @@ -92,7 +93,7 @@ PlatformFrameBufferAllocator::Private::~Private() > gralloc_close(allocDevice_); > } > > -std::unique_ptr<libcamera::FrameBuffer> > +std::unique_ptr<AndroidFrameBuffer> > PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, > const libcamera::Size &size, > uint32_t usage) > @@ -135,9 +136,9 @@ PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, > offset += planeSize; > } > > - return std::make_unique<FrameBuffer>( > - std::make_unique<GenericFrameBufferData>(allocDevice_, handle), > - planes); > + return std::make_unique<AndroidFrameBuffer>(handle, > + std::make_unique<GenericFrameBufferData>(allocDevice_, handle), > + planes); > } > > PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION
Thanks Laurent! No worries about the schedule. I'm not in a hurry :) I've splitted it into four CLs as you suggested in my PATCH v3 (Sorry for the spam as I forgot to add the Signed-off-by line :'( ) Please check :) BR, Harvey On Tue, Apr 26, 2022 at 6:40 AM Laurent Pinchart < laurent.pinchart@ideasonboard.com> wrote: > Hi Harvey, > > Thank you for the patch, and sorry for the late reply. Catching up with > e-mail after travel is painful. Next time I'll try to get the whole > world to travel at the same time, maybe I'll get less e-mails :-) > > On Wed, Apr 06, 2022 at 05:41:30PM +0800, Harvey Yang via libcamera-devel > wrote: > > This CL uses CrOS JpegCompressor with potential HW accelerator to do > > JPEG encoding. > > > > As CrOS JpegCompressor might need file descriptors to get the source > > data and pass the jpeg result, this CL extends FrameBuffer in the > > android source code as Android_FrameBuffer, which stores the > > buffer_handle_t when constructing the frame buffer, and adds a > > getter function to access it. > > > > This CL also redefines src/android/jpeg/encoder interfaces and adds > > Encoder::generateThumbnail, which might also be accelerated by CrOS > > HW. It simplifies PostProcessorJpeg's logic when generating the > > thumbnail. The original implementation is then moved into the > > EncoderLibJpeg::generateThumbnail. > > This is missing a Signed-off-by line, see > Documentation/contributing.rst. > > > --- > > include/libcamera/framebuffer.h | 3 +- > > src/android/android_framebuffer.cpp | 32 ++++++++ > > src/android/android_framebuffer.h | 28 +++++++ > > src/android/camera_device.cpp | 3 +- > > src/android/cros/camera3_hal.cpp | 3 + > > src/android/frame_buffer_allocator.h | 37 +++++---- > > src/android/jpeg/cros_post_processor_jpeg.cpp | 14 ++++ > > src/android/jpeg/encoder.h | 9 +- > > src/android/jpeg/encoder_jea.cpp | 82 +++++++++++++++++++ > > src/android/jpeg/encoder_jea.h | 35 ++++++++ > > src/android/jpeg/encoder_libjpeg.cpp | 70 ++++++++++++++++ > > src/android/jpeg/encoder_libjpeg.h | 21 ++++- > > .../jpeg/generic_post_processor_jpeg.cpp | 14 ++++ > > src/android/jpeg/meson.build | 16 ++++ > > src/android/jpeg/post_processor_jpeg.cpp | 60 ++------------ > > src/android/jpeg/post_processor_jpeg.h | 11 +-- > > src/android/meson.build | 6 +- > > .../mm/cros_frame_buffer_allocator.cpp | 13 +-- > > .../mm/generic_frame_buffer_allocator.cpp | 11 +-- > > There are lots of changes here, making this hard to review. Could you > please split this patch in pieces, with one logical change by patch, and > bundle them as a series ? Candidates are > > - Drop the final keyword from FrameBuffer and make the destructor > virtual > - Add AndroidFrameBuffer and use it in the HAL (you could even split > that in two if desired, but bundling a new class with its user(s) can > make review easier, if the result isn't too big) > - Rework the JPEG encoder API and implementation to prepare for the > needs of JEA > - Add the JEA implementation > > > 19 files changed, 367 insertions(+), 101 deletions(-) > > create mode 100644 src/android/android_framebuffer.cpp > > create mode 100644 src/android/android_framebuffer.h > > create mode 100644 src/android/jpeg/cros_post_processor_jpeg.cpp > > create mode 100644 src/android/jpeg/encoder_jea.cpp > > create mode 100644 src/android/jpeg/encoder_jea.h > > create mode 100644 src/android/jpeg/generic_post_processor_jpeg.cpp > > create mode 100644 src/android/jpeg/meson.build > > > > diff --git a/include/libcamera/framebuffer.h > b/include/libcamera/framebuffer.h > > index de172d97..c902cc18 100644 > > --- a/include/libcamera/framebuffer.h > > +++ b/include/libcamera/framebuffer.h > > @@ -46,7 +46,7 @@ private: > > std::vector<Plane> planes_; > > }; > > > > -class FrameBuffer final : public Extensible > > +class FrameBuffer : public Extensible > > { > > LIBCAMERA_DECLARE_PRIVATE() > > > > @@ -61,6 +61,7 @@ public: > > FrameBuffer(const std::vector<Plane> &planes, unsigned int cookie > = 0); > > FrameBuffer(std::unique_ptr<Private> d, > > const std::vector<Plane> &planes, unsigned int cookie > = 0); > > + virtual ~FrameBuffer() {} > > > > const std::vector<Plane> &planes() const { return planes_; } > > Request *request() const; > > diff --git a/src/android/android_framebuffer.cpp > b/src/android/android_framebuffer.cpp > > new file mode 100644 > > index 00000000..1ff7018e > > --- /dev/null > > +++ b/src/android/android_framebuffer.cpp > > @@ -0,0 +1,32 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2022, Google Inc. > > + * > > + * android_framebuffer.cpp - Android Frame buffer handling > > + */ > > + > > +#include "android_framebuffer.h" > > + > > +#include <hardware/camera3.h> > > + > > +AndroidFrameBuffer::AndroidFrameBuffer( > > + buffer_handle_t handle, > > + std::unique_ptr<Private> d, > > + const std::vector<Plane> &planes, > > + unsigned int cookie) > > + : FrameBuffer(std::move(d), planes, cookie), handle_(handle) > > +{ > > +} > > + > > +AndroidFrameBuffer::AndroidFrameBuffer( > > + buffer_handle_t handle, > > + const std::vector<Plane> &planes, > > + unsigned int cookie) > > + : FrameBuffer(planes, cookie), handle_(handle) > > +{ > > +} > > + > > +buffer_handle_t AndroidFrameBuffer::getHandle() const > > +{ > > + return handle_; > > +} > > diff --git a/src/android/android_framebuffer.h > b/src/android/android_framebuffer.h > > new file mode 100644 > > index 00000000..49df9756 > > --- /dev/null > > +++ b/src/android/android_framebuffer.h > > @@ -0,0 +1,28 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2022, Google Inc. > > + * > > + * android_framebuffer.h - Android Frame buffer handling > > + */ > > + > > +#pragma once > > + > > +#include "libcamera/internal/framebuffer.h" > > + > > +#include <hardware/camera3.h> > > + > > +class AndroidFrameBuffer final : public libcamera::FrameBuffer > > +{ > > +public: > > + AndroidFrameBuffer( > > + buffer_handle_t handle, std::unique_ptr<Private> d, > > + const std::vector<Plane> &planes, > > + unsigned int cookie = 0); > > + AndroidFrameBuffer(buffer_handle_t handle, > > + const std::vector<Plane> &planes, > > + unsigned int cookie = 0); > > + buffer_handle_t getHandle() const; > > + > > +private: > > + buffer_handle_t handle_ = nullptr; > > +}; > > diff --git a/src/android/camera_device.cpp > b/src/android/camera_device.cpp > > index 00d48471..643b4dee 100644 > > --- a/src/android/camera_device.cpp > > +++ b/src/android/camera_device.cpp > > @@ -25,6 +25,7 @@ > > > > #include "system/graphics.h" > > > > +#include "android_framebuffer.h" > > #include "camera_buffer.h" > > #include "camera_hal_config.h" > > #include "camera_ops.h" > > @@ -754,7 +755,7 @@ CameraDevice::createFrameBuffer(const > buffer_handle_t camera3buffer, > > planes[i].length = buf.size(i); > > } > > > > - return std::make_unique<FrameBuffer>(planes); > > + return std::make_unique<AndroidFrameBuffer>(camera3buffer, planes); > > } > > > > int CameraDevice::processControls(Camera3RequestDescriptor *descriptor) > > diff --git a/src/android/cros/camera3_hal.cpp > b/src/android/cros/camera3_hal.cpp > > index fb863b5f..ea5577f0 100644 > > --- a/src/android/cros/camera3_hal.cpp > > +++ b/src/android/cros/camera3_hal.cpp > > @@ -9,8 +9,11 @@ > > > > #include "../camera_hal_manager.h" > > > > +cros::CameraMojoChannelManagerToken *g_cros_camera_token = nullptr; > > + > > static void set_up([[maybe_unused]] cros::CameraMojoChannelManagerToken > *token) > > { > > + g_cros_camera_token = token; > > } > > > > static void tear_down() > > diff --git a/src/android/frame_buffer_allocator.h > b/src/android/frame_buffer_allocator.h > > index 5d2eeda1..e26422a3 100644 > > --- a/src/android/frame_buffer_allocator.h > > +++ b/src/android/frame_buffer_allocator.h > > @@ -13,9 +13,10 @@ > > #include <libcamera/base/class.h> > > > > #include <libcamera/camera.h> > > -#include <libcamera/framebuffer.h> > > #include <libcamera/geometry.h> > > > > +#include "android_framebuffer.h" > > + > > class CameraDevice; > > > > class PlatformFrameBufferAllocator : libcamera::Extensible > > @@ -31,25 +32,25 @@ public: > > * Note: The returned FrameBuffer needs to be destroyed before > > * PlatformFrameBufferAllocator is destroyed. > > */ > > - std::unique_ptr<libcamera::FrameBuffer> allocate( > > + std::unique_ptr<AndroidFrameBuffer> allocate( > > int halPixelFormat, const libcamera::Size &size, uint32_t > usage); > > }; > > > > -#define PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION \ > > -PlatformFrameBufferAllocator::PlatformFrameBufferAllocator( \ > > - CameraDevice *const cameraDevice) \ > > - : Extensible(std::make_unique<Private>(cameraDevice)) \ > > -{ \ > > -} \ > > -PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator() > \ > > -{ \ > > -} \ > > -std::unique_ptr<libcamera::FrameBuffer> > \ > > -PlatformFrameBufferAllocator::allocate(int halPixelFormat, \ > > - const libcamera::Size &size, \ > > - uint32_t usage) \ > > -{ \ > > - return _d()->allocate(halPixelFormat, size, usage); \ > > -} > > +#define PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION > \ > > + PlatformFrameBufferAllocator::PlatformFrameBufferAllocator( > \ > > + CameraDevice *const cameraDevice) > \ > > + : Extensible(std::make_unique<Private>(cameraDevice)) > \ > > + { > \ > > + } > \ > > + PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator() > \ > > + { > \ > > + } > \ > > + std::unique_ptr<AndroidFrameBuffer> > \ > > + PlatformFrameBufferAllocator::allocate(int halPixelFormat, > \ > > + const libcamera::Size > &size, \ > > + uint32_t usage) > \ > > + { > \ > > + return _d()->allocate(halPixelFormat, size, usage); > \ > > + } > > > > #endif /* __ANDROID_FRAME_BUFFER_ALLOCATOR_H__ */ > > diff --git a/src/android/jpeg/cros_post_processor_jpeg.cpp > b/src/android/jpeg/cros_post_processor_jpeg.cpp > > new file mode 100644 > > index 00000000..7020f0d0 > > --- /dev/null > > +++ b/src/android/jpeg/cros_post_processor_jpeg.cpp > > @@ -0,0 +1,14 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2022, Google Inc. > > + * > > + * cros_post_processor_jpeg.cpp - CrOS JPEG Post Processor > > + */ > > + > > +#include "encoder_jea.h" > > +#include "post_processor_jpeg.h" > > + > > +void PostProcessorJpeg::SetEncoder() > > +{ > > + encoder_ = std::make_unique<EncoderJea>(); > > +} > > diff --git a/src/android/jpeg/encoder.h b/src/android/jpeg/encoder.h > > index b974d367..6d527d91 100644 > > --- a/src/android/jpeg/encoder.h > > +++ b/src/android/jpeg/encoder.h > > @@ -12,14 +12,19 @@ > > #include <libcamera/framebuffer.h> > > #include <libcamera/stream.h> > > > > +#include "../camera_request.h" > > + > > class Encoder > > { > > public: > > virtual ~Encoder() = default; > > > > virtual int configure(const libcamera::StreamConfiguration &cfg) = > 0; > > - virtual int encode(const libcamera::FrameBuffer &source, > > - libcamera::Span<uint8_t> destination, > > + virtual int encode(Camera3RequestDescriptor::StreamBuffer > *streamBuffer, > > libcamera::Span<const uint8_t> exifData, > > unsigned int quality) = 0; > > + virtual int generateThumbnail(const libcamera::FrameBuffer &source, > > + const libcamera::Size &targetSize, > > + unsigned int quality, > > + std::vector<unsigned char> > *thumbnail) = 0; > > }; > > diff --git a/src/android/jpeg/encoder_jea.cpp > b/src/android/jpeg/encoder_jea.cpp > > new file mode 100644 > > index 00000000..838e8647 > > --- /dev/null > > +++ b/src/android/jpeg/encoder_jea.cpp > > @@ -0,0 +1,82 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2022, Google Inc. > > + * > > + * encoder_jea.cpp - JPEG encoding using CrOS JEA > > + */ > > + > > +#include "encoder_jea.h" > > + > > +#include <libcamera/base/log.h> > > + > > +#include "libcamera/internal/mapped_framebuffer.h" > > + > > +#include <cros-camera/camera_mojo_channel_manager_token.h> > > + > > +#include "../android_framebuffer.h" > > + > > +extern cros::CameraMojoChannelManagerToken *g_cros_camera_token; > > + > > +EncoderJea::EncoderJea() = default; > > + > > +EncoderJea::~EncoderJea() = default; > > + > > +int EncoderJea::configure(const libcamera::StreamConfiguration &cfg) > > +{ > > + size_ = cfg.size; > > + > > + if (jpeg_compressor_.get()) > > + return 0; > > + > > + if (g_cros_camera_token == nullptr) > > + return -ENOTSUP; > > + > > + jpeg_compressor_ = > cros::JpegCompressor::GetInstance(g_cros_camera_token); > > + > > + return 0; > > +} > > + > > +int EncoderJea::encode(Camera3RequestDescriptor::StreamBuffer > *streamBuffer, > > + libcamera::Span<const uint8_t> exifData, > > + unsigned int quality) > > +{ > > + if (!jpeg_compressor_.get()) > > + return -1; > > + > > + uint32_t out_data_size = 0; > > + > > + if (!jpeg_compressor_->CompressImageFromHandle( > > + dynamic_cast<const AndroidFrameBuffer *>( > > + streamBuffer->srcBuffer) > > + ->getHandle(), > > + *streamBuffer->camera3Buffer, size_.width, > size_.height, quality, > > + exifData.data(), exifData.size(), &out_data_size)) { > > + return -1; > > + } > > + > > + return out_data_size; > > +} > > + > > +int EncoderJea::generateThumbnail(const libcamera::FrameBuffer &source, > > + const libcamera::Size &targetSize, > > + unsigned int quality, > > + std::vector<unsigned char> *thumbnail) > > +{ > > + if (!jpeg_compressor_.get()) > > + return -1; > > + > > + libcamera::MappedFrameBuffer frame(&source, > libcamera::MappedFrameBuffer::MapFlag::Read); > > + > > + if (frame.planes().empty()) > > + return 0; > > + > > + uint32_t out_data_size = 0; > > + > > + if (!jpeg_compressor_->GenerateThumbnail(frame.planes()[0].data(), > > + size_.width, > size_.height, targetSize.width, targetSize.height, > > + quality, > thumbnail->size(), thumbnail->data(), &out_data_size)) { > > + return -1; > > + } > > + > > + return out_data_size; > > +} > > diff --git a/src/android/jpeg/encoder_jea.h > b/src/android/jpeg/encoder_jea.h > > new file mode 100644 > > index 00000000..d5c9f1f7 > > --- /dev/null > > +++ b/src/android/jpeg/encoder_jea.h > > @@ -0,0 +1,35 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2022, Google Inc. > > + * > > + * encoder_jea.h - JPEG encoding using CrOS JEA > > + */ > > + > > +#pragma once > > + > > +#include <libcamera/geometry.h> > > + > > +#include <cros-camera/jpeg_compressor.h> > > + > > +#include "encoder.h" > > + > > +class EncoderJea : public Encoder > > +{ > > +public: > > + EncoderJea(); > > + ~EncoderJea(); > > + > > + int configure(const libcamera::StreamConfiguration &cfg) override; > > + int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, > > + libcamera::Span<const uint8_t> exifData, > > + unsigned int quality) override; > > + int generateThumbnail(const libcamera::FrameBuffer &source, > > + const libcamera::Size &targetSize, > > + unsigned int quality, > > + std::vector<unsigned char> *thumbnail) > override; > > + > > +private: > > + libcamera::Size size_; > > + > > + std::unique_ptr<cros::JpegCompressor> jpeg_compressor_; > > +}; > > diff --git a/src/android/jpeg/encoder_libjpeg.cpp > b/src/android/jpeg/encoder_libjpeg.cpp > > index 21a3b33d..b5591e33 100644 > > --- a/src/android/jpeg/encoder_libjpeg.cpp > > +++ b/src/android/jpeg/encoder_libjpeg.cpp > > @@ -24,6 +24,8 @@ > > #include "libcamera/internal/formats.h" > > #include "libcamera/internal/mapped_framebuffer.h" > > > > +#include "../camera_buffer.h" > > + > > using namespace libcamera; > > > > LOG_DECLARE_CATEGORY(JPEG) > > @@ -82,8 +84,17 @@ EncoderLibJpeg::~EncoderLibJpeg() > > } > > > > int EncoderLibJpeg::configure(const StreamConfiguration &cfg) > > +{ > > + thumbnailer_.configure(cfg.size, cfg.pixelFormat); > > + cfg_ = cfg; > > + > > + return internalConfigure(cfg); > > +} > > + > > +int EncoderLibJpeg::internalConfigure(const StreamConfiguration &cfg) > > { > > const struct JPEGPixelFormatInfo info = > findPixelInfo(cfg.pixelFormat); > > + > > if (info.colorSpace == JCS_UNKNOWN) > > return -ENOTSUP; > > > > @@ -178,6 +189,65 @@ void EncoderLibJpeg::compressNV(const > std::vector<Span<uint8_t>> &planes) > > } > > } > > > > +int EncoderLibJpeg::encode(Camera3RequestDescriptor::StreamBuffer > *streamBuffer, > > + libcamera::Span<const uint8_t> exifData, > > + unsigned int quality) > > +{ > > + internalConfigure(cfg_); > > + return encode(*streamBuffer->srcBuffer, > streamBuffer->dstBuffer.get()->plane(0), exifData, quality); > > +} > > + > > +int EncoderLibJpeg::generateThumbnail( > > + const libcamera::FrameBuffer &source, > > + const libcamera::Size &targetSize, > > + unsigned int quality, > > + std::vector<unsigned char> *thumbnail) > > +{ > > + /* Stores the raw scaled-down thumbnail bytes. */ > > + std::vector<unsigned char> rawThumbnail; > > + > > + thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); > > + > > + StreamConfiguration thCfg; > > + thCfg.size = targetSize; > > + thCfg.pixelFormat = thumbnailer_.pixelFormat(); > > + int ret = internalConfigure(thCfg); > > + > > + if (!rawThumbnail.empty() && !ret) { > > + /* > > + * \todo Avoid value-initialization of all elements of the > > + * vector. > > + */ > > + thumbnail->resize(rawThumbnail.size()); > > + > > + /* > > + * Split planes manually as the encoder expects a vector of > > + * planes. > > + * > > + * \todo Pass a vector of planes directly to > > + * Thumbnailer::createThumbnailer above and remove the > manual > > + * planes split from here. > > + */ > > + std::vector<Span<uint8_t>> thumbnailPlanes; > > + const PixelFormatInfo &formatNV12 = > PixelFormatInfo::info(formats::NV12); > > + size_t yPlaneSize = formatNV12.planeSize(targetSize, 0); > > + size_t uvPlaneSize = formatNV12.planeSize(targetSize, 1); > > + thumbnailPlanes.push_back({ rawThumbnail.data(), > yPlaneSize }); > > + thumbnailPlanes.push_back({ rawThumbnail.data() + > yPlaneSize, uvPlaneSize }); > > + > > + int jpeg_size = encode(thumbnailPlanes, *thumbnail, {}, > quality); > > + thumbnail->resize(jpeg_size); > > + > > + LOG(JPEG, Debug) > > + << "Thumbnail compress returned " > > + << jpeg_size << " bytes"; > > + > > + return jpeg_size; > > + } > > + > > + return -1; > > +} > > + > > int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> > dest, > > Span<const uint8_t> exifData, unsigned int > quality) > > { > > diff --git a/src/android/jpeg/encoder_libjpeg.h > b/src/android/jpeg/encoder_libjpeg.h > > index 1b3ac067..56b27bae 100644 > > --- a/src/android/jpeg/encoder_libjpeg.h > > +++ b/src/android/jpeg/encoder_libjpeg.h > > @@ -15,6 +15,8 @@ > > > > #include <jpeglib.h> > > > > +#include "thumbnailer.h" > > + > > class EncoderLibJpeg : public Encoder > > { > > public: > > @@ -22,19 +24,32 @@ public: > > ~EncoderLibJpeg(); > > > > int configure(const libcamera::StreamConfiguration &cfg) override; > > + int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, > > + libcamera::Span<const uint8_t> exifData, > > + unsigned int quality) override; > > + int generateThumbnail( > > + const libcamera::FrameBuffer &source, > > + const libcamera::Size &targetSize, > > + unsigned int quality, > > + std::vector<unsigned char> *thumbnail) override; > > + > > +private: > > + int internalConfigure(const libcamera::StreamConfiguration &cfg); > > + > > int encode(const libcamera::FrameBuffer &source, > > libcamera::Span<uint8_t> destination, > > libcamera::Span<const uint8_t> exifData, > > - unsigned int quality) override; > > + unsigned int quality); > > int encode(const std::vector<libcamera::Span<uint8_t>> &planes, > > libcamera::Span<uint8_t> destination, > > libcamera::Span<const uint8_t> exifData, > > unsigned int quality); > > > > -private: > > void compressRGB(const std::vector<libcamera::Span<uint8_t>> > &planes); > > void compressNV(const std::vector<libcamera::Span<uint8_t>> > &planes); > > > > + libcamera::StreamConfiguration cfg_; > > + > > struct jpeg_compress_struct compress_; > > struct jpeg_error_mgr jerr_; > > > > @@ -42,4 +57,6 @@ private: > > > > bool nv_; > > bool nvSwap_; > > + > > + Thumbnailer thumbnailer_; > > }; > > diff --git a/src/android/jpeg/generic_post_processor_jpeg.cpp > b/src/android/jpeg/generic_post_processor_jpeg.cpp > > new file mode 100644 > > index 00000000..890f6972 > > --- /dev/null > > +++ b/src/android/jpeg/generic_post_processor_jpeg.cpp > > @@ -0,0 +1,14 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2022, Google Inc. > > + * > > + * generic_post_processor_jpeg.cpp - Generic JPEG Post Processor > > + */ > > + > > +#include "encoder_libjpeg.h" > > +#include "post_processor_jpeg.h" > > + > > +void PostProcessorJpeg::SetEncoder() > > +{ > > + encoder_ = std::make_unique<EncoderLibJpeg>(); > > +} > > diff --git a/src/android/jpeg/meson.build b/src/android/jpeg/meson.build > > new file mode 100644 > > index 00000000..8606acc4 > > --- /dev/null > > +++ b/src/android/jpeg/meson.build > > @@ -0,0 +1,16 @@ > > +# SPDX-License-Identifier: CC0-1.0 > > + > > +android_hal_sources += files([ > > + 'exif.cpp', > > + 'post_processor_jpeg.cpp']) > > + > > +platform = get_option('android_platform') > > +if platform == 'generic' > > + android_hal_sources += files(['encoder_libjpeg.cpp', > > + 'generic_post_processor_jpeg.cpp', > > + 'thumbnailer.cpp']) > > +elif platform == 'cros' > > + android_hal_sources += files(['cros_post_processor_jpeg.cpp', > > + 'encoder_jea.cpp']) > > + android_deps += [dependency('libcros_camera')] > > +endif > > diff --git a/src/android/jpeg/post_processor_jpeg.cpp > b/src/android/jpeg/post_processor_jpeg.cpp > > index d72ebc3c..7ceba60e 100644 > > --- a/src/android/jpeg/post_processor_jpeg.cpp > > +++ b/src/android/jpeg/post_processor_jpeg.cpp > > @@ -9,10 +9,10 @@ > > > > #include <chrono> > > > > +#include "../android_framebuffer.h" > > #include "../camera_device.h" > > #include "../camera_metadata.h" > > #include "../camera_request.h" > > -#include "encoder_libjpeg.h" > > #include "exif.h" > > > > #include <libcamera/base/log.h> > > @@ -44,60 +44,11 @@ int PostProcessorJpeg::configure(const > StreamConfiguration &inCfg, > > > > streamSize_ = outCfg.size; > > > > - thumbnailer_.configure(inCfg.size, inCfg.pixelFormat); > > - > > - encoder_ = std::make_unique<EncoderLibJpeg>(); > > + SetEncoder(); > > > > return encoder_->configure(inCfg); > > } > > > > -void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, > > - const Size &targetSize, > > - unsigned int quality, > > - std::vector<unsigned char> > *thumbnail) > > -{ > > - /* Stores the raw scaled-down thumbnail bytes. */ > > - std::vector<unsigned char> rawThumbnail; > > - > > - thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); > > - > > - StreamConfiguration thCfg; > > - thCfg.size = targetSize; > > - thCfg.pixelFormat = thumbnailer_.pixelFormat(); > > - int ret = thumbnailEncoder_.configure(thCfg); > > - > > - if (!rawThumbnail.empty() && !ret) { > > - /* > > - * \todo Avoid value-initialization of all elements of the > > - * vector. > > - */ > > - thumbnail->resize(rawThumbnail.size()); > > - > > - /* > > - * Split planes manually as the encoder expects a vector of > > - * planes. > > - * > > - * \todo Pass a vector of planes directly to > > - * Thumbnailer::createThumbnailer above and remove the > manual > > - * planes split from here. > > - */ > > - std::vector<Span<uint8_t>> thumbnailPlanes; > > - const PixelFormatInfo &formatNV12 = > PixelFormatInfo::info(formats::NV12); > > - size_t yPlaneSize = formatNV12.planeSize(targetSize, 0); > > - size_t uvPlaneSize = formatNV12.planeSize(targetSize, 1); > > - thumbnailPlanes.push_back({ rawThumbnail.data(), > yPlaneSize }); > > - thumbnailPlanes.push_back({ rawThumbnail.data() + > yPlaneSize, uvPlaneSize }); > > - > > - int jpeg_size = thumbnailEncoder_.encode(thumbnailPlanes, > > - *thumbnail, {}, > quality); > > - thumbnail->resize(jpeg_size); > > - > > - LOG(JPEG, Debug) > > - << "Thumbnail compress returned " > > - << jpeg_size << " bytes"; > > - } > > -} > > - > > void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer > *streamBuffer) > > { > > ASSERT(encoder_); > > @@ -164,8 +115,8 @@ void > PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBu > > > > if (thumbnailSize != Size(0, 0)) { > > std::vector<unsigned char> thumbnail; > > - generateThumbnail(source, thumbnailSize, quality, > &thumbnail); > > - if (!thumbnail.empty()) > > + ret = encoder_->generateThumbnail(source, > thumbnailSize, quality, &thumbnail); > > + if (ret > 0 && !thumbnail.empty()) > > exif.setThumbnail(thumbnail, > Exif::Compression::JPEG); > > } > > > > @@ -194,8 +145,7 @@ void > PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBu > > const uint8_t quality = ret ? *entry.data.u8 : 95; > > resultMetadata->addEntry(ANDROID_JPEG_QUALITY, quality); > > > > - int jpeg_size = encoder_->encode(source, destination->plane(0), > > - exif.data(), quality); > > + int jpeg_size = encoder_->encode(streamBuffer, exif.data(), > quality); > > if (jpeg_size < 0) { > > LOG(JPEG, Error) << "Failed to encode stream image"; > > processComplete.emit(streamBuffer, > PostProcessor::Status::Error); > > diff --git a/src/android/jpeg/post_processor_jpeg.h > b/src/android/jpeg/post_processor_jpeg.h > > index 98309b01..a09f8798 100644 > > --- a/src/android/jpeg/post_processor_jpeg.h > > +++ b/src/android/jpeg/post_processor_jpeg.h > > @@ -8,11 +8,11 @@ > > #pragma once > > > > #include "../post_processor.h" > > -#include "encoder_libjpeg.h" > > -#include "thumbnailer.h" > > > > #include <libcamera/geometry.h> > > > > +#include "encoder.h" > > + > > class CameraDevice; > > > > class PostProcessorJpeg : public PostProcessor > > @@ -25,14 +25,9 @@ public: > > void process(Camera3RequestDescriptor::StreamBuffer *streamBuffer) > override; > > > > private: > > - void generateThumbnail(const libcamera::FrameBuffer &source, > > - const libcamera::Size &targetSize, > > - unsigned int quality, > > - std::vector<unsigned char> *thumbnail); > > + void SetEncoder(); > > > > CameraDevice *const cameraDevice_; > > std::unique_ptr<Encoder> encoder_; > > libcamera::Size streamSize_; > > - EncoderLibJpeg thumbnailEncoder_; > > - Thumbnailer thumbnailer_; > > }; > > diff --git a/src/android/meson.build b/src/android/meson.build > > index 75b4bf20..026b8b3c 100644 > > --- a/src/android/meson.build > > +++ b/src/android/meson.build > > @@ -38,6 +38,7 @@ endif > > android_deps += [libyuv_dep] > > > > android_hal_sources = files([ > > + 'android_framebuffer.cpp', > > 'camera3_hal.cpp', > > 'camera_capabilities.cpp', > > 'camera_device.cpp', > > @@ -47,10 +48,6 @@ android_hal_sources = files([ > > 'camera_ops.cpp', > > 'camera_request.cpp', > > 'camera_stream.cpp', > > - 'jpeg/encoder_libjpeg.cpp', > > - 'jpeg/exif.cpp', > > - 'jpeg/post_processor_jpeg.cpp', > > - 'jpeg/thumbnailer.cpp', > > 'yuv/post_processor_yuv.cpp' > > ]) > > > > @@ -58,6 +55,7 @@ android_cpp_args = [] > > > > subdir('cros') > > subdir('mm') > > +subdir('jpeg') > > > > android_camera_metadata_sources = files([ > > 'metadata/camera_metadata.c', > > diff --git a/src/android/mm/cros_frame_buffer_allocator.cpp > b/src/android/mm/cros_frame_buffer_allocator.cpp > > index 52e8c180..163c5d75 100644 > > --- a/src/android/mm/cros_frame_buffer_allocator.cpp > > +++ b/src/android/mm/cros_frame_buffer_allocator.cpp > > @@ -14,6 +14,7 @@ > > > > #include "libcamera/internal/framebuffer.h" > > > > +#include "../android_framebuffer.h" > > #include "../camera_device.h" > > #include "../frame_buffer_allocator.h" > > #include "cros-camera/camera_buffer_manager.h" > > @@ -47,11 +48,11 @@ public: > > { > > } > > > > - std::unique_ptr<libcamera::FrameBuffer> > > + std::unique_ptr<AndroidFrameBuffer> > > allocate(int halPixelFormat, const libcamera::Size &size, uint32_t > usage); > > }; > > > > -std::unique_ptr<libcamera::FrameBuffer> > > +std::unique_ptr<AndroidFrameBuffer> > > PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, > > const libcamera::Size > &size, > > uint32_t usage) > > @@ -80,9 +81,11 @@ PlatformFrameBufferAllocator::Private::allocate(int > halPixelFormat, > > plane.length = > cros::CameraBufferManager::GetPlaneSize(handle, i); > > } > > > > - return std::make_unique<FrameBuffer>( > > - > std::make_unique<CrosFrameBufferData>(std::move(scopedHandle)), > > - planes); > > + auto fb = std::make_unique<AndroidFrameBuffer>(handle, > > + > std::make_unique<CrosFrameBufferData>(std::move(scopedHandle)), > > + planes); > > + > > + return fb; > > } > > > > PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION > > diff --git a/src/android/mm/generic_frame_buffer_allocator.cpp > b/src/android/mm/generic_frame_buffer_allocator.cpp > > index acb2fa2b..c79b7b10 100644 > > --- a/src/android/mm/generic_frame_buffer_allocator.cpp > > +++ b/src/android/mm/generic_frame_buffer_allocator.cpp > > @@ -18,6 +18,7 @@ > > #include <hardware/gralloc.h> > > #include <hardware/hardware.h> > > > > +#include "../android_framebuffer.h" > > #include "../camera_device.h" > > #include "../frame_buffer_allocator.h" > > > > @@ -77,7 +78,7 @@ public: > > > > ~Private() override; > > > > - std::unique_ptr<libcamera::FrameBuffer> > > + std::unique_ptr<AndroidFrameBuffer> > > allocate(int halPixelFormat, const libcamera::Size &size, uint32_t > usage); > > > > private: > > @@ -92,7 +93,7 @@ PlatformFrameBufferAllocator::Private::~Private() > > gralloc_close(allocDevice_); > > } > > > > -std::unique_ptr<libcamera::FrameBuffer> > > +std::unique_ptr<AndroidFrameBuffer> > > PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, > > const libcamera::Size > &size, > > uint32_t usage) > > @@ -135,9 +136,9 @@ PlatformFrameBufferAllocator::Private::allocate(int > halPixelFormat, > > offset += planeSize; > > } > > > > - return std::make_unique<FrameBuffer>( > > - std::make_unique<GenericFrameBufferData>(allocDevice_, > handle), > > - planes); > > + return std::make_unique<AndroidFrameBuffer>(handle, > > + > std::make_unique<GenericFrameBufferData>(allocDevice_, handle), > > + planes); > > } > > > > PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION > > -- > Regards, > > Laurent Pinchart >
diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h index de172d97..c902cc18 100644 --- a/include/libcamera/framebuffer.h +++ b/include/libcamera/framebuffer.h @@ -46,7 +46,7 @@ private: std::vector<Plane> planes_; }; -class FrameBuffer final : public Extensible +class FrameBuffer : public Extensible { LIBCAMERA_DECLARE_PRIVATE() @@ -61,6 +61,7 @@ public: FrameBuffer(const std::vector<Plane> &planes, unsigned int cookie = 0); FrameBuffer(std::unique_ptr<Private> d, const std::vector<Plane> &planes, unsigned int cookie = 0); + virtual ~FrameBuffer() {} const std::vector<Plane> &planes() const { return planes_; } Request *request() const; diff --git a/src/android/android_framebuffer.cpp b/src/android/android_framebuffer.cpp new file mode 100644 index 00000000..1ff7018e --- /dev/null +++ b/src/android/android_framebuffer.cpp @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * + * android_framebuffer.cpp - Android Frame buffer handling + */ + +#include "android_framebuffer.h" + +#include <hardware/camera3.h> + +AndroidFrameBuffer::AndroidFrameBuffer( + buffer_handle_t handle, + std::unique_ptr<Private> d, + const std::vector<Plane> &planes, + unsigned int cookie) + : FrameBuffer(std::move(d), planes, cookie), handle_(handle) +{ +} + +AndroidFrameBuffer::AndroidFrameBuffer( + buffer_handle_t handle, + const std::vector<Plane> &planes, + unsigned int cookie) + : FrameBuffer(planes, cookie), handle_(handle) +{ +} + +buffer_handle_t AndroidFrameBuffer::getHandle() const +{ + return handle_; +} diff --git a/src/android/android_framebuffer.h b/src/android/android_framebuffer.h new file mode 100644 index 00000000..49df9756 --- /dev/null +++ b/src/android/android_framebuffer.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * + * android_framebuffer.h - Android Frame buffer handling + */ + +#pragma once + +#include "libcamera/internal/framebuffer.h" + +#include <hardware/camera3.h> + +class AndroidFrameBuffer final : public libcamera::FrameBuffer +{ +public: + AndroidFrameBuffer( + buffer_handle_t handle, std::unique_ptr<Private> d, + const std::vector<Plane> &planes, + unsigned int cookie = 0); + AndroidFrameBuffer(buffer_handle_t handle, + const std::vector<Plane> &planes, + unsigned int cookie = 0); + buffer_handle_t getHandle() const; + +private: + buffer_handle_t handle_ = nullptr; +}; diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index 00d48471..643b4dee 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -25,6 +25,7 @@ #include "system/graphics.h" +#include "android_framebuffer.h" #include "camera_buffer.h" #include "camera_hal_config.h" #include "camera_ops.h" @@ -754,7 +755,7 @@ CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer, planes[i].length = buf.size(i); } - return std::make_unique<FrameBuffer>(planes); + return std::make_unique<AndroidFrameBuffer>(camera3buffer, planes); } int CameraDevice::processControls(Camera3RequestDescriptor *descriptor) diff --git a/src/android/cros/camera3_hal.cpp b/src/android/cros/camera3_hal.cpp index fb863b5f..ea5577f0 100644 --- a/src/android/cros/camera3_hal.cpp +++ b/src/android/cros/camera3_hal.cpp @@ -9,8 +9,11 @@ #include "../camera_hal_manager.h" +cros::CameraMojoChannelManagerToken *g_cros_camera_token = nullptr; + static void set_up([[maybe_unused]] cros::CameraMojoChannelManagerToken *token) { + g_cros_camera_token = token; } static void tear_down() diff --git a/src/android/frame_buffer_allocator.h b/src/android/frame_buffer_allocator.h index 5d2eeda1..e26422a3 100644 --- a/src/android/frame_buffer_allocator.h +++ b/src/android/frame_buffer_allocator.h @@ -13,9 +13,10 @@ #include <libcamera/base/class.h> #include <libcamera/camera.h> -#include <libcamera/framebuffer.h> #include <libcamera/geometry.h> +#include "android_framebuffer.h" + class CameraDevice; class PlatformFrameBufferAllocator : libcamera::Extensible @@ -31,25 +32,25 @@ public: * Note: The returned FrameBuffer needs to be destroyed before * PlatformFrameBufferAllocator is destroyed. */ - std::unique_ptr<libcamera::FrameBuffer> allocate( + std::unique_ptr<AndroidFrameBuffer> allocate( int halPixelFormat, const libcamera::Size &size, uint32_t usage); }; -#define PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION \ -PlatformFrameBufferAllocator::PlatformFrameBufferAllocator( \ - CameraDevice *const cameraDevice) \ - : Extensible(std::make_unique<Private>(cameraDevice)) \ -{ \ -} \ -PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator() \ -{ \ -} \ -std::unique_ptr<libcamera::FrameBuffer> \ -PlatformFrameBufferAllocator::allocate(int halPixelFormat, \ - const libcamera::Size &size, \ - uint32_t usage) \ -{ \ - return _d()->allocate(halPixelFormat, size, usage); \ -} +#define PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION \ + PlatformFrameBufferAllocator::PlatformFrameBufferAllocator( \ + CameraDevice *const cameraDevice) \ + : Extensible(std::make_unique<Private>(cameraDevice)) \ + { \ + } \ + PlatformFrameBufferAllocator::~PlatformFrameBufferAllocator() \ + { \ + } \ + std::unique_ptr<AndroidFrameBuffer> \ + PlatformFrameBufferAllocator::allocate(int halPixelFormat, \ + const libcamera::Size &size, \ + uint32_t usage) \ + { \ + return _d()->allocate(halPixelFormat, size, usage); \ + } #endif /* __ANDROID_FRAME_BUFFER_ALLOCATOR_H__ */ diff --git a/src/android/jpeg/cros_post_processor_jpeg.cpp b/src/android/jpeg/cros_post_processor_jpeg.cpp new file mode 100644 index 00000000..7020f0d0 --- /dev/null +++ b/src/android/jpeg/cros_post_processor_jpeg.cpp @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * + * cros_post_processor_jpeg.cpp - CrOS JPEG Post Processor + */ + +#include "encoder_jea.h" +#include "post_processor_jpeg.h" + +void PostProcessorJpeg::SetEncoder() +{ + encoder_ = std::make_unique<EncoderJea>(); +} diff --git a/src/android/jpeg/encoder.h b/src/android/jpeg/encoder.h index b974d367..6d527d91 100644 --- a/src/android/jpeg/encoder.h +++ b/src/android/jpeg/encoder.h @@ -12,14 +12,19 @@ #include <libcamera/framebuffer.h> #include <libcamera/stream.h> +#include "../camera_request.h" + class Encoder { public: virtual ~Encoder() = default; virtual int configure(const libcamera::StreamConfiguration &cfg) = 0; - virtual int encode(const libcamera::FrameBuffer &source, - libcamera::Span<uint8_t> destination, + virtual int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, libcamera::Span<const uint8_t> exifData, unsigned int quality) = 0; + virtual int generateThumbnail(const libcamera::FrameBuffer &source, + const libcamera::Size &targetSize, + unsigned int quality, + std::vector<unsigned char> *thumbnail) = 0; }; diff --git a/src/android/jpeg/encoder_jea.cpp b/src/android/jpeg/encoder_jea.cpp new file mode 100644 index 00000000..838e8647 --- /dev/null +++ b/src/android/jpeg/encoder_jea.cpp @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * + * encoder_jea.cpp - JPEG encoding using CrOS JEA + */ + +#include "encoder_jea.h" + +#include <libcamera/base/log.h> + +#include "libcamera/internal/mapped_framebuffer.h" + +#include <cros-camera/camera_mojo_channel_manager_token.h> + +#include "../android_framebuffer.h" + +extern cros::CameraMojoChannelManagerToken *g_cros_camera_token; + +EncoderJea::EncoderJea() = default; + +EncoderJea::~EncoderJea() = default; + +int EncoderJea::configure(const libcamera::StreamConfiguration &cfg) +{ + size_ = cfg.size; + + if (jpeg_compressor_.get()) + return 0; + + if (g_cros_camera_token == nullptr) + return -ENOTSUP; + + jpeg_compressor_ = cros::JpegCompressor::GetInstance(g_cros_camera_token); + + return 0; +} + +int EncoderJea::encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, + libcamera::Span<const uint8_t> exifData, + unsigned int quality) +{ + if (!jpeg_compressor_.get()) + return -1; + + uint32_t out_data_size = 0; + + if (!jpeg_compressor_->CompressImageFromHandle( + dynamic_cast<const AndroidFrameBuffer *>( + streamBuffer->srcBuffer) + ->getHandle(), + *streamBuffer->camera3Buffer, size_.width, size_.height, quality, + exifData.data(), exifData.size(), &out_data_size)) { + return -1; + } + + return out_data_size; +} + +int EncoderJea::generateThumbnail(const libcamera::FrameBuffer &source, + const libcamera::Size &targetSize, + unsigned int quality, + std::vector<unsigned char> *thumbnail) +{ + if (!jpeg_compressor_.get()) + return -1; + + libcamera::MappedFrameBuffer frame(&source, libcamera::MappedFrameBuffer::MapFlag::Read); + + if (frame.planes().empty()) + return 0; + + uint32_t out_data_size = 0; + + if (!jpeg_compressor_->GenerateThumbnail(frame.planes()[0].data(), + size_.width, size_.height, targetSize.width, targetSize.height, + quality, thumbnail->size(), thumbnail->data(), &out_data_size)) { + return -1; + } + + return out_data_size; +} diff --git a/src/android/jpeg/encoder_jea.h b/src/android/jpeg/encoder_jea.h new file mode 100644 index 00000000..d5c9f1f7 --- /dev/null +++ b/src/android/jpeg/encoder_jea.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * + * encoder_jea.h - JPEG encoding using CrOS JEA + */ + +#pragma once + +#include <libcamera/geometry.h> + +#include <cros-camera/jpeg_compressor.h> + +#include "encoder.h" + +class EncoderJea : public Encoder +{ +public: + EncoderJea(); + ~EncoderJea(); + + int configure(const libcamera::StreamConfiguration &cfg) override; + int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, + libcamera::Span<const uint8_t> exifData, + unsigned int quality) override; + int generateThumbnail(const libcamera::FrameBuffer &source, + const libcamera::Size &targetSize, + unsigned int quality, + std::vector<unsigned char> *thumbnail) override; + +private: + libcamera::Size size_; + + std::unique_ptr<cros::JpegCompressor> jpeg_compressor_; +}; diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp index 21a3b33d..b5591e33 100644 --- a/src/android/jpeg/encoder_libjpeg.cpp +++ b/src/android/jpeg/encoder_libjpeg.cpp @@ -24,6 +24,8 @@ #include "libcamera/internal/formats.h" #include "libcamera/internal/mapped_framebuffer.h" +#include "../camera_buffer.h" + using namespace libcamera; LOG_DECLARE_CATEGORY(JPEG) @@ -82,8 +84,17 @@ EncoderLibJpeg::~EncoderLibJpeg() } int EncoderLibJpeg::configure(const StreamConfiguration &cfg) +{ + thumbnailer_.configure(cfg.size, cfg.pixelFormat); + cfg_ = cfg; + + return internalConfigure(cfg); +} + +int EncoderLibJpeg::internalConfigure(const StreamConfiguration &cfg) { const struct JPEGPixelFormatInfo info = findPixelInfo(cfg.pixelFormat); + if (info.colorSpace == JCS_UNKNOWN) return -ENOTSUP; @@ -178,6 +189,65 @@ void EncoderLibJpeg::compressNV(const std::vector<Span<uint8_t>> &planes) } } +int EncoderLibJpeg::encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, + libcamera::Span<const uint8_t> exifData, + unsigned int quality) +{ + internalConfigure(cfg_); + return encode(*streamBuffer->srcBuffer, streamBuffer->dstBuffer.get()->plane(0), exifData, quality); +} + +int EncoderLibJpeg::generateThumbnail( + const libcamera::FrameBuffer &source, + const libcamera::Size &targetSize, + unsigned int quality, + std::vector<unsigned char> *thumbnail) +{ + /* Stores the raw scaled-down thumbnail bytes. */ + std::vector<unsigned char> rawThumbnail; + + thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); + + StreamConfiguration thCfg; + thCfg.size = targetSize; + thCfg.pixelFormat = thumbnailer_.pixelFormat(); + int ret = internalConfigure(thCfg); + + if (!rawThumbnail.empty() && !ret) { + /* + * \todo Avoid value-initialization of all elements of the + * vector. + */ + thumbnail->resize(rawThumbnail.size()); + + /* + * Split planes manually as the encoder expects a vector of + * planes. + * + * \todo Pass a vector of planes directly to + * Thumbnailer::createThumbnailer above and remove the manual + * planes split from here. + */ + std::vector<Span<uint8_t>> thumbnailPlanes; + const PixelFormatInfo &formatNV12 = PixelFormatInfo::info(formats::NV12); + size_t yPlaneSize = formatNV12.planeSize(targetSize, 0); + size_t uvPlaneSize = formatNV12.planeSize(targetSize, 1); + thumbnailPlanes.push_back({ rawThumbnail.data(), yPlaneSize }); + thumbnailPlanes.push_back({ rawThumbnail.data() + yPlaneSize, uvPlaneSize }); + + int jpeg_size = encode(thumbnailPlanes, *thumbnail, {}, quality); + thumbnail->resize(jpeg_size); + + LOG(JPEG, Debug) + << "Thumbnail compress returned " + << jpeg_size << " bytes"; + + return jpeg_size; + } + + return -1; +} + int EncoderLibJpeg::encode(const FrameBuffer &source, Span<uint8_t> dest, Span<const uint8_t> exifData, unsigned int quality) { diff --git a/src/android/jpeg/encoder_libjpeg.h b/src/android/jpeg/encoder_libjpeg.h index 1b3ac067..56b27bae 100644 --- a/src/android/jpeg/encoder_libjpeg.h +++ b/src/android/jpeg/encoder_libjpeg.h @@ -15,6 +15,8 @@ #include <jpeglib.h> +#include "thumbnailer.h" + class EncoderLibJpeg : public Encoder { public: @@ -22,19 +24,32 @@ public: ~EncoderLibJpeg(); int configure(const libcamera::StreamConfiguration &cfg) override; + int encode(Camera3RequestDescriptor::StreamBuffer *streamBuffer, + libcamera::Span<const uint8_t> exifData, + unsigned int quality) override; + int generateThumbnail( + const libcamera::FrameBuffer &source, + const libcamera::Size &targetSize, + unsigned int quality, + std::vector<unsigned char> *thumbnail) override; + +private: + int internalConfigure(const libcamera::StreamConfiguration &cfg); + int encode(const libcamera::FrameBuffer &source, libcamera::Span<uint8_t> destination, libcamera::Span<const uint8_t> exifData, - unsigned int quality) override; + unsigned int quality); int encode(const std::vector<libcamera::Span<uint8_t>> &planes, libcamera::Span<uint8_t> destination, libcamera::Span<const uint8_t> exifData, unsigned int quality); -private: void compressRGB(const std::vector<libcamera::Span<uint8_t>> &planes); void compressNV(const std::vector<libcamera::Span<uint8_t>> &planes); + libcamera::StreamConfiguration cfg_; + struct jpeg_compress_struct compress_; struct jpeg_error_mgr jerr_; @@ -42,4 +57,6 @@ private: bool nv_; bool nvSwap_; + + Thumbnailer thumbnailer_; }; diff --git a/src/android/jpeg/generic_post_processor_jpeg.cpp b/src/android/jpeg/generic_post_processor_jpeg.cpp new file mode 100644 index 00000000..890f6972 --- /dev/null +++ b/src/android/jpeg/generic_post_processor_jpeg.cpp @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * + * generic_post_processor_jpeg.cpp - Generic JPEG Post Processor + */ + +#include "encoder_libjpeg.h" +#include "post_processor_jpeg.h" + +void PostProcessorJpeg::SetEncoder() +{ + encoder_ = std::make_unique<EncoderLibJpeg>(); +} diff --git a/src/android/jpeg/meson.build b/src/android/jpeg/meson.build new file mode 100644 index 00000000..8606acc4 --- /dev/null +++ b/src/android/jpeg/meson.build @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: CC0-1.0 + +android_hal_sources += files([ + 'exif.cpp', + 'post_processor_jpeg.cpp']) + +platform = get_option('android_platform') +if platform == 'generic' + android_hal_sources += files(['encoder_libjpeg.cpp', + 'generic_post_processor_jpeg.cpp', + 'thumbnailer.cpp']) +elif platform == 'cros' + android_hal_sources += files(['cros_post_processor_jpeg.cpp', + 'encoder_jea.cpp']) + android_deps += [dependency('libcros_camera')] +endif diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index d72ebc3c..7ceba60e 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -9,10 +9,10 @@ #include <chrono> +#include "../android_framebuffer.h" #include "../camera_device.h" #include "../camera_metadata.h" #include "../camera_request.h" -#include "encoder_libjpeg.h" #include "exif.h" #include <libcamera/base/log.h> @@ -44,60 +44,11 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg, streamSize_ = outCfg.size; - thumbnailer_.configure(inCfg.size, inCfg.pixelFormat); - - encoder_ = std::make_unique<EncoderLibJpeg>(); + SetEncoder(); return encoder_->configure(inCfg); } -void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, - const Size &targetSize, - unsigned int quality, - std::vector<unsigned char> *thumbnail) -{ - /* Stores the raw scaled-down thumbnail bytes. */ - std::vector<unsigned char> rawThumbnail; - - thumbnailer_.createThumbnail(source, targetSize, &rawThumbnail); - - StreamConfiguration thCfg; - thCfg.size = targetSize; - thCfg.pixelFormat = thumbnailer_.pixelFormat(); - int ret = thumbnailEncoder_.configure(thCfg); - - if (!rawThumbnail.empty() && !ret) { - /* - * \todo Avoid value-initialization of all elements of the - * vector. - */ - thumbnail->resize(rawThumbnail.size()); - - /* - * Split planes manually as the encoder expects a vector of - * planes. - * - * \todo Pass a vector of planes directly to - * Thumbnailer::createThumbnailer above and remove the manual - * planes split from here. - */ - std::vector<Span<uint8_t>> thumbnailPlanes; - const PixelFormatInfo &formatNV12 = PixelFormatInfo::info(formats::NV12); - size_t yPlaneSize = formatNV12.planeSize(targetSize, 0); - size_t uvPlaneSize = formatNV12.planeSize(targetSize, 1); - thumbnailPlanes.push_back({ rawThumbnail.data(), yPlaneSize }); - thumbnailPlanes.push_back({ rawThumbnail.data() + yPlaneSize, uvPlaneSize }); - - int jpeg_size = thumbnailEncoder_.encode(thumbnailPlanes, - *thumbnail, {}, quality); - thumbnail->resize(jpeg_size); - - LOG(JPEG, Debug) - << "Thumbnail compress returned " - << jpeg_size << " bytes"; - } -} - void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBuffer) { ASSERT(encoder_); @@ -164,8 +115,8 @@ void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBu if (thumbnailSize != Size(0, 0)) { std::vector<unsigned char> thumbnail; - generateThumbnail(source, thumbnailSize, quality, &thumbnail); - if (!thumbnail.empty()) + ret = encoder_->generateThumbnail(source, thumbnailSize, quality, &thumbnail); + if (ret > 0 && !thumbnail.empty()) exif.setThumbnail(thumbnail, Exif::Compression::JPEG); } @@ -194,8 +145,7 @@ void PostProcessorJpeg::process(Camera3RequestDescriptor::StreamBuffer *streamBu const uint8_t quality = ret ? *entry.data.u8 : 95; resultMetadata->addEntry(ANDROID_JPEG_QUALITY, quality); - int jpeg_size = encoder_->encode(source, destination->plane(0), - exif.data(), quality); + int jpeg_size = encoder_->encode(streamBuffer, exif.data(), quality); if (jpeg_size < 0) { LOG(JPEG, Error) << "Failed to encode stream image"; processComplete.emit(streamBuffer, PostProcessor::Status::Error); diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h index 98309b01..a09f8798 100644 --- a/src/android/jpeg/post_processor_jpeg.h +++ b/src/android/jpeg/post_processor_jpeg.h @@ -8,11 +8,11 @@ #pragma once #include "../post_processor.h" -#include "encoder_libjpeg.h" -#include "thumbnailer.h" #include <libcamera/geometry.h> +#include "encoder.h" + class CameraDevice; class PostProcessorJpeg : public PostProcessor @@ -25,14 +25,9 @@ public: void process(Camera3RequestDescriptor::StreamBuffer *streamBuffer) override; private: - void generateThumbnail(const libcamera::FrameBuffer &source, - const libcamera::Size &targetSize, - unsigned int quality, - std::vector<unsigned char> *thumbnail); + void SetEncoder(); CameraDevice *const cameraDevice_; std::unique_ptr<Encoder> encoder_; libcamera::Size streamSize_; - EncoderLibJpeg thumbnailEncoder_; - Thumbnailer thumbnailer_; }; diff --git a/src/android/meson.build b/src/android/meson.build index 75b4bf20..026b8b3c 100644 --- a/src/android/meson.build +++ b/src/android/meson.build @@ -38,6 +38,7 @@ endif android_deps += [libyuv_dep] android_hal_sources = files([ + 'android_framebuffer.cpp', 'camera3_hal.cpp', 'camera_capabilities.cpp', 'camera_device.cpp', @@ -47,10 +48,6 @@ android_hal_sources = files([ 'camera_ops.cpp', 'camera_request.cpp', 'camera_stream.cpp', - 'jpeg/encoder_libjpeg.cpp', - 'jpeg/exif.cpp', - 'jpeg/post_processor_jpeg.cpp', - 'jpeg/thumbnailer.cpp', 'yuv/post_processor_yuv.cpp' ]) @@ -58,6 +55,7 @@ android_cpp_args = [] subdir('cros') subdir('mm') +subdir('jpeg') android_camera_metadata_sources = files([ 'metadata/camera_metadata.c', diff --git a/src/android/mm/cros_frame_buffer_allocator.cpp b/src/android/mm/cros_frame_buffer_allocator.cpp index 52e8c180..163c5d75 100644 --- a/src/android/mm/cros_frame_buffer_allocator.cpp +++ b/src/android/mm/cros_frame_buffer_allocator.cpp @@ -14,6 +14,7 @@ #include "libcamera/internal/framebuffer.h" +#include "../android_framebuffer.h" #include "../camera_device.h" #include "../frame_buffer_allocator.h" #include "cros-camera/camera_buffer_manager.h" @@ -47,11 +48,11 @@ public: { } - std::unique_ptr<libcamera::FrameBuffer> + std::unique_ptr<AndroidFrameBuffer> allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage); }; -std::unique_ptr<libcamera::FrameBuffer> +std::unique_ptr<AndroidFrameBuffer> PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage) @@ -80,9 +81,11 @@ PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, plane.length = cros::CameraBufferManager::GetPlaneSize(handle, i); } - return std::make_unique<FrameBuffer>( - std::make_unique<CrosFrameBufferData>(std::move(scopedHandle)), - planes); + auto fb = std::make_unique<AndroidFrameBuffer>(handle, + std::make_unique<CrosFrameBufferData>(std::move(scopedHandle)), + planes); + + return fb; } PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION diff --git a/src/android/mm/generic_frame_buffer_allocator.cpp b/src/android/mm/generic_frame_buffer_allocator.cpp index acb2fa2b..c79b7b10 100644 --- a/src/android/mm/generic_frame_buffer_allocator.cpp +++ b/src/android/mm/generic_frame_buffer_allocator.cpp @@ -18,6 +18,7 @@ #include <hardware/gralloc.h> #include <hardware/hardware.h> +#include "../android_framebuffer.h" #include "../camera_device.h" #include "../frame_buffer_allocator.h" @@ -77,7 +78,7 @@ public: ~Private() override; - std::unique_ptr<libcamera::FrameBuffer> + std::unique_ptr<AndroidFrameBuffer> allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage); private: @@ -92,7 +93,7 @@ PlatformFrameBufferAllocator::Private::~Private() gralloc_close(allocDevice_); } -std::unique_ptr<libcamera::FrameBuffer> +std::unique_ptr<AndroidFrameBuffer> PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, const libcamera::Size &size, uint32_t usage) @@ -135,9 +136,9 @@ PlatformFrameBufferAllocator::Private::allocate(int halPixelFormat, offset += planeSize; } - return std::make_unique<FrameBuffer>( - std::make_unique<GenericFrameBufferData>(allocDevice_, handle), - planes); + return std::make_unique<AndroidFrameBuffer>(handle, + std::make_unique<GenericFrameBufferData>(allocDevice_, handle), + planes); } PUBLIC_FRAME_BUFFER_ALLOCATOR_IMPLEMENTATION