From patchwork Fri Feb 5 13:10:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11175 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 1E048BD162 for ; Fri, 5 Feb 2021 13:11:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EE45B614B4; Fri, 5 Feb 2021 14:11:00 +0100 (CET) Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1BADC614B0 for ; Fri, 5 Feb 2021 14:11:00 +0100 (CET) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 7B22D1F466AD From: Helen Koike To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Feb 2021 10:10:42 -0300 Message-Id: <20210205131044.512128-2-helen.koike@collabora.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210205131044.512128-1-helen.koike@collabora.com> References: <20210205131044.512128-1-helen.koike@collabora.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 1/3] include: uapi: Add header definitions for V4L2 Ext API 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: , Cc: kieran.bingham+renesas@ideasonboard.com, frkoenig@chromium.org, kernel@collabora.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add definitions for format and buffer Ext API. The Ext API unifies multi vs single planar handling, allows color planes to be placed in different offset in the same buffer, allow pixel modifiers to be used and enable some other features. Signed-of-by: Helen Koike --- include/linux/videodev2.h | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index c70d7661..4b7b8000 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1013,6 +1013,59 @@ struct v4l2_buffer { }; }; +/** + * struct v4l2_ext_plane - extended plane buffer info + * @offset: offset in the memory buffer where the plane starts. + * @bytesused: number of bytes occupied by data in the plane (payload). + * @mmap_offset: If V4L2_MEMORY_MMAP is used, then it can be a "cookie" + * that should be passed to mmap() called on the video node. + * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer pointing + * to this plane. + * @dmabuf_fd: when memory is V4L2_MEMORY_DMABUF, a userspace file descriptor + * associated with this plane. + * @reserved: extra space reserved for future fields, must be set to 0. + */ +struct v4l2_ext_plane { + __u32 offset; + __u32 bytesused; + union { + __u32 mmap_offset; + __u64 userptr; + __s32 dmabuf_fd; + } m; + __u32 reserved[6]; +}; + +/** + * struct v4l2_ext_buffer - extended video buffer info + * @index: id number of the buffer + * @type: V4L2_BUF_TYPE_VIDEO_CAPTURE or V4L2_BUF_TYPE_VIDEO_OUTPUT + * @field: enum v4l2_field; field order of the image in the buffer + * @sequence: sequence count of this frame + * @flags: buffer informational flags + * @timestamp: frame timestamp + * @memory: enum v4l2_memory; the method, in which the actual video + * data is passed + * @request_fd: fd of the request that this buffer should use + * @planes: per-plane buffer information + * @reserved: extra space reserved for future fields, must be set to 0 + * + * Contains data exchanged by application and driver using one of the Streaming + * I/O methods. + */ +struct v4l2_ext_buffer { + __u32 index; + __u32 type; + __u32 field; + __u32 sequence; + __u64 flags; + __u64 timestamp; + __u32 memory; + __s32 request_fd; + struct v4l2_ext_plane planes[VIDEO_MAX_PLANES]; + __u32 reserved[10]; +}; + /** * v4l2_timeval_to_ns - Convert timeval to nanoseconds * @ts: pointer to the timeval variable to be converted @@ -2195,6 +2248,43 @@ struct v4l2_pix_format_mplane { __u8 reserved[7]; } __attribute__ ((packed)); +/** + * struct v4l2_ext_pix_format - extended single/multiplanar format definition + * @type: type of the data stream; V4L2_BUF_TYPE_VIDEO_CAPTURE or + * V4L2_BUF_TYPE_VIDEO_OUTPUT + * @width: image width in pixels + * @height: image height in pixels + * @field: enum v4l2_field; field order (for interlaced video) + * @plane_fmt: per-plane information + * @pixelformat: little endian four character code (fourcc) + * @modifier: modifier applied to the format (used for tiled formats + * and other kind of HW-specific formats, like compressed + * formats) as defined in drm_fourcc.h + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding + * @hsv_enc: enum v4l2_hsv_encoding, HSV encoding + * @quantization: enum v4l2_quantization, colorspace quantization + * @reserved: extra space reserved for future fields, must be set to 0 + */ +struct v4l2_ext_pix_format { + __u32 type; + __u32 width; + __u32 height; + __u32 field; + struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES]; + __u32 pixelformat; + __u64 modifier; + __u32 colorspace; + __u32 xfer_func; + union { + __u32 ycbcr_enc; + __u32 hsv_enc; + }; + __u32 quantization; + __u32 reserved[9]; +}; + /** * struct v4l2_sdr_format - SDR format definition * @pixelformat: little endian four character code (fourcc) @@ -2504,6 +2594,12 @@ struct v4l2_create_buffers { #define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl) +#define VIDIOC_G_EXT_PIX_FMT _IOWR('V', 104, struct v4l2_ext_pix_format) +#define VIDIOC_S_EXT_PIX_FMT _IOWR('V', 105, struct v4l2_ext_pix_format) +#define VIDIOC_TRY_EXT_PIX_FMT _IOWR('V', 106, struct v4l2_ext_pix_format) +#define VIDIOC_EXT_QBUF _IOWR('V', 107, struct v4l2_ext_buffer) +#define VIDIOC_EXT_DQBUF _IOWR('V', 118, struct v4l2_ext_buffer) + /* Reminder: when adding new ioctls please add support for them to drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */ From patchwork Fri Feb 5 13:10:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11176 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 43052BD162 for ; Fri, 5 Feb 2021 13:11:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1CDFE614B1; Fri, 5 Feb 2021 14:11:04 +0100 (CET) Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2EE64614B0 for ; Fri, 5 Feb 2021 14:11:03 +0100 (CET) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 781101F466AB From: Helen Koike To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Feb 2021 10:10:43 -0300 Message-Id: <20210205131044.512128-3-helen.koike@collabora.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210205131044.512128-1-helen.koike@collabora.com> References: <20210205131044.512128-1-helen.koike@collabora.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 2/3] libcamera: Use VIDIOC_{S, G, TRY}_EXT_PIX_FMT API 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: , Cc: kieran.bingham+renesas@ideasonboard.com, frkoenig@chromium.org, kernel@collabora.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Use Ext API for format negotiation. Unify multi vs single planar handling, prepare to use modifiers. Signed-off-by: Helen Koike --- include/libcamera/internal/v4l2_videodevice.h | 8 +- src/libcamera/pipeline/ipu3/cio2.cpp | 1 - src/libcamera/pipeline/ipu3/imgu.cpp | 1 - .../pipeline/raspberrypi/raspberrypi.cpp | 4 + src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 4 +- src/libcamera/pipeline/simple/converter.cpp | 6 +- src/libcamera/pipeline/simple/simple.cpp | 8 +- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 2 + src/libcamera/pipeline/vimc/vimc.cpp | 2 + src/libcamera/v4l2_videodevice.cpp | 183 ++++++------------ 10 files changed, 75 insertions(+), 144 deletions(-) diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h index 626dfbcd..d2de44c0 100644 --- a/include/libcamera/internal/v4l2_videodevice.h +++ b/include/libcamera/internal/v4l2_videodevice.h @@ -163,7 +163,6 @@ public: Size size; std::array planes; - unsigned int planesCount = 0; const std::string toString() const; }; @@ -222,11 +221,8 @@ private: int getFormatMeta(V4L2DeviceFormat *format); int trySetFormatMeta(V4L2DeviceFormat *format, bool set); - int getFormatMultiplane(V4L2DeviceFormat *format); - int trySetFormatMultiplane(V4L2DeviceFormat *format, bool set); - - int getFormatSingleplane(V4L2DeviceFormat *format); - int trySetFormatSingleplane(V4L2DeviceFormat *format, bool set); + int getFormatExt(V4L2DeviceFormat *format); + int trySetFormatExt(V4L2DeviceFormat *format, bool set); std::vector enumPixelformats(uint32_t code); std::vector enumSizes(V4L2PixelFormat pixelFormat); diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp index 0ef3bc04..ea0c2b59 100644 --- a/src/libcamera/pipeline/ipu3/cio2.cpp +++ b/src/libcamera/pipeline/ipu3/cio2.cpp @@ -184,7 +184,6 @@ int CIO2Device::configure(const Size &size, V4L2DeviceFormat *outputFormat) outputFormat->fourcc = info.v4l2Format; outputFormat->size = sensorFormat.size; - outputFormat->planesCount = 1; ret = output_->setFormat(outputFormat); if (ret) diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp index d5cf05b0..7684b466 100644 --- a/src/libcamera/pipeline/ipu3/imgu.cpp +++ b/src/libcamera/pipeline/ipu3/imgu.cpp @@ -527,7 +527,6 @@ int ImgUDevice::configureVideoDevice(V4L2VideoDevice *dev, unsigned int pad, *outputFormat = {}; outputFormat->fourcc = dev->toV4L2PixelFormat(formats::NV12); outputFormat->size = cfg.size; - outputFormat->planesCount = 2; ret = dev->setFormat(outputFormat); if (ret) diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 0804a439..5f7a1488 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -373,6 +373,8 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() cfg.stride = sensorFormat.planes[0].bpl; cfg.frameSize = sensorFormat.planes[0].size; + for (unsigned int i = 1; i < sensorFormat.planes.size(); ++i) + cfg.frameSize += sensorFormat.planes[i].size; rawCount++; } else { @@ -445,6 +447,8 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() cfg.stride = format.planes[0].bpl; cfg.frameSize = format.planes[0].size; + for (unsigned int j = 1; j < format.planes.size(); ++j) + cfg.frameSize += format.planes[j].size; } diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp index 25f482eb..adea5590 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp @@ -89,6 +89,8 @@ CameraConfiguration::Status RkISP1Path::validate(StreamConfiguration *cfg) cfg->stride = format.planes[0].bpl; cfg->frameSize = format.planes[0].size; + for (unsigned int i = 1; i < format.planes.size(); ++i) + cfg->frameSize += format.planes[i].size; if (cfg->pixelFormat != reqCfg.pixelFormat || cfg->size != reqCfg.size) { LOG(RkISP1, Debug) @@ -144,11 +146,9 @@ int RkISP1Path::configure(const StreamConfiguration &config, << "Configured " << name_ << " resizer output pad with " << ispFormat.toString(); - const PixelFormatInfo &info = PixelFormatInfo::info(config.pixelFormat); V4L2DeviceFormat outputFormat; outputFormat.fourcc = video_->toV4L2PixelFormat(config.pixelFormat); outputFormat.size = config.size; - outputFormat.planesCount = info.numPlanes(); ret = video_->setFormat(&outputFormat); if (ret) diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/pipeline/simple/converter.cpp index a6a8e139..ccdd30cf 100644 --- a/src/libcamera/pipeline/simple/converter.cpp +++ b/src/libcamera/pipeline/simple/converter.cpp @@ -263,12 +263,16 @@ SimpleConverter::strideAndFrameSize(const Size &size, V4L2DeviceFormat format; format.fourcc = m2m_->capture()->toV4L2PixelFormat(pixelFormat); format.size = size; + uint32_t frameSize = 0; int ret = m2m_->capture()->tryFormat(&format); if (ret < 0) return std::make_tuple(0, 0); - return std::make_tuple(format.planes[0].bpl, format.planes[0].size); + for (unsigned int i = 0; i < format.planes.size(); ++i) + frameSize += format.planes[i].size; + + return std::make_tuple(format.planes[0].bpl, frameSize); } } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 23320d26..97111d30 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -487,6 +487,8 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() cfg.stride = format.planes[0].bpl; cfg.frameSize = format.planes[0].size; + for (unsigned int i = 1; i < format.planes.size(); ++i) + cfg.frameSize += format.planes[i].size; return status; } @@ -590,12 +592,6 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) if (ret) return ret; - if (captureFormat.planesCount != 1) { - LOG(SimplePipeline, Error) - << "Planar formats using non-contiguous memory not supported"; - return -EINVAL; - } - if (captureFormat.fourcc != videoFormat || captureFormat.size != pipeConfig.captureSize) { LOG(SimplePipeline, Error) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 08a59417..136399b6 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -160,6 +160,8 @@ CameraConfiguration::Status UVCCameraConfiguration::validate() cfg.stride = format.planes[0].bpl; cfg.frameSize = format.planes[0].size; + for (unsigned int i = 1; i < format.planes.size(); ++i) + cfg.frameSize += format.planes[i].size; return status; } diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index 36325ffb..d42c9ec0 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -171,6 +171,8 @@ CameraConfiguration::Status VimcCameraConfiguration::validate() cfg.stride = format.planes[0].bpl; cfg.frameSize = format.planes[0].size; + for (unsigned int i = 1; i < format.planes.size(); ++i) + cfg.frameSize += format.planes[i].size; return status; } diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index c77e1aff..fab3ba4c 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -337,27 +337,24 @@ bool V4L2BufferCache::Entry::operator==(const FrameBuffer &buffer) const * stride length and size, but only a global stride length which is applied to * all planes. * - * The V4L2DeviceFormat class describes both packed and planar image formats, - * regardless of the API type (single or multi plane) implemented by the video - * device the format has to be applied to. The total size and bytes per line - * of images represented with packed formats are configured using the first - * entry of the V4L2DeviceFormat::planes array, while the per-plane size and - * per-plane stride length of images represented with planar image formats are - * configured using the opportune number of entries of the - * V4L2DeviceFormat::planes array, as prescribed by the image format - * definition (semi-planar formats use 2 entries, while planar formats use the - * whole 3 entries). The number of valid entries of the - * V4L2DeviceFormat::planes array is defined by the - * V4L2DeviceFormat::planesCount value. + * The V4L2DeviceFormat class describes formats per color component and not + * memory planes. Even if a single memory buffer is used, color planes are still + * described separately. + * The size and bytes per line of each color component is defined separately + * with the V4L2DeviceFormat:::planes array. + * Except for metadata, this class uses the Ext API that unifies the + * multiplanar and single planar API. + * The number of valid entries of the V4L2DeviceFormat::planes array is defined + * by the number of non-zero bytesperline field, up to 3 planes. */ /** * \struct V4L2DeviceFormat::Plane - * \brief Per-plane memory size information + * \brief Per color plane size information * \var V4L2DeviceFormat::Plane::size - * \brief The plane total memory size (in bytes) + * \brief The color plane total memory size (in bytes) * \var V4L2DeviceFormat::Plane::bpl - * \brief The plane line stride (in bytes) + * \brief The color plane line stride (in bytes) */ /** @@ -375,17 +372,11 @@ bool V4L2BufferCache::Entry::operator==(const FrameBuffer &buffer) const /** * \var V4L2DeviceFormat::planes - * \brief The per-plane memory size information + * \brief The per color plane memory size information * * Images are stored in memory in one or more data planes. Each data plane has a * specific line stride and memory size, which could differ from the image * visible sizes to accommodate padding at the end of lines and end of planes. - * Only the first \ref planesCount entries are considered valid. - */ - -/** - * \var V4L2DeviceFormat::planesCount - * \brief The number of valid data planes */ /** @@ -723,10 +714,8 @@ int V4L2VideoDevice::getFormat(V4L2DeviceFormat *format) { if (caps_.isMeta()) return getFormatMeta(format); - else if (caps_.isMultiplanar()) - return getFormatMultiplane(format); else - return getFormatSingleplane(format); + return getFormatExt(format); } /** @@ -743,10 +732,8 @@ int V4L2VideoDevice::tryFormat(V4L2DeviceFormat *format) { if (caps_.isMeta()) return trySetFormatMeta(format, false); - else if (caps_.isMultiplanar()) - return trySetFormatMultiplane(format, false); else - return trySetFormatSingleplane(format, false); + return trySetFormatExt(format, false); } /** @@ -762,10 +749,8 @@ int V4L2VideoDevice::setFormat(V4L2DeviceFormat *format) { if (caps_.isMeta()) return trySetFormatMeta(format, true); - else if (caps_.isMultiplanar()) - return trySetFormatMultiplane(format, true); else - return trySetFormatSingleplane(format, true); + return trySetFormatExt(format, true); } int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format) @@ -784,9 +769,12 @@ int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format) format->size.width = 0; format->size.height = 0; format->fourcc = V4L2PixelFormat(pix->dataformat); - format->planesCount = 1; format->planes[0].bpl = pix->buffersize; format->planes[0].size = pix->buffersize; + for (unsigned int i = 1; i < format->planes.size(); ++i) { + format->planes[i].bpl = 0; + format->planes[i].size = 0; + } return 0; } @@ -800,6 +788,8 @@ int V4L2VideoDevice::trySetFormatMeta(V4L2DeviceFormat *format, bool set) v4l2Format.type = bufferType_; pix->dataformat = format->fourcc; pix->buffersize = format->planes[0].size; + for (unsigned int i = 1; i < format->planes.size(); ++i) + pix->buffersize += format->planes[i].size; ret = ioctl(set ? VIDIOC_S_FMT : VIDIOC_TRY_FMT, &v4l2Format); if (ret) { LOG(V4L2, Error) @@ -815,122 +805,60 @@ int V4L2VideoDevice::trySetFormatMeta(V4L2DeviceFormat *format, bool set) format->size.width = 0; format->size.height = 0; format->fourcc = V4L2PixelFormat(pix->dataformat); - format->planesCount = 1; format->planes[0].bpl = pix->buffersize; format->planes[0].size = pix->buffersize; + for (unsigned int i = 1; i < format->planes.size(); ++i) { + format->planes[i].bpl = 0; + format->planes[i].size = 0; + } return 0; } -int V4L2VideoDevice::getFormatMultiplane(V4L2DeviceFormat *format) +int V4L2VideoDevice::getFormatExt(V4L2DeviceFormat *format) { - struct v4l2_format v4l2Format = {}; - struct v4l2_pix_format_mplane *pix = &v4l2Format.fmt.pix_mp; + struct v4l2_ext_pix_format v4l2FormatExt = {}; int ret; - v4l2Format.type = bufferType_; - ret = ioctl(VIDIOC_G_FMT, &v4l2Format); + v4l2FormatExt.type = bufferType_; + ret = ioctl(VIDIOC_G_EXT_PIX_FMT, &v4l2FormatExt); if (ret) { - LOG(V4L2, Error) << "Unable to get format: " << strerror(-ret); + LOG(V4L2, Error) << "Unable to get format ext: " << strerror(-ret); return ret; } - format->size.width = pix->width; - format->size.height = pix->height; - format->fourcc = V4L2PixelFormat(pix->pixelformat); - format->planesCount = pix->num_planes; + format->size.width = v4l2FormatExt.width; + format->size.height = v4l2FormatExt.height; + format->fourcc = V4L2PixelFormat(v4l2FormatExt.pixelformat); - for (unsigned int i = 0; i < format->planesCount; ++i) { - format->planes[i].bpl = pix->plane_fmt[i].bytesperline; - format->planes[i].size = pix->plane_fmt[i].sizeimage; + for (unsigned int i = 0; i < format->planes.size(); ++i) { + format->planes[i].bpl = v4l2FormatExt.plane_fmt[i].bytesperline; + format->planes[i].size = v4l2FormatExt.plane_fmt[i].sizeimage; } return 0; } -int V4L2VideoDevice::trySetFormatMultiplane(V4L2DeviceFormat *format, bool set) +int V4L2VideoDevice::trySetFormatExt(V4L2DeviceFormat *format, bool set) { - struct v4l2_format v4l2Format = {}; - struct v4l2_pix_format_mplane *pix = &v4l2Format.fmt.pix_mp; + struct v4l2_ext_pix_format v4l2FormatExt = {}; int ret; - v4l2Format.type = bufferType_; - pix->width = format->size.width; - pix->height = format->size.height; - pix->pixelformat = format->fourcc; - pix->num_planes = format->planesCount; - pix->field = V4L2_FIELD_NONE; - - ASSERT(pix->num_planes <= std::size(pix->plane_fmt)); - - for (unsigned int i = 0; i < pix->num_planes; ++i) { - pix->plane_fmt[i].bytesperline = format->planes[i].bpl; - pix->plane_fmt[i].sizeimage = format->planes[i].size; - } - - ret = ioctl(set ? VIDIOC_S_FMT : VIDIOC_TRY_FMT, &v4l2Format); - if (ret) { - LOG(V4L2, Error) - << "Unable to " << (set ? "set" : "try") - << " format: " << strerror(-ret); - return ret; - } - - /* - * Return to caller the format actually applied on the video device, - * which might differ from the requested one. - */ - format->size.width = pix->width; - format->size.height = pix->height; - format->fourcc = V4L2PixelFormat(pix->pixelformat); - format->planesCount = pix->num_planes; - for (unsigned int i = 0; i < format->planesCount; ++i) { - format->planes[i].bpl = pix->plane_fmt[i].bytesperline; - format->planes[i].size = pix->plane_fmt[i].sizeimage; - } - - return 0; -} + v4l2FormatExt.type = bufferType_; + v4l2FormatExt.width = format->size.width; + v4l2FormatExt.height = format->size.height; + v4l2FormatExt.pixelformat = format->fourcc; + v4l2FormatExt.field = V4L2_FIELD_NONE; -int V4L2VideoDevice::getFormatSingleplane(V4L2DeviceFormat *format) -{ - struct v4l2_format v4l2Format = {}; - struct v4l2_pix_format *pix = &v4l2Format.fmt.pix; - int ret; - - v4l2Format.type = bufferType_; - ret = ioctl(VIDIOC_G_FMT, &v4l2Format); - if (ret) { - LOG(V4L2, Error) << "Unable to get format: " << strerror(-ret); - return ret; + for (unsigned int i = 0; i < format->planes.size(); ++i) { + v4l2FormatExt.plane_fmt[i].bytesperline = format->planes[i].bpl; + v4l2FormatExt.plane_fmt[i].sizeimage = format->planes[i].size; } - format->size.width = pix->width; - format->size.height = pix->height; - format->fourcc = V4L2PixelFormat(pix->pixelformat); - format->planesCount = 1; - format->planes[0].bpl = pix->bytesperline; - format->planes[0].size = pix->sizeimage; - - return 0; -} - -int V4L2VideoDevice::trySetFormatSingleplane(V4L2DeviceFormat *format, bool set) -{ - struct v4l2_format v4l2Format = {}; - struct v4l2_pix_format *pix = &v4l2Format.fmt.pix; - int ret; - - v4l2Format.type = bufferType_; - pix->width = format->size.width; - pix->height = format->size.height; - pix->pixelformat = format->fourcc; - pix->bytesperline = format->planes[0].bpl; - pix->field = V4L2_FIELD_NONE; - ret = ioctl(set ? VIDIOC_S_FMT : VIDIOC_TRY_FMT, &v4l2Format); + ret = ioctl(set ? VIDIOC_S_EXT_PIX_FMT : VIDIOC_TRY_EXT_PIX_FMT, &v4l2FormatExt); if (ret) { LOG(V4L2, Error) - << "Unable to " << (set ? "set" : "try") + << "Unable to " << (set ? "set ext pix" : "try ext pi") << " format: " << strerror(-ret); return ret; } @@ -939,12 +867,13 @@ int V4L2VideoDevice::trySetFormatSingleplane(V4L2DeviceFormat *format, bool set) * Return to caller the format actually applied on the device, * which might differ from the requested one. */ - format->size.width = pix->width; - format->size.height = pix->height; - format->fourcc = V4L2PixelFormat(pix->pixelformat); - format->planesCount = 1; - format->planes[0].bpl = pix->bytesperline; - format->planes[0].size = pix->sizeimage; + format->size.width = v4l2FormatExt.width; + format->size.height = v4l2FormatExt.height; + format->fourcc = V4L2PixelFormat(v4l2FormatExt.pixelformat); + for (unsigned int i = 0; i < format->planes.size(); ++i) { + format->planes[i].bpl = v4l2FormatExt.plane_fmt[i].bytesperline; + format->planes[i].size = v4l2FormatExt.plane_fmt[i].sizeimage; + } return 0; } From patchwork Fri Feb 5 13:10:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Helen Koike X-Patchwork-Id: 11177 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 A3BADBD162 for ; Fri, 5 Feb 2021 13:11:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7E8F1614BA; Fri, 5 Feb 2021 14:11:07 +0100 (CET) Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 33D69614B0 for ; Fri, 5 Feb 2021 14:11:06 +0100 (CET) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: koike) with ESMTPSA id 88BF21F466AD From: Helen Koike To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Feb 2021 10:10:44 -0300 Message-Id: <20210205131044.512128-4-helen.koike@collabora.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210205131044.512128-1-helen.koike@collabora.com> References: <20210205131044.512128-1-helen.koike@collabora.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 3/3] libcamera: Use VIDIOC_EXT_(D)QBUF for buffer handling 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: , Cc: kieran.bingham+renesas@ideasonboard.com, frkoenig@chromium.org, kernel@collabora.com Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Use Ext API for buffer handling. Allow memory buffers to be defined per color component. Signed-off-by: Helen Koike --- src/libcamera/v4l2_videodevice.cpp | 75 ++++++++++++------------------ src/v4l2/v4l2_camera_proxy.cpp | 20 ++++---- 2 files changed, 41 insertions(+), 54 deletions(-) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index fab3ba4c..0a724266 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -141,7 +141,7 @@ LOG_DECLARE_CATEGORY(V4L2) * \brief Hot cache of associations between V4L2 buffer indexes and FrameBuffer * * When importing buffers, V4L2 performs lazy mapping of dmabuf instances at - * VIDIOC_QBUF (or VIDIOC_PREPARE_BUF) time and keeps the mapping associated + * VIDIOC_EXT_QBUF (or VIDIOC_PREPARE_BUF) time and keeps the mapping associated * with the V4L2 buffer, as identified by its index. If the same V4L2 buffer is * then reused and queued with different dmabufs, the old dmabufs will be * unmapped and the new ones mapped. To keep this process efficient, it is @@ -1315,8 +1315,8 @@ int V4L2VideoDevice::releaseBuffers() */ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer) { - struct v4l2_plane v4l2Planes[VIDEO_MAX_PLANES] = {}; - struct v4l2_buffer buf = {}; + V4L2DeviceFormat format; + struct v4l2_ext_buffer buf = {}; int ret; ret = cache_->get(*buffer); @@ -1328,46 +1328,46 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer) buf.memory = memoryType_; buf.field = V4L2_FIELD_NONE; - bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type); const std::vector &planes = buffer->planes(); + ret = getFormat(&format); + if (ret < 0) + return ret; + if (buf.memory == V4L2_MEMORY_DMABUF) { - if (multiPlanar) { - for (unsigned int p = 0; p < planes.size(); ++p) - v4l2Planes[p].m.fd = planes[p].fd.fd(); + /* + * If there is a single memory plane, fill color planes with + * the same dmabuf fd but on a different offset + */ + if (planes.size() == 1) { + buf.planes[0].m.dmabuf_fd = planes[0].fd.fd(); + for (unsigned int p = 1; + p < format.planes.size() && format.planes[p].size; ++p) { + buf.planes[p].m.dmabuf_fd = planes[0].fd.fd(); + buf.planes[p].offset = format.planes[p - 1].size; + } } else { - buf.m.fd = planes[0].fd.fd(); + for (unsigned int p = 0; p < planes.size(); ++p) + buf.planes[p].m.dmabuf_fd = planes[p].fd.fd(); } } - if (multiPlanar) { - buf.length = planes.size(); - buf.m.planes = v4l2Planes; - } - if (V4L2_TYPE_IS_OUTPUT(buf.type)) { const FrameMetadata &metadata = buffer->metadata(); + unsigned int nplane = 0; - if (multiPlanar) { - unsigned int nplane = 0; - for (const FrameMetadata::Plane &plane : metadata.planes) { - v4l2Planes[nplane].bytesused = plane.bytesused; - v4l2Planes[nplane].length = buffer->planes()[nplane].length; - nplane++; - } - } else { - if (metadata.planes.size()) - buf.bytesused = metadata.planes[0].bytesused; + for (const FrameMetadata::Plane &plane : metadata.planes) { + buf.planes[nplane].bytesused = plane.bytesused; + nplane++; } buf.sequence = metadata.sequence; - buf.timestamp.tv_sec = metadata.timestamp / 1000000000; - buf.timestamp.tv_usec = (metadata.timestamp / 1000) % 1000000; + buf.timestamp = metadata.timestamp; } LOG(V4L2, Debug) << "Queueing buffer " << buf.index; - ret = ioctl(VIDIOC_QBUF, &buf); + ret = ioctl(VIDIOC_EXT_QBUF, &buf); if (ret < 0) { LOG(V4L2, Error) << "Failed to queue buffer " << buf.index << ": " @@ -1413,21 +1413,13 @@ void V4L2VideoDevice::bufferAvailable([[maybe_unused]] EventNotifier *notifier) */ FrameBuffer *V4L2VideoDevice::dequeueBuffer() { - struct v4l2_buffer buf = {}; - struct v4l2_plane planes[VIDEO_MAX_PLANES] = {}; + struct v4l2_ext_buffer buf = {}; int ret; buf.type = bufferType_; buf.memory = memoryType_; - bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type); - - if (multiPlanar) { - buf.length = VIDEO_MAX_PLANES; - buf.m.planes = planes; - } - - ret = ioctl(VIDIOC_DQBUF, &buf); + ret = ioctl(VIDIOC_EXT_DQBUF, &buf); if (ret < 0) { LOG(V4L2, Error) << "Failed to dequeue buffer: " << strerror(-ret); @@ -1449,16 +1441,11 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer() ? FrameMetadata::FrameError : FrameMetadata::FrameSuccess; buffer->metadata_.sequence = buf.sequence; - buffer->metadata_.timestamp = buf.timestamp.tv_sec * 1000000000ULL - + buf.timestamp.tv_usec * 1000ULL; + buffer->metadata_.timestamp = buf.timestamp; buffer->metadata_.planes.clear(); - if (multiPlanar) { - for (unsigned int nplane = 0; nplane < buf.length; nplane++) - buffer->metadata_.planes.push_back({ planes[nplane].bytesused }); - } else { - buffer->metadata_.planes.push_back({ buf.bytesused }); - } + for (unsigned int nplane = 0; buf.planes[nplane].bytesused; nplane++) + buffer->metadata_.planes.push_back({ buf.planes[nplane].bytesused }); return buffer; } diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index f8bfe595..32fed4b8 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -544,9 +544,9 @@ int V4L2CameraProxy::vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *a return 0; } -int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_ext_qbuf(V4L2CameraFile *file, struct v4l2_ext_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " + LOG(V4L2Compat, Debug) << "Servicing vidioc_ext_qbuf, index = " << arg->index << " fd = " << file->efd(); if (arg->index >= bufferCount_) @@ -574,8 +574,8 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) return ret; } -int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg, - MutexLocker *locker) +int V4L2CameraProxy::vidioc_ext_dqbuf(V4L2CameraFile *file, struct v4l2_ext_buffer *arg, + MutexLocker *locker) { LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << file->efd(); @@ -683,8 +683,8 @@ const std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_S_INPUT, VIDIOC_REQBUFS, VIDIOC_QUERYBUF, - VIDIOC_QBUF, - VIDIOC_DQBUF, + VIDIOC_EXT_QBUF, + VIDIOC_EXT_DQBUF, VIDIOC_STREAMON, VIDIOC_STREAMOFF, }; @@ -749,11 +749,11 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar case VIDIOC_QUERYBUF: ret = vidioc_querybuf(file, static_cast(arg)); break; - case VIDIOC_QBUF: - ret = vidioc_qbuf(file, static_cast(arg)); + case VIDIOC_EXT_QBUF: + ret = vidioc_ext_qbuf(file, static_cast(arg)); break; - case VIDIOC_DQBUF: - ret = vidioc_dqbuf(file, static_cast(arg), &locker); + case VIDIOC_EXT_DQBUF: + ret = vidioc_ext_dqbuf(file, static_cast(arg), &locker); break; case VIDIOC_STREAMON: ret = vidioc_streamon(file, static_cast(arg));