From patchwork Wed Jan 27 04:44:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 11030 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 80A5BC0F2B for ; Wed, 27 Jan 2021 04:44:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3FA9968341; Wed, 27 Jan 2021 05:44:36 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="hCwFQ84k"; dkim-atps=neutral Received: from mail-pf1-x429.google.com (mail-pf1-x429.google.com [IPv6:2607:f8b0:4864:20::429]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D5227682D2 for ; Wed, 27 Jan 2021 05:44:34 +0100 (CET) Received: by mail-pf1-x429.google.com with SMTP id e19so396517pfh.6 for ; Tue, 26 Jan 2021 20:44:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vkQ3zqn8eZPgJ/taJ6jejMnMmn9Txr96lvcs6mV6P+w=; b=hCwFQ84kURil6fenC9IjJbLGMJCXC0IWlDeiT0mnIsE1ERINl/PLSvBoF1u+/AzzQ4 3iAptzBINQYITNWm2OHgEoqMeyizcoVHQwIFvpOoR+bq+o/nx/8gUSc7B/XJyWtwmULQ Qyk8G6ccDA57BlG6sqOoBA5Bp/LnRa7eIZ9z0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vkQ3zqn8eZPgJ/taJ6jejMnMmn9Txr96lvcs6mV6P+w=; b=FHSfWZGwZcxF81rHCbiKwLc4/wfHjEqtfonhY4xBRW0fbPKCeWkX63sUrOcDsjw7Tv jjRYCbm694A/SvXQTuxyJjVSv9ueFt1wW1tH1wkau2SO0upTg3LtXH9/5VXlgj+z1XLk U7ZcsowklNvZ4FV49gaWnuMcmFOwKqrJzayZvpvyCdRchJ8PJWKSIZpddT4JKKo3Rq+Y WR1G2PxQe4yZH/ub9p1Y6tAplYXu25hpKR1RGpHNxIErkL4jMHtbFsLkcK/CO8eYbbwv z+Z9HIx6c8aTQTIBAgGCbmTJGgzLAPuMmw4QKtarkwvNQ8QQX+s1yfP5IaDDf4pyUqx8 Qusw== X-Gm-Message-State: AOAM5324d4clkVHoOzqTJ1EeIccy6LmaxOjjJiTwoL07ua9qzl+kchM+ 1o0qQWydUDdPfySE2WSrnDhtulkooUxN1WZR X-Google-Smtp-Source: ABdhPJyOo7VuO9WFyfxXxdmtyAr9v7yhV5qVyq2vOOWRJKPMTPRmtzymv4QD0igJhS2klZhiAcwFEQ== X-Received: by 2002:a62:7d03:0:b029:1bb:5919:6dec with SMTP id y3-20020a627d030000b02901bb59196decmr8857613pfc.76.1611722673210; Tue, 26 Jan 2021 20:44:33 -0800 (PST) Received: from hiroh.c.googlers.com.com (128.141.236.35.bc.googleusercontent.com. [35.236.141.128]) by smtp.gmail.com with ESMTPSA id z3sm645920pfb.157.2021.01.26.20.44.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 Jan 2021 20:44:32 -0800 (PST) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Wed, 27 Jan 2021 04:44:24 +0000 Message-Id: <20210127044425.2193480-2-hiroh@chromium.org> X-Mailer: git-send-email 2.30.0.280.ga3ce27912f-goog In-Reply-To: <20210127044425.2193480-1-hiroh@chromium.org> References: <20210127044425.2193480-1-hiroh@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 1/2] android: post_processor: Change the type destination in process() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The type of the destination buffer in PostProcessor::process() is libcamera::Span. libcamera::Span is used for one dimension buffer (e.g. blob buffer). The destination can be multiple dimensions buffer (e.g. yuv frame). Therefore, this changes the type of the destination buffer to MappedFrameBuffer. Signed-off-by: Hirokazu Honda Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/android/camera_stream.cpp | 4 ++-- src/android/camera_stream.h | 6 ++++-- src/android/jpeg/post_processor_jpeg.cpp | 6 +++--- src/android/jpeg/post_processor_jpeg.h | 2 +- src/android/post_processor.h | 7 ++++--- 5 files changed, 14 insertions(+), 11 deletions(-) -- 2.30.0.280.ga3ce27912f-goog diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp index 4c8020e5..611ec0d1 100644 --- a/src/android/camera_stream.cpp +++ b/src/android/camera_stream.cpp @@ -96,14 +96,14 @@ int CameraStream::configure() } int CameraStream::process(const libcamera::FrameBuffer &source, - MappedCamera3Buffer *dest, + libcamera::MappedBuffer *destination, const CameraMetadata &requestMetadata, CameraMetadata *resultMetadata) { if (!postProcessor_) return 0; - return postProcessor_->process(source, dest->maps()[0], + return postProcessor_->process(source, destination, requestMetadata, resultMetadata); } diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h index 298ffbf6..73bac0ba 100644 --- a/src/android/camera_stream.h +++ b/src/android/camera_stream.h @@ -19,9 +19,10 @@ #include #include +#include + class CameraDevice; class CameraMetadata; -class MappedCamera3Buffer; class PostProcessor; class CameraStream @@ -119,9 +120,10 @@ public: int configure(); int process(const libcamera::FrameBuffer &source, - MappedCamera3Buffer *dest, + libcamera::MappedBuffer *destination, const CameraMetadata &requestMetadata, CameraMetadata *resultMetadata); + libcamera::FrameBuffer *getBuffer(); void putBuffer(libcamera::FrameBuffer *buffer); diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index cac0087b..74e81c6f 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -83,7 +83,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, } int PostProcessorJpeg::process(const FrameBuffer &source, - Span destination, + libcamera::MappedBuffer *destination, const CameraMetadata &requestMetadata, CameraMetadata *resultMetadata) { @@ -171,8 +171,8 @@ int PostProcessorJpeg::process(const FrameBuffer &source, ret = requestMetadata.getEntry(ANDROID_JPEG_QUALITY, &entry); const uint8_t quality = ret ? *entry.data.u8 : 95; resultMetadata->addEntry(ANDROID_JPEG_QUALITY, &quality, 1); + int jpeg_size = encoder_->encode(source, destination->maps()[0], exif.data(), quality); - int jpeg_size = encoder_->encode(source, destination, exif.data(), quality); if (jpeg_size < 0) { LOG(JPEG, Error) << "Failed to encode stream image"; return jpeg_size; @@ -190,7 +190,7 @@ int PostProcessorJpeg::process(const FrameBuffer &source, * \todo Investigate if the buffer size mismatch is an issue or * expected behaviour. */ - uint8_t *resultPtr = destination.data() + + uint8_t *resultPtr = destination->maps()[0].data() + cameraDevice_->maxJpegBufferSize() - sizeof(struct camera3_jpeg_blob); auto *blob = reinterpret_cast(resultPtr); diff --git a/src/android/jpeg/post_processor_jpeg.h b/src/android/jpeg/post_processor_jpeg.h index d2dfa450..7689de73 100644 --- a/src/android/jpeg/post_processor_jpeg.h +++ b/src/android/jpeg/post_processor_jpeg.h @@ -25,7 +25,7 @@ public: int configure(const libcamera::StreamConfiguration &incfg, const libcamera::StreamConfiguration &outcfg) override; int process(const libcamera::FrameBuffer &source, - libcamera::Span destination, + libcamera::MappedBuffer *destination, const CameraMetadata &requestMetadata, CameraMetadata *resultMetadata) override; diff --git a/src/android/post_processor.h b/src/android/post_processor.h index bda93bb4..f5c99f03 100644 --- a/src/android/post_processor.h +++ b/src/android/post_processor.h @@ -8,9 +8,10 @@ #define __ANDROID_POST_PROCESSOR_H__ #include -#include #include +#include + class CameraMetadata; class PostProcessor @@ -21,9 +22,9 @@ public: virtual int configure(const libcamera::StreamConfiguration &inCfg, const libcamera::StreamConfiguration &outCfg) = 0; virtual int process(const libcamera::FrameBuffer &source, - libcamera::Span destination, + libcamera::MappedBuffer *destination, const CameraMetadata &requestMetadata, - CameraMetadata *resultMetadata) = 0; + CameraMetadata *metadata) = 0; }; #endif /* __ANDROID_POST_PROCESSOR_H__ */ From patchwork Wed Jan 27 04:44:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 11031 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E2848C0F2B for ; Wed, 27 Jan 2021 04:44:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B05B568348; Wed, 27 Jan 2021 05:44:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="GWBafH3M"; dkim-atps=neutral Received: from mail-pf1-x432.google.com (mail-pf1-x432.google.com [IPv6:2607:f8b0:4864:20::432]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 64AC768344 for ; Wed, 27 Jan 2021 05:44:36 +0100 (CET) Received: by mail-pf1-x432.google.com with SMTP id w14so408815pfi.2 for ; Tue, 26 Jan 2021 20:44:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=h+BnWovUvPMa/lZlazdSEmTYiy9CcnlwWIlxHpOF7/s=; b=GWBafH3MmRfaaAG/goSDT8Lin2mdmZ8r5tP2wUVzNHoIzhUGEh4lvMAD9ZA4xnHJkD Z5H7iN8XsU0BmtRE7z6o+YDZer3c81qa2mFnIeu+MSQ/9fxBCgDuZkhpGAmpBcV4wo/k XySsYBmkxJ+SOhZn7Pwc1dKZsqICSHhDeCnyU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=h+BnWovUvPMa/lZlazdSEmTYiy9CcnlwWIlxHpOF7/s=; b=F14jpvlg9ieqc965uHez5nqAAA/0mB/LZ5V4sDyiKLQMAg/y5xpMaRbmbgm/rs10Qc ewoWXvPa7i0boTrUPh6eMwjSbXjA/UnwJZo0JD5IwFtGZVs2+90dOK1SzwWQPmiro0Ak AhqMvup6NegiJoqT/ts8Q8NReXfrdDwGUEANZnLuzcw5RzDTYnT3X06SjV6r77lV53kd oHknWHOOoCpdtIRYxklpAWTpKURQQMZk2A6biQMiEoxJiBK2rBe/mdjH3wSushMfYHFo aci7evj2Q8MjaVomuK6mn6fV8Wdu5uk/R2PcNa6Qq9yw1JJn5INwQ+foeYvUaac6cvRr t+Uw== X-Gm-Message-State: AOAM530cwKmDoXWoX6eq3x5fCMrwXqpXFAdwpN1OWpYcb/y2+n2CF9Na QcgOHyer7P0E0yfFSO8QdBvbrBz7o4cCRZQg X-Google-Smtp-Source: ABdhPJxhue4yleM35Q2qfcKt2XG/nv1wYerDgrl8655V+OoxH4ljDc3ZibJW3iH2/EdOWwecQVqmmA== X-Received: by 2002:a62:f207:0:b029:1c0:434b:cc14 with SMTP id m7-20020a62f2070000b02901c0434bcc14mr8685017pfh.11.1611722674764; Tue, 26 Jan 2021 20:44:34 -0800 (PST) Received: from hiroh.c.googlers.com.com (128.141.236.35.bc.googleusercontent.com. [35.236.141.128]) by smtp.gmail.com with ESMTPSA id z3sm645920pfb.157.2021.01.26.20.44.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 Jan 2021 20:44:34 -0800 (PST) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Wed, 27 Jan 2021 04:44:25 +0000 Message-Id: <20210127044425.2193480-3-hiroh@chromium.org> X-Mailer: git-send-email 2.30.0.280.ga3ce27912f-goog In-Reply-To: <20210127044425.2193480-1-hiroh@chromium.org> References: <20210127044425.2193480-1-hiroh@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/2] android: libyuv: Introduce PostProcessorLibyuv X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" This adds PostProcessorLibyuv. It supports NV12 buffer scaling. Signed-off-by: Hirokazu Honda --- src/android/libyuv/post_processor_libyuv.cpp | 126 +++++++++++++++++++ src/android/libyuv/post_processor_libyuv.h | 38 ++++++ src/android/meson.build | 1 + 3 files changed, 165 insertions(+) create mode 100644 src/android/libyuv/post_processor_libyuv.cpp create mode 100644 src/android/libyuv/post_processor_libyuv.h -- 2.30.0.280.ga3ce27912f-goog diff --git a/src/android/libyuv/post_processor_libyuv.cpp b/src/android/libyuv/post_processor_libyuv.cpp new file mode 100644 index 00000000..5f40fd25 --- /dev/null +++ b/src/android/libyuv/post_processor_libyuv.cpp @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * post_processor_libyuv.cpp - Post Processor using libyuv + */ + +#include "post_processor_libyuv.h" + +#include + +#include +#include +#include +#include +#include + +using namespace libcamera; + +LOG_DEFINE_CATEGORY(LIBYUV) + +namespace { +void getNV12LengthAndStride(Size size, unsigned int length[2], + unsigned int stride[2]) +{ + const auto nv12Info = PixelFormatInfo::info(PixelFormat(formats::NV12)); + for (unsigned int i = 0; i < 2; i++) { + const unsigned int vertSubSample = + nv12Info.planes[i].verticalSubSampling; + length[i] = nv12Info.stride(size.width, i, /*align=*/1) * + ((size.height + vertSubSample - 1) / vertSubSample); + stride[i] = nv12Info.stride(size.width, i, 1); + } +} +} // namespace + +PostProcessorLibyuv::PostProcessorLibyuv() = default; + +int PostProcessorLibyuv::configure(const StreamConfiguration &inCfg, + const StreamConfiguration &outCfg) +{ + if (inCfg.pixelFormat != outCfg.pixelFormat) { + LOG(LIBYUV, Error) + << "Pixel format conversion is not supported" + << "-In: " << inCfg.toString() + << "-Out: " << outCfg.toString(); + return -EINVAL; + } + if (inCfg.size < outCfg.size) { + LOG(LIBYUV, Error) << "Up-scaling is not supported" + << ", -In: " << inCfg.toString() + << ", -Out: " << outCfg.toString(); + return -EINVAL; + } + if (inCfg.pixelFormat == formats::NV12) { + LOG(LIBYUV, Error) << "Only NV12 is supported" + << ", -In: " << inCfg.toString() + << ", -Out: " << outCfg.toString(); + return -EINVAL; + } + + getNV12LengthAndStride(inCfg.size, sourceLength_, sourceStride_); + getNV12LengthAndStride(outCfg.size, destinationLength_, + destinationStride_); + return 0; +} + +int PostProcessorLibyuv::process(const FrameBuffer &source, + libcamera::MappedBuffer *destination, + const CameraMetadata & /*requestMetadata*/, + CameraMetadata * /*metadata*/) +{ + if (!IsValidNV12Buffers(source, *destination)) { + LOG(LIBYUV, Error) << "Invalid source and destination"; + return -EINVAL; + } + + const MappedFrameBuffer sourceMapped(&source, PROT_READ); + if (!sourceMapped.isValid()) { + LOG(LIBYUV, Error) << "Failed to mmap camera frame buffer"; + return -EINVAL; + } + + return 0 == libyuv::NV12Scale(sourceMapped.maps()[0].data(), + sourceStride_[0], + sourceMapped.maps()[1].data(), + sourceStride_[1], + sourceSize_.width, sourceSize_.height, + destination->maps()[0].data(), + destinationStride_[0], + destination->maps()[1].data(), + destinationStride_[1], + destinationSize_.width, + destinationSize_.height, + libyuv::FilterMode::kFilterBilinear); +} + +bool PostProcessorLibyuv::IsValidNV12Buffers( + const FrameBuffer &source, + const libcamera::MappedBuffer &destination) const +{ + if (source.planes().size() != 2u) { + LOG(LIBYUV, Error) << "The number of source planes is not 2"; + return false; + } + if (destination.maps().size() != 2u) { + LOG(LIBYUV, Error) + << "The number of destination planes is not 2"; + return false; + } + + if (source.planes()[0].length < sourceLength_[0] || + source.planes()[1].length < sourceLength_[1]) { + LOG(LIBYUV, Error) + << "The source planes lengths are too small"; + return false; + } + if (destination.maps()[0].size() < destinationLength_[0] || + destination.maps()[1].size() < destinationLength_[1]) { + LOG(LIBYUV, Error) + << "The destination planes lengths are too small"; + return false; + } + + return true; +} diff --git a/src/android/libyuv/post_processor_libyuv.h b/src/android/libyuv/post_processor_libyuv.h new file mode 100644 index 00000000..40c635a1 --- /dev/null +++ b/src/android/libyuv/post_processor_libyuv.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Google Inc. + * + * post_processor_libyuv.h - Post Processor using libyuv + */ +#ifndef __ANDROID_POST_PROCESSOR_LIBYUV_H__ +#define __ANDROID_POST_PROCESSOR_LIBYUV_H__ + +#include "../post_processor.h" + +class CameraDevice; + +class PostProcessorLibyuv : public PostProcessor +{ +public: + PostProcessorLibyuv(); + + int configure(const libcamera::StreamConfiguration &incfg, + const libcamera::StreamConfiguration &outcfg) override; + int process(const libcamera::FrameBuffer &source, + libcamera::MappedBuffer *destination, + const CameraMetadata & /*requestMetadata*/, + CameraMetadata *metadata) override; + +private: + bool IsValidNV12Buffers(const libcamera::FrameBuffer &source, + const libcamera::MappedBuffer &destination) const; + + libcamera::Size sourceSize_; + libcamera::Size destinationSize_; + unsigned int sourceLength_[2] = {}; + unsigned int destinationLength_[2] = {}; + unsigned int sourceStride_[2] = {}; + unsigned int destinationStride_[2] = {}; +}; + +#endif /* __ANDROID_POST_PROCESSOR_LIBYUV_H__ */ diff --git a/src/android/meson.build b/src/android/meson.build index 3d4d3be4..ff067d12 100644 --- a/src/android/meson.build +++ b/src/android/meson.build @@ -26,6 +26,7 @@ android_hal_sources = files([ 'jpeg/exif.cpp', 'jpeg/post_processor_jpeg.cpp', 'jpeg/thumbnailer.cpp', + 'libyuv/post_processor_libyuv.cpp' ]) android_camera_metadata_sources = files([