[{"id":14781,"web_url":"https://patchwork.libcamera.org/comment/14781/","msgid":"<20210126131758.qtsgektuer3mfqzw@uno.localdomain>","date":"2021-01-26T13:17:58","subject":"Re: [libcamera-devel] [PATCH v5 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 Tue, Jan 26, 2021 at 07:28:23PM +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 v5:\n> - add metadata entries to availableResultKeys and add the necessary\n>   bytes to the static metadata pack size\n\nI don't see it in this patch, am I missing it ?\n\nThanks\n  j\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            |  8 +++--\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, 41 insertions(+), 42 deletions(-)\n>\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index 096c2463..f0a24514 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -1918,7 +1918,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> @@ -1926,10 +1926,12 @@ 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) = 4 bytes\n> -\t * Total bytes for JPEG metadata: 73\n> +\t * ANDROID_JPEG_THUMBNAIL_QUALITY (byte) = 1 byte\n> +\t * ANDROID_JPEG_THUMBNAIL_SIZE (int32 x 2) = 8 bytes\n> +\t * Total bytes for JPEG metadata: 82\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 7e49e9d9..e990ba04 100644\n> --- a/src/android/jpeg/post_processor_jpeg.cpp\n> +++ b/src/android/jpeg/post_processor_jpeg.cpp\n> @@ -44,12 +44,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> @@ -57,14 +51,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> @@ -129,6 +129,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> @@ -144,11 +166,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 3B6ECBD808\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 26 Jan 2021 13:17:40 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 166C968302;\n\tTue, 26 Jan 2021 14:17:40 +0100 (CET)","from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net\n\t[217.70.183.196])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E8EAC682EC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 Jan 2021 14:17:38 +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 relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 6C00AE0011;\n\tTue, 26 Jan 2021 13:17:38 +0000 (UTC)"],"X-Originating-IP":"93.34.118.233","Date":"Tue, 26 Jan 2021 14:17:58 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<20210126131758.qtsgektuer3mfqzw@uno.localdomain>","References":"<20210126102825.147026-1-paul.elder@ideasonboard.com>\n\t<20210126102825.147026-7-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210126102825.147026-7-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v5 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>"}}]