From patchwork Fri Jan 22 09:23:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 10943 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 A4210BD808 for ; Fri, 22 Jan 2021 09:23:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7330C68234; Fri, 22 Jan 2021 10:23:47 +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="Vur8YXST"; dkim-atps=neutral Received: from mail-pf1-x430.google.com (mail-pf1-x430.google.com [IPv6:2607:f8b0:4864:20::430]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 49F8468231 for ; Fri, 22 Jan 2021 10:23:45 +0100 (CET) Received: by mail-pf1-x430.google.com with SMTP id i63so3305793pfg.7 for ; Fri, 22 Jan 2021 01:23:45 -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=8Wq+PS/uRinNEcnYjMG14qJ4bHumshR/fp+X8IXeppQ=; b=Vur8YXSTNCx7+nJKokQndz1tL3OzvAz+q+S53RlC7MwTh8El38rsPnn2GWW2Kgc449 1UXvYowbiUePvDx0oQ9s4uiKc7ECh7KV4DOFgxIJLLM+cQKPcsQ3dOAWUIjzSqJ0N8/K w0ECrjOMESxMWvmRX+gZ0vyp/wPQPqU0gmpOc= 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=8Wq+PS/uRinNEcnYjMG14qJ4bHumshR/fp+X8IXeppQ=; b=cCas60LLj8ARB8gf1vfsTK6iNB/T7ZDEf5rdrSTVrv5tguN/n9NmYYJXQNpR5ySbYi tPV08B+fO/5n7xRyBQanky1rCfRheJ4EpcRwMUkF+7Te4bGC8S5W107ezHtuf6oqSZX2 +mBCaMH3FtpoUrNL+tITMrrIlfuEEax4YPERNmUBaUQqoM4H+YhBnStUyH6yLfW5k8QA GCC7eBUEvnnbOCol6qQEVkpG1HihnbChdm+vzk0F2S73w2J+FfGJMSbGXUjeyDax8U7t 6sTCZ+/3ACp8zYW6wQ63e8aYsUvn8tNyaXe9CX2fEmbg+GFuGO9b7ApUPeE3YTbwBFfi srCA== X-Gm-Message-State: AOAM532+Mjy3d/iGhNPPQTijUai3V/mdoyGbGLSUGruBQBo/oaTXnsxS 5S9Qtl28oUIJqQcyNEx1zPmaOrt0rO25hTJI X-Google-Smtp-Source: ABdhPJzv2wo0ixciHGdUtJFyRgduZoLQb26TKIaIdRWTTRL1SErDNLG+mtZZqszEUbzagydRGEHJ0w== X-Received: by 2002:a62:8801:0:b029:1b9:c4af:8148 with SMTP id l1-20020a6288010000b02901b9c4af8148mr4151520pfd.18.1611307423460; Fri, 22 Jan 2021 01:23:43 -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 mv17sm8466031pjb.17.2021.01.22.01.23.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jan 2021 01:23:42 -0800 (PST) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Fri, 22 Jan 2021 09:23:35 +0000 Message-Id: <20210122092335.254626-2-hiroh@chromium.org> X-Mailer: git-send-email 2.30.0.280.ga3ce27912f-goog In-Reply-To: <20210122092335.254626-1-hiroh@chromium.org> References: <20210122092335.254626-1-hiroh@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 | 120 +++++++++++++++++++ src/android/libyuv/post_processor_libyuv.h | 33 +++++ src/android/meson.build | 1 + 3 files changed, 154 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..7cfa0539 --- /dev/null +++ b/src/android/libyuv/post_processor_libyuv.cpp @@ -0,0 +1,120 @@ +/* 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 getNV12Length(Size size, unsigned int length[2]) +{ + 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); + } +} + +unsigned int getNV12Stride(Size size, unsigned int i) +{ + auto nv12Info = PixelFormatInfo::info(PixelFormat(formats::NV12)); + return nv12Info.stride(size.width, i, 1); +} +} // namespace + +PostProcessorLibyuv::PostProcessorLibyuv() = default; + +int PostProcessorLibyuv::configure(const StreamConfiguration &inCfg, + const StreamConfiguration &outCfg) +{ + if (inCfg.pixelFormat != outCfg.pixelFormat || + inCfg.size < outCfg.size) { + LOG(LIBYUV, Error) << "Only down-scaling is supported"; + return -EINVAL; + } + if (inCfg.pixelFormat == formats::NV12) { + LOG(LIBYUV, Error) << "Only NV12 is supported"; + return -EINVAL; + } + inCfg_ = inCfg; + outCfg_ = outCfg; + return 0; +} + +int PostProcessorLibyuv::process(const FrameBuffer &source, + libcamera::MappedBuffer *destination, + 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(), + getNV12Stride(inCfg_.size, 0), + sourceMapped.maps()[1].data(), + getNV12Stride(inCfg_.size, 1), + inCfg_.size.height, inCfg_.size.width, + destination->maps()[0].data(), + getNV12Stride(outCfg_.size, 0), + destination->maps()[1].data(), + getNV12Stride(outCfg_.size, 1), + outCfg_.size.width, outCfg_.size.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; + } + + unsigned int sourceLength[2] = {}; + unsigned int destinationLength[2] = {}; + getNV12Length(inCfg_.size, sourceLength); + getNV12Length(outCfg_.size, destinationLength); + + 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..860a664b --- /dev/null +++ b/src/android/libyuv/post_processor_libyuv.h @@ -0,0 +1,33 @@ +/* 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, + CameraMetadata *metadata) override; + +private: + bool IsValidNV12Buffers(const libcamera::FrameBuffer &source, + const libcamera::MappedBuffer &destination) const; + + libcamera::StreamConfiguration inCfg_; + libcamera::StreamConfiguration outCfg_; +}; + +#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([