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.
