Patch Detail
Show a patch.
GET /api/1.1/patches/10272/?format=api
{ "id": 10272, "url": "https://patchwork.libcamera.org/api/1.1/patches/10272/?format=api", "web_url": "https://patchwork.libcamera.org/patch/10272/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20201027212447.131431-4-email@uajain.com>", "date": "2020-10-27T21:24:47", "name": "[libcamera-devel,v2,3/3] android: jpeg: post_processor_jpeg: Embed thumbnail into Exif metadata", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "210dacd625477b7a4aac6e5dee38b2bcd37e0a30", "submitter": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/people/1/?format=api", "name": "Umang Jain", "email": "email@uajain.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/10272/mbox/", "series": [ { "id": 1422, "url": "https://patchwork.libcamera.org/api/1.1/series/1422/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1422", "date": "2020-10-27T21:24:44", "name": "android: jpeg: exif: Embed a JPEG-encoded thumbnail", "version": 2, "mbox": "https://patchwork.libcamera.org/series/1422/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/10272/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/10272/checks/", "tags": {}, "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 7F615C3B5C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 27 Oct 2020 21:25:07 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4C28A62217;\n\tTue, 27 Oct 2020 22:25:07 +0100 (CET)", "from mail.uajain.com (static.126.159.217.95.clients.your-server.de\n\t[95.217.159.126])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7BA4F6216C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 27 Oct 2020 22:25:05 +0100 (CET)" ], "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=uajain.com header.i=@uajain.com\n\theader.b=\"H9Kgq3pn\"; dkim-atps=neutral", "From": "Umang Jain <email@uajain.com>", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=uajain.com; s=mail;\n\tt=1603833905; bh=zZN38HVOZfCYW8HQqMLkBMj1+5ocwg133e5pxkpY7RU=;\n\th=From:To:Cc:Subject:In-Reply-To:References;\n\tb=H9Kgq3pnC28ioRBVLBRs6vsy5BuTnER2dYtroYMQ5nCjIheKRHqfZaeX88bmn/fQb\n\tQJPzrq5ftM17T/s6cXwsWZ69uXe81KJlO86qPE1fewbCqNWEeJonBGQSdp9OJGzwEK\n\ttl8K7zL9HPB0R+mmJcgE+M8RqOZmedsZgsjrDyeUzvShTwxPmnJJFdRMgqsXSEFpad\n\tLHMFUBJ/v4/8RYM2l3XBsnOs01srfd2WJVkE/eCBRXFNsTMydRHjSHI/+1jMCzgCOw\n\tCDFG0BXjnFjMiiupXv+Tmgok6TuZ1koPkQyQNChft81SFuefbMIOgL7WPzTFM2Kvfv\n\t9FPkJPdt9c2OA==", "To": "libcamera-devel@lists.libcamera.org", "Date": "Wed, 28 Oct 2020 02:54:47 +0530", "Message-Id": "<20201027212447.131431-4-email@uajain.com>", "In-Reply-To": "<20201027212447.131431-1-email@uajain.com>", "References": "<20201027212447.131431-1-email@uajain.com>", "Mime-Version": "1.0", "Subject": "[libcamera-devel] [PATCH v2 3/3] android: jpeg:\n\tpost_processor_jpeg: Embed thumbnail into Exif 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>", "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>" }, "content": "Embed a Jpeg-encoded thumbnail into Exif metadata using the Thumbnailer\nclass that got introduced.\n\nIntroduce a helper function in Exif class for setting the thumbnail\ndata. Set the EXIF_TAG_COMPRESSION to '6' to denote that the thumbnail\nis jpeg-compressed, as mentioned in Exif v2.31.\n\nSigned-off-by: Umang Jain <email@uajain.com>\n---\n src/android/jpeg/exif.cpp | 24 ++++++++++++++++-\n src/android/jpeg/exif.h | 2 ++\n src/android/jpeg/post_processor_jpeg.cpp | 34 ++++++++++++++++++++++++\n src/android/jpeg/post_processor_jpeg.h | 8 +++++-\n 4 files changed, 66 insertions(+), 2 deletions(-)", "diff": "diff --git a/src/android/jpeg/exif.cpp b/src/android/jpeg/exif.cpp\nindex d21534a..6ac52c6 100644\n--- a/src/android/jpeg/exif.cpp\n+++ b/src/android/jpeg/exif.cpp\n@@ -75,8 +75,16 @@ Exif::~Exif()\n \tif (exifData_)\n \t\tfree(exifData_);\n \n-\tif (data_)\n+\tif (data_) {\n+\t\t/*\n+\t\t * Reset thumbnail data to avoid getting double-freed by\n+\t\t * libexif. It is owned by the caller (i.e. PostProcessorJpeg).\n+\t\t */\n+\t\tdata_->data = nullptr;\n+\t\tdata_->size = 0;\n+\n \t\texif_data_unref(data_);\n+\t}\n \n \tif (mem_)\n \t\texif_mem_unref(mem_);\n@@ -268,6 +276,20 @@ void Exif::setOrientation(int orientation)\n \tsetShort(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);\n }\n \n+/*\n+ * The thumbnail data should remain valid until the Exif object is destroyed.\n+ * Failing to do so, might result in no thumbnail data being set even after a\n+ * call to Exif::setThumbnail().\n+ */\n+void Exif::setThumbnail(Span<const unsigned char> thumbnail,\n+\t\t\tuint16_t compression)\n+{\n+\tdata_->data = const_cast<unsigned char *>(thumbnail.data());\n+\tdata_->size = thumbnail.size();\n+\n+\tsetShort(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);\n+}\n+\n [[nodiscard]] int Exif::generate()\n {\n \tif (exifData_) {\ndiff --git a/src/android/jpeg/exif.h b/src/android/jpeg/exif.h\nindex 12c27b6..6987b31 100644\n--- a/src/android/jpeg/exif.h\n+++ b/src/android/jpeg/exif.h\n@@ -26,6 +26,8 @@ public:\n \n \tvoid setOrientation(int orientation);\n \tvoid setSize(const libcamera::Size &size);\n+\tvoid setThumbnail(libcamera::Span<const unsigned char> thumbnail,\n+\t\t\t uint16_t compression);\n \tvoid setTimestamp(time_t timestamp);\n \n \tlibcamera::Span<const uint8_t> data() const { return { exifData_, size_ }; }\ndiff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp\nindex c56f1b2..a0db793 100644\n--- a/src/android/jpeg/post_processor_jpeg.cpp\n+++ b/src/android/jpeg/post_processor_jpeg.cpp\n@@ -39,11 +39,41 @@ int PostProcessorJpeg::configure(const StreamConfiguration &inCfg,\n \t}\n \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 \treturn encoder_->configure(inCfg);\n }\n \n+void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source,\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+\n+\tif (!rawThumbnail.empty()) {\n+\t\tthumbnail->resize(rawThumbnail.size());\n+\n+\t\tint jpeg_size = thumbnailEncoder_.encode(rawThumbnail,\n+\t\t\t\t\t\t\t *thumbnail, { });\n+\t\tthumbnail->resize(jpeg_size);\n+\n+\t\tLOG(JPEG, Debug)\n+\t\t\t<< \"Thumbnail compress returned \"\n+\t\t\t<< jpeg_size << \" bytes\";\n+\t}\n+}\n+\n int PostProcessorJpeg::process(const FrameBuffer &source,\n \t\t\t Span<uint8_t> destination,\n \t\t\t CameraMetadata *metadata)\n@@ -64,6 +94,10 @@ int PostProcessorJpeg::process(const FrameBuffer &source,\n \t * second, it is good enough.\n \t */\n \texif.setTimestamp(std::time(nullptr));\n+\tstd::vector<unsigned char> thumbnail;\n+\tgenerateThumbnail(source, &thumbnail);\n+\tif(!thumbnail.empty())\n+\t\texif.setThumbnail(thumbnail, 6);\n \tif (exif.generate() != 0)\n \t\tLOG(JPEG, Error) << \"Failed to generate valid EXIF data\";\n \ndiff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h\nindex 3706cec..5afa831 100644\n--- a/src/android/jpeg/post_processor_jpeg.h\n+++ b/src/android/jpeg/post_processor_jpeg.h\n@@ -8,12 +8,13 @@\n #define __ANDROID_POST_PROCESSOR_JPEG_H__\n \n #include \"../post_processor.h\"\n+#include \"encoder_libjpeg.h\"\n+#include \"thumbnailer.h\"\n \n #include <libcamera/geometry.h>\n \n #include \"libcamera/internal/buffer.h\"\n \n-class Encoder;\n class CameraDevice;\n \n class PostProcessorJpeg : public PostProcessor\n@@ -28,9 +29,14 @@ public:\n \t\t CameraMetadata *metadata) override;\n \n private:\n+\tvoid generateThumbnail(const libcamera::FrameBuffer &source,\n+\t\t\t std::vector<unsigned char> *thumbnail);\n+\n \tCameraDevice *const cameraDevice_;\n \tstd::unique_ptr<Encoder> encoder_;\n \tlibcamera::Size streamSize_;\n+\tEncoderLibJpeg thumbnailEncoder_;\n+\tThumbnailer thumbnailer_;\n };\n \n #endif /* __ANDROID_POST_PROCESSOR_JPEG_H__ */\n", "prefixes": [ "libcamera-devel", "v2", "3/3" ] }