xiaoxiang781216 commented on code in PR #1449:
URL: https://github.com/apache/nuttx-apps/pull/1449#discussion_r1044234190


##########
system/nxcamera/nxcamera.c:
##########
@@ -0,0 +1,889 @@
+/****************************************************************************
+ * apps/system/nxcamera/nxcamera.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/queue.h>
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <system/nxcamera.h>
+
+#ifdef CONFIG_LIBYUV
+#  include <libyuv.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXCAMERA_STATE_IDLE      0
+#define NXCAMERA_STATE_STREAMING 1
+#define NXCAMERA_STATE_LOOPING   2
+#define NXCAMERA_STATE_PAUSED    3
+
+#ifndef MIN
+#  define MIN(a, b)              (((a) < (b)) ? (a) : (b))
+#endif
+
+#define convert_frame            ConvertToARGB
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int show_image(FAR struct nxcamera_s *pcam, FAR v4l2_buffer_t *buf)
+{
+#ifdef CONFIG_LIBYUV
+  return convert_frame(pcam->bufs[buf->index],
+                       pcam->buf_sizes[buf->index],
+                       pcam->display_pinfo.fbmem,
+                       pcam->display_pinfo.stride,
+                       0,
+                       0,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       0,
+                       pcam->fmt.fmt.pix.pixelformat);
+#else
+  uint32_t *pbuf = pcam->bufs[buf->index];
+  vinfo("show image from %p: %lx %lx", pbuf, pbuf[0], pbuf[1]);
+  return 0;
+#endif
+}
+
+/****************************************************************************
+ * Name: nxcamera_opendevice
+ *
+ *   nxcamera_opendevice() tries to open the preferred devices as specified.
+ *
+ * Return:
+ *    OK        if compatible device opened (searched or preferred)
+ *    -ENODEV   if no compatible device opened.
+ *    -ENOENT   if preferred device couldn't be opened.
+ *
+ ****************************************************************************/
+
+static int nxcamera_opendevice(FAR struct nxcamera_s *pcam)
+{
+  int errcode;
+
+  if (pcam->capturedev[0] != '\0')
+    {
+      pcam->capture_fd = open(pcam->capturedev, O_RDWR);
+      if (pcam->capture_fd == -1)
+        {
+          errcode = errno;
+          DEBUGASSERT(errcode > 0);
+
+          verr("ERROR: Failed to open pcam->capturedev %d\n", -errcode);
+          return -errcode;
+        }
+
+      if (pcam->displaydev[0] != '\0')
+        {
+          pcam->display_fd = open(pcam->displaydev, O_RDWR);
+          if (pcam->display_fd == -1)
+            {
+              errcode = errno;
+              DEBUGASSERT(errcode > 0);
+
+              close(pcam->capture_fd);
+              pcam->capture_fd = -1;
+              verr("ERROR: Failed to open pcam->displaydev %d\n", -errcode);
+              return -errcode;
+            }
+
+          errcode = ioctl(pcam->display_fd, FBIOGET_PLANEINFO,
+                          ((uintptr_t)&pcam->display_pinfo));
+
+          if (errcode == OK)
+            {
+              pcam->display_pinfo.fbmem = mmap(NULL,
+                                               pcam->display_pinfo.fblen,
+                                               PROT_READ | PROT_WRITE,
+                                               MAP_SHARED | MAP_FILE,
+                                               pcam->display_fd,
+                                               0);
+            }
+
+          if (errcode < 0 || pcam->display_pinfo.fbmem == MAP_FAILED)
+            {
+              errcode = errno;
+              close(pcam->capture_fd);
+              close(pcam->display_fd);
+              verr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", -errcode);
+              return -errcode;
+            }
+
+          return OK;
+        }
+      else
+        {
+          /* TODO: Add file output */
+
+          return -ENOTSUP;
+        }
+    }
+
+  return -ENODEV;
+}
+
+/****************************************************************************
+ * Name: nxcamera_loopthread
+ *
+ *  This is the thread that streams the video and handles video controls.
+ *
+ ****************************************************************************/
+
+static void *nxcamera_loopthread(pthread_addr_t pvarg)
+{
+  FAR struct nxcamera_s   *pcam = (FAR struct nxcamera_s *)pvarg;
+  unsigned int            prio;
+  ssize_t                 size;
+  struct video_msg_s      msg;
+  bool                    streaming = true;
+  int                     i;
+  int                     ret;
+  struct v4l2_buffer      buf;
+  uint32_t                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  vinfo("Entry\n");
+
+  for (i = 0; i < pcam->nbuffers; i++)
+    {
+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QBUF failed: %d\n", ret);
+          goto err_out;
+        }
+    }
+
+  /* VIDIOC_STREAMON start stream */
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_STREAMON, (uintptr_t)&type);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_STREAMON failed: %d\n", ret);
+      goto err_out;
+    }
+  else
+    {
+      pcam->loopstate = NXCAMERA_STATE_STREAMING;
+    }
+
+  /* Loop until we specifically break. streaming == true means that we are
+   * still looping waiting for the stream to complete.  All of the data
+   * may have been sent, but the stream is not complete until we get
+   * VIDEO_MSG_STOP message
+   *
+   * The normal protocol for looping errors detected by the video driver
+   * is as follows:
+   *
+   * (1) The video driver will indicated the error by returning a negated
+   *     error value when the next buffer is enqueued.  The upper level
+   *     then knows that this buffer was not queued.
+   * (2) The video driver must return all queued buffers using the
+   *     VIDEO_MSG_DEQUEUE message.
+   */
+
+  while (streaming)
+    {
+      size = mq_receive(pcam->mq, (FAR char *)&msg, sizeof(msg), &prio);
+
+      /* Validate a message was received */
+
+      if (size == sizeof(msg))
+        {
+          /* Perform operation based on message id */
+
+          vinfo("message received size %zd id%d\n", size, msg.msg_id);
+          switch (msg.msg_id)
+            {
+              /* Someone wants to stop the stream. */
+
+              case VIDEO_MSG_STOP:
+
+                /* Send a stop message to the device */
+
+                vinfo("Stopping looping\n");
+                ioctl(pcam->capture_fd, VIDIOC_STREAMOFF, (uintptr_t)&type);
+                streaming = false;
+                goto err_out;
+
+              /* Unknown / unsupported message ID */
+
+              default:
+                break;
+            }
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_DQBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail DQBUF %d\n", errno);
+          goto err_out;
+        }
+
+      ret = show_image(pcam, &buf);
+      if (ret < 0)
+        {
+          verr("Fail to show image %d\n", -ret);
+          goto err_out;
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail QBUF %d\n", errno);
+          goto err_out;
+        }
+    }
+
+  /* Release our video buffers and unregister / release the device */
+
+err_out:
+  vinfo("Clean-up and exit\n");
+
+  /* Cleanup */
+
+  pthread_mutex_lock(&pcam->mutex);  /* Lock the mutex */
+
+  close(pcam->display_fd);           /* Close the display device */
+  close(pcam->capture_fd);           /* Close the capture device */
+  pcam->display_fd = -1;             /* Mark display device as closed */
+  pcam->capture_fd = -1;             /* Mark capture device as closed */
+  mq_close(pcam->mq);                /* Close the message queue */
+  mq_unlink(pcam->mqname);           /* Unlink the message queue */
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  pthread_mutex_unlock(&pcam->mutex);     /* Unlock the mutex */
+
+  vinfo("Exit\n");
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxcamera_setdevice
+ *
+ *   nxcamera_setdevice() sets the preferred video device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setdevice(FAR struct nxcamera_s *pcam,
+                       FAR const char *device)
+{
+  int                    temp_fd;
+  struct v4l2_capability caps;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a video device by issuing an VIDIOC_QUERYCAP ioctl */
+
+  if (ioctl(temp_fd, VIDIOC_QUERYCAP, (uintptr_t)&caps) != OK)
+    {
+      /* Not a video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the preferred device */
+
+  if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+    {
+      return -ENODEV;
+    }
+
+  strlcpy(pcam->capturedev, device, sizeof(pcam->capturedev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfb
+ *
+ *   nxcamera_setfb() sets the output framebuffer device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfb(FAR struct nxcamera_s *pcam, FAR const char *device)
+{
+  int                    temp_fd;
+  struct fb_videoinfo_s  vinfo;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a fb device by issuing an FBIOGET_VIDEOINFO ioctl */
+
+  if (ioctl(temp_fd, FBIOGET_VIDEOINFO, (uintptr_t)&vinfo) != OK)
+    {
+      /* Not an Video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  if (vinfo.nplanes == 0)
+    {
+      return -ENODEV;
+    }
+
+  /* Save the path of the framebuffer device */
+
+  strlcpy(pcam->displaydev, device, sizeof(pcam->displaydev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfile
+ *
+ *   nxcamera_setfile() sets the output file path to use with the provided
+ *   nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfile(FAR struct nxcamera_s *pcam, FAR const char *pfile,
+                     bool isimage)
+{
+  int temp_fd;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(pfile != NULL);
+
+  /* Try to open the file */
+
+  temp_fd = open(pfile, O_CREAT | O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the file */
+
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the output file */
+
+  if (isimage)
+    {
+      strlcpy(pcam->oimagepath, pfile, sizeof(pcam->oimagepath));
+    }
+  else
+    {
+      strlcpy(pcam->ovideopath, pfile, sizeof(pcam->ovideopath));
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stop
+ *
+ *   nxcamera_stop() stops the current playback to loop and closes the
+ *   file and the associated device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized looper context
+ *
+ ****************************************************************************/
+
+int nxcamera_stop(FAR struct nxcamera_s *pcam)
+{
+  struct video_msg_s term_msg;
+  FAR void           *value;
+
+  DEBUGASSERT(pcam != NULL);
+
+  /* Validate we are not in IDLE state */
+
+  pthread_mutex_lock(&pcam->mutex);          /* Lock the mutex */
+  if (pcam->loopstate == NXCAMERA_STATE_IDLE)
+    {
+      pthread_mutex_unlock(&pcam->mutex);    /* Unlock the mutex */
+      return OK;
+    }
+
+  /* Notify the stream thread that it needs to cancel the stream */
+
+  term_msg.msg_id = VIDEO_MSG_STOP;
+  term_msg.u.data = 0;
+  mq_send(pcam->mq, (FAR const char *)&term_msg, sizeof(term_msg),
+          CONFIG_NXCAMERA_MSG_PRIO);
+
+  pthread_mutex_unlock(&pcam->mutex);
+
+  /* Join the thread.  The thread will do all the cleanup. */
+
+  pthread_join(pcam->loop_id, &value);
+  pcam->loop_id = 0;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stream
+ *
+ *   nxcamera_stream() tries to capture and then display the raw data using
+ *   the Video system. If a capture device is specified, it will try to use
+ *   that device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized Looper context
+ *   width      Capture frame width
+ *   height     Capture frame height
+ *   framerate  Capture frame rate
+ *   format     Capture frame pixel format
+ *
+ * Returns:
+ *   OK         Video is being looped
+ *   -EBUSY     Capture device is busy
+ *   -ENOSYS    No supported video format found
+ *   -ENODEV    No video capture or framebuffer device suitable
+ *
+ ****************************************************************************/
+
+int nxcamera_stream(FAR struct nxcamera_s *pcam,
+                    uint16_t width, uint16_t height,
+                    uint32_t framerate, uint32_t format)
+{
+  struct mq_attr              attr;
+  struct sched_param          sparam;
+  pthread_attr_t              tattr;
+  FAR void                    *value;
+  int                         ret;
+  int                         i;
+  struct v4l2_buffer          buf;
+  struct v4l2_requestbuffers  req;
+  struct v4l2_streamparm      parm;
+
+  DEBUGASSERT(pcam != NULL);
+
+  if (pcam->loopstate != NXCAMERA_STATE_IDLE)
+    {
+      return -EBUSY;
+    }
+
+  vinfo("==============================\n");
+  vinfo("streaming video\n");
+  vinfo("==============================\n");
+
+  /* Try to open the device */
+
+  ret = nxcamera_opendevice(pcam);
+  if (ret < 0)
+    {
+      /* Error opening the device */
+
+      verr("ERROR: nxcamera_opendevice failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_S_FMT set format */
+
+  pcam->fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  pcam->fmt.fmt.pix.width       = width;
+  pcam->fmt.fmt.pix.height      = height;
+  pcam->fmt.fmt.pix.field       = V4L2_FIELD_ANY;
+  pcam->fmt.fmt.pix.pixelformat = format;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_FMT, (uintptr_t)&pcam->fmt);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_FMT failed: %d\n", ret);
+      return ret;
+    }
+
+  memset(&parm, 0, sizeof(parm));
+  parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  parm.parm.capture.timeperframe.denominator = framerate;
+  parm.parm.capture.timeperframe.numerator = 1;
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_PARM, (uintptr_t)&parm);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_PARM failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_REQBUFS initiate user pointer I/O */
+
+  req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  req.memory = V4L2_MEMORY_MMAP;
+  req.count  = CONFIG_VIDEO_REQBUFS_COUNT_MAX;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_REQBUFS, (uintptr_t)&req);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_REQBUFS failed: %d\n", ret);
+      return ret;
+    }
+
+  if (req.count < 2)
+    {
+      verr("VIDIOC_REQBUFS failed: not enough buffers\n");
+      return -ENOMEM;
+    }
+
+  pcam->nbuffers = req.count;
+  pcam->bufs = calloc(req.count, sizeof(*pcam->bufs));
+  pcam->buf_sizes = calloc(req.count, sizeof(*pcam->buf_sizes));
+  if (!pcam->bufs || !pcam->buf_sizes)
+    {
+      verr("Cannot allocate buffer pointers\n");
+      ret = -ENOMEM;
+      goto err_out;
+    }
+
+  /* VIDIOC_QBUF enqueue buffer */
+
+  for (i = 0; i < req.count; i++)
+    {
+      buf.type = req.type;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QUERYBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QUERYBUF failed: %d\n", ret);
+          goto err_out;
+        }
+
+      pcam->bufs[i] = mmap(NULL, buf.length,
+                           PROT_READ | PROT_WRITE, MAP_SHARED,
+                           pcam->capture_fd, buf.m.offset);
+      if (pcam->bufs[i] == MAP_FAILED)
+        {
+          ret = -errno;
+          verr("MMAP failed\n");
+          goto err_out;
+        }
+
+      pcam->buf_sizes[i] = buf.length;
+    }
+
+  /* Create a message queue for the loopthread */
+
+  attr.mq_maxmsg  = 8;
+  attr.mq_msgsize = sizeof(struct video_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags   = 0;
+
+  snprintf(pcam->mqname, sizeof(pcam->mqname), "/tmp/%lx",
+           (unsigned long)((uintptr_t)pcam) & 0xffffffff);
+
+  pcam->mq = mq_open(pcam->mqname, O_RDWR | O_CREAT | O_NONBLOCK, 0644,
+                     &attr);
+  if (pcam->mq == (mqd_t)-1)
+    {
+      /* Unable to open message queue! */
+
+      ret = -errno;
+      verr("ERROR: mq_open failed: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Check if there was a previous thread and join it if there was
+   * to perform clean-up.
+   */
+
+  if (pcam->loop_id != 0)
+    {
+      pthread_join(pcam->loop_id, &value);
+    }
+
+  pthread_attr_init(&tattr);
+  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9;
+  pthread_attr_setschedparam(&tattr, &sparam);
+  pthread_attr_setstacksize(&tattr, CONFIG_NXCAMERA_LOOPTHREAD_STACKSIZE);
+
+  /* Add a reference count to the looper for the thread and start the
+   * thread.  We increment for the thread to avoid thread start-up
+   * race conditions.
+   */
+
+  nxcamera_reference(pcam);
+  ret = pthread_create(&pcam->loop_id, &tattr, nxcamera_loopthread,
+                       (pthread_addr_t)pcam);
+  pthread_attr_destroy(&tattr);
+  if (ret != OK)
+    {
+      ret = -ret;
+      verr("ERROR: Failed to create loopthread: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Name the thread */
+
+  pthread_setname_np(pcam->loop_id, "nxcameraloop");
+  return OK;
+
+err_out:
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nxcamera_create
+ *
+ *   nxcamera_create() allocates and initializes a nxcamera context for
+ *   use by further nxcamera operations.  This routine must be called before
+ *   to perform the create for proper reference counting.
+ *
+ * Input Parameters:  None
+ *
+ * Returned values:
+ *   Pointer to the created context or NULL if there was an error.
+ *
+ ****************************************************************************/
+
+FAR struct nxcamera_s *nxcamera_create(void)
+{
+  FAR struct nxcamera_s *pcam;
+  int err;
+
+  /* Allocate the memory */
+
+  pcam = (FAR struct nxcamera_s *)calloc(1, sizeof(struct nxcamera_s));
+  if (pcam == NULL)
+    {
+      return NULL;
+    }
+
+  /* Initialize the context data */
+
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  pcam->display_fd = -1;
+  pcam->capture_fd = -1;
+  err = pthread_mutex_init(&pcam->mutex, NULL);
+  if (err)
+    {
+      verr("ERROR: pthread_mutex_init failed: %d\n", err);
+      free(pcam);
+      pcam = NULL;
+    }
+
+  return pcam;
+}
+
+/****************************************************************************
+ * Name: nxcamera_release
+ *
+ *   nxcamera_release() reduces the reference count by one and if it
+ *   reaches zero, frees the context.
+ *
+ * Input Parameters:
+ *   pcam    Pointer to the NxCamera context
+ *
+ * Returned values:    None
+ *
+ ****************************************************************************/
+
+void nxcamera_release(FAR struct nxcamera_s *pcam)
+{
+  int      refcount;
+  FAR void *value;
+  int errcode;
+
+  /* Lock the mutex */
+
+  while ((errcode = pthread_mutex_trylock(&pcam->mutex)))

Review Comment:
   why not use pthread_mutex_lock and remove errcode



##########
system/nxcamera/nxcamera.c:
##########
@@ -0,0 +1,889 @@
+/****************************************************************************
+ * apps/system/nxcamera/nxcamera.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/queue.h>
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <system/nxcamera.h>
+
+#ifdef CONFIG_LIBYUV
+#  include <libyuv.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXCAMERA_STATE_IDLE      0
+#define NXCAMERA_STATE_STREAMING 1
+#define NXCAMERA_STATE_LOOPING   2
+#define NXCAMERA_STATE_PAUSED    3
+
+#ifndef MIN
+#  define MIN(a, b)              (((a) < (b)) ? (a) : (b))
+#endif
+
+#define convert_frame            ConvertToARGB
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int show_image(FAR struct nxcamera_s *pcam, FAR v4l2_buffer_t *buf)
+{
+#ifdef CONFIG_LIBYUV
+  return convert_frame(pcam->bufs[buf->index],
+                       pcam->buf_sizes[buf->index],
+                       pcam->display_pinfo.fbmem,
+                       pcam->display_pinfo.stride,
+                       0,
+                       0,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       0,
+                       pcam->fmt.fmt.pix.pixelformat);
+#else
+  uint32_t *pbuf = pcam->bufs[buf->index];
+  vinfo("show image from %p: %lx %lx", pbuf, pbuf[0], pbuf[1]);
+  return 0;
+#endif
+}
+
+/****************************************************************************
+ * Name: nxcamera_opendevice
+ *
+ *   nxcamera_opendevice() tries to open the preferred devices as specified.
+ *
+ * Return:
+ *    OK        if compatible device opened (searched or preferred)
+ *    -ENODEV   if no compatible device opened.
+ *    -ENOENT   if preferred device couldn't be opened.
+ *
+ ****************************************************************************/
+
+static int nxcamera_opendevice(FAR struct nxcamera_s *pcam)
+{
+  int errcode;
+
+  if (pcam->capturedev[0] != '\0')
+    {
+      pcam->capture_fd = open(pcam->capturedev, O_RDWR);
+      if (pcam->capture_fd == -1)
+        {
+          errcode = errno;
+          DEBUGASSERT(errcode > 0);
+
+          verr("ERROR: Failed to open pcam->capturedev %d\n", -errcode);
+          return -errcode;
+        }
+
+      if (pcam->displaydev[0] != '\0')
+        {
+          pcam->display_fd = open(pcam->displaydev, O_RDWR);
+          if (pcam->display_fd == -1)
+            {
+              errcode = errno;
+              DEBUGASSERT(errcode > 0);
+
+              close(pcam->capture_fd);
+              pcam->capture_fd = -1;
+              verr("ERROR: Failed to open pcam->displaydev %d\n", -errcode);
+              return -errcode;
+            }
+
+          errcode = ioctl(pcam->display_fd, FBIOGET_PLANEINFO,
+                          ((uintptr_t)&pcam->display_pinfo));
+
+          if (errcode == OK)
+            {
+              pcam->display_pinfo.fbmem = mmap(NULL,
+                                               pcam->display_pinfo.fblen,
+                                               PROT_READ | PROT_WRITE,
+                                               MAP_SHARED | MAP_FILE,
+                                               pcam->display_fd,
+                                               0);
+            }
+
+          if (errcode < 0 || pcam->display_pinfo.fbmem == MAP_FAILED)
+            {
+              errcode = errno;
+              close(pcam->capture_fd);
+              close(pcam->display_fd);
+              verr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", -errcode);
+              return -errcode;
+            }
+
+          return OK;
+        }
+      else
+        {
+          /* TODO: Add file output */
+
+          return -ENOTSUP;
+        }
+    }
+
+  return -ENODEV;
+}
+
+/****************************************************************************
+ * Name: nxcamera_loopthread
+ *
+ *  This is the thread that streams the video and handles video controls.
+ *
+ ****************************************************************************/
+
+static void *nxcamera_loopthread(pthread_addr_t pvarg)
+{
+  FAR struct nxcamera_s   *pcam = (FAR struct nxcamera_s *)pvarg;
+  unsigned int            prio;
+  ssize_t                 size;
+  struct video_msg_s      msg;
+  bool                    streaming = true;
+  int                     i;
+  int                     ret;
+  struct v4l2_buffer      buf;
+  uint32_t                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  vinfo("Entry\n");
+
+  for (i = 0; i < pcam->nbuffers; i++)
+    {
+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QBUF failed: %d\n", ret);
+          goto err_out;
+        }
+    }
+
+  /* VIDIOC_STREAMON start stream */
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_STREAMON, (uintptr_t)&type);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_STREAMON failed: %d\n", ret);
+      goto err_out;
+    }
+  else
+    {
+      pcam->loopstate = NXCAMERA_STATE_STREAMING;
+    }
+
+  /* Loop until we specifically break. streaming == true means that we are
+   * still looping waiting for the stream to complete.  All of the data
+   * may have been sent, but the stream is not complete until we get
+   * VIDEO_MSG_STOP message
+   *
+   * The normal protocol for looping errors detected by the video driver
+   * is as follows:
+   *
+   * (1) The video driver will indicated the error by returning a negated
+   *     error value when the next buffer is enqueued.  The upper level
+   *     then knows that this buffer was not queued.
+   * (2) The video driver must return all queued buffers using the
+   *     VIDEO_MSG_DEQUEUE message.
+   */
+
+  while (streaming)
+    {
+      size = mq_receive(pcam->mq, (FAR char *)&msg, sizeof(msg), &prio);
+
+      /* Validate a message was received */
+
+      if (size == sizeof(msg))
+        {
+          /* Perform operation based on message id */
+
+          vinfo("message received size %zd id%d\n", size, msg.msg_id);
+          switch (msg.msg_id)
+            {
+              /* Someone wants to stop the stream. */
+
+              case VIDEO_MSG_STOP:
+
+                /* Send a stop message to the device */
+
+                vinfo("Stopping looping\n");
+                ioctl(pcam->capture_fd, VIDIOC_STREAMOFF, (uintptr_t)&type);
+                streaming = false;
+                goto err_out;
+
+              /* Unknown / unsupported message ID */
+
+              default:
+                break;
+            }
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_DQBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail DQBUF %d\n", errno);
+          goto err_out;
+        }
+
+      ret = show_image(pcam, &buf);
+      if (ret < 0)
+        {
+          verr("Fail to show image %d\n", -ret);
+          goto err_out;
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail QBUF %d\n", errno);
+          goto err_out;
+        }
+    }
+
+  /* Release our video buffers and unregister / release the device */
+
+err_out:
+  vinfo("Clean-up and exit\n");
+
+  /* Cleanup */
+
+  pthread_mutex_lock(&pcam->mutex);  /* Lock the mutex */
+
+  close(pcam->display_fd);           /* Close the display device */
+  close(pcam->capture_fd);           /* Close the capture device */
+  pcam->display_fd = -1;             /* Mark display device as closed */
+  pcam->capture_fd = -1;             /* Mark capture device as closed */
+  mq_close(pcam->mq);                /* Close the message queue */
+  mq_unlink(pcam->mqname);           /* Unlink the message queue */
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  pthread_mutex_unlock(&pcam->mutex);     /* Unlock the mutex */
+
+  vinfo("Exit\n");
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxcamera_setdevice
+ *
+ *   nxcamera_setdevice() sets the preferred video device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setdevice(FAR struct nxcamera_s *pcam,
+                       FAR const char *device)
+{
+  int                    temp_fd;
+  struct v4l2_capability caps;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a video device by issuing an VIDIOC_QUERYCAP ioctl */
+
+  if (ioctl(temp_fd, VIDIOC_QUERYCAP, (uintptr_t)&caps) != OK)
+    {
+      /* Not a video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the preferred device */
+
+  if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+    {
+      return -ENODEV;
+    }
+
+  strlcpy(pcam->capturedev, device, sizeof(pcam->capturedev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfb
+ *
+ *   nxcamera_setfb() sets the output framebuffer device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfb(FAR struct nxcamera_s *pcam, FAR const char *device)
+{
+  int                    temp_fd;
+  struct fb_videoinfo_s  vinfo;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a fb device by issuing an FBIOGET_VIDEOINFO ioctl */
+
+  if (ioctl(temp_fd, FBIOGET_VIDEOINFO, (uintptr_t)&vinfo) != OK)
+    {
+      /* Not an Video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  if (vinfo.nplanes == 0)
+    {
+      return -ENODEV;
+    }
+
+  /* Save the path of the framebuffer device */
+
+  strlcpy(pcam->displaydev, device, sizeof(pcam->displaydev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfile
+ *
+ *   nxcamera_setfile() sets the output file path to use with the provided
+ *   nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfile(FAR struct nxcamera_s *pcam, FAR const char *pfile,
+                     bool isimage)
+{
+  int temp_fd;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(pfile != NULL);
+
+  /* Try to open the file */
+
+  temp_fd = open(pfile, O_CREAT | O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the file */
+
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the output file */
+
+  if (isimage)
+    {
+      strlcpy(pcam->oimagepath, pfile, sizeof(pcam->oimagepath));
+    }
+  else
+    {
+      strlcpy(pcam->ovideopath, pfile, sizeof(pcam->ovideopath));
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stop
+ *
+ *   nxcamera_stop() stops the current playback to loop and closes the
+ *   file and the associated device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized looper context
+ *
+ ****************************************************************************/
+
+int nxcamera_stop(FAR struct nxcamera_s *pcam)
+{
+  struct video_msg_s term_msg;
+  FAR void           *value;
+
+  DEBUGASSERT(pcam != NULL);
+
+  /* Validate we are not in IDLE state */
+
+  pthread_mutex_lock(&pcam->mutex);          /* Lock the mutex */
+  if (pcam->loopstate == NXCAMERA_STATE_IDLE)
+    {
+      pthread_mutex_unlock(&pcam->mutex);    /* Unlock the mutex */
+      return OK;
+    }
+
+  /* Notify the stream thread that it needs to cancel the stream */
+
+  term_msg.msg_id = VIDEO_MSG_STOP;
+  term_msg.u.data = 0;
+  mq_send(pcam->mq, (FAR const char *)&term_msg, sizeof(term_msg),
+          CONFIG_NXCAMERA_MSG_PRIO);
+
+  pthread_mutex_unlock(&pcam->mutex);
+
+  /* Join the thread.  The thread will do all the cleanup. */
+
+  pthread_join(pcam->loop_id, &value);
+  pcam->loop_id = 0;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stream
+ *
+ *   nxcamera_stream() tries to capture and then display the raw data using
+ *   the Video system. If a capture device is specified, it will try to use
+ *   that device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized Looper context
+ *   width      Capture frame width
+ *   height     Capture frame height
+ *   framerate  Capture frame rate
+ *   format     Capture frame pixel format
+ *
+ * Returns:
+ *   OK         Video is being looped
+ *   -EBUSY     Capture device is busy
+ *   -ENOSYS    No supported video format found
+ *   -ENODEV    No video capture or framebuffer device suitable
+ *
+ ****************************************************************************/
+
+int nxcamera_stream(FAR struct nxcamera_s *pcam,
+                    uint16_t width, uint16_t height,
+                    uint32_t framerate, uint32_t format)
+{
+  struct mq_attr              attr;
+  struct sched_param          sparam;
+  pthread_attr_t              tattr;
+  FAR void                    *value;
+  int                         ret;
+  int                         i;
+  struct v4l2_buffer          buf;
+  struct v4l2_requestbuffers  req;
+  struct v4l2_streamparm      parm;
+
+  DEBUGASSERT(pcam != NULL);
+
+  if (pcam->loopstate != NXCAMERA_STATE_IDLE)
+    {
+      return -EBUSY;
+    }
+
+  vinfo("==============================\n");
+  vinfo("streaming video\n");
+  vinfo("==============================\n");
+
+  /* Try to open the device */
+
+  ret = nxcamera_opendevice(pcam);
+  if (ret < 0)
+    {
+      /* Error opening the device */
+
+      verr("ERROR: nxcamera_opendevice failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_S_FMT set format */
+
+  pcam->fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  pcam->fmt.fmt.pix.width       = width;
+  pcam->fmt.fmt.pix.height      = height;
+  pcam->fmt.fmt.pix.field       = V4L2_FIELD_ANY;
+  pcam->fmt.fmt.pix.pixelformat = format;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_FMT, (uintptr_t)&pcam->fmt);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_FMT failed: %d\n", ret);
+      return ret;
+    }
+
+  memset(&parm, 0, sizeof(parm));
+  parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  parm.parm.capture.timeperframe.denominator = framerate;
+  parm.parm.capture.timeperframe.numerator = 1;
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_PARM, (uintptr_t)&parm);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_PARM failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_REQBUFS initiate user pointer I/O */
+
+  req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  req.memory = V4L2_MEMORY_MMAP;
+  req.count  = CONFIG_VIDEO_REQBUFS_COUNT_MAX;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_REQBUFS, (uintptr_t)&req);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_REQBUFS failed: %d\n", ret);
+      return ret;
+    }
+
+  if (req.count < 2)
+    {
+      verr("VIDIOC_REQBUFS failed: not enough buffers\n");
+      return -ENOMEM;
+    }
+
+  pcam->nbuffers = req.count;
+  pcam->bufs = calloc(req.count, sizeof(*pcam->bufs));
+  pcam->buf_sizes = calloc(req.count, sizeof(*pcam->buf_sizes));
+  if (!pcam->bufs || !pcam->buf_sizes)
+    {
+      verr("Cannot allocate buffer pointers\n");
+      ret = -ENOMEM;
+      goto err_out;
+    }
+
+  /* VIDIOC_QBUF enqueue buffer */
+
+  for (i = 0; i < req.count; i++)
+    {
+      buf.type = req.type;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QUERYBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QUERYBUF failed: %d\n", ret);
+          goto err_out;
+        }
+
+      pcam->bufs[i] = mmap(NULL, buf.length,
+                           PROT_READ | PROT_WRITE, MAP_SHARED,
+                           pcam->capture_fd, buf.m.offset);
+      if (pcam->bufs[i] == MAP_FAILED)
+        {
+          ret = -errno;
+          verr("MMAP failed\n");
+          goto err_out;
+        }
+
+      pcam->buf_sizes[i] = buf.length;
+    }
+
+  /* Create a message queue for the loopthread */
+
+  attr.mq_maxmsg  = 8;
+  attr.mq_msgsize = sizeof(struct video_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags   = 0;
+
+  snprintf(pcam->mqname, sizeof(pcam->mqname), "/tmp/%lx",
+           (unsigned long)((uintptr_t)pcam) & 0xffffffff);
+
+  pcam->mq = mq_open(pcam->mqname, O_RDWR | O_CREAT | O_NONBLOCK, 0644,
+                     &attr);
+  if (pcam->mq == (mqd_t)-1)
+    {
+      /* Unable to open message queue! */
+
+      ret = -errno;
+      verr("ERROR: mq_open failed: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Check if there was a previous thread and join it if there was
+   * to perform clean-up.
+   */
+
+  if (pcam->loop_id != 0)
+    {
+      pthread_join(pcam->loop_id, &value);
+    }
+
+  pthread_attr_init(&tattr);
+  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9;
+  pthread_attr_setschedparam(&tattr, &sparam);
+  pthread_attr_setstacksize(&tattr, CONFIG_NXCAMERA_LOOPTHREAD_STACKSIZE);
+
+  /* Add a reference count to the looper for the thread and start the
+   * thread.  We increment for the thread to avoid thread start-up
+   * race conditions.
+   */
+
+  nxcamera_reference(pcam);
+  ret = pthread_create(&pcam->loop_id, &tattr, nxcamera_loopthread,
+                       (pthread_addr_t)pcam);
+  pthread_attr_destroy(&tattr);
+  if (ret != OK)
+    {
+      ret = -ret;
+      verr("ERROR: Failed to create loopthread: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Name the thread */
+
+  pthread_setname_np(pcam->loop_id, "nxcameraloop");
+  return OK;
+
+err_out:
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nxcamera_create
+ *
+ *   nxcamera_create() allocates and initializes a nxcamera context for
+ *   use by further nxcamera operations.  This routine must be called before
+ *   to perform the create for proper reference counting.
+ *
+ * Input Parameters:  None
+ *
+ * Returned values:
+ *   Pointer to the created context or NULL if there was an error.
+ *
+ ****************************************************************************/
+
+FAR struct nxcamera_s *nxcamera_create(void)
+{
+  FAR struct nxcamera_s *pcam;
+  int err;
+
+  /* Allocate the memory */
+
+  pcam = (FAR struct nxcamera_s *)calloc(1, sizeof(struct nxcamera_s));
+  if (pcam == NULL)
+    {
+      return NULL;
+    }
+
+  /* Initialize the context data */
+
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  pcam->display_fd = -1;
+  pcam->capture_fd = -1;
+  err = pthread_mutex_init(&pcam->mutex, NULL);
+  if (err)
+    {
+      verr("ERROR: pthread_mutex_init failed: %d\n", err);
+      free(pcam);
+      pcam = NULL;
+    }
+
+  return pcam;
+}
+
+/****************************************************************************
+ * Name: nxcamera_release
+ *
+ *   nxcamera_release() reduces the reference count by one and if it
+ *   reaches zero, frees the context.
+ *
+ * Input Parameters:
+ *   pcam    Pointer to the NxCamera context
+ *
+ * Returned values:    None
+ *
+ ****************************************************************************/
+
+void nxcamera_release(FAR struct nxcamera_s *pcam)
+{
+  int      refcount;
+  FAR void *value;
+  int errcode;
+
+  /* Lock the mutex */
+
+  while ((errcode = pthread_mutex_trylock(&pcam->mutex)))
+    {
+      DEBUGASSERT(errcode > 0);
+
+      if (errcode != EBUSY)
+        {
+          verr("ERROR: pthread_mutex_trylock failed: %d\n", errcode);
+          return;
+        }
+    }
+
+  /* Check if there was a previous thread and join it if there was */
+
+  if (pcam->loop_id != 0)
+    {
+      pthread_mutex_unlock(&pcam->mutex);
+      pthread_join(pcam->loop_id, &value);
+      pcam->loop_id = 0;
+
+      while ((errcode = pthread_mutex_trylock(&pcam->mutex)))
+        {
+          DEBUGASSERT(errcode > 0);
+
+          if (errcode != EBUSY)
+            {
+              verr("ERROR: pthread_mutex_trylock failed: %d\n", errcode);
+              return;
+            }
+        }
+    }
+
+  /* Reduce the reference count */
+
+  refcount = pcam->crefs--;
+  pthread_mutex_unlock(&pcam->mutex);
+
+  /* If the ref count *was* one, then free the context */
+
+  if (refcount == 1)
+    {
+      pthread_mutex_destroy(&pcam->mutex);
+      free(pcam);
+    }
+}
+
+/****************************************************************************
+ * Name: nxcamera_reference
+ *
+ *   nxcamera_reference() increments the reference count by one.
+ *
+ * Input Parameters:
+ *   pcam    Pointer to the NxCamera context
+ *
+ * Returned values:    None
+ *
+ ****************************************************************************/
+
+void nxcamera_reference(FAR struct nxcamera_s *pcam)
+{
+  int errcode;
+
+  /* Lock the mutex */
+
+  while ((errcode = pthread_mutex_trylock(&pcam->mutex)))

Review Comment:
   why not use pthread_mutex_lock and remove errcode



##########
include/system/nxcamera.h:
##########
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * apps/include/system/nxcamera.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_SYSTEM_NXCAMERA_H
+#define __APPS_INCLUDE_SYSTEM_NXCAMERA_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <mqueue.h>
+#include <pthread.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Standard Video Message Queue message IDs */
+
+#define VIDEO_MSG_NONE              0
+#define VIDEO_MSG_STOP              1
+
+/****************************************************************************
+ * Public Type Declarations
+ ****************************************************************************/
+
+/* This structure describes the internal state of the nxcamera */
+
+struct nxcamera_s
+{
+  int                   loopstate;                   /* Current looper test 
state */
+  int                   capture_fd;                  /* File descriptor of 
active
+                                                      * capture device */
+  char                  capturedev[CONFIG_NAME_MAX]; /* Preferred capture 
device */
+  int                   display_fd;                  /* File descriptor of 
active
+                                                      * display device */
+  char                  displaydev[CONFIG_NAME_MAX]; /* Display framebuffer 
device */
+  struct fb_planeinfo_s display_pinfo;               /* Display plane info */
+  char                  ovideopath[CONFIG_NAME_MAX]; /* Output video file path 
*/
+  char                  oimagepath[CONFIG_NAME_MAX]; /* Output image file path 
*/

Review Comment:
   ```suggestion
     char                  imagepath[CONFIG_NAME_MAX]; /* Output image file 
path */
   ```



##########
include/system/nxcamera.h:
##########
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * apps/include/system/nxcamera.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_SYSTEM_NXCAMERA_H
+#define __APPS_INCLUDE_SYSTEM_NXCAMERA_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <mqueue.h>
+#include <pthread.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Standard Video Message Queue message IDs */
+
+#define VIDEO_MSG_NONE              0
+#define VIDEO_MSG_STOP              1
+
+/****************************************************************************
+ * Public Type Declarations
+ ****************************************************************************/
+
+/* This structure describes the internal state of the nxcamera */
+
+struct nxcamera_s
+{
+  int                   loopstate;                   /* Current looper test 
state */
+  int                   capture_fd;                  /* File descriptor of 
active
+                                                      * capture device */
+  char                  capturedev[CONFIG_NAME_MAX]; /* Preferred capture 
device */
+  int                   display_fd;                  /* File descriptor of 
active
+                                                      * display device */
+  char                  displaydev[CONFIG_NAME_MAX]; /* Display framebuffer 
device */
+  struct fb_planeinfo_s display_pinfo;               /* Display plane info */
+  char                  ovideopath[CONFIG_NAME_MAX]; /* Output video file path 
*/

Review Comment:
   ```suggestion
     char                  videopath[CONFIG_NAME_MAX]; /* Output video file 
path */
   ```



##########
system/nxcamera/nxcamera.c:
##########
@@ -0,0 +1,889 @@
+/****************************************************************************
+ * apps/system/nxcamera/nxcamera.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/queue.h>
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <system/nxcamera.h>
+
+#ifdef CONFIG_LIBYUV
+#  include <libyuv.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXCAMERA_STATE_IDLE      0
+#define NXCAMERA_STATE_STREAMING 1
+#define NXCAMERA_STATE_LOOPING   2
+#define NXCAMERA_STATE_PAUSED    3
+
+#ifndef MIN
+#  define MIN(a, b)              (((a) < (b)) ? (a) : (b))
+#endif
+
+#define convert_frame            ConvertToARGB
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int show_image(FAR struct nxcamera_s *pcam, FAR v4l2_buffer_t *buf)
+{
+#ifdef CONFIG_LIBYUV
+  return convert_frame(pcam->bufs[buf->index],
+                       pcam->buf_sizes[buf->index],
+                       pcam->display_pinfo.fbmem,
+                       pcam->display_pinfo.stride,
+                       0,
+                       0,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       0,
+                       pcam->fmt.fmt.pix.pixelformat);
+#else
+  uint32_t *pbuf = pcam->bufs[buf->index];
+  vinfo("show image from %p: %lx %lx", pbuf, pbuf[0], pbuf[1]);
+  return 0;
+#endif
+}
+
+/****************************************************************************
+ * Name: nxcamera_opendevice
+ *
+ *   nxcamera_opendevice() tries to open the preferred devices as specified.
+ *
+ * Return:
+ *    OK        if compatible device opened (searched or preferred)
+ *    -ENODEV   if no compatible device opened.
+ *    -ENOENT   if preferred device couldn't be opened.
+ *
+ ****************************************************************************/
+
+static int nxcamera_opendevice(FAR struct nxcamera_s *pcam)
+{
+  int errcode;
+
+  if (pcam->capturedev[0] != '\0')
+    {
+      pcam->capture_fd = open(pcam->capturedev, O_RDWR);
+      if (pcam->capture_fd == -1)
+        {
+          errcode = errno;
+          DEBUGASSERT(errcode > 0);
+
+          verr("ERROR: Failed to open pcam->capturedev %d\n", -errcode);
+          return -errcode;
+        }
+
+      if (pcam->displaydev[0] != '\0')
+        {
+          pcam->display_fd = open(pcam->displaydev, O_RDWR);
+          if (pcam->display_fd == -1)
+            {
+              errcode = errno;
+              DEBUGASSERT(errcode > 0);
+
+              close(pcam->capture_fd);
+              pcam->capture_fd = -1;
+              verr("ERROR: Failed to open pcam->displaydev %d\n", -errcode);
+              return -errcode;
+            }
+
+          errcode = ioctl(pcam->display_fd, FBIOGET_PLANEINFO,
+                          ((uintptr_t)&pcam->display_pinfo));
+
+          if (errcode == OK)
+            {
+              pcam->display_pinfo.fbmem = mmap(NULL,
+                                               pcam->display_pinfo.fblen,
+                                               PROT_READ | PROT_WRITE,
+                                               MAP_SHARED | MAP_FILE,
+                                               pcam->display_fd,
+                                               0);
+            }
+
+          if (errcode < 0 || pcam->display_pinfo.fbmem == MAP_FAILED)
+            {
+              errcode = errno;
+              close(pcam->capture_fd);
+              close(pcam->display_fd);
+              verr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", -errcode);
+              return -errcode;
+            }
+
+          return OK;
+        }
+      else
+        {
+          /* TODO: Add file output */
+
+          return -ENOTSUP;
+        }
+    }
+
+  return -ENODEV;
+}
+
+/****************************************************************************
+ * Name: nxcamera_loopthread
+ *
+ *  This is the thread that streams the video and handles video controls.
+ *
+ ****************************************************************************/
+
+static void *nxcamera_loopthread(pthread_addr_t pvarg)
+{
+  FAR struct nxcamera_s   *pcam = (FAR struct nxcamera_s *)pvarg;
+  unsigned int            prio;
+  ssize_t                 size;
+  struct video_msg_s      msg;
+  bool                    streaming = true;
+  int                     i;
+  int                     ret;
+  struct v4l2_buffer      buf;
+  uint32_t                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  vinfo("Entry\n");
+
+  for (i = 0; i < pcam->nbuffers; i++)
+    {
+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QBUF failed: %d\n", ret);
+          goto err_out;
+        }
+    }
+
+  /* VIDIOC_STREAMON start stream */
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_STREAMON, (uintptr_t)&type);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_STREAMON failed: %d\n", ret);
+      goto err_out;
+    }
+  else
+    {
+      pcam->loopstate = NXCAMERA_STATE_STREAMING;
+    }
+
+  /* Loop until we specifically break. streaming == true means that we are
+   * still looping waiting for the stream to complete.  All of the data
+   * may have been sent, but the stream is not complete until we get
+   * VIDEO_MSG_STOP message
+   *
+   * The normal protocol for looping errors detected by the video driver
+   * is as follows:
+   *
+   * (1) The video driver will indicated the error by returning a negated
+   *     error value when the next buffer is enqueued.  The upper level
+   *     then knows that this buffer was not queued.
+   * (2) The video driver must return all queued buffers using the
+   *     VIDEO_MSG_DEQUEUE message.
+   */
+
+  while (streaming)
+    {
+      size = mq_receive(pcam->mq, (FAR char *)&msg, sizeof(msg), &prio);
+
+      /* Validate a message was received */
+
+      if (size == sizeof(msg))
+        {
+          /* Perform operation based on message id */
+
+          vinfo("message received size %zd id%d\n", size, msg.msg_id);
+          switch (msg.msg_id)
+            {
+              /* Someone wants to stop the stream. */
+
+              case VIDEO_MSG_STOP:
+
+                /* Send a stop message to the device */
+
+                vinfo("Stopping looping\n");
+                ioctl(pcam->capture_fd, VIDIOC_STREAMOFF, (uintptr_t)&type);
+                streaming = false;
+                goto err_out;
+
+              /* Unknown / unsupported message ID */
+
+              default:
+                break;
+            }
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_DQBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail DQBUF %d\n", errno);
+          goto err_out;
+        }
+
+      ret = show_image(pcam, &buf);
+      if (ret < 0)
+        {
+          verr("Fail to show image %d\n", -ret);
+          goto err_out;
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail QBUF %d\n", errno);
+          goto err_out;
+        }
+    }
+
+  /* Release our video buffers and unregister / release the device */
+
+err_out:
+  vinfo("Clean-up and exit\n");
+
+  /* Cleanup */
+
+  pthread_mutex_lock(&pcam->mutex);  /* Lock the mutex */
+
+  close(pcam->display_fd);           /* Close the display device */
+  close(pcam->capture_fd);           /* Close the capture device */
+  pcam->display_fd = -1;             /* Mark display device as closed */
+  pcam->capture_fd = -1;             /* Mark capture device as closed */
+  mq_close(pcam->mq);                /* Close the message queue */
+  mq_unlink(pcam->mqname);           /* Unlink the message queue */
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)

Review Comment:
   remove the check, don't need



##########
system/nxcamera/nxcamera.c:
##########
@@ -0,0 +1,889 @@
+/****************************************************************************
+ * apps/system/nxcamera/nxcamera.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/queue.h>
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <system/nxcamera.h>
+
+#ifdef CONFIG_LIBYUV
+#  include <libyuv.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXCAMERA_STATE_IDLE      0
+#define NXCAMERA_STATE_STREAMING 1
+#define NXCAMERA_STATE_LOOPING   2
+#define NXCAMERA_STATE_PAUSED    3
+
+#ifndef MIN
+#  define MIN(a, b)              (((a) < (b)) ? (a) : (b))
+#endif
+
+#define convert_frame            ConvertToARGB
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int show_image(FAR struct nxcamera_s *pcam, FAR v4l2_buffer_t *buf)
+{
+#ifdef CONFIG_LIBYUV
+  return convert_frame(pcam->bufs[buf->index],
+                       pcam->buf_sizes[buf->index],
+                       pcam->display_pinfo.fbmem,
+                       pcam->display_pinfo.stride,
+                       0,
+                       0,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       0,
+                       pcam->fmt.fmt.pix.pixelformat);
+#else
+  uint32_t *pbuf = pcam->bufs[buf->index];
+  vinfo("show image from %p: %lx %lx", pbuf, pbuf[0], pbuf[1]);
+  return 0;
+#endif
+}
+
+/****************************************************************************
+ * Name: nxcamera_opendevice
+ *
+ *   nxcamera_opendevice() tries to open the preferred devices as specified.
+ *
+ * Return:
+ *    OK        if compatible device opened (searched or preferred)
+ *    -ENODEV   if no compatible device opened.
+ *    -ENOENT   if preferred device couldn't be opened.
+ *
+ ****************************************************************************/
+
+static int nxcamera_opendevice(FAR struct nxcamera_s *pcam)
+{
+  int errcode;
+
+  if (pcam->capturedev[0] != '\0')
+    {
+      pcam->capture_fd = open(pcam->capturedev, O_RDWR);
+      if (pcam->capture_fd == -1)
+        {
+          errcode = errno;
+          DEBUGASSERT(errcode > 0);
+
+          verr("ERROR: Failed to open pcam->capturedev %d\n", -errcode);
+          return -errcode;
+        }
+
+      if (pcam->displaydev[0] != '\0')
+        {
+          pcam->display_fd = open(pcam->displaydev, O_RDWR);
+          if (pcam->display_fd == -1)
+            {
+              errcode = errno;
+              DEBUGASSERT(errcode > 0);
+
+              close(pcam->capture_fd);
+              pcam->capture_fd = -1;
+              verr("ERROR: Failed to open pcam->displaydev %d\n", -errcode);
+              return -errcode;
+            }
+
+          errcode = ioctl(pcam->display_fd, FBIOGET_PLANEINFO,
+                          ((uintptr_t)&pcam->display_pinfo));
+
+          if (errcode == OK)
+            {
+              pcam->display_pinfo.fbmem = mmap(NULL,
+                                               pcam->display_pinfo.fblen,
+                                               PROT_READ | PROT_WRITE,
+                                               MAP_SHARED | MAP_FILE,
+                                               pcam->display_fd,
+                                               0);
+            }
+
+          if (errcode < 0 || pcam->display_pinfo.fbmem == MAP_FAILED)
+            {
+              errcode = errno;
+              close(pcam->capture_fd);
+              close(pcam->display_fd);
+              verr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", -errcode);
+              return -errcode;
+            }
+
+          return OK;
+        }
+      else
+        {
+          /* TODO: Add file output */
+
+          return -ENOTSUP;
+        }
+    }
+
+  return -ENODEV;
+}
+
+/****************************************************************************
+ * Name: nxcamera_loopthread
+ *
+ *  This is the thread that streams the video and handles video controls.
+ *
+ ****************************************************************************/
+
+static void *nxcamera_loopthread(pthread_addr_t pvarg)
+{
+  FAR struct nxcamera_s   *pcam = (FAR struct nxcamera_s *)pvarg;
+  unsigned int            prio;
+  ssize_t                 size;
+  struct video_msg_s      msg;
+  bool                    streaming = true;
+  int                     i;
+  int                     ret;
+  struct v4l2_buffer      buf;
+  uint32_t                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  vinfo("Entry\n");
+
+  for (i = 0; i < pcam->nbuffers; i++)
+    {
+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QBUF failed: %d\n", ret);
+          goto err_out;
+        }
+    }
+
+  /* VIDIOC_STREAMON start stream */
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_STREAMON, (uintptr_t)&type);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_STREAMON failed: %d\n", ret);
+      goto err_out;
+    }
+  else
+    {
+      pcam->loopstate = NXCAMERA_STATE_STREAMING;
+    }
+
+  /* Loop until we specifically break. streaming == true means that we are
+   * still looping waiting for the stream to complete.  All of the data
+   * may have been sent, but the stream is not complete until we get
+   * VIDEO_MSG_STOP message
+   *
+   * The normal protocol for looping errors detected by the video driver
+   * is as follows:
+   *
+   * (1) The video driver will indicated the error by returning a negated
+   *     error value when the next buffer is enqueued.  The upper level
+   *     then knows that this buffer was not queued.
+   * (2) The video driver must return all queued buffers using the
+   *     VIDEO_MSG_DEQUEUE message.
+   */
+
+  while (streaming)
+    {
+      size = mq_receive(pcam->mq, (FAR char *)&msg, sizeof(msg), &prio);
+
+      /* Validate a message was received */
+
+      if (size == sizeof(msg))
+        {
+          /* Perform operation based on message id */
+
+          vinfo("message received size %zd id%d\n", size, msg.msg_id);
+          switch (msg.msg_id)
+            {
+              /* Someone wants to stop the stream. */
+
+              case VIDEO_MSG_STOP:
+
+                /* Send a stop message to the device */
+
+                vinfo("Stopping looping\n");
+                ioctl(pcam->capture_fd, VIDIOC_STREAMOFF, (uintptr_t)&type);
+                streaming = false;
+                goto err_out;
+
+              /* Unknown / unsupported message ID */
+
+              default:
+                break;
+            }
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_DQBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail DQBUF %d\n", errno);
+          goto err_out;
+        }
+
+      ret = show_image(pcam, &buf);
+      if (ret < 0)
+        {
+          verr("Fail to show image %d\n", -ret);
+          goto err_out;
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail QBUF %d\n", errno);
+          goto err_out;
+        }
+    }
+
+  /* Release our video buffers and unregister / release the device */
+
+err_out:
+  vinfo("Clean-up and exit\n");
+
+  /* Cleanup */
+
+  pthread_mutex_lock(&pcam->mutex);  /* Lock the mutex */
+
+  close(pcam->display_fd);           /* Close the display device */
+  close(pcam->capture_fd);           /* Close the capture device */
+  pcam->display_fd = -1;             /* Mark display device as closed */
+  pcam->capture_fd = -1;             /* Mark capture device as closed */
+  mq_close(pcam->mq);                /* Close the message queue */
+  mq_unlink(pcam->mqname);           /* Unlink the message queue */
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  pthread_mutex_unlock(&pcam->mutex);     /* Unlock the mutex */
+
+  vinfo("Exit\n");
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxcamera_setdevice
+ *
+ *   nxcamera_setdevice() sets the preferred video device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setdevice(FAR struct nxcamera_s *pcam,
+                       FAR const char *device)
+{
+  int                    temp_fd;
+  struct v4l2_capability caps;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a video device by issuing an VIDIOC_QUERYCAP ioctl */
+
+  if (ioctl(temp_fd, VIDIOC_QUERYCAP, (uintptr_t)&caps) != OK)
+    {
+      /* Not a video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the preferred device */
+
+  if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+    {
+      return -ENODEV;
+    }
+
+  strlcpy(pcam->capturedev, device, sizeof(pcam->capturedev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfb
+ *
+ *   nxcamera_setfb() sets the output framebuffer device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfb(FAR struct nxcamera_s *pcam, FAR const char *device)
+{
+  int                    temp_fd;
+  struct fb_videoinfo_s  vinfo;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a fb device by issuing an FBIOGET_VIDEOINFO ioctl */
+
+  if (ioctl(temp_fd, FBIOGET_VIDEOINFO, (uintptr_t)&vinfo) != OK)
+    {
+      /* Not an Video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  if (vinfo.nplanes == 0)
+    {
+      return -ENODEV;
+    }
+
+  /* Save the path of the framebuffer device */
+
+  strlcpy(pcam->displaydev, device, sizeof(pcam->displaydev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfile
+ *
+ *   nxcamera_setfile() sets the output file path to use with the provided
+ *   nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfile(FAR struct nxcamera_s *pcam, FAR const char *pfile,
+                     bool isimage)
+{
+  int temp_fd;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(pfile != NULL);
+
+  /* Try to open the file */
+
+  temp_fd = open(pfile, O_CREAT | O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the file */
+
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the output file */
+
+  if (isimage)
+    {
+      strlcpy(pcam->oimagepath, pfile, sizeof(pcam->oimagepath));
+    }
+  else
+    {
+      strlcpy(pcam->ovideopath, pfile, sizeof(pcam->ovideopath));
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stop
+ *
+ *   nxcamera_stop() stops the current playback to loop and closes the
+ *   file and the associated device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized looper context
+ *
+ ****************************************************************************/
+
+int nxcamera_stop(FAR struct nxcamera_s *pcam)
+{
+  struct video_msg_s term_msg;
+  FAR void           *value;
+
+  DEBUGASSERT(pcam != NULL);
+
+  /* Validate we are not in IDLE state */
+
+  pthread_mutex_lock(&pcam->mutex);          /* Lock the mutex */
+  if (pcam->loopstate == NXCAMERA_STATE_IDLE)
+    {
+      pthread_mutex_unlock(&pcam->mutex);    /* Unlock the mutex */
+      return OK;
+    }
+
+  /* Notify the stream thread that it needs to cancel the stream */
+
+  term_msg.msg_id = VIDEO_MSG_STOP;
+  term_msg.u.data = 0;
+  mq_send(pcam->mq, (FAR const char *)&term_msg, sizeof(term_msg),
+          CONFIG_NXCAMERA_MSG_PRIO);
+
+  pthread_mutex_unlock(&pcam->mutex);
+
+  /* Join the thread.  The thread will do all the cleanup. */
+
+  pthread_join(pcam->loop_id, &value);
+  pcam->loop_id = 0;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stream
+ *
+ *   nxcamera_stream() tries to capture and then display the raw data using
+ *   the Video system. If a capture device is specified, it will try to use
+ *   that device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized Looper context
+ *   width      Capture frame width
+ *   height     Capture frame height
+ *   framerate  Capture frame rate
+ *   format     Capture frame pixel format
+ *
+ * Returns:
+ *   OK         Video is being looped
+ *   -EBUSY     Capture device is busy
+ *   -ENOSYS    No supported video format found
+ *   -ENODEV    No video capture or framebuffer device suitable
+ *
+ ****************************************************************************/
+
+int nxcamera_stream(FAR struct nxcamera_s *pcam,
+                    uint16_t width, uint16_t height,
+                    uint32_t framerate, uint32_t format)
+{
+  struct mq_attr              attr;
+  struct sched_param          sparam;
+  pthread_attr_t              tattr;
+  FAR void                    *value;
+  int                         ret;
+  int                         i;
+  struct v4l2_buffer          buf;
+  struct v4l2_requestbuffers  req;
+  struct v4l2_streamparm      parm;
+
+  DEBUGASSERT(pcam != NULL);
+
+  if (pcam->loopstate != NXCAMERA_STATE_IDLE)
+    {
+      return -EBUSY;
+    }
+
+  vinfo("==============================\n");
+  vinfo("streaming video\n");
+  vinfo("==============================\n");
+
+  /* Try to open the device */
+
+  ret = nxcamera_opendevice(pcam);
+  if (ret < 0)
+    {
+      /* Error opening the device */
+
+      verr("ERROR: nxcamera_opendevice failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_S_FMT set format */
+
+  pcam->fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  pcam->fmt.fmt.pix.width       = width;
+  pcam->fmt.fmt.pix.height      = height;
+  pcam->fmt.fmt.pix.field       = V4L2_FIELD_ANY;
+  pcam->fmt.fmt.pix.pixelformat = format;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_FMT, (uintptr_t)&pcam->fmt);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_FMT failed: %d\n", ret);
+      return ret;
+    }
+
+  memset(&parm, 0, sizeof(parm));
+  parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  parm.parm.capture.timeperframe.denominator = framerate;
+  parm.parm.capture.timeperframe.numerator = 1;
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_PARM, (uintptr_t)&parm);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_PARM failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_REQBUFS initiate user pointer I/O */
+
+  req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  req.memory = V4L2_MEMORY_MMAP;
+  req.count  = CONFIG_VIDEO_REQBUFS_COUNT_MAX;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_REQBUFS, (uintptr_t)&req);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_REQBUFS failed: %d\n", ret);
+      return ret;
+    }
+
+  if (req.count < 2)
+    {
+      verr("VIDIOC_REQBUFS failed: not enough buffers\n");
+      return -ENOMEM;
+    }
+
+  pcam->nbuffers = req.count;
+  pcam->bufs = calloc(req.count, sizeof(*pcam->bufs));
+  pcam->buf_sizes = calloc(req.count, sizeof(*pcam->buf_sizes));
+  if (!pcam->bufs || !pcam->buf_sizes)
+    {
+      verr("Cannot allocate buffer pointers\n");
+      ret = -ENOMEM;
+      goto err_out;
+    }
+
+  /* VIDIOC_QBUF enqueue buffer */
+
+  for (i = 0; i < req.count; i++)
+    {
+      buf.type = req.type;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QUERYBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QUERYBUF failed: %d\n", ret);
+          goto err_out;
+        }
+
+      pcam->bufs[i] = mmap(NULL, buf.length,
+                           PROT_READ | PROT_WRITE, MAP_SHARED,
+                           pcam->capture_fd, buf.m.offset);
+      if (pcam->bufs[i] == MAP_FAILED)
+        {
+          ret = -errno;
+          verr("MMAP failed\n");
+          goto err_out;
+        }
+
+      pcam->buf_sizes[i] = buf.length;
+    }
+
+  /* Create a message queue for the loopthread */
+
+  attr.mq_maxmsg  = 8;
+  attr.mq_msgsize = sizeof(struct video_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags   = 0;
+
+  snprintf(pcam->mqname, sizeof(pcam->mqname), "/tmp/%lx",
+           (unsigned long)((uintptr_t)pcam) & 0xffffffff);
+
+  pcam->mq = mq_open(pcam->mqname, O_RDWR | O_CREAT | O_NONBLOCK, 0644,
+                     &attr);
+  if (pcam->mq == (mqd_t)-1)
+    {
+      /* Unable to open message queue! */
+
+      ret = -errno;
+      verr("ERROR: mq_open failed: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Check if there was a previous thread and join it if there was
+   * to perform clean-up.
+   */
+
+  if (pcam->loop_id != 0)
+    {
+      pthread_join(pcam->loop_id, &value);
+    }
+
+  pthread_attr_init(&tattr);
+  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9;
+  pthread_attr_setschedparam(&tattr, &sparam);
+  pthread_attr_setstacksize(&tattr, CONFIG_NXCAMERA_LOOPTHREAD_STACKSIZE);
+
+  /* Add a reference count to the looper for the thread and start the
+   * thread.  We increment for the thread to avoid thread start-up
+   * race conditions.
+   */
+
+  nxcamera_reference(pcam);
+  ret = pthread_create(&pcam->loop_id, &tattr, nxcamera_loopthread,
+                       (pthread_addr_t)pcam);
+  pthread_attr_destroy(&tattr);
+  if (ret != OK)
+    {
+      ret = -ret;
+      verr("ERROR: Failed to create loopthread: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Name the thread */
+
+  pthread_setname_np(pcam->loop_id, "nxcameraloop");
+  return OK;
+
+err_out:
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nxcamera_create
+ *
+ *   nxcamera_create() allocates and initializes a nxcamera context for
+ *   use by further nxcamera operations.  This routine must be called before
+ *   to perform the create for proper reference counting.
+ *
+ * Input Parameters:  None
+ *
+ * Returned values:
+ *   Pointer to the created context or NULL if there was an error.
+ *
+ ****************************************************************************/
+
+FAR struct nxcamera_s *nxcamera_create(void)
+{
+  FAR struct nxcamera_s *pcam;
+  int err;
+
+  /* Allocate the memory */
+
+  pcam = (FAR struct nxcamera_s *)calloc(1, sizeof(struct nxcamera_s));
+  if (pcam == NULL)
+    {
+      return NULL;
+    }
+
+  /* Initialize the context data */
+
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  pcam->display_fd = -1;
+  pcam->capture_fd = -1;
+  err = pthread_mutex_init(&pcam->mutex, NULL);
+  if (err)
+    {
+      verr("ERROR: pthread_mutex_init failed: %d\n", err);
+      free(pcam);
+      pcam = NULL;
+    }
+
+  return pcam;
+}
+
+/****************************************************************************
+ * Name: nxcamera_release
+ *
+ *   nxcamera_release() reduces the reference count by one and if it
+ *   reaches zero, frees the context.
+ *
+ * Input Parameters:
+ *   pcam    Pointer to the NxCamera context
+ *
+ * Returned values:    None
+ *
+ ****************************************************************************/
+
+void nxcamera_release(FAR struct nxcamera_s *pcam)
+{
+  int      refcount;

Review Comment:
    FAR void *value;
   int refcount;
   int errcode;



##########
system/nxcamera/nxcamera.c:
##########
@@ -0,0 +1,889 @@
+/****************************************************************************
+ * apps/system/nxcamera/nxcamera.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/queue.h>
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <system/nxcamera.h>
+
+#ifdef CONFIG_LIBYUV
+#  include <libyuv.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXCAMERA_STATE_IDLE      0
+#define NXCAMERA_STATE_STREAMING 1
+#define NXCAMERA_STATE_LOOPING   2
+#define NXCAMERA_STATE_PAUSED    3
+
+#ifndef MIN
+#  define MIN(a, b)              (((a) < (b)) ? (a) : (b))
+#endif
+
+#define convert_frame            ConvertToARGB
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int show_image(FAR struct nxcamera_s *pcam, FAR v4l2_buffer_t *buf)
+{
+#ifdef CONFIG_LIBYUV
+  return convert_frame(pcam->bufs[buf->index],
+                       pcam->buf_sizes[buf->index],
+                       pcam->display_pinfo.fbmem,
+                       pcam->display_pinfo.stride,
+                       0,
+                       0,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       0,
+                       pcam->fmt.fmt.pix.pixelformat);
+#else
+  uint32_t *pbuf = pcam->bufs[buf->index];
+  vinfo("show image from %p: %lx %lx", pbuf, pbuf[0], pbuf[1]);
+  return 0;
+#endif
+}
+
+/****************************************************************************
+ * Name: nxcamera_opendevice
+ *
+ *   nxcamera_opendevice() tries to open the preferred devices as specified.
+ *
+ * Return:
+ *    OK        if compatible device opened (searched or preferred)
+ *    -ENODEV   if no compatible device opened.
+ *    -ENOENT   if preferred device couldn't be opened.
+ *
+ ****************************************************************************/
+
+static int nxcamera_opendevice(FAR struct nxcamera_s *pcam)
+{
+  int errcode;
+
+  if (pcam->capturedev[0] != '\0')
+    {
+      pcam->capture_fd = open(pcam->capturedev, O_RDWR);
+      if (pcam->capture_fd == -1)
+        {
+          errcode = errno;
+          DEBUGASSERT(errcode > 0);
+
+          verr("ERROR: Failed to open pcam->capturedev %d\n", -errcode);
+          return -errcode;
+        }
+
+      if (pcam->displaydev[0] != '\0')
+        {
+          pcam->display_fd = open(pcam->displaydev, O_RDWR);
+          if (pcam->display_fd == -1)
+            {
+              errcode = errno;
+              DEBUGASSERT(errcode > 0);
+
+              close(pcam->capture_fd);
+              pcam->capture_fd = -1;
+              verr("ERROR: Failed to open pcam->displaydev %d\n", -errcode);
+              return -errcode;
+            }
+
+          errcode = ioctl(pcam->display_fd, FBIOGET_PLANEINFO,
+                          ((uintptr_t)&pcam->display_pinfo));
+
+          if (errcode == OK)
+            {
+              pcam->display_pinfo.fbmem = mmap(NULL,
+                                               pcam->display_pinfo.fblen,
+                                               PROT_READ | PROT_WRITE,
+                                               MAP_SHARED | MAP_FILE,
+                                               pcam->display_fd,
+                                               0);
+            }
+
+          if (errcode < 0 || pcam->display_pinfo.fbmem == MAP_FAILED)
+            {
+              errcode = errno;
+              close(pcam->capture_fd);
+              close(pcam->display_fd);
+              verr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", -errcode);
+              return -errcode;
+            }
+
+          return OK;
+        }
+      else
+        {
+          /* TODO: Add file output */
+
+          return -ENOTSUP;
+        }
+    }
+
+  return -ENODEV;
+}
+
+/****************************************************************************
+ * Name: nxcamera_loopthread
+ *
+ *  This is the thread that streams the video and handles video controls.
+ *
+ ****************************************************************************/
+
+static void *nxcamera_loopthread(pthread_addr_t pvarg)
+{
+  FAR struct nxcamera_s   *pcam = (FAR struct nxcamera_s *)pvarg;
+  unsigned int            prio;
+  ssize_t                 size;
+  struct video_msg_s      msg;
+  bool                    streaming = true;
+  int                     i;
+  int                     ret;
+  struct v4l2_buffer      buf;
+  uint32_t                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  vinfo("Entry\n");
+

Review Comment:
   let's zero buf



##########
system/nxcamera/nxcamera.c:
##########
@@ -0,0 +1,889 @@
+/****************************************************************************
+ * apps/system/nxcamera/nxcamera.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/queue.h>
+#include <nuttx/video/video.h>
+#include <nuttx/video/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <system/nxcamera.h>
+
+#ifdef CONFIG_LIBYUV
+#  include <libyuv.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXCAMERA_STATE_IDLE      0
+#define NXCAMERA_STATE_STREAMING 1
+#define NXCAMERA_STATE_LOOPING   2
+#define NXCAMERA_STATE_PAUSED    3
+
+#ifndef MIN
+#  define MIN(a, b)              (((a) < (b)) ? (a) : (b))
+#endif
+
+#define convert_frame            ConvertToARGB
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int show_image(FAR struct nxcamera_s *pcam, FAR v4l2_buffer_t *buf)
+{
+#ifdef CONFIG_LIBYUV
+  return convert_frame(pcam->bufs[buf->index],
+                       pcam->buf_sizes[buf->index],
+                       pcam->display_pinfo.fbmem,
+                       pcam->display_pinfo.stride,
+                       0,
+                       0,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       pcam->fmt.fmt.pix.width,
+                       pcam->fmt.fmt.pix.height,
+                       0,
+                       pcam->fmt.fmt.pix.pixelformat);
+#else
+  uint32_t *pbuf = pcam->bufs[buf->index];
+  vinfo("show image from %p: %lx %lx", pbuf, pbuf[0], pbuf[1]);
+  return 0;
+#endif
+}
+
+/****************************************************************************
+ * Name: nxcamera_opendevice
+ *
+ *   nxcamera_opendevice() tries to open the preferred devices as specified.
+ *
+ * Return:
+ *    OK        if compatible device opened (searched or preferred)
+ *    -ENODEV   if no compatible device opened.
+ *    -ENOENT   if preferred device couldn't be opened.
+ *
+ ****************************************************************************/
+
+static int nxcamera_opendevice(FAR struct nxcamera_s *pcam)
+{
+  int errcode;
+
+  if (pcam->capturedev[0] != '\0')
+    {
+      pcam->capture_fd = open(pcam->capturedev, O_RDWR);
+      if (pcam->capture_fd == -1)
+        {
+          errcode = errno;
+          DEBUGASSERT(errcode > 0);
+
+          verr("ERROR: Failed to open pcam->capturedev %d\n", -errcode);
+          return -errcode;
+        }
+
+      if (pcam->displaydev[0] != '\0')
+        {
+          pcam->display_fd = open(pcam->displaydev, O_RDWR);
+          if (pcam->display_fd == -1)
+            {
+              errcode = errno;
+              DEBUGASSERT(errcode > 0);
+
+              close(pcam->capture_fd);
+              pcam->capture_fd = -1;
+              verr("ERROR: Failed to open pcam->displaydev %d\n", -errcode);
+              return -errcode;
+            }
+
+          errcode = ioctl(pcam->display_fd, FBIOGET_PLANEINFO,
+                          ((uintptr_t)&pcam->display_pinfo));
+
+          if (errcode == OK)
+            {
+              pcam->display_pinfo.fbmem = mmap(NULL,
+                                               pcam->display_pinfo.fblen,
+                                               PROT_READ | PROT_WRITE,
+                                               MAP_SHARED | MAP_FILE,
+                                               pcam->display_fd,
+                                               0);
+            }
+
+          if (errcode < 0 || pcam->display_pinfo.fbmem == MAP_FAILED)
+            {
+              errcode = errno;
+              close(pcam->capture_fd);
+              close(pcam->display_fd);
+              verr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", -errcode);
+              return -errcode;
+            }
+
+          return OK;
+        }
+      else
+        {
+          /* TODO: Add file output */
+
+          return -ENOTSUP;
+        }
+    }
+
+  return -ENODEV;
+}
+
+/****************************************************************************
+ * Name: nxcamera_loopthread
+ *
+ *  This is the thread that streams the video and handles video controls.
+ *
+ ****************************************************************************/
+
+static void *nxcamera_loopthread(pthread_addr_t pvarg)
+{
+  FAR struct nxcamera_s   *pcam = (FAR struct nxcamera_s *)pvarg;
+  unsigned int            prio;
+  ssize_t                 size;
+  struct video_msg_s      msg;
+  bool                    streaming = true;
+  int                     i;
+  int                     ret;
+  struct v4l2_buffer      buf;
+  uint32_t                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  vinfo("Entry\n");
+
+  for (i = 0; i < pcam->nbuffers; i++)
+    {
+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QBUF failed: %d\n", ret);
+          goto err_out;
+        }
+    }
+
+  /* VIDIOC_STREAMON start stream */
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_STREAMON, (uintptr_t)&type);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_STREAMON failed: %d\n", ret);
+      goto err_out;
+    }
+  else
+    {
+      pcam->loopstate = NXCAMERA_STATE_STREAMING;
+    }
+
+  /* Loop until we specifically break. streaming == true means that we are
+   * still looping waiting for the stream to complete.  All of the data
+   * may have been sent, but the stream is not complete until we get
+   * VIDEO_MSG_STOP message
+   *
+   * The normal protocol for looping errors detected by the video driver
+   * is as follows:
+   *
+   * (1) The video driver will indicated the error by returning a negated
+   *     error value when the next buffer is enqueued.  The upper level
+   *     then knows that this buffer was not queued.
+   * (2) The video driver must return all queued buffers using the
+   *     VIDEO_MSG_DEQUEUE message.
+   */
+
+  while (streaming)
+    {
+      size = mq_receive(pcam->mq, (FAR char *)&msg, sizeof(msg), &prio);
+
+      /* Validate a message was received */
+
+      if (size == sizeof(msg))
+        {
+          /* Perform operation based on message id */
+
+          vinfo("message received size %zd id%d\n", size, msg.msg_id);
+          switch (msg.msg_id)
+            {
+              /* Someone wants to stop the stream. */
+
+              case VIDEO_MSG_STOP:
+
+                /* Send a stop message to the device */
+
+                vinfo("Stopping looping\n");
+                ioctl(pcam->capture_fd, VIDIOC_STREAMOFF, (uintptr_t)&type);
+                streaming = false;
+                goto err_out;
+
+              /* Unknown / unsupported message ID */
+
+              default:
+                break;
+            }
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_DQBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail DQBUF %d\n", errno);
+          goto err_out;
+        }
+
+      ret = show_image(pcam, &buf);
+      if (ret < 0)
+        {
+          verr("Fail to show image %d\n", -ret);
+          goto err_out;
+        }
+
+      ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("Fail QBUF %d\n", errno);
+          goto err_out;
+        }
+    }
+
+  /* Release our video buffers and unregister / release the device */
+
+err_out:
+  vinfo("Clean-up and exit\n");
+
+  /* Cleanup */
+
+  pthread_mutex_lock(&pcam->mutex);  /* Lock the mutex */
+
+  close(pcam->display_fd);           /* Close the display device */
+  close(pcam->capture_fd);           /* Close the capture device */
+  pcam->display_fd = -1;             /* Mark display device as closed */
+  pcam->capture_fd = -1;             /* Mark capture device as closed */
+  mq_close(pcam->mq);                /* Close the message queue */
+  mq_unlink(pcam->mqname);           /* Unlink the message queue */
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  pthread_mutex_unlock(&pcam->mutex);     /* Unlock the mutex */
+
+  vinfo("Exit\n");
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxcamera_setdevice
+ *
+ *   nxcamera_setdevice() sets the preferred video device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setdevice(FAR struct nxcamera_s *pcam,
+                       FAR const char *device)
+{
+  int                    temp_fd;
+  struct v4l2_capability caps;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a video device by issuing an VIDIOC_QUERYCAP ioctl */
+
+  if (ioctl(temp_fd, VIDIOC_QUERYCAP, (uintptr_t)&caps) != OK)
+    {
+      /* Not a video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the preferred device */
+
+  if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+    {
+      return -ENODEV;
+    }
+
+  strlcpy(pcam->capturedev, device, sizeof(pcam->capturedev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfb
+ *
+ *   nxcamera_setfb() sets the output framebuffer device to use with the
+ *   provided nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfb(FAR struct nxcamera_s *pcam, FAR const char *device)
+{
+  int                    temp_fd;
+  struct fb_videoinfo_s  vinfo;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(device != NULL);
+
+  /* Try to open the device */
+
+  temp_fd = open(device, O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the device */
+
+      return -errno;
+    }
+
+  /* Validate it's a fb device by issuing an FBIOGET_VIDEOINFO ioctl */
+
+  if (ioctl(temp_fd, FBIOGET_VIDEOINFO, (uintptr_t)&vinfo) != OK)
+    {
+      /* Not an Video device! */
+
+      close(temp_fd);
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  if (vinfo.nplanes == 0)
+    {
+      return -ENODEV;
+    }
+
+  /* Save the path of the framebuffer device */
+
+  strlcpy(pcam->displaydev, device, sizeof(pcam->displaydev));
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_setfile
+ *
+ *   nxcamera_setfile() sets the output file path to use with the provided
+ *   nxcamera context.
+ *
+ ****************************************************************************/
+
+int nxcamera_setfile(FAR struct nxcamera_s *pcam, FAR const char *pfile,
+                     bool isimage)
+{
+  int temp_fd;
+
+  DEBUGASSERT(pcam != NULL);
+  DEBUGASSERT(pfile != NULL);
+
+  /* Try to open the file */
+
+  temp_fd = open(pfile, O_CREAT | O_RDWR);
+  if (temp_fd == -1)
+    {
+      /* Error opening the file */
+
+      return -errno;
+    }
+
+  /* Close the file */
+
+  close(temp_fd);
+
+  /* Save the path of the output file */
+
+  if (isimage)
+    {
+      strlcpy(pcam->oimagepath, pfile, sizeof(pcam->oimagepath));
+    }
+  else
+    {
+      strlcpy(pcam->ovideopath, pfile, sizeof(pcam->ovideopath));
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stop
+ *
+ *   nxcamera_stop() stops the current playback to loop and closes the
+ *   file and the associated device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized looper context
+ *
+ ****************************************************************************/
+
+int nxcamera_stop(FAR struct nxcamera_s *pcam)
+{
+  struct video_msg_s term_msg;
+  FAR void           *value;
+
+  DEBUGASSERT(pcam != NULL);
+
+  /* Validate we are not in IDLE state */
+
+  pthread_mutex_lock(&pcam->mutex);          /* Lock the mutex */
+  if (pcam->loopstate == NXCAMERA_STATE_IDLE)
+    {
+      pthread_mutex_unlock(&pcam->mutex);    /* Unlock the mutex */
+      return OK;
+    }
+
+  /* Notify the stream thread that it needs to cancel the stream */
+
+  term_msg.msg_id = VIDEO_MSG_STOP;
+  term_msg.u.data = 0;
+  mq_send(pcam->mq, (FAR const char *)&term_msg, sizeof(term_msg),
+          CONFIG_NXCAMERA_MSG_PRIO);
+
+  pthread_mutex_unlock(&pcam->mutex);
+
+  /* Join the thread.  The thread will do all the cleanup. */
+
+  pthread_join(pcam->loop_id, &value);
+  pcam->loop_id = 0;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nxcamera_stream
+ *
+ *   nxcamera_stream() tries to capture and then display the raw data using
+ *   the Video system. If a capture device is specified, it will try to use
+ *   that device.
+ *
+ * Input:
+ *   pcam    Pointer to the initialized Looper context
+ *   width      Capture frame width
+ *   height     Capture frame height
+ *   framerate  Capture frame rate
+ *   format     Capture frame pixel format
+ *
+ * Returns:
+ *   OK         Video is being looped
+ *   -EBUSY     Capture device is busy
+ *   -ENOSYS    No supported video format found
+ *   -ENODEV    No video capture or framebuffer device suitable
+ *
+ ****************************************************************************/
+
+int nxcamera_stream(FAR struct nxcamera_s *pcam,
+                    uint16_t width, uint16_t height,
+                    uint32_t framerate, uint32_t format)
+{
+  struct mq_attr              attr;
+  struct sched_param          sparam;
+  pthread_attr_t              tattr;
+  FAR void                    *value;
+  int                         ret;
+  int                         i;
+  struct v4l2_buffer          buf;
+  struct v4l2_requestbuffers  req;
+  struct v4l2_streamparm      parm;
+
+  DEBUGASSERT(pcam != NULL);
+
+  if (pcam->loopstate != NXCAMERA_STATE_IDLE)
+    {
+      return -EBUSY;
+    }
+
+  vinfo("==============================\n");
+  vinfo("streaming video\n");
+  vinfo("==============================\n");
+
+  /* Try to open the device */
+
+  ret = nxcamera_opendevice(pcam);
+  if (ret < 0)
+    {
+      /* Error opening the device */
+
+      verr("ERROR: nxcamera_opendevice failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_S_FMT set format */
+
+  pcam->fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  pcam->fmt.fmt.pix.width       = width;
+  pcam->fmt.fmt.pix.height      = height;
+  pcam->fmt.fmt.pix.field       = V4L2_FIELD_ANY;
+  pcam->fmt.fmt.pix.pixelformat = format;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_FMT, (uintptr_t)&pcam->fmt);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_FMT failed: %d\n", ret);
+      return ret;
+    }
+
+  memset(&parm, 0, sizeof(parm));
+  parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  parm.parm.capture.timeperframe.denominator = framerate;
+  parm.parm.capture.timeperframe.numerator = 1;
+  ret = ioctl(pcam->capture_fd, VIDIOC_S_PARM, (uintptr_t)&parm);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_S_PARM failed: %d\n", ret);
+      return ret;
+    }
+
+  /* VIDIOC_REQBUFS initiate user pointer I/O */
+
+  req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  req.memory = V4L2_MEMORY_MMAP;
+  req.count  = CONFIG_VIDEO_REQBUFS_COUNT_MAX;
+
+  ret = ioctl(pcam->capture_fd, VIDIOC_REQBUFS, (uintptr_t)&req);
+  if (ret < 0)
+    {
+      ret = -errno;
+      verr("VIDIOC_REQBUFS failed: %d\n", ret);
+      return ret;
+    }
+
+  if (req.count < 2)
+    {
+      verr("VIDIOC_REQBUFS failed: not enough buffers\n");
+      return -ENOMEM;
+    }
+
+  pcam->nbuffers = req.count;
+  pcam->bufs = calloc(req.count, sizeof(*pcam->bufs));
+  pcam->buf_sizes = calloc(req.count, sizeof(*pcam->buf_sizes));
+  if (!pcam->bufs || !pcam->buf_sizes)
+    {
+      verr("Cannot allocate buffer pointers\n");
+      ret = -ENOMEM;
+      goto err_out;
+    }
+
+  /* VIDIOC_QBUF enqueue buffer */
+
+  for (i = 0; i < req.count; i++)
+    {
+      buf.type = req.type;
+      buf.memory = V4L2_MEMORY_MMAP;
+      buf.index = i;
+      ret = ioctl(pcam->capture_fd, VIDIOC_QUERYBUF, (uintptr_t)&buf);
+      if (ret < 0)
+        {
+          ret = -errno;
+          verr("VIDIOC_QUERYBUF failed: %d\n", ret);
+          goto err_out;
+        }
+
+      pcam->bufs[i] = mmap(NULL, buf.length,
+                           PROT_READ | PROT_WRITE, MAP_SHARED,
+                           pcam->capture_fd, buf.m.offset);
+      if (pcam->bufs[i] == MAP_FAILED)
+        {
+          ret = -errno;
+          verr("MMAP failed\n");
+          goto err_out;
+        }
+
+      pcam->buf_sizes[i] = buf.length;
+    }
+
+  /* Create a message queue for the loopthread */
+
+  attr.mq_maxmsg  = 8;
+  attr.mq_msgsize = sizeof(struct video_msg_s);
+  attr.mq_curmsgs = 0;
+  attr.mq_flags   = 0;
+
+  snprintf(pcam->mqname, sizeof(pcam->mqname), "/tmp/%lx",
+           (unsigned long)((uintptr_t)pcam) & 0xffffffff);
+
+  pcam->mq = mq_open(pcam->mqname, O_RDWR | O_CREAT | O_NONBLOCK, 0644,
+                     &attr);
+  if (pcam->mq == (mqd_t)-1)
+    {
+      /* Unable to open message queue! */
+
+      ret = -errno;
+      verr("ERROR: mq_open failed: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Check if there was a previous thread and join it if there was
+   * to perform clean-up.
+   */
+
+  if (pcam->loop_id != 0)
+    {
+      pthread_join(pcam->loop_id, &value);
+    }
+
+  pthread_attr_init(&tattr);
+  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9;
+  pthread_attr_setschedparam(&tattr, &sparam);
+  pthread_attr_setstacksize(&tattr, CONFIG_NXCAMERA_LOOPTHREAD_STACKSIZE);
+
+  /* Add a reference count to the looper for the thread and start the
+   * thread.  We increment for the thread to avoid thread start-up
+   * race conditions.
+   */
+
+  nxcamera_reference(pcam);
+  ret = pthread_create(&pcam->loop_id, &tattr, nxcamera_loopthread,
+                       (pthread_addr_t)pcam);
+  pthread_attr_destroy(&tattr);
+  if (ret != OK)
+    {
+      ret = -ret;
+      verr("ERROR: Failed to create loopthread: %d\n", ret);
+      goto err_out;
+    }
+
+  /* Name the thread */
+
+  pthread_setname_np(pcam->loop_id, "nxcameraloop");
+  return OK;
+
+err_out:
+  if (pcam->bufs)
+    {
+      for (i = 0; i < pcam->nbuffers; i++)
+        {
+          if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
+            {
+              munmap(pcam->bufs[i], pcam->buf_sizes[i]);
+            }
+        }
+
+      free(pcam->bufs);
+    }
+
+  if (pcam->buf_sizes)
+    {
+      free(pcam->buf_sizes);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nxcamera_create
+ *
+ *   nxcamera_create() allocates and initializes a nxcamera context for
+ *   use by further nxcamera operations.  This routine must be called before
+ *   to perform the create for proper reference counting.
+ *
+ * Input Parameters:  None
+ *
+ * Returned values:
+ *   Pointer to the created context or NULL if there was an error.
+ *
+ ****************************************************************************/
+
+FAR struct nxcamera_s *nxcamera_create(void)
+{
+  FAR struct nxcamera_s *pcam;
+  int err;
+
+  /* Allocate the memory */
+
+  pcam = (FAR struct nxcamera_s *)calloc(1, sizeof(struct nxcamera_s));
+  if (pcam == NULL)
+    {
+      return NULL;
+    }
+
+  /* Initialize the context data */
+
+  pcam->loopstate = NXCAMERA_STATE_IDLE;
+  pcam->display_fd = -1;
+  pcam->capture_fd = -1;
+  err = pthread_mutex_init(&pcam->mutex, NULL);
+  if (err)
+    {
+      verr("ERROR: pthread_mutex_init failed: %d\n", err);
+      free(pcam);
+      pcam = NULL;
+    }
+
+  return pcam;
+}
+
+/****************************************************************************
+ * Name: nxcamera_release
+ *
+ *   nxcamera_release() reduces the reference count by one and if it
+ *   reaches zero, frees the context.
+ *
+ * Input Parameters:
+ *   pcam    Pointer to the NxCamera context
+ *
+ * Returned values:    None
+ *
+ ****************************************************************************/
+
+void nxcamera_release(FAR struct nxcamera_s *pcam)
+{
+  int      refcount;
+  FAR void *value;
+  int errcode;
+
+  /* Lock the mutex */
+
+  while ((errcode = pthread_mutex_trylock(&pcam->mutex)))
+    {
+      DEBUGASSERT(errcode > 0);
+
+      if (errcode != EBUSY)
+        {
+          verr("ERROR: pthread_mutex_trylock failed: %d\n", errcode);
+          return;
+        }
+    }
+
+  /* Check if there was a previous thread and join it if there was */
+
+  if (pcam->loop_id != 0)
+    {
+      pthread_mutex_unlock(&pcam->mutex);
+      pthread_join(pcam->loop_id, &value);
+      pcam->loop_id = 0;
+
+      while ((errcode = pthread_mutex_trylock(&pcam->mutex)))

Review Comment:
   why not use pthread_mutex_lock and remove errcode



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to