From patchwork Thu Mar 26 22:58:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 3345 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 32B2A605D2 for ; Thu, 26 Mar 2020 23:58:58 +0100 (CET) X-Halon-ID: 5e51ac23-6fb5-11ea-aeed-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de [79.202.35.146]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 5e51ac23-6fb5-11ea-aeed-005056917f90; Thu, 26 Mar 2020 23:58:55 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Thu, 26 Mar 2020 23:58:38 +0100 Message-Id: <20200326225844.4117712-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> References: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 1/7] libcamera: stream: Add StillCaptureRaw role 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: , X-List-Received-Date: Thu, 26 Mar 2020 22:58:58 -0000 Add a role for capturing high resolution, low frame rate, still images in RAW format. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- include/libcamera/stream.h | 1 + src/libcamera/stream.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index b1441f8ec6749fda..18142dc997bb8885 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -58,6 +58,7 @@ private: enum StreamRole { StillCapture, + StillCaptureRaw, VideoRecording, Viewfinder, }; diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index ea3d214271ad287a..ef16aaa1b2f4586a 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -361,6 +361,9 @@ std::string StreamConfiguration::toString() const * \var StillCapture * The stream is intended to capture high-resolution, high-quality still images * with low frame rate. The captured frames may be exposed with flash. + * \var StillCaptureRaw + * The stream is intended to capture high-resolution, raw still images with low + * frame rate. * \var VideoRecording * The stream is intended to capture video for the purpose of recording or * streaming. The video stream may produce a high frame rate and may be From patchwork Thu Mar 26 22:58:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 3346 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B2C4E605D2 for ; Thu, 26 Mar 2020 23:58:58 +0100 (CET) X-Halon-ID: 5eb454a0-6fb5-11ea-aeed-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de [79.202.35.146]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 5eb454a0-6fb5-11ea-aeed-005056917f90; Thu, 26 Mar 2020 23:58:55 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Thu, 26 Mar 2020 23:58:39 +0100 Message-Id: <20200326225844.4117712-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> References: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/7] cam: Add option to capture StillCaptureRaw stream 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: , X-List-Received-Date: Thu, 26 Mar 2020 22:58:59 -0000 Add a role name 'stillraw' to request a StillCaptureRaw stream. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- src/cam/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 7cdd215ba5398aec..718740f49762ec7b 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -155,7 +155,7 @@ int CamApp::parseOptions(int argc, char *argv[]) { KeyValueParser streamKeyValue; streamKeyValue.addOption("role", OptionString, - "Role for the stream (viewfinder, video, still)", + "Role for the stream (viewfinder, video, still, stillraw)", ArgumentRequired); streamKeyValue.addOption("width", OptionInteger, "Width in pixels", ArgumentRequired); @@ -219,6 +219,8 @@ int CamApp::prepareConfig() roles.push_back(StreamRole::VideoRecording); } else if (role == "still") { roles.push_back(StreamRole::StillCapture); + } else if (role == "stillraw") { + roles.push_back(StreamRole::StillCaptureRaw); } else { std::cerr << "Unknown stream role " << role << std::endl; From patchwork Thu Mar 26 22:58:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 3347 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7D49262D31 for ; Thu, 26 Mar 2020 23:58:59 +0100 (CET) X-Halon-ID: 5f08face-6fb5-11ea-aeed-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de [79.202.35.146]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 5f08face-6fb5-11ea-aeed-005056917f90; Thu, 26 Mar 2020 23:58:56 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Thu, 26 Mar 2020 23:58:40 +0100 Message-Id: <20200326225844.4117712-4-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> References: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 3/7] include: drm_fourcc: Add Bayer FourCC and modifiers 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: , X-List-Received-Date: Thu, 26 Mar 2020 22:59:01 -0000 Add Bayer format and modifiers for patch submitted for upstream inclusion. The formats have not been accepted upstream yet but is needed to progress with RAW capture support in libcamera. Intention is to merge this in libcamera and update the header file the upstream patch is picked up upstream. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Acked-by: Laurent Pinchart --- * Changes since v1 - Removed DNI label --- include/linux/drm_fourcc.h | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/include/linux/drm_fourcc.h b/include/linux/drm_fourcc.h index 4bb1bfe93d5f4390..69240dfe1df0df28 100644 --- a/include/linux/drm_fourcc.h +++ b/include/linux/drm_fourcc.h @@ -288,6 +288,62 @@ extern "C" { /* Compressed formats */ #define DRM_FORMAT_MJPEG fourcc_code('M', 'J', 'P', 'G') /* Motion-JPEG */ +/* + * Bayer formats + * + * Bayer formats contain green, red and blue components, with alternating lines + * of red and green, and blue and green pixels in different orders. For each + * block of 2x2 pixels there is one pixel with a red filter, two with a green + * filter, and one with a blue filter. The filters can be arranged in different + * patterns. + * + * For example, RGGB: + * row0: RGRGRGRG... + * row1: GBGBGBGB... + * row3: RGRGRGRG... + * row4: GBGBGBGB... + * ... + * + * Vendors have different methods to pack the sampling formats to increase data + * density. For this reason the fourcc only describes pixel sample size and the + * filter pattern for each block of 2x2 pixels. A modifier is needed to + * describe the memory layout. + * + * In addition to vendor modifiers for memory layout DRM_FORMAT_MOD_LINEAR may + * be used to describe a layout where all samples are placed consecutively in + * memory. If the sample does not fit inside a single byte, the sample storage + * is extended to the minimum number of (little endian) bytes that can hold the + * sample and any unused most-significant bits are defined as padding. + * + * For example, SRGGB10: + * Each 10-bit sample is contained in 2 consecutive little endian bytes, where + * the 6 most-significant bits are unused. + */ + +/* 8-bit Bayer formats */ +#define DRM_FORMAT_SRGGB8 fourcc_code('R', 'G', 'G', 'B') +#define DRM_FORMAT_SGRBG8 fourcc_code('G', 'R', 'B', 'G') +#define DRM_FORMAT_SGBRG8 fourcc_code('G', 'B', 'R', 'G') +#define DRM_FORMAT_SBGGR8 fourcc_code('B', 'A', '8', '1') + +/* 10-bit Bayer formats */ +#define DRM_FORMAT_SRGGB10 fourcc_code('R', 'G', '1', '0') +#define DRM_FORMAT_SGRBG10 fourcc_code('B', 'A', '1', '0') +#define DRM_FORMAT_SGBRG10 fourcc_code('G', 'B', '1', '0') +#define DRM_FORMAT_SBGGR10 fourcc_code('B', 'G', '1', '0') + +/* 12-bit Bayer formats */ +#define DRM_FORMAT_SRGGB12 fourcc_code('R', 'G', '1', '2') +#define DRM_FORMAT_SGRBG12 fourcc_code('B', 'A', '1', '2') +#define DRM_FORMAT_SGBRG12 fourcc_code('G', 'B', '1', '2') +#define DRM_FORMAT_SBGGR12 fourcc_code('B', 'G', '1', '2') + +/* 14-bit Bayer formats */ +#define DRM_FORMAT_SRGGB14 fourcc_code('R', 'G', '1', '4') +#define DRM_FORMAT_SGRBG14 fourcc_code('B', 'A', '1', '4') +#define DRM_FORMAT_SGBRG14 fourcc_code('G', 'B', '1', '4') +#define DRM_FORMAT_SBGGR14 fourcc_code('B', 'G', '1', '4') + /* * Format Modifiers: * @@ -311,6 +367,7 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 +#define DRM_FORMAT_MOD_VENDOR_MIPI 0x0a /* add more to the end as needed */ @@ -412,6 +469,16 @@ extern "C" { #define I915_FORMAT_MOD_Y_TILED_CCS fourcc_mod_code(INTEL, 4) #define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5) +/* + * IPU3 Bayer packing layout + * + * The IPU3 raw Bayer formats use a custom packing layout where there are no + * gaps between each 10-bit sample. It packs 25 pixels into 32 bytes leaving + * the 6 most significant bits in the last byte unused. The format is little + * endian. + */ +#define IPU3_FORMAT_MOD_PACKED fourcc_mod_code(INTEL, 8) + /* * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks * @@ -758,6 +825,33 @@ extern "C" { */ #define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) +/* Mobile Industry Processor Interface (MIPI) modifiers */ + +/* + * MIPI CSI-2 packing layout + * + * The CSI-2 RAW formats (for example Bayer) use a different packing layout + * depenindg on the sample size. + * + * - 10-bits per sample + * Every four consecutive samples are packed into 5 bytes. Each of the first 4 + * bytes contain the 8 high order bits of the pixels, and the 5th byte + * contains the 2 least-significant bits of each pixel, in the same order. + * + * - 12-bits per sample + * Every two consecutive samples are packed into three bytes. Each of the + * first two bytes contain the 8 high order bits of the pixels, and the third + * byte contains the four least-significant bits of each pixel, in the same + * order. + * + * - 14-bits per sample + * Every four consecutive samples are packed into seven bytes. Each of the + * first four bytes contain the eight high order bits of the pixels, and the + * three following bytes contains the six least-significant bits of each + * pixel, in the same order. + */ +#define MIPI_FORMAT_MOD_CSI2_PACKED fourcc_mod_code(MIPI, 1) + #if defined(__cplusplus) } #endif From patchwork Thu Mar 26 22:58:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 3348 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 08BC062D13 for ; Thu, 26 Mar 2020 23:58:59 +0100 (CET) X-Halon-ID: 5f67028a-6fb5-11ea-aeed-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de [79.202.35.146]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 5f67028a-6fb5-11ea-aeed-005056917f90; Thu, 26 Mar 2020 23:58:57 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Thu, 26 Mar 2020 23:58:41 +0100 Message-Id: <20200326225844.4117712-5-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> References: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 4/7] libcamera: FrameBuffer: Add a method to copy buffer content 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: , X-List-Received-Date: Thu, 26 Mar 2020 22:59:01 -0000 This method may be used to memory copy a whole FrameBuffer content from another buffer. The operation is not fast and should not be used without great care by pipelines. The intended use-case is to have an option to copy out RAW buffers from the middle of a pipeline. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- * Changes since v1 - Update documentation - s/NULL/nullptr/ * Changes since RFC - Make method member of FrameBuffer - Add documentation - s/out/dstmem/ and s/in/src/mem/ --- include/libcamera/buffer.h | 1 + src/libcamera/buffer.cpp | 68 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h index 8e5ec699e3925eee..ef3a3b36cd4e4e17 100644 --- a/include/libcamera/buffer.h +++ b/include/libcamera/buffer.h @@ -57,6 +57,7 @@ public: unsigned int cookie() const { return cookie_; } void setCookie(unsigned int cookie) { cookie_ = cookie; } + int copyFrom(const FrameBuffer *src); private: friend class Request; /* Needed to update request_. */ friend class V4L2VideoDevice; /* Needed to update metadata_. */ diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp index 673a63d3d1658190..93057568fc56a6f5 100644 --- a/src/libcamera/buffer.cpp +++ b/src/libcamera/buffer.cpp @@ -211,4 +211,72 @@ FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie) * core never modifies the buffer cookie. */ +/** + * \brief Copy the contents from another buffer + * \param[in] src Buffer to copy + * + * Copy the buffer contents and metadata from \a src to this buffer. The + * destination FrameBuffer shall have the same number of planes as the source + * buffer, and each destination plane shall be larger than or equal to the + * corresponding source plane. + * + * The complete metadata of the source buffer is copied to the destination + * buffer. If an error occurs during the copy, the destination buffer's metadata + * status is set to FrameMetadata::FrameError, and other metadata fields are not + * modified. + * + * The operation is performed using memcpy() so is very slow, users needs to + * consider this before copying buffers. + * + * \return 0 on success or a negative error code otherwise + */ +int FrameBuffer::copyFrom(const FrameBuffer *src) +{ + if (planes_.size() != src->planes_.size()) { + LOG(Buffer, Error) << "Different number of planes"; + metadata_.status = FrameMetadata::FrameError; + return -EINVAL; + } + + for (unsigned int i = 0; i < planes_.size(); i++) { + if (planes_[i].length < src->planes_[i].length) { + LOG(Buffer, Error) << "Plane " << i << " is too small"; + metadata_.status = FrameMetadata::FrameError; + return -EINVAL; + } + } + + for (unsigned int i = 0; i < planes_.size(); i++) { + void *dstmem = mmap(nullptr, planes_[i].length, PROT_WRITE, + MAP_SHARED, planes_[i].fd.fd(), 0); + + if (dstmem == MAP_FAILED) { + LOG(Buffer, Error) + << "Failed to map destination plane " << i; + metadata_.status = FrameMetadata::FrameError; + return -EINVAL; + } + + void *srcmem = mmap(nullptr, src->planes_[i].length, PROT_READ, + MAP_SHARED, src->planes_[i].fd.fd(), 0); + + if (srcmem == MAP_FAILED) { + munmap(dstmem, planes_[i].length); + LOG(Buffer, Error) + << "Failed to map source plane " << i; + metadata_.status = FrameMetadata::FrameError; + return -EINVAL; + } + + memcpy(dstmem, srcmem, src->planes_[i].length); + + munmap(srcmem, src->planes_[i].length); + munmap(dstmem, planes_[i].length); + } + + metadata_ = src->metadata_; + + return 0; +} + } /* namespace libcamera */ From patchwork Thu Mar 26 22:58:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 3349 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7D4C060412 for ; Thu, 26 Mar 2020 23:59:00 +0100 (CET) X-Halon-ID: 5fc7990c-6fb5-11ea-aeed-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de [79.202.35.146]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 5fc7990c-6fb5-11ea-aeed-005056917f90; Thu, 26 Mar 2020 23:58:57 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Thu, 26 Mar 2020 23:58:42 +0100 Message-Id: <20200326225844.4117712-6-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> References: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 5/7] libcamera: FrameBuffer: Add a setRequest() interface 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: , X-List-Received-Date: Thu, 26 Mar 2020 22:59:01 -0000 Add the ability to set the Request a buffer is associated with. This is needed for buffers that live inside a pipeline handler and is temporarily associated with a request as it's being processed inside the pipeline. While we are at it delete a stray semicolon. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- include/libcamera/buffer.h | 3 ++- src/libcamera/buffer.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h index ef3a3b36cd4e4e17..6bb2e4f8558f03ac 100644 --- a/include/libcamera/buffer.h +++ b/include/libcamera/buffer.h @@ -52,7 +52,8 @@ public: const std::vector &planes() const { return planes_; } Request *request() const { return request_; } - const FrameMetadata &metadata() const { return metadata_; }; + void setRequest(Request *request) { request_ = request; } + const FrameMetadata &metadata() const { return metadata_; } unsigned int cookie() const { return cookie_; } void setCookie(unsigned int cookie) { cookie_ = cookie; } diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp index 93057568fc56a6f5..0c5e56cf10621ab2 100644 --- a/src/libcamera/buffer.cpp +++ b/src/libcamera/buffer.cpp @@ -182,6 +182,17 @@ FrameBuffer::FrameBuffer(const std::vector &planes, unsigned int cookie) * not associated with a request */ +/** + * \fn FrameBuffer::setRequest() + * \brief Set the request this buffer belongs to + * \param[in] request Request to set + * + * The intended callers of this method are pipeline handlers and only for + * buffers that are internal to the pipeline. + * + * \todo Shall be hidden from applications with a d-pointer design. + */ + /** * \fn FrameBuffer::metadata() * \brief Retrieve the dynamic metadata From patchwork Thu Mar 26 22:58:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 3350 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2149862D31 for ; Thu, 26 Mar 2020 23:59:01 +0100 (CET) X-Halon-ID: 60183a52-6fb5-11ea-aeed-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de [79.202.35.146]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 60183a52-6fb5-11ea-aeed-005056917f90; Thu, 26 Mar 2020 23:58:58 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Thu, 26 Mar 2020 23:58:43 +0100 Message-Id: <20200326225844.4117712-7-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> References: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 6/7] libcamera: ipu3: Do not unconditionally queue buffers to CIO2 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: , X-List-Received-Date: Thu, 26 Mar 2020 22:59:01 -0000 Instead of unconditionally cycling buffers between the CIO2 and IMGU pick a buffer when a request is queued to the pipeline. This is needed if operations are to be applied to the buffer coming from CIO2 with parameters coming from a Request. The approach to pick a CIO2 buffer when a request is queued is similar to other pipelines, where parameters and statistic buffers are picked this way. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- * Changes since v1 - Update comments * Changes since RFC - Drop cio2ToRequest_ lookup map and use Request * in FrameBuffer. - Removed duplicated LOG() from CIO2Device::allocateBuffers. - Reassign instead of iterate to empty availableBuffers_. - Fold CIO2Device::queueBuffer() into the only caller. --- src/libcamera/pipeline/ipu3/ipu3.cpp | 53 ++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 1b44460e4d887d14..0933a03c9f718591 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -118,6 +119,9 @@ public: int allocateBuffers(); void freeBuffers(); + FrameBuffer *getBuffer(); + void putBuffer(FrameBuffer *buffer); + int start(); int stop(); @@ -129,6 +133,7 @@ public: private: std::vector> buffers_; + std::queue availableBuffers_; }; class IPU3Stream : public Stream @@ -716,11 +721,21 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request) { + IPU3CameraData *data = cameraData(camera); + FrameBuffer *buffer; int error = 0; + /* Get a CIO2 buffer, associate it with the request and queue it. */ + buffer = data->cio2_.getBuffer(); + if (!buffer) + return -EINVAL; + + buffer->setRequest(request); + data->cio2_.output_->queueBuffer(buffer); + for (auto it : request->buffers()) { IPU3Stream *stream = static_cast(it.first); - FrameBuffer *buffer = it.second; + buffer = it.second; int ret = stream->device_->dev->queueBuffer(buffer); if (ret < 0) @@ -892,7 +907,7 @@ void IPU3CameraData::imguInputBufferReady(FrameBuffer *buffer) if (buffer->metadata().status == FrameMetadata::FrameCancelled) return; - cio2_.output_->queueBuffer(buffer); + cio2_.putBuffer(buffer); } /** @@ -1416,29 +1431,45 @@ int CIO2Device::allocateBuffers() { int ret = output_->allocateBuffers(CIO2_BUFFER_COUNT, &buffers_); if (ret < 0) - LOG(IPU3, Error) << "Failed to allocate CIO2 buffers"; + return ret; + + for (std::unique_ptr &buffer : buffers_) + availableBuffers_.push(buffer.get()); return ret; } void CIO2Device::freeBuffers() { + availableBuffers_ = {}; + buffers_.clear(); if (output_->releaseBuffers()) LOG(IPU3, Error) << "Failed to release CIO2 buffers"; } +FrameBuffer *CIO2Device::getBuffer() +{ + if (availableBuffers_.empty()) { + LOG(IPU3, Error) << "CIO2 buffer underrun"; + return nullptr; + } + + FrameBuffer *buffer = availableBuffers_.front(); + + availableBuffers_.pop(); + + return buffer; +} + +void CIO2Device::putBuffer(FrameBuffer *buffer) +{ + availableBuffers_.push(buffer); +} + int CIO2Device::start() { - for (const std::unique_ptr &buffer : buffers_) { - int ret = output_->queueBuffer(buffer.get()); - if (ret) { - LOG(IPU3, Error) << "Failed to queue CIO2 buffer"; - return ret; - } - } - return output_->streamOn(); } From patchwork Thu Mar 26 22:58:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 3351 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E7AAB62684 for ; Thu, 26 Mar 2020 23:59:01 +0100 (CET) X-Halon-ID: 60774018-6fb5-11ea-aeed-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de [79.202.35.146]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 60774018-6fb5-11ea-aeed-005056917f90; Thu, 26 Mar 2020 23:58:58 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Thu, 26 Mar 2020 23:58:44 +0100 Message-Id: <20200326225844.4117712-8-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> References: <20200326225844.4117712-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 7/7] libcamera: ipu3: Add support for a RAW still capture stream 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: , X-List-Received-Date: Thu, 26 Mar 2020 22:59:03 -0000 Allow the RAW buffer cycling between CIO2 and IMGU to be memory copied to a new FrameBuffer in a new RAW stream. This allows users to capture the raw Bayer format coming from the sensor. As the RAW frame is memory copied queueing requests with the StillCaptureRaw stream might impact performance. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- * Changes since v1 - Break out translation of mbus code to pixel format to a static map and make use of it in validate() and generateConfiguration() - Move cfg.bufferCount = IPU3_BUFFER_COUNT from adjustStream() to validate() - Added comment and updated an error message. - Added todo to not configure and start the ImgU if only a single raw stream is requested. * Changes from RFC - Add definition for IPU3_MAX_STREAMS. - Deal with all IPU3 Bayer patterns. - Rework size logic. --- src/libcamera/pipeline/ipu3/ipu3.cpp | 111 ++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 10 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0933a03c9f718591..30bc662cc8bfa935 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -33,6 +33,13 @@ LOG_DEFINE_CATEGORY(IPU3) class IPU3CameraData; +static const std::map sensorMbusToPixel = { + { MEDIA_BUS_FMT_SBGGR10_1X10, PixelFormat(DRM_FORMAT_SBGGR10, { IPU3_FORMAT_MOD_PACKED }) }, + { MEDIA_BUS_FMT_SGBRG10_1X10, PixelFormat(DRM_FORMAT_SGBRG10, { IPU3_FORMAT_MOD_PACKED }) }, + { MEDIA_BUS_FMT_SGRBG10_1X10, PixelFormat(DRM_FORMAT_SGRBG10, { IPU3_FORMAT_MOD_PACKED }) }, + { MEDIA_BUS_FMT_SRGGB10_1X10, PixelFormat(DRM_FORMAT_SRGGB10, { IPU3_FORMAT_MOD_PACKED }) }, +}; + class ImgUDevice { public: @@ -140,11 +147,12 @@ class IPU3Stream : public Stream { public: IPU3Stream() - : active_(false), device_(nullptr) + : active_(false), raw_(false), device_(nullptr) { } bool active_; + bool raw_; std::string name_; ImgUDevice::ImgUOutput *device_; }; @@ -166,6 +174,7 @@ public: IPU3Stream outStream_; IPU3Stream vfStream_; + IPU3Stream rawStream_; }; class IPU3CameraConfiguration : public CameraConfiguration @@ -180,6 +189,7 @@ public: private: static constexpr unsigned int IPU3_BUFFER_COUNT = 4; + static constexpr unsigned int IPU3_MAX_STREAMS = 3; void adjustStream(StreamConfiguration &cfg, bool scale); @@ -291,8 +301,6 @@ void IPU3CameraConfiguration::adjustStream(StreamConfiguration &cfg, bool scale) cfg.size.width &= ~7; cfg.size.height &= ~3; } - - cfg.bufferCount = IPU3_BUFFER_COUNT; } CameraConfiguration::Status IPU3CameraConfiguration::validate() @@ -304,8 +312,8 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() return Invalid; /* Cap the number of entries to the available streams. */ - if (config_.size() > 2) { - config_.resize(2); + if (config_.size() > IPU3_MAX_STREAMS) { + config_.resize(IPU3_MAX_STREAMS); status = Adjusted; } @@ -345,6 +353,7 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() std::set availableStreams = { &data_->outStream_, &data_->vfStream_, + &data_->rawStream_, }; streams_.clear(); @@ -356,7 +365,9 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() const Size size = cfg.size; const IPU3Stream *stream; - if (cfg.size == sensorFormat_.size) + if (cfg.pixelFormat.modifiers().count(IPU3_FORMAT_MOD_PACKED)) + stream = &data_->rawStream_; + else if (cfg.size == sensorFormat_.size) stream = &data_->outStream_; else stream = &data_->vfStream_; @@ -367,8 +378,20 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate() LOG(IPU3, Debug) << "Assigned '" << stream->name_ << "' to stream " << i; - bool scale = stream == &data_->vfStream_; - adjustStream(config_[i], scale); + if (stream->raw_) { + const auto &itFormat = + sensorMbusToPixel.find(sensorFormat_.mbus_code); + if (itFormat == sensorMbusToPixel.end()) + return Invalid; + + cfg.pixelFormat = itFormat->second; + cfg.size = sensorFormat_.size; + } else { + bool scale = stream == &data_->vfStream_; + adjustStream(config_[i], scale); + } + + cfg.bufferCount = IPU3_BUFFER_COUNT; if (cfg.pixelFormat != pixelFormat || cfg.size != size) { LOG(IPU3, Debug) @@ -397,6 +420,7 @@ CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera, std::set streams = { &data->outStream_, &data->vfStream_, + &data->rawStream_, }; config = new IPU3CameraConfiguration(camera, data); @@ -438,6 +462,29 @@ CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera, break; + case StreamRole::StillCaptureRaw: { + if (streams.find(&data->rawStream_) == streams.end()) { + LOG(IPU3, Error) + << "No stream available for requested role " + << role; + break; + } + + stream = &data->rawStream_; + + cfg.size = data->cio2_.sensor_->resolution(); + + V4L2SubdeviceFormat sensorFormat = + data->cio2_.sensor_->getFormat({ MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10 }, + cfg.size); + cfg.pixelFormat = + sensorMbusToPixel.at(sensorFormat.mbus_code); + break; + } + case StreamRole::Viewfinder: case StreamRole::VideoRecording: { /* @@ -535,6 +582,9 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) /* * \todo: Enable links selectively based on the requested streams. * As of now, enable all links unconditionally. + * \todo Don't configure the ImgU at all if we only have a single + * stream which is for raw capture, in which case no buffers will + * never be queued to the ImgU. */ ret = data->imgu_->enableLinks(true); if (ret) @@ -571,6 +621,13 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) stream->active_ = true; cfg.setStream(stream); + /* + * The RAW still capture stream just copies buffers from the + * internal queue and doesn't need any specific configuration. + */ + if (stream->raw_) + continue; + ret = imgu->configureOutput(stream->device_, cfg); if (ret) return ret; @@ -621,9 +678,15 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) int PipelineHandlerIPU3::exportFrameBuffers(Camera *camera, Stream *stream, std::vector> *buffers) { + IPU3CameraData *data = cameraData(camera); IPU3Stream *ipu3stream = static_cast(stream); - V4L2VideoDevice *video = ipu3stream->device_->dev; unsigned int count = stream->configuration().bufferCount; + V4L2VideoDevice *video; + + if (ipu3stream->raw_) + video = data->cio2_.output_; + else + video = ipu3stream->device_->dev; return video->exportBuffers(count, buffers); } @@ -737,6 +800,10 @@ int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request) IPU3Stream *stream = static_cast(it.first); buffer = it.second; + /* Skip raw streams, they are copied from the CIO2 buffer. */ + if (stream->raw_) + continue; + int ret = stream->device_->dev->queueBuffer(buffer); if (ret < 0) error = ret; @@ -831,6 +898,7 @@ int PipelineHandlerIPU3::registerCameras() std::set streams = { &data->outStream_, &data->vfStream_, + &data->rawStream_, }; CIO2Device *cio2 = &data->cio2_; @@ -852,6 +920,8 @@ int PipelineHandlerIPU3::registerCameras() data->outStream_.name_ = "output"; data->vfStream_.device_ = &data->imgu_->viewfinder_; data->vfStream_.name_ = "viewfinder"; + data->rawStream_.raw_ = true; + data->rawStream_.name_ = "raw"; /* * Connect video devices' 'bufferReady' signals to their @@ -941,7 +1011,28 @@ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer) if (buffer->metadata().status == FrameMetadata::FrameCancelled) return; - imgu_->input_->queueBuffer(buffer); + Request *request = buffer->request(); + FrameBuffer *raw = request->findBuffer(&rawStream_); + + if (!raw) { + /* No RAW buffers present, just queue to IMGU. */ + imgu_->input_->queueBuffer(buffer); + return; + } + + /* RAW buffers present, special care is needed. */ + if (request->buffers().size() > 1) + imgu_->input_->queueBuffer(buffer); + + if (raw->copyFrom(buffer)) + LOG(IPU3, Debug) << "Copy of FrameBuffer failed"; + + pipe_->completeBuffer(camera_, request, raw); + + if (request->buffers().size() == 1) { + cio2_.putBuffer(buffer); + pipe_->completeRequest(camera_, request); + } } /* -----------------------------------------------------------------------------