@@ -22,4 +22,9 @@ public:
libcamera::Span<uint8_t> destination,
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;
};
@@ -83,12 +83,23 @@ EncoderLibJpeg::~EncoderLibJpeg()
int EncoderLibJpeg::configure(const StreamConfiguration &cfg)
{
- const struct JPEGPixelFormatInfo info = findPixelInfo(cfg.pixelFormat);
+ thumbnailer_.configure(cfg.size, cfg.pixelFormat);
+ pixelFormat_ = cfg.pixelFormat;
+ size_ = cfg.size;
+
+ return configureEncoder(pixelFormat_, size_);
+}
+
+int EncoderLibJpeg::configureEncoder(libcamera::PixelFormat pixelFormat,
+ libcamera::Size size)
+{
+ const struct JPEGPixelFormatInfo info = findPixelInfo(pixelFormat);
+
if (info.colorSpace == JCS_UNKNOWN)
return -ENOTSUP;
- compress_.image_width = cfg.size.width;
- compress_.image_height = cfg.size.height;
+ compress_.image_width = size.width;
+ compress_.image_height = size.height;
compress_.in_color_space = info.colorSpace;
compress_.input_components = info.colorSpace == JCS_GRAYSCALE ? 1 : 3;
@@ -178,9 +189,62 @@ void EncoderLibJpeg::compressNV(const std::vector<Span<uint8_t>> &planes)
}
}
+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);
+
+ int ret = configureEncoder(thumbnailer_.pixelFormat(), targetSize);
+
+ 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)
{
+ configureEncoder(pixelFormat_, size_);
+
MappedFrameBuffer frame(&source, MappedFrameBuffer::MapFlag::Read);
if (!frame.isValid()) {
LOG(JPEG, Error) << "Failed to map FrameBuffer : "
@@ -15,6 +15,8 @@
#include <jpeglib.h>
+#include "thumbnailer.h"
+
class EncoderLibJpeg : public Encoder
{
public:
@@ -26,15 +28,27 @@ public:
libcamera::Span<uint8_t> destination,
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 configureEncoder(libcamera::PixelFormat pixelFormat,
+ libcamera::Size size);
+
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::PixelFormat pixelFormat_;
+ libcamera::Size size_;
+
struct jpeg_compress_struct compress_;
struct jpeg_error_mgr jerr_;
@@ -42,4 +56,6 @@ private:
bool nv_;
bool nvSwap_;
+
+ Thumbnailer thumbnailer_;
};
@@ -44,60 +44,11 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,
streamSize_ = outCfg.size;
- thumbnailer_.configure(inCfg.size, inCfg.pixelFormat);
-
encoder_ = std::make_unique<EncoderLibJpeg>();
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,9 @@ 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);
}
@@ -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,7 @@ 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);
-
CameraDevice *const cameraDevice_;
std::unique_ptr<Encoder> encoder_;
libcamera::Size streamSize_;
- EncoderLibJpeg thumbnailEncoder_;
- Thumbnailer thumbnailer_;
};
In the following patch, generateThumbnail will have a different implementation in the jea encoder. Therefore, this patch moves the generateThumbnail function from PostProcessorJpeg to Encoder. Signed-off-by: Harvey Yang <chenghaoyang@chromium.org> --- src/android/jpeg/encoder.h | 5 ++ src/android/jpeg/encoder_libjpeg.cpp | 70 +++++++++++++++++++++++- src/android/jpeg/encoder_libjpeg.h | 18 +++++- src/android/jpeg/post_processor_jpeg.cpp | 54 +----------------- src/android/jpeg/post_processor_jpeg.h | 11 +--- 5 files changed, 94 insertions(+), 64 deletions(-)