This is an automated email from the ASF dual-hosted git repository.

pkarashchenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 9c578504668f5d24e3f4c147dcdc0f083b34038c
Author: SPRESENSE <[email protected]>
AuthorDate: Mon Dec 20 21:46:18 2021 +0900

    drivers/video: Support clip
    
    Support clip by ioctl(VIDIOC_S_SELECTION) and ioctl(VIDIOC_G_SELECTION).
---
 drivers/video/video.c           | 198 +++++++++++++++++++++++++++++++++++++++-
 include/nuttx/video/imgsensor.h |  17 ++++
 include/nuttx/video/video.h     |  45 +++++++++
 3 files changed, 258 insertions(+), 2 deletions(-)

diff --git a/drivers/video/video.c b/drivers/video/video.c
index c8e4980cd1..462639b68c 100644
--- a/drivers/video/video.c
+++ b/drivers/video/video.c
@@ -119,6 +119,7 @@ struct video_type_inf_s
   video_wait_capture_t wait_capture;
   uint8_t              nr_fmt;
   video_format_t       fmt[MAX_VIDEO_FMT];
+  struct v4l2_rect     clip;
   struct v4l2_fract    frame_interval;
   video_framebuff_t    bufinf;
 };
@@ -215,6 +216,10 @@ static int save_scene_param(enum v4l2_scene_mode mode,
                             uint32_t id,
                             struct v4l2_ext_control *control);
 static int video_complete_capture(uint8_t  err_code, uint32_t datasize);
+static int validate_frame_setting(enum v4l2_buf_type type,
+                                  uint8_t nr_fmt,
+                                  FAR video_format_t *vfmt,
+                                  FAR struct v4l2_fract *interval);
 
 /* internal function for each cmds of ioctl */
 
@@ -579,12 +584,69 @@ static void convert_to_imgsensorinterval(FAR struct 
v4l2_fract *video,
   sensor->denominator = video->denominator;
 }
 
+static bool is_clipped(FAR struct v4l2_rect *clip)
+{
+  bool ret = false;
+
+  if (clip)
+    {
+      if ((clip->left   != 0) ||
+          (clip->top    != 0) ||
+          (clip->width  != 0) ||
+          (clip->height != 0))
+        {
+          ret = true;
+        }
+    }
+
+  return ret;
+}
+
+static void get_clipped_format(uint8_t              nr_fmt,
+                               FAR video_format_t   *fmt,
+                               FAR struct v4l2_rect *clip,
+                               FAR video_format_t   *c_fmt)
+{
+  DEBUGASSERT(fmt && c_fmt);
+
+  if (is_clipped(clip))
+    {
+      c_fmt[VIDEO_FMT_MAIN].width  = clip->width;
+      c_fmt[VIDEO_FMT_MAIN].height = clip->height;
+      c_fmt[VIDEO_FMT_MAIN].pixelformat
+        = fmt[VIDEO_FMT_MAIN].pixelformat;
+
+      if (nr_fmt > 1)
+        {
+          /* clipped size of  thumbnail is
+           * small as ratio of main size and thumbnal size.
+           */
+
+          memcpy(&c_fmt[VIDEO_FMT_SUB],
+                 &fmt[VIDEO_FMT_SUB],
+                 sizeof(video_format_t));
+
+          c_fmt[VIDEO_FMT_SUB].width *= clip->width;
+          c_fmt[VIDEO_FMT_SUB].width /= fmt[VIDEO_FMT_MAIN].width;
+
+          c_fmt[VIDEO_FMT_SUB].height *= clip->height;
+          c_fmt[VIDEO_FMT_SUB].height /= fmt[VIDEO_FMT_MAIN].height;
+        }
+    }
+  else
+    {
+      memcpy(c_fmt, fmt, sizeof(video_format_t));
+    }
+}
+
 static int start_capture(enum v4l2_buf_type type,
                          uint8_t nr_fmt,
                          FAR video_format_t *fmt,
+                         FAR struct v4l2_rect *clip,
                          FAR struct v4l2_fract *interval,
                          uint32_t bufaddr, uint32_t bufsize)
 {
+  video_format_t c_fmt[MAX_VIDEO_FMT];
   imgdata_format_t df[MAX_VIDEO_FMT];
   imgsensor_format_t sf[MAX_VIDEO_FMT];
   imgdata_interval_t di;
@@ -599,8 +661,10 @@ static int start_capture(enum v4l2_buf_type type,
       return -ENOTTY;
     }
 
-  convert_to_imgdatafmt(&fmt[VIDEO_FMT_MAIN], &df[IMGDATA_FMT_MAIN]);
-  convert_to_imgdatafmt(&fmt[VIDEO_FMT_SUB], &df[IMGDATA_FMT_SUB]);
+  get_clipped_format(nr_fmt, fmt, clip, c_fmt);
+
+  convert_to_imgdatafmt(&c_fmt[VIDEO_FMT_MAIN], &df[IMGDATA_FMT_MAIN]);
+  convert_to_imgdatafmt(&c_fmt[VIDEO_FMT_SUB], &df[IMGDATA_FMT_SUB]);
   convert_to_imgdatainterval(interval, &di);
   convert_to_imgsensorfmt(&fmt[VIDEO_FMT_MAIN], &sf[IMGSENSOR_FMT_MAIN]);
   convert_to_imgsensorfmt(&fmt[VIDEO_FMT_SUB], &sf[IMGSENSOR_FMT_SUB]);
@@ -635,6 +699,7 @@ static void change_video_state(FAR video_mng_t    *vmng,
           start_capture(V4L2_BUF_TYPE_VIDEO_CAPTURE,
                         vmng->video_inf.nr_fmt,
                         vmng->video_inf.fmt,
+                        &vmng->video_inf.clip,
                         &vmng->video_inf.frame_interval,
                         container->buf.m.userptr,
                         container->buf.length);
@@ -1140,6 +1205,7 @@ static int video_qbuf(FAR struct video_mng_s *vmng,
               start_capture(buf->type,
                             type_inf->nr_fmt,
                             type_inf->fmt,
+                            &type_inf->clip,
                             &type_inf->frame_interval,
                             container->buf.m.userptr,
                             container->buf.length);
@@ -1256,6 +1322,123 @@ static int video_cancel_dqbuf(FAR struct video_mng_s 
*vmng,
   return OK;
 }
 
+static bool validate_clip_setting(FAR struct v4l2_rect *clip,
+                                  FAR video_format_t *fmt)
+{
+  int ret = true;
+
+  DEBUGASSERT(clip && fmt);
+
+  /* Not permit the setting which do not fit inside frame size. */
+
+  if ((clip->left < 0) ||
+      (clip->top  < 0) ||
+      (clip->left + clip->width > fmt->width) ||
+      (clip->top + clip->height > fmt->height))
+    {
+      ret = false;
+    }
+
+  return ret;
+}
+
+static int video_s_selection(FAR struct video_mng_s    *vmng,
+                             FAR struct v4l2_selection *clip)
+{
+  FAR video_type_inf_t *type_inf;
+  int ret;
+  int32_t id;
+  uint32_t p_u32[IMGSENSOR_CLIP_NELEM];
+  imgsensor_value_t val;
+  video_format_t c_fmt[MAX_VIDEO_FMT];
+
+  ASSERT(g_video_sensor_ops && vmng);
+
+  if (g_video_sensor_ops->set_value == NULL)
+    {
+      return -ENOTTY;
+    }
+
+  if (clip == NULL)
+    {
+      return -EINVAL;
+    }
+
+  type_inf = get_video_type_inf(vmng, clip->type);
+  if (type_inf == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (type_inf->state != VIDEO_STATE_STREAMOFF)
+    {
+      return -EBUSY;
+    }
+
+  if (!validate_clip_setting(&clip->r, type_inf->fmt))
+    {
+      return -EINVAL;
+    }
+
+  /* Query that clipped size is available. */
+
+  get_clipped_format(type_inf->nr_fmt,
+                     type_inf->fmt,
+                     &clip->r,
+                     c_fmt);
+
+  ret = validate_frame_setting(clip->type,
+                               type_inf->nr_fmt,
+                               c_fmt,
+                               &type_inf->frame_interval);
+  if (ret != OK)
+    {
+      return ret;
+    }
+
+  id = (clip->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+       IMGSENSOR_ID_CLIP_VIDEO : IMGSENSOR_ID_CLIP_STILL;
+
+  p_u32[IMGSENSOR_CLIP_INDEX_LEFT]   = (uint32_t)clip->r.left;
+  p_u32[IMGSENSOR_CLIP_INDEX_TOP]    = (uint32_t)clip->r.top;
+  p_u32[IMGSENSOR_CLIP_INDEX_WIDTH]  = clip->r.width;
+  p_u32[IMGSENSOR_CLIP_INDEX_HEIGHT] = clip->r.height;
+
+  val.p_u32 = p_u32;
+  ret = g_video_sensor_ops->set_value
+         (id, sizeof(p_u32), val);
+  if (ret != OK)
+    {
+      return ret;
+    }
+
+  memcpy(&type_inf->clip, &clip->r, sizeof(struct v4l2_rect));
+
+  return ret;
+}
+
+static int video_g_selection(FAR struct video_mng_s    *vmng,
+                             FAR struct v4l2_selection *clip)
+{
+  FAR video_type_inf_t *type_inf;
+
+  ASSERT(vmng);
+
+  if (clip == NULL)
+    {
+      return -EINVAL;
+    }
+
+  type_inf = get_video_type_inf(vmng, clip->type);
+  if (type_inf == NULL)
+    {
+      return -EINVAL;
+    }
+
+  memcpy(&clip->r, &type_inf->clip, sizeof(struct v4l2_rect));
+  return OK;
+}
+
 static int validate_frame_setting(enum v4l2_buf_type type,
                                   uint8_t nr_fmt,
                                   FAR video_format_t *vfmt,
@@ -1623,6 +1806,7 @@ static int video_takepict_start(FAR struct video_mng_s 
*vmng,
           start_capture(V4L2_BUF_TYPE_STILL_CAPTURE,
                         vmng->still_inf.nr_fmt,
                         vmng->still_inf.fmt,
+                        &vmng->still_inf.clip,
                         &vmng->still_inf.frame_interval,
                         container->buf.m.userptr,
                         container->buf.length);
@@ -2763,6 +2947,16 @@ static int video_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
 
         break;
 
+      case VIDIOC_S_SELECTION:
+        ret = video_s_selection(priv, (FAR struct v4l2_selection *)arg);
+
+        break;
+
+      case VIDIOC_G_SELECTION:
+        ret = video_g_selection(priv, (FAR struct v4l2_selection *)arg);
+
+        break;
+
       case VIDIOC_TRY_FMT:
         ret = video_try_fmt(priv, (FAR struct v4l2_format *)arg);
 
diff --git a/include/nuttx/video/imgsensor.h b/include/nuttx/video/imgsensor.h
index 8d1f60109b..d40aa080f5 100644
--- a/include/nuttx/video/imgsensor.h
+++ b/include/nuttx/video/imgsensor.h
@@ -75,6 +75,23 @@
 #define IMGSENSOR_ID_3A_STATUS            (0x00010015)
 #define IMGSENSOR_ID_FLASH_LED_MODE       (0x00020000)
 #define IMGSENSOR_ID_JPEG_QUALITY         (0x00030000)
+#define IMGSENSOR_ID_CLIP_VIDEO           (0xFFFF0000)
+#define IMGSENSOR_ID_CLIP_STILL           (0xFFFF0001)
+
+/* Number of elements in clip data array
+ * in IMGSENSOR_ID_CLIP_VIDEO and IMGSENSOR_ID_CLIP_STILL case
+ */
+
+#define IMGSENSOR_CLIP_NELEM              (4)
+
+/* Index of clip information
+ * in IMGSENSOR_ID_CLIP_VIDEO and IMGSENSOR_ID_CLIP_STILL case
+ */
+
+#define IMGSENSOR_CLIP_INDEX_LEFT         (0)
+#define IMGSENSOR_CLIP_INDEX_TOP          (1)
+#define IMGSENSOR_CLIP_INDEX_WIDTH        (2)
+#define IMGSENSOR_CLIP_INDEX_HEIGHT       (3)
 
 /* bit definition for IMGSENSOR_ID_3A_LOCK */
 
diff --git a/include/nuttx/video/video.h b/include/nuttx/video/video.h
index c237125d10..bf35e88d9e 100644
--- a/include/nuttx/video/video.h
+++ b/include/nuttx/video/video.h
@@ -178,6 +178,18 @@ extern "C"
 
 #define VIDIOC_QUERYCAP               _VIDIOC(0x001b)
 
+/* Set clip
+ * Address pointing to struct v4l2_selection
+ */
+
+#define VIDIOC_S_SELECTION            _VIDIOC(0x001c)
+
+/* Get clip
+ * Address pointing to struct v4l2_selection
+ */
+
+#define VIDIOC_G_SELECTION            _VIDIOC(0x001d)
+
 #define VIDEO_HSIZE_QVGA        (320)   /* QVGA    horizontal size */
 #define VIDEO_VSIZE_QVGA        (240)   /* QVGA    vertical   size */
 #define VIDEO_HSIZE_VGA         (640)   /* VGA     horizontal size */
@@ -258,6 +270,39 @@ struct v4l2_capability
   uint32_t device_caps;  /* Device capabilities of the opened device */
 };
 
+/* Rectangle information */
+
+struct v4l2_rect
+{
+  /* Horizontal offset of the top, left corner of the rectangle, in pixels. */
+
+  int32_t left;
+
+  /* Vertical offset of the top, left corner of the rectangle, in pixels. */
+
+  int32_t top;
+
+  /* Width of the rectangle, in pixels. */
+
+  uint32_t width;
+
+  /* Height of the rectangle, in pixels. */
+
+  uint32_t height;
+};
+
+/* V4L2 selection info for VIDIOC_S_SELECTION and VIDIOC_G_SELECTION.
+ * Currently, only member type and r are supported.
+ */
+
+struct v4l2_selection
+{
+  uint32_t type;       /* Buffer type */
+  uint32_t target;
+  uint32_t flags;
+  struct v4l2_rect r;  /* The selection rectangle. */
+};
+
 /* Buffer type.
  *  Currently, support only V4L2_BUF_TYPE_VIDEO_CAPTURE and
  *  V4L2_BUF_TYPE_STILL_CAPTURE.

Reply via email to