[{"id":14759,"web_url":"https://patchwork.libcamera.org/comment/14759/","msgid":"<20210125120911.m4apkn34rhmq7v57@uno.localdomain>","date":"2021-01-25T12:09:11","subject":"Re: [libcamera-devel] [PATCH v4 6/8] android: jpeg: Configure\n\tthumbnailer based on request metadata","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Paul,\n\nOn Mon, Jan 25, 2021 at 04:14:42PM +0900, Paul Elder wrote:\n> Configure the thumbnailer based on the thumbnail parameters given by the\n> android request metadata. Only the thumbnail encoder needs to be\n> configured, and since it is only used at post-processing time, move the\n> configuration out of the post-processor constructor and into the\n> processing step.\n>\n> Also set the following android result metadata tags:\n> - ANDROID_JPEG_THUMBNAIL_SIZE\n> - ANDROID_JPEG_THUMBNAIL_QUALITY\n>\n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>\n> ---\n> Changes in v4:\n> - cosmetic changes\n>\n> New in v3\n> - split from \"android: Set result metadata and EXIF fields based on\n>   request\"\n> ---\n>  src/android/camera_device.cpp            |  6 ++--\n>  src/android/jpeg/post_processor_jpeg.cpp | 43 +++++++++++++++++-------\n>  src/android/jpeg/post_processor_jpeg.h   |  1 +\n>  src/android/jpeg/thumbnailer.cpp         | 25 ++------------\n>  src/android/jpeg/thumbnailer.h           |  6 ++--\n>  5 files changed, 40 insertions(+), 41 deletions(-)\n>\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index 2cd3c8a1..3068f89f 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -1915,7 +1915,7 @@ CameraDevice::getResultMetadata(Camera3RequestDescriptor *descriptor,\n>\n>  \t/*\n>  \t * \\todo Keep this in sync with the actual number of entries.\n> -\t * Currently: 38 entries, 147 bytes\n> +\t * Currently: 40 entries, 156 bytes\n>  \t *\n>  \t * Reserve more space for the JPEG metadata set by the post-processor.\n>  \t * Currently: ANDROID_JPEG_SIZE (int32_t), ANDROID_JPEG_QUALITY (byte),\n> @@ -1923,11 +1923,13 @@ CameraDevice::getResultMetadata(Camera3RequestDescriptor *descriptor,\n>  \t * ANDROID_JPEG_GPS_PROCESSING_METHOD (byte x 32) = 32 bytes\n>  \t * ANDROID_JPEG_GPS_TIMESTAMP (int64) = 8 bytes\n>  \t * ANDROID_JPEG_ORIENTATION (int32_t) = 3 entries, 9 bytes.\n> +\t * ANDROID_JPEG_THUMBNAIL_QUALITY (byte) = 1 byte\n> +\t * ANDROID_JPEG_THUMBNAIL_SIZE (int32 x 2) = 8 bytes\n\nSame comment as the previous patch. The new tags should be added to\navailableResultKeys and the static metadata pack size updated\naccordingly.\n\n>  \t * ANDROID_LENS_APERTURE (float) = 4 bytes\n>  \t * ANDROID_LENS_FOCAL_LENGTH (float) = 4 bytes\n>  \t */\n>  \tstd::unique_ptr<CameraMetadata> resultMetadata =\n> -\t\tstd::make_unique<CameraMetadata>(38, 147);\n> +\t\tstd::make_unique<CameraMetadata>(40, 156);\n>  \tif (!resultMetadata->isValid()) {\n>  \t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n>  \t\treturn nullptr;\n> diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp\n> index 10c71a47..d35fe361 100644\n> --- a/src/android/jpeg/post_processor_jpeg.cpp\n> +++ b/src/android/jpeg/post_processor_jpeg.cpp\n> @@ -43,12 +43,6 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,\n>  \tstreamSize_ = outCfg.size;\n>\n>  \tthumbnailer_.configure(inCfg.size, inCfg.pixelFormat);\n> -\tStreamConfiguration thCfg = inCfg;\n> -\tthCfg.size = thumbnailer_.size();\n> -\tif (thumbnailEncoder_.configure(thCfg) != 0) {\n> -\t\tLOG(JPEG, Error) << \"Failed to configure thumbnail encoder\";\n> -\t\treturn -EINVAL;\n> -\t}\n>\n>  \tencoder_ = std::make_unique<EncoderLibJpeg>();\n>\n> @@ -56,14 +50,20 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,\n>  }\n>\n>  void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,\n> +\t\t\t\t\t  const Size &targetSize,\n>  \t\t\t\t\t  std::vector<unsigned char> *thumbnail)\n>  {\n>  \t/* Stores the raw scaled-down thumbnail bytes. */\n>  \tstd::vector<unsigned char> rawThumbnail;\n>\n> -\tthumbnailer_.createThumbnail(source, &rawThumbnail);\n> +\tthumbnailer_.createThumbnail(source, targetSize, &rawThumbnail);\n>\n> -\tif (!rawThumbnail.empty()) {\n> +\tStreamConfiguration thCfg;\n> +\tthCfg.size = targetSize;\n> +\tthCfg.pixelFormat = thumbnailer_.pixelFormat();\n> +\tint ret = thumbnailEncoder_.configure(thCfg);\n> +\n> +\tif (!rawThumbnail.empty() && !ret) {\n>  \t\t/*\n>  \t\t * \\todo Avoid value-initialization of all elements of the\n>  \t\t * vector.\n> @@ -127,6 +127,28 @@ int PostProcessorJpeg::process(const FrameBuffer &source,\n>  \t\t\t\t\t entry.data.i64, 1);\n>  \t}\n>\n> +\tret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_SIZE, &entry);\n> +\tif (ret) {\n> +\t\tconst int32_t *data = entry.data.i32;\n> +\t\tSize thumbnailSize = { static_cast<uint32_t>(data[0]),\n> +\t\t\t\t       static_cast<uint32_t>(data[1]) };\n> +\n> +\t\tif (thumbnailSize != Size(0, 0)) {\n> +\t\t\tstd::vector<unsigned char> thumbnail;\n> +\t\t\tgenerateThumbnail(source, thumbnailSize, &thumbnail);\n> +\t\t\tif (!thumbnail.empty())\n> +\t\t\t\texif.setThumbnail(thumbnail, Exif::Compression::JPEG);\n> +\t\t}\n> +\n> +\t\tresultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_SIZE, data, 2);\n> +\n> +\t\t/* \\todo Use this quality as a parameter to the encoder */\n> +\t\tret = requestMetadata.getEntry(ANDROID_JPEG_THUMBNAIL_QUALITY, &entry);\n> +\t\tif (ret)\n> +\t\t\tresultMetadata->addEntry(ANDROID_JPEG_THUMBNAIL_QUALITY,\n> +\t\t\t\t\t\t entry.data.u8, 1);\n> +\t}\n> +\n>  \tret = requestMetadata.getEntry(ANDROID_JPEG_GPS_COORDINATES, &entry);\n>  \tif (ret) {\n>  \t\texif.setGPSLocation(entry.data.d);\n> @@ -142,11 +164,6 @@ int PostProcessorJpeg::process(const FrameBuffer &source,\n>  \t\t\t\t\t entry.data.u8, entry.count);\n>  \t}\n>\n> -\tstd::vector<unsigned char> thumbnail;\n> -\tgenerateThumbnail(source, &thumbnail);\n> -\tif (!thumbnail.empty())\n> -\t\texif.setThumbnail(thumbnail, Exif::Compression::JPEG);\n> -\n>  \tif (exif.generate() != 0)\n>  \t\tLOG(JPEG, Error) << \"Failed to generate valid EXIF data\";\n>\n> diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h\n> index d721d1b9..660b79b4 100644\n> --- a/src/android/jpeg/post_processor_jpeg.h\n> +++ b/src/android/jpeg/post_processor_jpeg.h\n> @@ -31,6 +31,7 @@ public:\n>\n>  private:\n>  \tvoid generateThumbnail(const libcamera::FrameBuffer &source,\n> +\t\t\t       const libcamera::Size &targetSize,\n>  \t\t\t       std::vector<unsigned char> *thumbnail);\n>\n>  \tCameraDevice *const cameraDevice_;\n> diff --git a/src/android/jpeg/thumbnailer.cpp b/src/android/jpeg/thumbnailer.cpp\n> index 5374538a..f709d343 100644\n> --- a/src/android/jpeg/thumbnailer.cpp\n> +++ b/src/android/jpeg/thumbnailer.cpp\n> @@ -32,30 +32,11 @@ void Thumbnailer::configure(const Size &sourceSize, PixelFormat pixelFormat)\n>  \t\treturn;\n>  \t}\n>\n> -\ttargetSize_ = computeThumbnailSize();\n> -\n>  \tvalid_ = true;\n>  }\n>\n> -/*\n> - * The Exif specification recommends the width of the thumbnail to be a\n> - * multiple of 16 (section 4.8.1). Hence, compute the corresponding height\n> - * keeping the aspect ratio same as of the source.\n> - */\n> -Size Thumbnailer::computeThumbnailSize() const\n> -{\n> -\tunsigned int targetHeight;\n> -\tconstexpr unsigned int kTargetWidth = 160;\n> -\n> -\ttargetHeight = kTargetWidth * sourceSize_.height / sourceSize_.width;\n> -\n> -\tif (targetHeight & 1)\n> -\t\ttargetHeight++;\n> -\n> -\treturn Size(kTargetWidth, targetHeight);\n> -}\n> -\n>  void Thumbnailer::createThumbnail(const FrameBuffer &source,\n> +\t\t\t\t  const Size &targetSize,\n>  \t\t\t\t  std::vector<unsigned char> *destination)\n>  {\n>  \tMappedFrameBuffer frame(&source, PROT_READ);\n> @@ -73,8 +54,8 @@ void Thumbnailer::createThumbnail(const FrameBuffer &source,\n>\n>  \tconst unsigned int sw = sourceSize_.width;\n>  \tconst unsigned int sh = sourceSize_.height;\n> -\tconst unsigned int tw = targetSize_.width;\n> -\tconst unsigned int th = targetSize_.height;\n> +\tconst unsigned int tw = targetSize.width;\n> +\tconst unsigned int th = targetSize.height;\n>\n>  \tASSERT(tw % 2 == 0 && th % 2 == 0);\n>\n> diff --git a/src/android/jpeg/thumbnailer.h b/src/android/jpeg/thumbnailer.h\n> index 98f11833..4e9226c3 100644\n> --- a/src/android/jpeg/thumbnailer.h\n> +++ b/src/android/jpeg/thumbnailer.h\n> @@ -20,15 +20,13 @@ public:\n>  \tvoid configure(const libcamera::Size &sourceSize,\n>  \t\t       libcamera::PixelFormat pixelFormat);\n>  \tvoid createThumbnail(const libcamera::FrameBuffer &source,\n> +\t\t\t     const libcamera::Size &targetSize,\n>  \t\t\t     std::vector<unsigned char> *dest);\n> -\tconst libcamera::Size &size() const { return targetSize_; }\n> +\tconst libcamera::PixelFormat &pixelFormat() const { return pixelFormat_; }\n>\n>  private:\n> -\tlibcamera::Size computeThumbnailSize() const;\n> -\n>  \tlibcamera::PixelFormat pixelFormat_;\n>  \tlibcamera::Size sourceSize_;\n> -\tlibcamera::Size targetSize_;\n>\n>  \tbool valid_;\n>  };\n> --\n> 2.27.0\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 6924BC0F2B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 25 Jan 2021 12:08:53 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E5B26682C3;\n\tMon, 25 Jan 2021 13:08:52 +0100 (CET)","from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net\n\t[217.70.183.200])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8BF7A682BB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 25 Jan 2021 13:08:51 +0100 (CET)","from uno.localdomain (93-34-118-233.ip49.fastwebnet.it\n\t[93.34.118.233]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay7-d.mail.gandi.net (Postfix) with ESMTPSA id F1AE520009;\n\tMon, 25 Jan 2021 12:08:50 +0000 (UTC)"],"X-Originating-IP":"93.34.118.233","Date":"Mon, 25 Jan 2021 13:09:11 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<20210125120911.m4apkn34rhmq7v57@uno.localdomain>","References":"<20210125071444.26252-1-paul.elder@ideasonboard.com>\n\t<20210125071444.26252-7-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210125071444.26252-7-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 6/8] android: jpeg: Configure\n\tthumbnailer based on request metadata","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]