/*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* NVIDIA Multimedia API: V4L2 Element Plane
*
* @b Description: This file declares a helper class for operations
* performed on a V4L2 Element plane.
*/
/**
* @defgroup l4t_mm_nvv4lelementplane_group NvV4l2ElementPlane Class
* @ingroup l4t_mm_nvelement_group
*
* Helper class for operations performed on a V4L2 element plane.
* This includes getting/setting plane formats, plane buffers,
* and cropping.
* @{
*/
#ifndef __NV_V4L2_ELELMENT_PLANE_H__
#define __NV_V4L2_ELELMENT_PLANE_H__
#include
#include "NvElement.h"
#include "NvLogging.h"
#include "NvBuffer.h"
/**
* Prints a plane-specific message of level LOG_LEVEL_DEBUG.
* Must not be used by applications.
*/
#define PLANE_DEBUG_MSG(str) COMP_DEBUG_MSG(plane_name << ":" << str);
/**
* Prints a plane-specific message of level LOG_LEVEL_INFO.
* Must not be used by applications.
*/
#define PLANE_INFO_MSG(str) COMP_INFO_MSG(plane_name << ":" << str);
/**
* Prints a plane-specific message of level LOG_LEVEL_WARN.
* Must not be used by applications.
*/
#define PLANE_WARN_MSG(str) COMP_WARN_MSG(plane_name << ":" << str);
/**
* Prints a plane-specific message of level LOG_LEVEL_ERROR.
* Must not be used by applications.
*/
#define PLANE_ERROR_MSG(str) COMP_ERROR_MSG(plane_name << ":" << str);
/**
* Prints a plane-specific system error message of level LOG_LEVEL_ERROR.
* Must not be used by applications.
*/
#define PLANE_SYS_ERROR_MSG(str) COMP_SYS_ERROR_MSG(plane_name << ":" << str);
/**
* @brief Defines a helper class for operations performed on a V4L2 Element plane.
*
* This derived class is modeled on the planes of a V4L2 Element. It provides
* convenient wrapper methods around V4L2 IOCTLs associated with plane
* operations such as VIDIOC_G_FMT/VIDIOC_S_FMT
, \c VIDIOC_REQBUFS,
* VIDIOC_STREAMON/VIDIOC_STREAMOFF
, etc.
*
* The plane buffer type can be either \c V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE (for
* the output plane) or \c V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE (for the capture
* plane).
*
* The plane has an array of NvBuffer object pointers that is allocated and
* initialized during reqbuf call. These \c NvBuffer objects are similar to the
* \c v4l2_buffer structures that are queued/dequeued.
*
* This class provides another feature useful for multi-threading. On calling
* #startDQThread, it internally spawns a thread that runs infinitely until
* signaled to stop. This thread keeps trying to dequeue a buffer from the
* plane and calls a #dqThreadCallback method specified by the user on
* successful dequeue.
*
*/
class NvV4l2ElementPlane
{
public:
/**
* Gets the plane format.
*
* Calls @b VIDIOC_G_FMT \c IOCTL internally.
*
* @param[in,out] format A reference to the \c v4l2_format structure to be filled.
* @return 0 for success, -1 otherwise.
*/
int getFormat(struct v4l2_format & format);
/**
* Sets the plane format.
*
* Calls @b VIDIOC_S_FMT \c IOCTL internally.
*
* @param[in] format A reference to the \c v4l2_format structure to be set on the plane.
* @return 0 for success, -1 otherwise.
*/
int setFormat(struct v4l2_format & format);
/**
* Maps the NvMMBuffer to NvBuffer for V4L2_MEMORY_DMABUF.
*
* @param[in] v4l2_buf Address of the NvBuffer to which the NvMMBuffer is mapped.
* @param[in] dmabuff_fd Index to the field that holds NvMMBuffer attributes.
* @return 0 for success, -1 otherwise.
*/
int mapOutputBuffers(struct v4l2_buffer &v4l2_buf, int dmabuff_fd);
/**
* Unmaps the NvMMBuffer for V4L2_MEMORY_DMABUF.
*
* @param[in] index for the current buffer index.
* @param[in] dmabuff_fd Index to the field that holds NvMMBuffer attributes.
* @return 0 for success, -1 otherwise.
*/
int unmapOutputBuffers(int index, int dmabuff_fd);
/**
* Gets the cropping rectangle for the plane.
*
* Calls @b VIDIOC_G_CROP \c IOCTL internally.
*
* @param[in] crop A reference to the \c v4l2_crop structure to be filled.
* @return 0 for success, -1 otherwise.
*/
int getCrop(struct v4l2_crop & crop);
/**
* Sets the selection rectangle for the plane.
*
* Calls @b VIDIOC_S_SELECTION IOCTL internally.
*
* @param[in] target Specifies the rectangle selection type.
* @param[in] flags Specifies the flags to control selection adjustments.
* @param[in] rect A reference to the selection rectangle.
* @return 0 for success, -1 otherwise.
*/
int setSelection(uint32_t target, uint32_t flags, struct v4l2_rect & rect);
/**
* Requests for buffers on the plane.
*
* Calls \c VIDIOC_REQBUFS IOCTL internally. Creates an array of NvBuffer of
* length equal to the count returned by the IOCTL.
*
* @param[in] mem_type Specifies the type of V4L2 memory to be requested.
* @param[in] num Specifies the number of buffers to request on the plane.
* @return 0 for success, -1 otherwise.
*/
int reqbufs(enum v4l2_memory mem_type, uint32_t num);
/**
* Queries the status of the buffer at the index.
*
* @warning This method works only for \c V4L2_MEMORY_MMAP memory.
*
* Calls \c VIDIOC_QUERYBUF IOCTL internally. Populates the \a length and \a
* mem_offset members of all the NvBuffer::NvBufferPlane members of the
* \c %NvBuffer object at index \a buf_index.
*
* @param[in] buf_index Specifies the index of the buffer to query.
* @return 0 for success, -1 otherwise.
*/
int queryBuffer(uint32_t buf_index);
/**
* Exports the buffer as DMABUF FD.
*
* @warning This method works only for \c V4L2_MEMORY_MMAP memory.
*
* Calls \c VIDIOC_EXPBUF IOCTL internally. Populates the \a fd member of all
* the \c NvBuffer::NvBufferPlane members of \c NvBuffer object at index \a buf_in.
*
* @param[in] buf_index Specifies the index of the buffer to export.
* @return 0 for success, -1 otherwise.
*/
int exportBuffer(uint32_t buf_index);
/**
* Starts or stops streaming on the plane.
*
* Calls \c VIDIOC_STREAMON/VIDIOC_STREAMOFF IOCTLs internally.
*
* @param[in] status Must be TRUE to start the stream, FALSE to stop the stream.
* @return 0 for success, -1 otherwise.
*/
int setStreamStatus(bool status);
/**
* Checks whether the plane is streaming.
*
* @returns true if the plane is streaming, false otherwise.
*/
bool getStreamStatus();
/**
* Sets streaming parameters.
*
* Calls \c VIDIOC_S_PARM IOCTL internally.
*
* @param[in] parm A reference to the \c v4l2_streamparm structure to be set on the
* plane.
* @return 0 for success, -1 otherwise.
*/
int setStreamParms(struct v4l2_streamparm & parm);
/**
* Helper method that encapsulates all the method calls required to
* set up the plane for streaming.
*
* Calls reqbuf internally. Then, for each of the buffers, calls #queryBuffer,
* #exportBuffer and maps the buffer/allocates the buffer memory depending
* on the memory type.
*
* @sa deinitPlane
*
* @param[in] mem_type V4L2 Memory to use on the buffer.
* @param[in] num_buffers Number of buffer to request on the plane.
* @param[in] map boolean value indicating if the buffers should be mapped to
memory (Only for V4L2_MEMORY_MMAP).
* @param[in] allocate boolean valued indicating whether the buffers should be
allocated memory (Only for V4L2_MEMORY_USERPTR).
* @return 0 for success, -1 otherwise.
*/
int setupPlane(enum v4l2_memory mem_type, uint32_t num_buffers, bool map, bool allocate);
/**
* Helper method that encapsulates all the method calls required to
* deinitialize the plane for streaming.
*
* For each of the buffers, unmaps/deallocates memory depending on the
* memory type. Then, calls reqbuf with count zero.
*
* @sa setupPlane
*/
void deinitPlane();
/**
* Gets the streaming/buffer type of this plane.
*
* @returns Type of the buffer belonging to enum \c v4l2_buf_type.
*/
inline enum v4l2_buf_type getBufType()
{
return buf_type;
}
/**
* Gets the \c NvBuffer object at index n.
*
* @returns \c %NvBuffer object at index n, NULL if n >= number of buffers.
*/
NvBuffer *getNthBuffer(uint32_t n);
/**
* Dequeues a buffer from the plane.
*
* This is a blocking call. This call returns when a buffer is successfully
* dequeued or timeout is reached. If \a buffer is not NULL, returns the
* \c NvBuffer object at the index returned by the \c VIDIOC_DQBUF IOCTL. If this
* plane shares a buffer with other elements and \a shared_buffer is not
* NULL, returns the shared \c %NvBuffer object in \a shared_buffer.
*
* @param[in] v4l2_buf A reference to the \c v4l2_buffer structure to use for dequeueing.
* @param[out] buffer Returns a pointer to a pointer to the \c %NvBuffer object associated with the dequeued
* buffer. Can be NULL.
* @param[out] shared_buffer Returns a pointer to a pointer to the shared \c %NvBuffer object if the queued
buffer is shared with other elements. Can be NULL.
* @param[in] num_retries Number of times to try dequeuing a buffer before
* a failure is returned. In case of non-blocking
* mode, this is equivalent to the number of
* milliseconds to try to dequeue a buffer.
* @return 0 for success, -1 otherwise.
*/
int dqBuffer(struct v4l2_buffer &v4l2_buf, NvBuffer ** buffer,
NvBuffer ** shared_buffer, uint32_t num_retries);
/**
* Queues a buffer on the plane.
*
* This method calls \c VIDIOC_QBUF internally. If this plane is sharing a
* buffer with other elements, the application can pass the pointer to the
* shared NvBuffer object in \a shared_buffer.
*
* @param[in] v4l2_buf A reference to the \c v4l2_buffer structure to use for queueing.
* @param[in] shared_buffer A pointer to the shared \c %NvBuffer object.
* @return 0 for success, -1 otherwise.
*/
int qBuffer(struct v4l2_buffer &v4l2_buf, NvBuffer * shared_buffer);
/**
* Gets the number of buffers allocated/requested on the plane.
*
* @returns Number of buffers.
*/
inline uint32_t getNumBuffers()
{
return num_buffers;
}
/**
* Gets the number of planes buffers on this plane for the currently
* set format.
*
* @returns Number of planes.
*/
inline uint32_t getNumPlanes()
{
return n_planes;
}
/**
* Sets the format of the planes of the buffer that is used with this
* plane.
*
* The buffer plane format must be set before calling reqbuf since
* these are needed by the NvBuffer constructor.
*
* @sa reqbufs
*
* @param[in] n_planes Number of planes in the buffer.
* @param[in] planefmts A pointer to the array of \c NvBufferPlaneFormat that describes the
* format of each of the plane. The array length must be at
* least @a n_planes.
*/
void setBufferPlaneFormat(int n_planes, NvBuffer::NvBufferPlaneFormat * planefmts);
/**
* Gets the number of buffers currently queued on the plane.
*
* @returns Number of buffers currently queued on the plane.
*/
inline uint32_t getNumQueuedBuffers()
{
return num_queued_buffers;
}
/**
* Gets the total number of buffers dequeued from the plane.
*
* @returns Total number of buffers dequeued from the plane.
*/
inline uint32_t getTotalDequeuedBuffers()
{
return total_dequeued_buffers;
}
/**
* Gets the total number of buffers queued on the plane.
*
* @returns Total number of buffers queued on the plane.
*/
inline uint32_t getTotalQueuedBuffers()
{
return total_queued_buffers;
}
/**
* Waits until all buffers of the plane are queued.
*
* This is a blocking call that returns when all the buffers are queued
* or timeout is reached.
* @param[in] max_wait_ms Maximum time to wait, in milliseconds.
* @return 0 for success, -1 otherwise.
*/
int waitAllBuffersQueued(uint32_t max_wait_ms);
/**
* Waits until all buffers of the plane are dequeued.
*
* This is a blocking call that returns when all the buffers are dequeued
* or timeout is reached.
* @param[in] max_wait_ms Maximum time to wait, in milliseconds
* @return 0 for success, -1 otherwise.
*/
int waitAllBuffersDequeued(uint32_t max_wait_ms);
/**
* This is a callback function type method that is called by the DQ Thread when
* it successfully dequeues a buffer from the plane. Applications must implement
* this and set the callback using #setDQThreadCallback.
*
* Setting the stream to off automatically stops this thread.
*
* @sa setDQThreadCallback, #startDQThread
*
* @param v4l2_buf A pointer to the \c v4l2_buffer structure that is used for dequeueing.
* @param buffer A pointer to the NvBuffer object at the \c index contained in \c v4l2_buf.
* @param shared_buffer A pointer to the NvBuffer object if the plane shares a buffer with other elements,
* else NULL.
* @param data A pointer to application specific data that is set with
* #startDQThread.
* @returns If the application implementing this call returns FALSE,
* the DQThread is stopped; else, the DQ Thread continues running.
*/
typedef bool(*dqThreadCallback) (struct v4l2_buffer * v4l2_buf,
NvBuffer * buffer, NvBuffer * shared_buffer,
void *data);
/**
* Sets the DQ Thread callback method.
*
* The callback method is called from the DQ Thread once a buffer is
* successfully dequeued.
* @param[in] callback Method to be called upon succesful dequeue.
* @returns TRUE for success, FALSE for failure.
*/
bool setDQThreadCallback(dqThreadCallback callback);
/**
* Starts DQ Thread.
*
* This method starts a thread internally. On successful dequeue of a
* buffer from the plane, the #dqThreadCallback method set using
* #setDQThreadCallback is called.
*
* Setting the stream to off automatically stops the thread.
*
* @sa stopDQThread, waitForDQThread
*
* @param[in] data A pointer to the application data. This is provided as an
* argument in the \c dqThreadCallback method.
* @return 0 for success, -1 otherwise.
*/
int startDQThread(void *data);
/**
* Force stops the DQ Thread if it is running.
*
* Does not work when the device is opened in blocking mode.
*
* @sa startDQThread, waitForDQThread
*
* @return 0 for success, -1 otherwise.
*/
int stopDQThread();
/**
* Waits for the DQ Thread to stop.
*
* This method waits until the DQ Thread stops or timeout is reached.
*
* @sa startDQThread, stopDQThread
*
* @param[in] max_wait_ms Maximum wait time, in milliseconds.
* @return 0 for success, -1 otherwise.
*/
int waitForDQThread(uint32_t max_wait_ms);
pthread_mutex_t plane_lock; /**< Mutex lock used along with #plane_cond. */
pthread_cond_t plane_cond; /**< Plane condition that application can wait on
to receive notifications from
#qBuffer/#dqBuffer. */
private:
int &fd; /**< A reference to the FD of the V4l2 Element the plane is associated with. */
const char *plane_name; /**< A pointer to the name of the plane. Could be "Output Plane" or
"Capture Plane". Used only for debug logs. */
enum v4l2_buf_type buf_type; /**< Speciifes the type of the stream. */
bool blocking; /**< Specifies whether the V4l2 element is opened with
blocking mode. */
uint32_t num_buffers; /**< Holds the number of buffers returned by \c VIDIOC_REQBUFS
IOCTL. */
NvBuffer **buffers; /**< A pointer to an array of NvBuffer object pointers. This array is
allocated and initialized in #reqbufs. */
uint8_t n_planes; /**< Specifies the number of planes in the buffers. */
NvBuffer::NvBufferPlaneFormat planefmts[MAX_PLANES];
/**< Format of the buffer planes. This must be
initialized before calling #reqbufs since this
is required by the \c %NvBuffer constructor. */
enum v4l2_memory memory_type; /**< Specifies the V4l2 memory type of the buffers. */
uint32_t num_queued_buffers; /**< Holds the number of buffers currently queued on the
plane. */
uint32_t total_queued_buffers; /**< Holds the total number of buffers queued on the
plane. */
uint32_t total_dequeued_buffers; /**< Holds the total number of buffers dequeued from
the plane. */
bool streamon; /**< Specifies whether the plane is streaming. */
bool dqthread_running; /**< Specifies whether DQ Thread is running.
Its value is toggled by the DQ Thread. */
bool stop_dqthread; /**< Specifies the value used to signal the DQ Thread to stop. */
pthread_t dq_thread; /**< Speciifes the pthread ID of the DQ Thread. */
dqThreadCallback callback; /**< Specifies the callback method used by the DQ Thread. */
void *dqThread_data; /**< Application supplied pointer provided as an
argument in #dqThreadCallback. */
/**
* The DQ thread method.
*
* This method runs indefinitely until it is signaled to stop
* by #stopDQThread or the #dqThreadCallback method returns FALSE.
* It keeps on trying to dequeue a buffer from the plane and calls the
* #dqThreadCallback method on successful dequeue.
*
* @param[in] v4l2_element_plane A pointer to the NvV4l2ElementPlane object
* for which the thread started.
*/
static void *dqThread(void *v4l2_element_plane);
NvElementProfiler &v4l2elem_profiler; /**< A reference to the profiler belonging
to the plane's parent element. */
/**
* Indicates whether the plane encountered an error during its operation.
*
* @return 0 if no error was encountered, a non-zero value if an
* error was encountered.
*/
inline int isInError()
{
return is_in_error;
}
/**
* Creates a new V4l2Element plane.
*
*
* @param[in] buf_type Type of the stream.
* @param[in] device_name A pointer to the name of the element the plane belongs to.
* @param[in] fd A reference to the FD of the device opened using v4l2_open.
* @param[in] blocking A flag that indicates whether the device has been opened with blocking mode.
* @param[in] profiler The profiler.
*/
NvV4l2ElementPlane(enum v4l2_buf_type buf_type, const char *device_name,
int &fd, bool blocking, NvElementProfiler &profiler);
/**
* Disallows copy constructor.
*/
NvV4l2ElementPlane(const NvV4l2ElementPlane& that);
/**
* Disallows assignment.
*/
void operator=(NvV4l2ElementPlane const&);
/**
* NvV4l2ElementPlane destructor.
*
* Calls #deinitPlane internally.
*/
~NvV4l2ElementPlane();
int is_in_error; /**< Indicates if an error was encountered during
the operation of the element. */
const char *comp_name; /**< Specifies the name of the component,
for debugging. */
friend class NvV4l2Element;
};
/** @} */
#endif