From 894ca69f60435e3402de5786682d621362979171 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 6 Sep 2021 16:25:06 +0300 Subject: android: jpeg: Support multi-planar buffers The JPEG post-processor uses MappedFrameBuffer to access pixel data, but only uses data from the first plane. Pass the vector of planes to the encode() function to correctly handle multi-planar formats (currently limited to NV12). Signed-off-by: Laurent Pinchart Acked-by: Umang Jain Tested-by: Umang Jain Reviewed-by: Hirokazu Honda Reviewed-by: Kieran Bingham --- src/android/jpeg/encoder_libjpeg.cpp | 19 +++++++++++-------- src/android/jpeg/encoder_libjpeg.h | 8 +++++--- src/android/jpeg/post_processor_jpeg.cpp | 2 +- src/android/jpeg/thumbnailer.cpp | 5 +++-- 4 files changed, 20 insertions(+), 14 deletions(-) (limited to 'src/android') diff --git a/src/android/jpeg/encoder_libjpeg.cpp b/src/android/jpeg/encoder_libjpeg.cpp index 807a0949..21a3b33d 100644 --- a/src/android/jpeg/encoder_libjpeg.cpp +++ b/src/android/jpeg/encoder_libjpeg.cpp @@ -103,9 +103,9 @@ int EncoderLibJpeg::configure(const StreamConfiguration &cfg) return 0; } -void EncoderLibJpeg::compressRGB(Span frame) +void EncoderLibJpeg::compressRGB(const std::vector> &planes) { - unsigned char *src = const_cast(frame.data()); + unsigned char *src = const_cast(planes[0].data()); /* \todo Stride information should come from buffer configuration. */ unsigned int stride = pixelFormatInfo_->stride(compress_.image_width, 0); @@ -121,7 +121,7 @@ void EncoderLibJpeg::compressRGB(Span frame) * Compress the incoming buffer from a supported NV format. * This naively unpacks the semi-planar NV12 to a YUV888 format for libjpeg. */ -void EncoderLibJpeg::compressNV(Span frame) +void EncoderLibJpeg::compressNV(const std::vector> &planes) { uint8_t tmprowbuf[compress_.image_width * 3]; @@ -143,8 +143,8 @@ void EncoderLibJpeg::compressNV(Span frame) unsigned int cb_pos = nvSwap_ ? 1 : 0; unsigned int cr_pos = nvSwap_ ? 0 : 1; - const unsigned char *src = frame.data(); - const unsigned char *src_c = src + y_stride * compress_.image_height; + const unsigned char *src = planes[0].data(); + const unsigned char *src_c = planes[1].data(); JSAMPROW row_pointer[1]; row_pointer[0] = &tmprowbuf[0]; @@ -188,11 +188,12 @@ int EncoderLibJpeg::encode(const FrameBuffer &source, Span dest, return frame.error(); } - return encode(frame.planes()[0], dest, exifData, quality); + return encode(frame.planes(), dest, exifData, quality); } -int EncoderLibJpeg::encode(Span src, Span dest, - Span exifData, unsigned int quality) +int EncoderLibJpeg::encode(const std::vector> &src, + Span dest, Span exifData, + unsigned int quality) { unsigned char *destination = dest.data(); unsigned long size = dest.size(); @@ -220,6 +221,8 @@ int EncoderLibJpeg::encode(Span src, Span dest, LOG(JPEG, Debug) << "JPEG Encode Starting:" << compress_.image_width << "x" << compress_.image_height; + ASSERT(src.size() == pixelFormatInfo_->numPlanes()); + if (nv_) compressNV(src); else diff --git a/src/android/jpeg/encoder_libjpeg.h b/src/android/jpeg/encoder_libjpeg.h index 61fbd1a6..45ffbd7f 100644 --- a/src/android/jpeg/encoder_libjpeg.h +++ b/src/android/jpeg/encoder_libjpeg.h @@ -9,6 +9,8 @@ #include "encoder.h" +#include + #include "libcamera/internal/formats.h" #include @@ -24,14 +26,14 @@ public: libcamera::Span destination, libcamera::Span exifData, unsigned int quality) override; - int encode(libcamera::Span source, + int encode(const std::vector> &planes, libcamera::Span destination, libcamera::Span exifData, unsigned int quality); private: - void compressRGB(libcamera::Span frame); - void compressNV(libcamera::Span frame); + void compressRGB(const std::vector> &planes); + void compressNV(const std::vector> &planes); struct jpeg_compress_struct compress_; struct jpeg_error_mgr jerr_; diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index 3160a784..68d74842 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -72,7 +72,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, */ thumbnail->resize(rawThumbnail.size()); - int jpeg_size = thumbnailEncoder_.encode(rawThumbnail, + int jpeg_size = thumbnailEncoder_.encode({ rawThumbnail }, *thumbnail, {}, quality); thumbnail->resize(jpeg_size); diff --git a/src/android/jpeg/thumbnailer.cpp b/src/android/jpeg/thumbnailer.cpp index 043c7b33..1fab8072 100644 --- a/src/android/jpeg/thumbnailer.cpp +++ b/src/android/jpeg/thumbnailer.cpp @@ -59,11 +59,12 @@ void Thumbnailer::createThumbnail(const FrameBuffer &source, const unsigned int tw = targetSize.width; const unsigned int th = targetSize.height; + ASSERT(frame.planes().size() == 2); ASSERT(tw % 2 == 0 && th % 2 == 0); /* Image scaling block implementing nearest-neighbour algorithm. */ - unsigned char *src = static_cast(frame.planes()[0].data()); - unsigned char *srcC = src + sh * sw; + unsigned char *src = frame.planes()[0].data(); + unsigned char *srcC = frame.planes()[1].data(); unsigned char *srcCb, *srcCr; unsigned char *dstY, *srcY; -- cgit v1.2.1