00001 /* 00002 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * * Redistributions of source code must retain the above copyright 00008 * notice, this list of conditions and the following disclaimer. 00009 * * Redistributions in binary form must reproduce the above copyright 00010 * notice, this list of conditions and the following disclaimer in the 00011 * documentation and/or other materials provided with the distribution. 00012 * * Neither the name of NVIDIA CORPORATION nor the names of its 00013 * contributors may be used to endorse or promote products derived 00014 * from this software without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 00017 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00019 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 00020 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00021 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00022 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00023 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00024 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00026 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00029 /** 00030 * @file NvV4l2ElementPlane.h 00031 * 00032 * @brief Helper Class for operations performed on a V4L2 Element plane 00033 */ 00034 00035 #ifndef __NV_V4L2_ELELMENT_PLANE_H__ 00036 #define __NV_V4L2_ELELMENT_PLANE_H__ 00037 00038 #include <pthread.h> 00039 #include "NvElement.h" 00040 #include "NvLogging.h" 00041 #include "NvBuffer.h" 00042 00043 /** 00044 * Prints a plane specific message of level #LOG_LEVEL_DEBUG. 00045 * Should not be used by applications. 00046 */ 00047 #define PLANE_DEBUG_MSG(str) COMP_DEBUG_MSG(plane_name << ":" << str); 00048 /** 00049 * Prints a plane specific message of level #LOG_LEVEL_INFO. 00050 * Should not be used by applications. 00051 */ 00052 #define PLANE_INFO_MSG(str) COMP_INFO_MSG(plane_name << ":" << str); 00053 /** 00054 * Prints a plane specific message of level #LOG_LEVEL_WARN. 00055 * Should not be used by applications. 00056 */ 00057 #define PLANE_WARN_MSG(str) COMP_WARN_MSG(plane_name << ":" << str); 00058 /** 00059 * Prints a plane specific message of level #LOG_LEVEL_ERROR. 00060 * Should not be used by applications. 00061 */ 00062 #define PLANE_ERROR_MSG(str) COMP_ERROR_MSG(plane_name << ":" << str); 00063 /** 00064 * Prints a plane specific system error message of level #LOG_LEVEL_ERROR. 00065 * Should not be used by applications. 00066 */ 00067 #define PLANE_SYS_ERROR_MSG(str) COMP_SYS_ERROR_MSG(plane_name << ":" << str); 00068 00069 /** 00070 * @brief Helper Class for operations performed on a V4L2 Element plane. 00071 * 00072 * This class is modelled on the planes of a V4L2 Element. It provides 00073 * convenient wrapper functions around V4L2 ioctls associated with plane 00074 * operations such as VIDIOC_G_FMT/VIDIOC_S_FMT, VIDIOC_REQBUFS,\ 00075 * VIDIOC_STREAMON/VIDIOC_STREAMOFF, etc. 00076 * 00077 * The plane buffer type can be either V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE (for 00078 * the output plane) or V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE (for the capture 00079 * plane). 00080 * 00081 * The plane has an array of NvBuffer object pointers which is allocated and 00082 * initialized during #reqbufs call. These NvBuffer objects are similar to the 00083 * v4l2_buffer structures which are queued/dequeued. 00084 * 00085 * This class provides another feature useful for multi-threading. On calling 00086 * #startDQThread, it internally spawns a thread which runs infinitely till 00087 * signalled to stop. This thread keeps on trying to dequeue a buffer from the 00088 * plane and calls a #dqThreadCallback function specified by the user on 00089 * successful dequeue. 00090 * 00091 */ 00092 class NvV4l2ElementPlane 00093 { 00094 00095 public: 00096 /** 00097 * Get the plane format 00098 * 00099 * Calls @b VIDIOC_G_FMT ioctl internally. 00100 * 00101 * @param[in,out] format Reference to v4l2_format structure to be filled 00102 * @returns 0 for success, -1 for failure 00103 */ 00104 int getFormat(struct v4l2_format & format); 00105 /** 00106 * Set the plane format 00107 * 00108 * Calls @b VIDIOC_S_FMT ioctl internally. 00109 * 00110 * @param[in] format Reference to v4l2_format structure to be set on the plane 00111 * @returns 0 for success, -1 for failure 00112 */ 00113 int setFormat(struct v4l2_format & format); 00114 00115 /** 00116 * Get the cropping rectangle for the plane 00117 * 00118 * Calls @b VIDIOC_G_CROP ioctl internally. 00119 * 00120 * @param[in] crop Reference to v4l2_crop structure to be filled 00121 * @returns 0 for success, -1 for failure 00122 */ 00123 int getCrop(struct v4l2_crop & crop); 00124 00125 /** 00126 * Set the selection rectangle for the plane 00127 * 00128 * Calls @b VIDIOC_S_SELECTION ioctl internally. 00129 * 00130 * @param[in] target Rectangle selection type 00131 * @param[in] flags Flags to control selection adjustments 00132 * @param[in] rect Selection rectangle 00133 * @returns 0 for success, -1 for failure 00134 */ 00135 int setSelection(uint32_t target, uint32_t flags, struct v4l2_rect & rect); 00136 00137 /** 00138 * Request for buffers on the plane. 00139 * 00140 * Calls @b VIDIOC_REQBUFS ioctl internally. Creates an array of NvBuffer of 00141 * length equal to the count returned by the ioctl. 00142 * 00143 * @param[in] mem_type Type of V4L2 Memory to be requested 00144 * @param[in] num Number of buffers to request on the plane 00145 * @returns 0 for success, -1 for failure 00146 */ 00147 int reqbufs(enum v4l2_memory mem_type, uint32_t num); 00148 /** 00149 * Query the status of buffer at index 00150 * 00151 * @warning This functions works only for V4L2_MEMORY_MMAP memory. 00152 * 00153 * Calls VIDIOC_QUERYBUF ioctl internally. Populates the \a length and \a 00154 * mem_offset members of all the NvBuffer::NvBufferPlane members of the 00155 * NvBuffer object at index \a buf_index. 00156 * 00157 * @param[in] buf_index Index of the buffer to query 00158 * @returns 0 for success, -1 for failure 00159 */ 00160 int queryBuffer(uint32_t buf_index); 00161 /** 00162 * Export the buffer as DMABUF FD. 00163 * 00164 * @warning This functions works only for V4L2_MEMORY_MMAP memory. 00165 * 00166 * Calls VIDIOC_EXPBUF ioctl internally. Populates the \a fd member of all 00167 * the NvBuffer::NvBufferPlane members of NvBuffer object at index \a buf_in. 00168 * 00169 * @param[in] buf_index Index of the buffer to export 00170 * @returns 0 for success, -1 for failure 00171 */ 00172 int exportBuffer(uint32_t buf_index); 00173 00174 /** 00175 * Start or stop streaming on the plane. 00176 * 00177 * Calls VIDIOC_STREAMON/VIDIOC_STREAMOFF ioctls internally. 00178 * 00179 * @param[in] status Should be true to start stream, false to stop stream 00180 * @returns 0 for success, -1 for failure 00181 */ 00182 int setStreamStatus(bool status); 00183 00184 /** 00185 * Check if the plane is streaming. 00186 * 00187 * @returns true if the plane is streaming, false otherwise. 00188 */ 00189 bool getStreamStatus(); 00190 00191 /** 00192 * Set streaming parameters. 00193 * 00194 * Calls VIDIOC_S_PARM ioctl internally. 00195 * 00196 * @param[in] parm Reference to v4l2_streamparm structure to be set on the 00197 * plane 00198 * @returns 0 for success, -1 for failure 00199 */ 00200 int setStreamParms(struct v4l2_streamparm & parm); 00201 00202 /** 00203 * Helper function which encapsulates all the function calls required to 00204 * setup the plane for streaming. 00205 * 00206 * Calls #reqbufs internally. Then, for each of the buffers calls #queryBuffer, 00207 * #exportBuffer and maps the buffer/allocates the buffer memory depending 00208 * on the memory type. 00209 * 00210 * @sa deinitPlane 00211 * 00212 * @param[in] mem_type V4L2 Memory to use on the buffer 00213 * @param[in] num_buffers Number of buffer to request on the plane 00214 * @param[in] map boolean value indicating if the buffers should be mapped to 00215 memory (Only for V4L2_MEMORY_MMAP) 00216 * @param[in] allocate boolean valued indicating if the buffers should be 00217 allocated memory (Only for V4L2_MEMORY_USERPTR) 00218 * @returns 0 for success, -1 for failure 00219 */ 00220 int setupPlane(enum v4l2_memory mem_type, uint32_t num_buffers, bool map, bool allocate); 00221 /** 00222 * Helper function which encapsulates all the function calls required to 00223 * deinitialize the plane for streaming. 00224 * 00225 * For each of the buffers unmaps/deallocates memory depending on the 00226 * memory type. Then, calls reqbufs with count zero. 00227 * 00228 * @sa setupPlane 00229 */ 00230 void deinitPlane(); 00231 00232 /** 00233 * Get the streaming/buffer type of this plane. 00234 * 00235 * @returns Type of the buffer belonging to enum v4l2_buf_type 00236 */ 00237 inline enum v4l2_buf_type getBufType() 00238 { 00239 return buf_type; 00240 } 00241 00242 /** 00243 * Get the NvBuffer object at index n 00244 * 00245 * @returns NvBuffer object at index n, NULL if n >= Number of buffers 00246 */ 00247 NvBuffer *getNthBuffer(uint32_t n); 00248 00249 /** 00250 * Dequeue a buffer from the plane. 00251 * 00252 * This is a blocking call. This call returns when a buffer is successfully 00253 * dequeued or timeout is reached. If \a buffer is not NULL returns the 00254 * NvBuffer object at the index returned by the VIDIOC_DQBUF ioctl. If this 00255 * plane shares a buffer with other element and \a shared_buffer is not 00256 * NULL returns the shared NvBuffer object in \a shared_buffer. 00257 * 00258 * @param[in] v4l2_buf v4l2_buffer structure to be used for dequeueing 00259 * @param[out] buffer Returns the NvBuffer object associated with the dequeued 00260 * buffer. Can be NULL 00261 * @param[out] shared_buffer Returns the shared NvBuffer object, if the queued 00262 * buffer is being shared with other elements. Can be NULL. 00263 * @param[in] num_retries Number of times to try dequeuing a buffer before 00264 * a failure is returned. In case of non-blocking 00265 * mode, this is equivalent to the number of 00266 * milliseconds to try to dequeue a buffer. 00267 * @returns 0 for success, -1 for failure/timeout 00268 */ 00269 int dqBuffer(struct v4l2_buffer &v4l2_buf, NvBuffer ** buffer, 00270 NvBuffer ** shared_buffer, uint32_t num_retries); 00271 /** 00272 * Queue a buffer on the plane. 00273 * 00274 * This function calls VIDIOC_QBUF internally. If this plane is sharing 00275 * buffer with other elements, the application can pass the pointer to the 00276 * shared NvBuffer object in \a shared_buffer. 00277 * 00278 * @param[in] v4l2_buf v4l2_buffer structure to be used for queueing 00279 * @param[in] shared_buffer Pointer to the shared NvBuffer object 00280 * @returns 0 for success, -1 for failure/timeout 00281 */ 00282 int qBuffer(struct v4l2_buffer &v4l2_buf, NvBuffer * shared_buffer); 00283 00284 /** 00285 * Get the number of buffers allocated/requested on the plane 00286 * 00287 * @returns Number of buffers 00288 */ 00289 inline uint32_t getNumBuffers() 00290 { 00291 return num_buffers; 00292 } 00293 00294 /** 00295 * Get the number of planes buffers on this plane contain for the currently 00296 * set format 00297 * 00298 * @returns Number of planes 00299 */ 00300 inline uint32_t getNumPlanes() 00301 { 00302 return n_planes; 00303 } 00304 00305 /** 00306 * Set the format of the planes of the buffer which will be used with this 00307 * plane. 00308 * 00309 * The buffer plane format needs to be set before calling #reqbufs, since 00310 * these are needed by the NvBuffer constructor. 00311 * 00312 * @sa reqbufs 00313 * 00314 * @param[in] n_planes Number of planes in the buffer 00315 * @param[in] planefmts Array of NvBufferPlaneFormat which describes the 00316 * format of each of the plane. The array length should be at 00317 * least @a n_planes. 00318 */ 00319 void setBufferPlaneFormat(int n_planes, NvBuffer::NvBufferPlaneFormat * planefmts); 00320 00321 /** 00322 * Get the number of buffers currently queued on the plane 00323 * 00324 * @returns number of buffers currently queued on the plane 00325 */ 00326 inline uint32_t getNumQueuedBuffers() 00327 { 00328 return num_queued_buffers; 00329 } 00330 00331 /** 00332 * Get the total number of buffers dequeued from the plane 00333 * 00334 * @returns total number of buffers dequeued from the plane 00335 */ 00336 inline uint32_t getTotalDequeuedBuffers() 00337 { 00338 return total_dequeued_buffers; 00339 } 00340 00341 /** 00342 * Get the total number of buffers queued on the plane 00343 * 00344 * @returns total number of buffers queued on the plane 00345 */ 00346 inline uint32_t getTotalQueuedBuffers() 00347 { 00348 return total_queued_buffers; 00349 } 00350 00351 /** 00352 * Wait till all the buffers of the plane get queued 00353 * 00354 * This is a blocking call which returns when all the buffers get queued 00355 * or timeout is reached. 00356 00357 * @param[in] max_wait_ms Maximum time to wait in milliseconds 00358 * @returns 0 for success, -1 for failure/timeout 00359 */ 00360 int waitAllBuffersQueued(uint32_t max_wait_ms); 00361 /** 00362 * Wait till all the buffers of the plane get dequeued 00363 * 00364 * This is a blocking call which returns when all the buffers get dequeued 00365 * or timeout is reached. 00366 00367 * @param[in] max_wait_ms Maximum time to wait in milliseconds 00368 * @returns 0 for success, -1 for failure/timeout 00369 */ 00370 int waitAllBuffersDequeued(uint32_t max_wait_ms); 00371 00372 /** 00373 * This is a callback function type which is called by the DQ Thread when 00374 * it successfully dequeues a buffer from the plane. Applications must implement 00375 * this and set the callback using #setDQThreadCallback. 00376 * 00377 * Setting the stream to off will automatically stop this thread. 00378 * 00379 * @sa setDQThreadCallback, #startDQThread 00380 * 00381 * @param v4l2_buf v4l2_buffer structure which was used for dequeueing 00382 * @param buffer NvBuffer object at the @a index contained in @a v4l2_buf 00383 * @param shared_buffer If the plane shares buffer with another elements 00384 * pointer to the NvBuffer object else NULL 00385 * @param data Pointer to application specific data which was set with 00386 * #startDQThread 00387 * @returns If the application implementing this calls returns false, 00388 * the DQThread will be stopped else the DQThread will continue running. 00389 */ 00390 typedef bool(*dqThreadCallback) (struct v4l2_buffer * v4l2_buf, 00391 NvBuffer * buffer, NvBuffer * shared_buffer, 00392 void *data); 00393 00394 /** 00395 * Set the DQ Thread callback function. 00396 * 00397 * The callback function is called from the DQ Thread once a buffer is 00398 * successfully dequeued. 00399 00400 * @param[in] callback Function to be called on succesful dequeue 00401 * @returns true for success, false for failure 00402 */ 00403 bool setDQThreadCallback(dqThreadCallback callback); 00404 /** 00405 * Start DQ Thread. 00406 * 00407 * This function starts a thread internally. On successful dequeue of a 00408 * buffer from the plane, #dqThreadCallback function set using 00409 * setDQThreadCallback gets called. 00410 * 00411 * Setting the stream to off will automatically stop the thread. 00412 * 00413 * @sa stopDQThread, waitForDQThread 00414 * 00415 * @param[in] data Application data pointer. This is provided as an 00416 * argument in the dqThreadCallback function 00417 * @returns 0 for success, -1 for failure/timeout 00418 */ 00419 int startDQThread(void *data); 00420 /** 00421 * Force stop the DQ Thread if it is running. 00422 * 00423 * Does not work when the device has been opened in blocking mode. 00424 * 00425 * @sa startDQThread, waitForDQThread 00426 * 00427 * @returns 0 for success, -1 for failure/timeout 00428 */ 00429 int stopDQThread(); 00430 /** 00431 * Wait for the DQ Thread to stop 00432 * 00433 * This function waits till the DQ Thread stops or timeout is reached 00434 * 00435 * @sa startDQThread, stopDQThread 00436 * 00437 * @param[in] max_wait_ms 00438 * @returns 0 for success, -1 for failure/timeout 00439 */ 00440 int waitForDQThread(uint32_t max_wait_ms); 00441 00442 pthread_mutex_t plane_lock; /**< Mutex lock used along with #plane_cond */ 00443 pthread_cond_t plane_cond; /**< Plane condition which application can wait on 00444 to receive notifications from 00445 #qBuffer/#dqBuffer */ 00446 00447 private: 00448 int &fd; /**< FD of the V4l2 Element the plane is associated with */ 00449 00450 const char *plane_name; /**< Name of the plane. Could be "Output Plane" or 00451 "Capture Plane". Used only for debug logs */ 00452 00453 enum v4l2_buf_type buf_type; /**< Type of the stream. */ 00454 00455 bool blocking; /**< Whether the V4l2 element has been opened with 00456 blocking mode */ 00457 00458 uint32_t num_buffers; /**< Number of buffers returned by VIDIOC_REQBUFS 00459 ioctl */ 00460 NvBuffer **buffers; /**< Array of NvBuffer object pointers. This array is 00461 allocated and initialized in #reqbufs. */ 00462 00463 uint8_t n_planes; /**< Number of planes in the buffers */ 00464 NvBuffer::NvBufferPlaneFormat planefmts[MAX_PLANES]; 00465 /**< Format of the buffer planes. This should be 00466 initialized before calling #reqbufs since this 00467 is required by the NvBuffer constructor */ 00468 00469 enum v4l2_memory memory_type; /**< V4l2 memory type of the buffers */ 00470 00471 uint32_t num_queued_buffers; /**< Number of buffers currently queued on the 00472 plane */ 00473 uint32_t total_queued_buffers; /**< Total number of buffers queued on the 00474 plane */ 00475 uint32_t total_dequeued_buffers; /**< Total number of buffers dequeued from 00476 the plane */ 00477 00478 bool streamon; /**< Boolean indicating if the plane is streaming */ 00479 00480 bool dqthread_running; /**< Boolean indicating if the DQ Thread is running. 00481 Its value is toggled by the DQ Thread */ 00482 bool stop_dqthread; /**< Boolean value used to signal the DQ Thread to stop */ 00483 00484 pthread_t dq_thread; /**< pthread ID of the DQ Thread */ 00485 00486 dqThreadCallback callback; /**< Callback function used by the DQ Thread */ 00487 00488 void *dqThread_data; /**< Application supplied pointer provided as an 00489 argument in #dqThreadCallback */ 00490 00491 /** 00492 * The DQ thread function. 00493 * 00494 * This function keeps on running infinitely till it is signalled to stop 00495 * by #stopDQThread or the #dqThreadCallback function returns false. 00496 * It keeps on trying to dequeue a buffer from the plane and calls the 00497 * #dqThreadCallback function on successful dequeue 00498 * 00499 * @param[in] v4l2_element_plane Pointer to the NvV4l2ElementPlane object 00500 * for which the thread has been started 00501 */ 00502 static void *dqThread(void *v4l2_element_plane); 00503 00504 NvElementProfiler &v4l2elem_profiler; /**< A reference to the profiler belonging 00505 to the plane's parent element. */ 00506 00507 /** 00508 * Indicates if the plane encountered an error during its operation. 00509 * 00510 * @return 0 if no error was encountered, a non-zero value if an 00511 * error was encountered. 00512 */ 00513 inline int isInError() 00514 { 00515 return is_in_error; 00516 } 00517 00518 /** 00519 * Creates a new V4l2Element plane 00520 * 00521 * 00522 * @param[in] buf_type Type of the stream 00523 * @param[in] device_name Name of the element the plane belongs to 00524 * @param[in] fd FD of the device opened using v4l2_open 00525 * @param[in] blocking Whether the device has been opened with blocking mode 00526 */ 00527 NvV4l2ElementPlane(enum v4l2_buf_type buf_type, const char *device_name, 00528 int &fd, bool blocking, NvElementProfiler &profiler); 00529 00530 /** 00531 * Disallow copy constructor. 00532 */ 00533 NvV4l2ElementPlane(const NvV4l2ElementPlane& that); 00534 /** 00535 * Disallow assignment. 00536 */ 00537 void operator=(NvV4l2ElementPlane const&); 00538 00539 /** 00540 * NvV4l2ElementPlane destructor. 00541 * 00542 * Calls #deinitPlane internally. 00543 */ 00544 ~NvV4l2ElementPlane(); 00545 00546 int is_in_error; /**< Indicates if an error was encountered during 00547 the operation of the element. */ 00548 const char *comp_name; /**< Specifies the name of the component, 00549 for debugging. */ 00550 00551 friend class NvV4l2Element; 00552 }; 00553 00554 #endif