From patchwork Fri Jan 22 09:23:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hirokazu Honda X-Patchwork-Id: 10942 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 A278ABD808 for ; Fri, 22 Jan 2021 09:23:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1C29B6822F; Fri, 22 Jan 2021 10:23:45 +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="NN5F7kWp"; dkim-atps=neutral Received: from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com [IPv6:2607:f8b0:4864:20::102a]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A96D6681DF for ; Fri, 22 Jan 2021 10:23:43 +0100 (CET) Received: by mail-pj1-x102a.google.com with SMTP id e6so3377431pjj.1 for ; Fri, 22 Jan 2021 01:23:43 -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:mime-version :content-transfer-encoding; bh=jUbURkHoqZRN4MBSE8Edz5lGPkBFHeRc3jP1R9FJXS0=; b=NN5F7kWpbm7muYCgyzMVAGg09Qz1sRWYvz1EH24TlCeLQsR+TW6T0AM3Y6b/rRJEP1 PIm62kUjcJIIZ6MYHKflLlijguGjczC0fL1Q1EtRXA90ImvBEQb8oaHopsnnCHbD8YUc XZDxtHQFFwfKubktMCJSDGHZFDrzIWQHM4nQM= 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:mime-version :content-transfer-encoding; bh=jUbURkHoqZRN4MBSE8Edz5lGPkBFHeRc3jP1R9FJXS0=; b=AvDr9XTLeujF5PaCBOIZOjWgHtVOBqCnvZhsKpivqlCyj/rD/Qri35ux2d51BZwJJS DNARmMWTgBUFi2V0xlsSGaOPaNBYKv0NmDV6HMZLKLe1Sd3NwIqbeOh02xF58RwMTf5U sDLg7WuJYunteChgNmKUQdzuXpcBpwjhepbJqcaGwMk33CBKDlTAAFrWr/deWjrZHjH6 zRfG5/3CGe2ry5M2tIcoQCLC876rKB2QxMPqwaDqZ7l4xr9DYY6Q0wBSWqPFvie5SwkZ YtkfX3gXltRPtwhRm05Gk2YdibYR+WUUAv5owa8hT1DSW6YmUp27dKF4GJGFNvXdQfpC ThOA== X-Gm-Message-State: AOAM533BGGjqUYmIJszjon1CGs1gs0e8/GhYCTH6WCZkeit579Gl6y5f bsDJjJZfnwldGioZwQn10y+j1nPpzQ5eEA== X-Google-Smtp-Source: ABdhPJxc/lSQEq5f+e0gRyhPeGlqStqW3oanoKMivaVP2PnMJ+pDlG7b2svyNw3PIdqJuR+Eb1Javg== X-Received: by 2002:a17:90b:1b50:: with SMTP id nv16mr4105789pjb.153.1611307421834; Fri, 22 Jan 2021 01:23:41 -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.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jan 2021 01:23:40 -0800 (PST) From: Hirokazu Honda To: libcamera-devel@lists.libcamera.org Date: Fri, 22 Jan 2021 09:23:34 +0000 Message-Id: <20210122092335.254626-1-hiroh@chromium.org> X-Mailer: git-send-email 2.30.0.280.ga3ce27912f-goog MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 | 5 +++-- src/android/camera_stream.h | 5 +++-- src/android/jpeg/post_processor_jpeg.cpp | 7 ++++--- src/android/jpeg/post_processor_jpeg.h | 2 +- src/android/post_processor.h | 3 ++- 5 files changed, 13 insertions(+), 9 deletions(-) -- 2.30.0.280.ga3ce27912f-goog diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp index dba351a4..33d0e005 100644 --- a/src/android/camera_stream.cpp +++ b/src/android/camera_stream.cpp @@ -96,12 +96,13 @@ int CameraStream::configure() } int CameraStream::process(const libcamera::FrameBuffer &source, - MappedCamera3Buffer *dest, CameraMetadata *metadata) + libcamera::MappedBuffer *destination, + CameraMetadata *metadata) { if (!postProcessor_) return 0; - return postProcessor_->process(source, dest->maps()[0], metadata); + return postProcessor_->process(source, destination, metadata); } FrameBuffer *CameraStream::getBuffer() diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h index cc9d5470..7d7b2b16 100644 --- a/src/android/camera_stream.h +++ b/src/android/camera_stream.h @@ -17,11 +17,11 @@ #include #include #include +#include #include class CameraDevice; class CameraMetadata; -class MappedCamera3Buffer; class PostProcessor; class CameraStream @@ -119,7 +119,8 @@ public: int configure(); int process(const libcamera::FrameBuffer &source, - MappedCamera3Buffer *dest, CameraMetadata *metadata); + libcamera::MappedBuffer *destination, + CameraMetadata *metadata); 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 436a50f8..2374716d 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -79,7 +79,7 @@ void PostProcessorJpeg::generateThumbnail(const FrameBuffer &source, } int PostProcessorJpeg::process(const FrameBuffer &source, - Span destination, + libcamera::MappedBuffer *destination, CameraMetadata *metadata) { if (!encoder_) @@ -107,7 +107,8 @@ int PostProcessorJpeg::process(const FrameBuffer &source, if (exif.generate() != 0) LOG(JPEG, Error) << "Failed to generate valid EXIF data"; - int jpeg_size = encoder_->encode(source, destination, exif.data()); + int jpeg_size = encoder_->encode(source, destination->maps()[0], + exif.data()); if (jpeg_size < 0) { LOG(JPEG, Error) << "Failed to encode stream image"; return jpeg_size; @@ -125,7 +126,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 5afa831c..68a38410 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, CameraMetadata *metadata) override; private: diff --git a/src/android/post_processor.h b/src/android/post_processor.h index e0f91880..368e0fe5 100644 --- a/src/android/post_processor.h +++ b/src/android/post_processor.h @@ -7,6 +7,7 @@ #ifndef __ANDROID_POST_PROCESSOR_H__ #define __ANDROID_POST_PROCESSOR_H__ +#include #include #include #include @@ -21,7 +22,7 @@ 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, CameraMetadata *metadata) = 0; }; 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([