From patchwork Mon Sep 6 02:00:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13623 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 7CCDAC324B for ; Mon, 6 Sep 2021 02:01:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E59F26917B; Mon, 6 Sep 2021 04:01:39 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="p3ccUtT2"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8E0F469174 for ; Mon, 6 Sep 2021 04:01:26 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1E7838D7; Mon, 6 Sep 2021 04:01:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630893686; bh=ADgP6wyAOxxkbNZHhYHjOLTRGZIwB18N9UIOasiuSEc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=p3ccUtT2jzcZCA6ZY+fgZN2mGhRHjW+MGR8Dz6SY66zmApfTNon8eNT80msnRy6sq py9G98XFSzLV8nB75LpRvmCsmEHqGRtjFoCf2HEL1WangD55kCFt3F+bnfe47ao7Jd NT9u4Bk7jtATFYjk1WGDpmRYBGXSbCM8hwc3vx04= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 6 Sep 2021 05:00:47 +0300 Message-Id: <20210906020100.14430-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210906020100.14430-1-laurent.pinchart@ideasonboard.com> References: <20210906020100.14430-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 14/27] libcamera: v4l2_videodevice: Split planes when dequeuing buffer 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" When dequeueing a buffer from a V4L2VideoDevice, the number of planes in the FrameBuffer may not match the number of V4L2 buffer planes if the PixelFormat is multi-planar (has multiple colour planes) and the V4L2 format is single-planar (has a single buffer plane). In this case, we need to split the single V4L2 buffer plane into FrameBuffer planes. Do so, and add checks to reject invalid V4L2 buffers in case of a driver issue. Signed-off-by: Laurent Pinchart Reviewed-by: Hirokazu Honda --- Changes since v1: - Reduce indentation --- src/libcamera/v4l2_videodevice.cpp | 53 +++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 625d5da40337..0a7fbdb7e011 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -7,6 +7,7 @@ #include "libcamera/internal/v4l2_videodevice.h" +#include #include #include #include @@ -1664,12 +1665,54 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() buffer->metadata_.timestamp = buf.timestamp.tv_sec * 1000000000ULL + buf.timestamp.tv_usec * 1000ULL; - buffer->metadata_.planes.clear(); - if (multiPlanar) { - for (unsigned int nplane = 0; nplane < buf.length; nplane++) - buffer->metadata_.planes.push_back({ planes[nplane].bytesused }); + if (V4L2_TYPE_IS_OUTPUT(buf.type)) + return buffer; + + unsigned int numV4l2Planes = multiPlanar ? buf.length : 1; + FrameMetadata &metadata = buffer->metadata_; + metadata.planes.clear(); + + if (numV4l2Planes != buffer->planes().size()) { + /* + * If we have a multi-planar buffer with a V4L2 + * single-planar format, split the V4L2 buffer across + * the buffer planes. Only the last plane may have less + * bytes used than its length. + */ + if (numV4l2Planes != 1) { + LOG(V4L2, Error) + << "Invalid number of planes (" << numV4l2Planes + << " != " << buffer->planes().size() << ")"; + + metadata.status = FrameMetadata::FrameError; + return buffer; + } + + unsigned int bytesused = multiPlanar ? planes[0].bytesused + : buf.bytesused; + + for (auto [i, plane] : utils::enumerate(buffer->planes())) { + if (!bytesused) { + LOG(V4L2, Error) + << "Dequeued buffer is too small"; + + metadata.status = FrameMetadata::FrameError; + return buffer; + } + + metadata.planes.push_back({ std::min(plane.length, bytesused) }); + bytesused -= metadata.planes.back().bytesused; + } + } else if (multiPlanar) { + /* + * If we use the multi-planar API, fill in the planes. + * The number of planes in the frame buffer and in the + * V4L2 buffer is guaranteed to be equal at this point. + */ + for (unsigned int i = 0; i < numV4l2Planes; ++i) + metadata.planes.push_back({ planes[i].bytesused }); } else { - buffer->metadata_.planes.push_back({ buf.bytesused }); + metadata.planes.push_back({ buf.bytesused }); } return buffer;