[media] v4l: vsp1: Add cropping support
Implement the get and set selection operations on the RPF and WPF entities. Only the crop targets are currently available. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
Родитель
3299ba5c0b
Коммит
e5ad37b64d
|
@ -47,25 +47,36 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
struct vsp1_rwpf *rpf = to_rwpf(subdev);
|
struct vsp1_rwpf *rpf = to_rwpf(subdev);
|
||||||
const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo;
|
const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo;
|
||||||
const struct v4l2_pix_format_mplane *format = &rpf->video.format;
|
const struct v4l2_pix_format_mplane *format = &rpf->video.format;
|
||||||
|
const struct v4l2_rect *crop = &rpf->crop;
|
||||||
u32 pstride;
|
u32 pstride;
|
||||||
u32 infmt;
|
u32 infmt;
|
||||||
|
|
||||||
if (!enable)
|
if (!enable)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Source size and stride. Cropping isn't supported yet. */
|
/* Source size, stride and crop offsets.
|
||||||
|
*
|
||||||
|
* The crop offsets correspond to the location of the crop rectangle top
|
||||||
|
* left corner in the plane buffer. Only two offsets are needed, as
|
||||||
|
* planes 2 and 3 always have identical strides.
|
||||||
|
*/
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
|
vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
|
||||||
(format->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
|
(crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
|
||||||
(format->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
|
(crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
|
vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
|
||||||
(format->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
|
(crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
|
||||||
(format->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
|
(crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
|
||||||
|
|
||||||
|
rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
|
||||||
|
+ crop->left * fmtinfo->bpp[0] / 8;
|
||||||
pstride = format->plane_fmt[0].bytesperline
|
pstride = format->plane_fmt[0].bytesperline
|
||||||
<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
|
<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
|
||||||
if (format->num_planes > 1)
|
if (format->num_planes > 1) {
|
||||||
|
rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
|
||||||
|
+ crop->left * fmtinfo->bpp[1] / 8;
|
||||||
pstride |= format->plane_fmt[1].bytesperline
|
pstride |= format->plane_fmt[1].bytesperline
|
||||||
<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
|
<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
|
vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
|
||||||
|
|
||||||
|
@ -113,6 +124,8 @@ static struct v4l2_subdev_pad_ops rpf_pad_ops = {
|
||||||
.enum_frame_size = vsp1_rwpf_enum_frame_size,
|
.enum_frame_size = vsp1_rwpf_enum_frame_size,
|
||||||
.get_fmt = vsp1_rwpf_get_format,
|
.get_fmt = vsp1_rwpf_get_format,
|
||||||
.set_fmt = vsp1_rwpf_set_format,
|
.set_fmt = vsp1_rwpf_set_format,
|
||||||
|
.get_selection = vsp1_rwpf_get_selection,
|
||||||
|
.set_selection = vsp1_rwpf_set_selection,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct v4l2_subdev_ops rpf_ops = {
|
static struct v4l2_subdev_ops rpf_ops = {
|
||||||
|
@ -129,11 +142,14 @@ static void rpf_vdev_queue(struct vsp1_video *video,
|
||||||
{
|
{
|
||||||
struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video);
|
struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video);
|
||||||
|
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, buf->addr[0]);
|
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
|
||||||
|
buf->addr[0] + rpf->offsets[0]);
|
||||||
if (buf->buf.num_planes > 1)
|
if (buf->buf.num_planes > 1)
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, buf->addr[1]);
|
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
|
||||||
|
buf->addr[1] + rpf->offsets[1]);
|
||||||
if (buf->buf.num_planes > 2)
|
if (buf->buf.num_planes > 2)
|
||||||
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, buf->addr[2]);
|
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
|
||||||
|
buf->addr[2] + rpf->offsets[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct vsp1_video_operations rpf_vdev_ops = {
|
static const struct vsp1_video_operations rpf_vdev_ops = {
|
||||||
|
|
|
@ -71,6 +71,19 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct v4l2_rect *
|
||||||
|
vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which)
|
||||||
|
{
|
||||||
|
switch (which) {
|
||||||
|
case V4L2_SUBDEV_FORMAT_TRY:
|
||||||
|
return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK);
|
||||||
|
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
||||||
|
return &rwpf->crop;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||||
struct v4l2_subdev_format *fmt)
|
struct v4l2_subdev_format *fmt)
|
||||||
{
|
{
|
||||||
|
@ -87,6 +100,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||||
{
|
{
|
||||||
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
|
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
|
||||||
struct v4l2_mbus_framefmt *format;
|
struct v4l2_mbus_framefmt *format;
|
||||||
|
struct v4l2_rect *crop;
|
||||||
|
|
||||||
/* Default to YUV if the requested format is not supported. */
|
/* Default to YUV if the requested format is not supported. */
|
||||||
if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
|
if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
|
||||||
|
@ -115,6 +129,13 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||||
|
|
||||||
fmt->format = *format;
|
fmt->format = *format;
|
||||||
|
|
||||||
|
/* Update the sink crop rectangle. */
|
||||||
|
crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which);
|
||||||
|
crop->left = 0;
|
||||||
|
crop->top = 0;
|
||||||
|
crop->width = fmt->format.width;
|
||||||
|
crop->height = fmt->format.height;
|
||||||
|
|
||||||
/* Propagate the format to the source pad. */
|
/* Propagate the format to the source pad. */
|
||||||
format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
|
format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
|
||||||
fmt->which);
|
fmt->which);
|
||||||
|
@ -122,3 +143,78 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
|
||||||
|
struct v4l2_subdev_fh *fh,
|
||||||
|
struct v4l2_subdev_selection *sel)
|
||||||
|
{
|
||||||
|
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
|
||||||
|
struct v4l2_mbus_framefmt *format;
|
||||||
|
|
||||||
|
/* Cropping is implemented on the sink pad. */
|
||||||
|
if (sel->pad != RWPF_PAD_SINK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (sel->target) {
|
||||||
|
case V4L2_SEL_TGT_CROP:
|
||||||
|
sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case V4L2_SEL_TGT_CROP_BOUNDS:
|
||||||
|
format = vsp1_entity_get_pad_format(&rwpf->entity, fh,
|
||||||
|
RWPF_PAD_SINK, sel->which);
|
||||||
|
sel->r.left = 0;
|
||||||
|
sel->r.top = 0;
|
||||||
|
sel->r.width = format->width;
|
||||||
|
sel->r.height = format->height;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
|
||||||
|
struct v4l2_subdev_fh *fh,
|
||||||
|
struct v4l2_subdev_selection *sel)
|
||||||
|
{
|
||||||
|
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
|
||||||
|
struct v4l2_mbus_framefmt *format;
|
||||||
|
struct v4l2_rect *crop;
|
||||||
|
|
||||||
|
/* Cropping is implemented on the sink pad. */
|
||||||
|
if (sel->pad != RWPF_PAD_SINK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (sel->target != V4L2_SEL_TGT_CROP)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Make sure the crop rectangle is entirely contained in the image. The
|
||||||
|
* WPF top and left offsets are limited to 255.
|
||||||
|
*/
|
||||||
|
format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK,
|
||||||
|
sel->which);
|
||||||
|
sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);
|
||||||
|
sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);
|
||||||
|
if (rwpf->entity.type == VSP1_ENTITY_WPF) {
|
||||||
|
sel->r.left = min_t(unsigned int, sel->r.left, 255);
|
||||||
|
sel->r.top = min_t(unsigned int, sel->r.top, 255);
|
||||||
|
}
|
||||||
|
sel->r.width = min_t(unsigned int, sel->r.width,
|
||||||
|
format->width - sel->r.left);
|
||||||
|
sel->r.height = min_t(unsigned int, sel->r.height,
|
||||||
|
format->height - sel->r.top);
|
||||||
|
|
||||||
|
crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which);
|
||||||
|
*crop = sel->r;
|
||||||
|
|
||||||
|
/* Propagate the format to the source pad. */
|
||||||
|
format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
|
||||||
|
sel->which);
|
||||||
|
format->width = crop->width;
|
||||||
|
format->height = crop->height;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@ struct vsp1_rwpf {
|
||||||
|
|
||||||
unsigned int max_width;
|
unsigned int max_width;
|
||||||
unsigned int max_height;
|
unsigned int max_height;
|
||||||
|
|
||||||
|
struct v4l2_rect crop;
|
||||||
|
|
||||||
|
unsigned int offsets[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
|
static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
|
||||||
|
@ -49,5 +53,11 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||||
struct v4l2_subdev_format *fmt);
|
struct v4l2_subdev_format *fmt);
|
||||||
int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
|
||||||
struct v4l2_subdev_format *fmt);
|
struct v4l2_subdev_format *fmt);
|
||||||
|
int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
|
||||||
|
struct v4l2_subdev_fh *fh,
|
||||||
|
struct v4l2_subdev_selection *sel);
|
||||||
|
int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
|
||||||
|
struct v4l2_subdev_fh *fh,
|
||||||
|
struct v4l2_subdev_selection *sel);
|
||||||
|
|
||||||
#endif /* __VSP1_RWPF_H__ */
|
#endif /* __VSP1_RWPF_H__ */
|
||||||
|
|
|
@ -48,8 +48,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
struct vsp1_pipeline *pipe =
|
struct vsp1_pipeline *pipe =
|
||||||
to_vsp1_pipeline(&wpf->entity.subdev.entity);
|
to_vsp1_pipeline(&wpf->entity.subdev.entity);
|
||||||
struct vsp1_device *vsp1 = wpf->entity.vsp1;
|
struct vsp1_device *vsp1 = wpf->entity.vsp1;
|
||||||
const struct v4l2_mbus_framefmt *format =
|
const struct v4l2_rect *crop = &wpf->crop;
|
||||||
&wpf->entity.formats[RWPF_PAD_SOURCE];
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
u32 srcrpf = 0;
|
u32 srcrpf = 0;
|
||||||
u32 outfmt = 0;
|
u32 outfmt = 0;
|
||||||
|
@ -68,7 +67,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
|
|
||||||
vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
|
vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
|
||||||
|
|
||||||
/* Destination stride. Cropping isn't supported yet. */
|
/* Destination stride. */
|
||||||
if (!pipe->lif) {
|
if (!pipe->lif) {
|
||||||
struct v4l2_pix_format_mplane *format = &wpf->video.format;
|
struct v4l2_pix_format_mplane *format = &wpf->video.format;
|
||||||
|
|
||||||
|
@ -79,10 +78,12 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
format->plane_fmt[1].bytesperline);
|
format->plane_fmt[1].bytesperline);
|
||||||
}
|
}
|
||||||
|
|
||||||
vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP,
|
vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
|
||||||
format->width << VI6_WPF_SZCLIP_SIZE_SHIFT);
|
(crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
|
||||||
vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP,
|
(crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
|
||||||
format->height << VI6_WPF_SZCLIP_SIZE_SHIFT);
|
vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
|
||||||
|
(crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) |
|
||||||
|
(crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
|
||||||
|
|
||||||
/* Format */
|
/* Format */
|
||||||
if (!pipe->lif) {
|
if (!pipe->lif) {
|
||||||
|
@ -130,6 +131,8 @@ static struct v4l2_subdev_pad_ops wpf_pad_ops = {
|
||||||
.enum_frame_size = vsp1_rwpf_enum_frame_size,
|
.enum_frame_size = vsp1_rwpf_enum_frame_size,
|
||||||
.get_fmt = vsp1_rwpf_get_format,
|
.get_fmt = vsp1_rwpf_get_format,
|
||||||
.set_fmt = vsp1_rwpf_set_format,
|
.set_fmt = vsp1_rwpf_set_format,
|
||||||
|
.get_selection = vsp1_rwpf_get_selection,
|
||||||
|
.set_selection = vsp1_rwpf_set_selection,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct v4l2_subdev_ops wpf_ops = {
|
static struct v4l2_subdev_ops wpf_ops = {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче