[libcamera-devel] [PATCH 5/9] libcamera: v4l2_videodevice: Add standalone buffer export support
Niklas Söderlund
niklas.soderlund at ragnatech.se
Mon Mar 16 14:58:14 CET 2020
Hi Laurent,
Thanks for your work.
On 2020-03-15 01:57:24 +0200, Laurent Pinchart wrote:
> Add a new exportBuffers() function that only performs buffer allocation
> and export, but leaves the V4L2 buffer queue unallocated on return. This
> function will be used to simplify buffer allocation for pipeline
> handlers. This is made possible by the V4L2 buffer orphaning feature
> introduced in Linux v5.0, so add a version check to catch and report
> issues early.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
> src/libcamera/include/v4l2_videodevice.h | 2 +
> src/libcamera/v4l2_videodevice.cpp | 140 ++++++++++++++++++++++-
> 2 files changed, 140 insertions(+), 2 deletions(-)
>
> diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h
> index 358d89e57414..16fc6b60de02 100644
> --- a/src/libcamera/include/v4l2_videodevice.h
> +++ b/src/libcamera/include/v4l2_videodevice.h
> @@ -193,6 +193,8 @@ public:
>
> int allocateBuffers(unsigned int count,
> std::vector<std::unique_ptr<FrameBuffer>> *buffers);
> + int exportBuffers(unsigned int count,
> + std::vector<std::unique_ptr<FrameBuffer>> *buffers);
> int importBuffers(unsigned int count);
> int releaseBuffers();
>
> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> index d02b02ef77d6..e37136af8eb7 100644
> --- a/src/libcamera/v4l2_videodevice.cpp
> +++ b/src/libcamera/v4l2_videodevice.cpp
> @@ -19,6 +19,7 @@
> #include <vector>
>
> #include <linux/drm_fourcc.h>
> +#include <linux/version.h>
>
> #include <libcamera/event_notifier.h>
> #include <libcamera/file_descriptor.h>
> @@ -404,6 +405,53 @@ const std::string V4L2DeviceFormat::toString() const
> * No API call other than open(), isOpen() and close() shall be called on an
> * unopened device instance.
> *
> + * The V4L2VideoDevice class supports the V4L2 MMAP and DMABUF memory types:
> + *
> + * - The allocateBuffers() function wraps buffer allocation with the V4L2 MMAP
> + * memory type. It requests buffers from the driver, allocating the
> + * corresponding memory, and exports them as a set of FrameBuffer objects.
> + * Upon successful return the driver's internal buffer management is
> + * initialized in MMAP mode, and the video device is ready to accept
> + * queueBuffer() calls.
> + *
> + * This is the most traditional V4L2 buffer management, and is mostly useful
> + * to support internal buffer pools in pipeline handlers, either for CPU
> + * consumption (such as statistics or parameters pools), or for internal
> + * image buffers shared between devices.
> + *
> + * - The exportBuffers() function operates similarly to allocateBuffers(), but
> + * leaves the driver's internal buffer management uninitialized. It uses the
> + * V4L2 buffer orphaning support to allocate buffers with the MMAP method,
> + * export them as a set of FrameBuffer objects, and reset the driver's
> + * internal buffer management. The video device shall be initialized with
> + * importBuffers() or allocateBuffers() before it can accept queueBuffer()
> + * calls. The exported buffers are directly usable with any V4L2 video device
> + * in DMABUF mode, or with other dmabuf importers.
> + *
> + * This method is mostly useful to implement buffer allocation helpers or to
> + * allocate ancillary buffers, when a V4L2 video device is used in DMABUF
> + * mode but no other source of buffers is available. An example use case
> + * would be allocation of scratch buffers to be used in case of buffer
> + * underruns on a video device that is otherwise supplied with external
> + * buffers.
> + *
> + * - The importBuffers() function initializes the driver's buffer management to
> + * import buffers in DMABUF mode. It requests buffers from the driver, but
> + * doesn't allocate memory. Upon successful return, the video device is ready
> + * to accept queueBuffer() calls. The buffers to be imported are provided to
> + * queueBuffer(), and may be supplied externally, or come from a previous
> + * exportBuffers() call.
> + *
> + * This is the usual buffers initialization method for video devices whose
> + * buffers are exposed outside of libcamera. It is also typically used on one
> + * of the two video device that participate in buffer sharing inside
> + * pipelines, the other video device typically using allocateBuffers().
> + *
> + * - The releaseBuffers() function resets the driver's internal buffer
> + * management that was initialized by a previous call to allocateBuffers() or
> + * importBuffers(). Any memory allocated by allocateBuffers() is freed.
> + * Buffer exported by exportBuffers() are not affected by this function.
> + *
> * The V4L2VideoDevice class tracks queued buffers and handles buffer events. It
> * automatically dequeues completed buffers and emits the \ref bufferReady
> * signal.
> @@ -466,6 +514,15 @@ int V4L2VideoDevice::open()
> return ret;
> }
>
> + if (caps_.version < KERNEL_VERSION(5, 0, 0)) {
> + LOG(V4L2, Error)
> + << "V4L2 API v" << (caps_.version >> 16)
> + << "." << ((caps_.version >> 8) & 0xff)
> + << "." << (caps_.version & 0xff)
> + << " too old, v5.0.0 or later is required";
> + return -EINVAL;
> + }
> +
> if (!caps_.hasStreaming()) {
> LOG(V4L2, Error) << "Device does not support streaming I/O";
> return -EINVAL;
> @@ -1044,11 +1101,27 @@ int V4L2VideoDevice::requestBuffers(unsigned int count,
> }
>
> /**
> - * \brief Allocate buffers from the video device
> + * \brief Allocate and export buffers from the video device
> * \param[in] count Number of buffers to allocate
> * \param[out] buffers Vector to store allocated buffers
> + *
> + * This function wraps buffer allocation with the V4L2 MMAP memory type. It
> + * requests \a count buffers from the driver, allocating the corresponding
> + * memory, and exports them as a set of FrameBuffer objects in \a buffers. Upon
> + * successful return the driver's internal buffer management is initialized in
> + * MMAP mode, and the video device is ready to accept queueBuffer() calls.
> + *
> + * The number of planes and the plane sizes for the allocation are determined
> + * by the currently active format on the device as set by setFormat().
> + *
> + * Buffers allocated with this function shall later be free with
> + * releaseBuffers(). If buffers have already been allocated with
> + * allocateBuffers() or imported with importBuffers(), this function returns
> + * -EBUSY.
> + *
> * \return The number of allocated buffers on success or a negative error code
> * otherwise
> + * \retval -EBUSY buffers have already been allocated or imported
> */
> int V4L2VideoDevice::allocateBuffers(unsigned int count,
> std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> @@ -1063,6 +1136,49 @@ int V4L2VideoDevice::allocateBuffers(unsigned int count,
> return ret;
> }
>
> +/**
> + * \brief Export buffers from the video device
> + * \param[in] count Number of buffers to allocate
> + * \param[out] buffers Vector to store allocated buffers
> + *
> + * This function allocates \a count buffer from the video device and exports
> + * them as dmabuf objects, stored in \a buffers. Unlike allocateBuffers(), this
> + * function leaves the driver's internal buffer management uninitialized. The
> + * video device shall be initialized with importBuffers() or allocateBuffers()
> + * before it can accept queueBuffer() calls. The exported buffers are directly
> + * usable with any V4L2 video device in DMABUF mode, or with other dmabuf
> + * importers.
> + *
> + * The number of planes and the plane sizes for the allocation are determined
> + * by the currently active format on the device as set by setFormat().
> + *
> + * Multiple independent sets of buffers can be allocated with multiple calls to
> + * this function. Device-specific limitations may apply regarding the minimum
> + * and maximum number of buffers per set, or to total amount of allocated
> + * memory. The exported dmabuf lifetime is tied to the returned \a buffers. To
> + * free a buffer, the caller shall delete the corresponding FrameBuffer
> + * instance. No bookkeeping and automatic free is performed by the
> + * V4L2VideoDevice class.
> + *
> + * If buffers have already been allocated with allocateBuffers() or imported
> + * with importBuffers(), this function returns -EBUSY.
> + *
> + * \return The number of allocated buffers on success or a negative error code
> + * otherwise
> + * \retval -EBUSY buffers have already been allocated or imported
> + */
> +int V4L2VideoDevice::exportBuffers(unsigned int count,
> + std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> +{
> + int ret = createBuffers(count, buffers);
> + if (ret < 0)
> + return ret;
> +
> + requestBuffers(0, V4L2_MEMORY_MMAP);
> +
> + return ret;
> +}
> +
> int V4L2VideoDevice::createBuffers(unsigned int count,
> std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> {
> @@ -1160,7 +1276,22 @@ FileDescriptor V4L2VideoDevice::exportDmabufFd(unsigned int index,
> /**
> * \brief Prepare the device to import \a count buffers
> * \param[in] count Number of buffers to prepare to import
> + *
> + * This function initializes the driver's buffer management to import buffers
> + * in DMABUF mode. It requests buffers from the driver, but doesn't allocate
> + * memory.
> + *
> + * Upon successful return, the video device is ready to accept queueBuffer()
> + * calls. The buffers to be imported are provided to queueBuffer(), and may be
> + * supplied externally, or come from a previous exportBuffers() call.
> + *
> + * Device initialization performed by this function shall later be cleaned up
> + * with releaseBuffers(). If buffers have already been allocated with
> + * allocateBuffers() or imported with importBuffers(), this function returns
> + * -EBUSY.
> + *
> * \return 0 on success or a negative error code otherwise
> + * \retval -EBUSY buffers have already been allocated or imported
> */
> int V4L2VideoDevice::importBuffers(unsigned int count)
> {
> @@ -1183,7 +1314,12 @@ int V4L2VideoDevice::importBuffers(unsigned int count)
> }
>
> /**
> - * \brief Release all internally allocated buffers
> + * \brief Release resources allocated by importBuffers()
or allocateBuffers(), right?
With this fixed,
Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> + *
> + * This function resets the driver's internal buffer management that was
> + * initialized by a previous call to allocateBuffers() or importBuffers(). Any
> + * memory allocated by allocateBuffers() is freed. Buffer exported by
> + * exportBuffers(), if any, are not affected.
> */
> int V4L2VideoDevice::releaseBuffers()
> {
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
--
Regards,
Niklas Söderlund
More information about the libcamera-devel
mailing list