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([