You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/10/25 19:57:35 UTC

[incubator-nuttx] 03/08: drivers/video/isx012: Support clip feature

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

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

commit e48f8be8c539dc22a36a819a8969ab6be56f7869
Author: SPRESENSE <41...@users.noreply.github.com>
AuthorDate: Mon Oct 24 21:39:59 2022 +0900

    drivers/video/isx012: Support clip feature
---
 drivers/video/isx012.c | 242 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 223 insertions(+), 19 deletions(-)

diff --git a/drivers/video/isx012.c b/drivers/video/isx012.c
index e603d91023..08500bcbb9 100644
--- a/drivers/video/isx012.c
+++ b/drivers/video/isx012.c
@@ -144,6 +144,14 @@
 #define ISX012_CHIPID_L (0x0000c460)
 #define ISX012_CHIPID_H (0x00005516)
 
+#define BASE_HSIZE_FOR_CLIP_OFFSET (2592)
+#define BASE_VSIZE_FOR_CLIP_OFFSET (1944)
+
+#define ZOOM_UNIT        (0x0100)
+#define CLIP_OFFSET_UNIT (0x0010)
+#define CLIP_SIZE_UNIT   (8)
+#define RESCALE_FOR_CLIP(v, a, b)  (((v) * (a)) / (b))
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -167,6 +175,16 @@ struct isx012_reg_s
 
 typedef struct isx012_reg_s isx012_reg_t;
 
+struct isx012_rect_s
+{
+  int32_t left;
+  int32_t top;
+  uint32_t width;
+  uint32_t height;
+};
+
+typedef struct isx012_rect_s isx012_rect_t;
+
 struct isx012_dev_s
 {
   mutex_t                 i2c_lock;
@@ -175,6 +193,8 @@ struct isx012_dev_s
   int                     i2c_freq;    /* Frequency */
   isx012_state_t          state;       /* ISX012 status */
   uint8_t                 mode;        /* ISX012 mode */
+  isx012_rect_t           clip_video;  /* Clip information for VIDEO */
+  isx012_rect_t           clip_still;  /* Clip information for STILL */
 };
 
 typedef struct isx012_dev_s isx012_dev_t;
@@ -299,6 +319,7 @@ static const isx012_reg_t g_isx012_def_init[] =
   {FASTMOVE_TIMEOUT,  0x2d, 0x01},
   {YGAMMA_MODE,       0x01, 0x01},
   {INT_QLTY2,         0x50, 0x01},
+  {JPEG_PRED_MODE,    0x00, 0x01},
 };
 
 #define ISX012_RESET_NENTRIES ARRAY_NENTRIES(g_isx012_def_init)
@@ -826,7 +847,134 @@ static bool is_movie_needed(uint8_t fmt, uint8_t fps)
   return need;
 }
 
-static int isx012_set_mode_param(isx012_dev_t *priv,
+static void resize_for_clip(uint8_t nr_fmt,
+                            FAR imgsensor_format_t *fmt,
+                            FAR isx012_rect_t *clip,
+                            FAR uint16_t *w,
+                            FAR uint16_t *h,
+                            FAR uint16_t *s_w,
+                            FAR uint16_t *s_h)
+{
+  ASSERT(fmt && clip && w && h && s_w && s_h);
+
+  *w = (clip->width  == 0) ? fmt[IMGSENSOR_FMT_MAIN].width  : clip->width;
+  *h = (clip->height == 0) ? fmt[IMGSENSOR_FMT_MAIN].height : clip->height;
+
+  if (nr_fmt > 1)
+    {
+      *s_w = fmt[IMGSENSOR_FMT_SUB].width;
+      if (clip->width > 0)
+        {
+          *s_w = (uint32_t)*s_w * clip->width /
+                 fmt[IMGSENSOR_FMT_MAIN].width;
+        }
+
+      *s_h = fmt[IMGSENSOR_FMT_SUB].height;
+      if (clip->height > 0)
+        {
+          *s_h = (uint32_t)*s_h * clip->height /
+                 fmt[IMGSENSOR_FMT_MAIN].height;
+        }
+    }
+}
+
+static void calc_clip_regval(uint16_t pos,
+                             uint16_t clip_sz,
+                             uint16_t frm_sz,
+                             uint16_t basis_sz,
+                             FAR uint32_t *ratio,
+                             FAR int32_t  *offset)
+{
+  DEBUGASSERT(ratio && offset);
+
+  *ratio = ZOOM_UNIT;
+  *offset = 0;
+
+  if (clip_sz != 0)
+    {
+      /* Clip by setting zoom up. */
+
+      *ratio *= frm_sz;
+      *ratio /= clip_sz;
+
+      /* Applications' request pos means position from the upper left corner.
+       * On the other hand, ISX012's register means the center of the image,
+       * which has the maximum size of the sensor.
+       */
+
+      *offset = CLIP_OFFSET_UNIT;
+      *offset *= (int16_t)(pos + (clip_sz / 2) - (frm_sz / 2));
+      *offset *= basis_sz;
+      *offset /= (int32_t)frm_sz;
+    }
+}
+
+static bool is_clipped(FAR isx012_rect_t *clip)
+{
+  DEBUGASSERT(clip);
+
+  if ((clip->left   == 0) &&
+      (clip->top    == 0) &&
+      (clip->width  == 0) &&
+      (clip->height == 0))
+    {
+      return false;
+    }
+
+  return true;
+}
+
+static void activate_clip(FAR isx012_dev_t *priv,
+                          uint16_t w,
+                          uint16_t h,
+                          FAR isx012_rect_t *clip)
+{
+  uint8_t  hvfree = 0;
+  uint32_t r_x    = ZOOM_UNIT;
+  uint32_t r_y    = ZOOM_UNIT;
+  int32_t  x      = 0;
+  int32_t  y      = 0;
+
+  DEBUGASSERT(priv && clip);
+
+  if (is_clipped(clip))
+    {
+      hvfree = 1;
+
+      calc_clip_regval
+        (clip->left, clip->width,  w, BASE_HSIZE_FOR_CLIP_OFFSET, &r_x, &x);
+      calc_clip_regval
+        (clip->top,  clip->height, h, BASE_VSIZE_FOR_CLIP_OFFSET, &r_y, &y);
+
+      if (w * 3 > h * 4)
+        {
+          /* In case that aspect ratio is longer horizontally than 4:3,
+           * re-scaling vertical component setting.
+           */
+
+          r_y = RESCALE_FOR_CLIP(r_y, w * 3, h * 4);
+          y   = RESCALE_FOR_CLIP(y,   h * 4, w * 3);
+        }
+      else if (w * 3 < h * 4)
+        {
+          /* In case that aspect ratio is longer vertically than 4:3,
+           * re-scaling horizontal component setting.
+           */
+
+          r_x = RESCALE_FOR_CLIP(r_x, h * 4, w * 3);
+          x   = RESCALE_FOR_CLIP(x,   w * 3, h * 4);
+        }
+    }
+
+  isx012_putreg(priv, HVFREEZOOM, hvfree, 1);
+  isx012_putreg(priv, EZOOM_MAG,  ZOOM_UNIT,     sizeof(uint16_t));
+  isx012_putreg(priv, EZOOM_HMAG, (uint16_t)r_x, sizeof(uint16_t));
+  isx012_putreg(priv, EZOOM_VMAG, (uint16_t)r_y, sizeof(uint16_t));
+  isx012_putreg(priv, OFFSET_X, (int16_t)x, sizeof(int16_t));
+  isx012_putreg(priv, OFFSET_Y, (int16_t)y, sizeof(int16_t));
+}
+
+static int isx012_set_mode_param(FAR isx012_dev_t *priv,
                                  imgsensor_stream_type_t type,
                                  uint8_t nr_fmt,
                                  FAR imgsensor_format_t *fmt,
@@ -840,8 +988,13 @@ static int isx012_set_mode_param(isx012_dev_t *priv,
   uint16_t smode_addr;
   uint16_t hsize_addr;
   uint16_t vsize_addr;
-  uint8_t  smode;
-  uint8_t  mode;
+  uint8_t smode;
+  uint8_t mode;
+  FAR isx012_rect_t *clip;
+  uint16_t w = 0;
+  uint16_t h = 0;
+  uint16_t s_w = 0;
+  uint16_t s_h = 0;
 
   /* Get register address for type  */
 
@@ -874,6 +1027,8 @@ static int isx012_set_mode_param(isx012_dev_t *priv,
           vsize_addr = VSIZE_MONI;
           mode       = REGVAL_MODESEL_MON;
         }
+
+      clip = &priv->clip_video;
     }
   else
     {
@@ -883,6 +1038,8 @@ static int isx012_set_mode_param(isx012_dev_t *priv,
       hsize_addr = HSIZE_CAP;
       vsize_addr = VSIZE_CAP;
       mode       = REGVAL_MODESEL_CAP;
+
+      clip = &priv->clip_still;
     }
 
   ret = isx012_putreg(priv, fps_addr, fps_val, sizeof(uint8_t));
@@ -922,19 +1079,19 @@ static int isx012_set_mode_param(isx012_dev_t *priv,
       return ret;
     }
 
-  ret = isx012_putreg(priv,
-                      hsize_addr,
-                      fmt[IMGSENSOR_FMT_MAIN].width,
-                      sizeof(uint16_t));
+  resize_for_clip(nr_fmt, fmt, clip, &w, &h, &s_w, &s_h);
+  activate_clip(priv,
+                fmt[IMGSENSOR_FMT_MAIN].width,
+                fmt[IMGSENSOR_FMT_MAIN].height,
+                clip);
+
+  ret = isx012_putreg(priv, hsize_addr, w, sizeof(uint16_t));
   if (ret < 0)
     {
       return ret;
     }
 
-  ret = isx012_putreg(priv,
-                      vsize_addr,
-                      fmt[IMGSENSOR_FMT_MAIN].height,
-                      sizeof(uint16_t));
+  ret = isx012_putreg(priv, vsize_addr, h, sizeof(uint16_t));
   if (ret < 0)
     {
       return ret;
@@ -942,19 +1099,13 @@ static int isx012_set_mode_param(isx012_dev_t *priv,
 
   if (fmt_val == REGVAL_OUTFMT_INTERLEAVE)
     {
-      ret = isx012_putreg(priv,
-                          HSIZE_TN,
-                          fmt[IMGSENSOR_FMT_SUB].width,
-                          sizeof(uint16_t));
+      ret = isx012_putreg(priv, HSIZE_TN, s_w, sizeof(uint16_t));
       if (ret < 0)
         {
           return ret;
         }
 
-      ret = isx012_putreg(priv,
-                          VSIZE_TN,
-                          fmt[IMGSENSOR_FMT_SUB].height,
-                          sizeof(uint16_t));
+      ret = isx012_putreg(priv, VSIZE_TN, s_h, sizeof(uint16_t));
       if (ret < 0)
         {
           return ret;
@@ -2151,6 +2302,49 @@ static int isx012_get_value(uint32_t id,
   return ret;
 }
 
+static bool validate_clip_setting(uint32_t sz, FAR uint32_t *clip)
+{
+  bool ret = false;
+  uint32_t w;
+  uint32_t h;
+
+  DEBUGASSERT(clip);
+
+  if (sz != IMGSENSOR_CLIP_NELEM * sizeof(uint32_t))
+    {
+      return ret;
+    }
+
+  w = clip[IMGSENSOR_CLIP_INDEX_WIDTH];
+  h = clip[IMGSENSOR_CLIP_INDEX_HEIGHT];
+
+  if ((w % CLIP_SIZE_UNIT == 0) && (h % CLIP_SIZE_UNIT == 0))
+    {
+      ret = true;
+    }
+
+  return ret;
+}
+
+static int set_clip(uint32_t size,
+                    FAR uint32_t *val,
+                    FAR isx012_rect_t *target)
+{
+  DEBUGASSERT(target);
+
+  if (!validate_clip_setting(size, val))
+    {
+      return -EINVAL;
+    }
+
+  target->left   = (int32_t)val[IMGSENSOR_CLIP_INDEX_LEFT];
+  target->top    = (int32_t)val[IMGSENSOR_CLIP_INDEX_TOP];
+  target->width  = val[IMGSENSOR_CLIP_INDEX_WIDTH];
+  target->height = val[IMGSENSOR_CLIP_INDEX_HEIGHT];
+
+  return OK;
+}
+
 static int isx012_set_value(uint32_t id,
                             uint32_t size,
                             FAR imgsensor_value_t value)
@@ -2733,6 +2927,16 @@ static int isx012_set_value(uint32_t id,
                             ISX012_SIZE_JPGQUALITY);
         break;
 
+      case IMGSENSOR_ID_CLIP_VIDEO:
+        ret = set_clip(size, value.p_u32, &priv->clip_video);
+
+        break;
+
+      case IMGSENSOR_ID_CLIP_STILL:
+        ret = set_clip(size, value.p_u32, &priv->clip_still);
+
+        break;
+
       default: /* Unsupported control id */
 
         break;