[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