drivers/video: Support clip

Support clip by ioctl(VIDIOC_S_SELECTION) and ioctl(VIDIOC_G_SELECTION).
This commit is contained in:
SPRESENSE 2021-12-20 21:46:18 +09:00 committed by Petro Karashchenko
parent b45489753a
commit 9c57850466
3 changed files with 258 additions and 2 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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.