diff options
author | Archit Taneja <archit@ti.com> | 2014-03-13 07:44:09 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-05-23 13:32:58 -0400 |
commit | 2ef114f6821b013c42d2ef1e31600d957a47542b (patch) | |
tree | dac425e318755a4a0b3fef7359062dbfe31bebea | |
parent | 928bf2ba2f0e65a971a60e940c69af0b02ae4a57 (diff) |
[media] v4l: ti-vpe: Add selection API in VPE driver
Add selection ioctl ops. For VPE, cropping makes sense only for the input to
VPE(or V4L2_BUF_TYPE_VIDEO_OUTPUT/MPLANE buffers) and composing makes sense
only for the output of VPE(or V4L2_BUF_TYPE_VIDEO_CAPTURE/MPLANE buffers).
For the CAPTURE type, V4L2_SEL_TGT_COMPOSE results in VPE writing the output
in a rectangle within the capture buffer. For the OUTPUT type, V4L2_SEL_TGT_CROP
results in selecting a rectangle region within the source buffer.
Setting the crop/compose rectangles should successfully result in
re-configuration of registers which are affected when either source or
destination dimensions change, set_srcdst_params() is called for this purpose.
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r-- | drivers/media/platform/ti-vpe/vpe.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1c9e57c278e9..972f43f69206 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c | |||
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx, | |||
410 | { | 410 | { |
411 | switch (type) { | 411 | switch (type) { |
412 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | 412 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
413 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
413 | return &ctx->q_data[Q_DATA_SRC]; | 414 | return &ctx->q_data[Q_DATA_SRC]; |
414 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | 415 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
416 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
415 | return &ctx->q_data[Q_DATA_DST]; | 417 | return &ctx->q_data[Q_DATA_DST]; |
416 | default: | 418 | default: |
417 | BUG(); | 419 | BUG(); |
@@ -1591,6 +1593,151 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
1591 | return set_srcdst_params(ctx); | 1593 | return set_srcdst_params(ctx); |
1592 | } | 1594 | } |
1593 | 1595 | ||
1596 | static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) | ||
1597 | { | ||
1598 | struct vpe_q_data *q_data; | ||
1599 | |||
1600 | if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
1601 | (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) | ||
1602 | return -EINVAL; | ||
1603 | |||
1604 | q_data = get_q_data(ctx, s->type); | ||
1605 | if (!q_data) | ||
1606 | return -EINVAL; | ||
1607 | |||
1608 | switch (s->target) { | ||
1609 | case V4L2_SEL_TGT_COMPOSE: | ||
1610 | /* | ||
1611 | * COMPOSE target is only valid for capture buffer type, return | ||
1612 | * error for output buffer type | ||
1613 | */ | ||
1614 | if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1615 | return -EINVAL; | ||
1616 | break; | ||
1617 | case V4L2_SEL_TGT_CROP: | ||
1618 | /* | ||
1619 | * CROP target is only valid for output buffer type, return | ||
1620 | * error for capture buffer type | ||
1621 | */ | ||
1622 | if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1623 | return -EINVAL; | ||
1624 | break; | ||
1625 | /* | ||
1626 | * bound and default crop/compose targets are invalid targets to | ||
1627 | * try/set | ||
1628 | */ | ||
1629 | default: | ||
1630 | return -EINVAL; | ||
1631 | } | ||
1632 | |||
1633 | if (s->r.top < 0 || s->r.left < 0) { | ||
1634 | vpe_err(ctx->dev, "negative values for top and left\n"); | ||
1635 | s->r.top = s->r.left = 0; | ||
1636 | } | ||
1637 | |||
1638 | v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1, | ||
1639 | &s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN); | ||
1640 | |||
1641 | /* adjust left/top if cropping rectangle is out of bounds */ | ||
1642 | if (s->r.left + s->r.width > q_data->width) | ||
1643 | s->r.left = q_data->width - s->r.width; | ||
1644 | if (s->r.top + s->r.height > q_data->height) | ||
1645 | s->r.top = q_data->height - s->r.height; | ||
1646 | |||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | static int vpe_g_selection(struct file *file, void *fh, | ||
1651 | struct v4l2_selection *s) | ||
1652 | { | ||
1653 | struct vpe_ctx *ctx = file2ctx(file); | ||
1654 | struct vpe_q_data *q_data; | ||
1655 | bool use_c_rect = false; | ||
1656 | |||
1657 | if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
1658 | (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) | ||
1659 | return -EINVAL; | ||
1660 | |||
1661 | q_data = get_q_data(ctx, s->type); | ||
1662 | if (!q_data) | ||
1663 | return -EINVAL; | ||
1664 | |||
1665 | switch (s->target) { | ||
1666 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
1667 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
1668 | if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1669 | return -EINVAL; | ||
1670 | break; | ||
1671 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1672 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
1673 | if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1674 | return -EINVAL; | ||
1675 | break; | ||
1676 | case V4L2_SEL_TGT_COMPOSE: | ||
1677 | if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1678 | return -EINVAL; | ||
1679 | use_c_rect = true; | ||
1680 | break; | ||
1681 | case V4L2_SEL_TGT_CROP: | ||
1682 | if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1683 | return -EINVAL; | ||
1684 | use_c_rect = true; | ||
1685 | break; | ||
1686 | default: | ||
1687 | return -EINVAL; | ||
1688 | } | ||
1689 | |||
1690 | if (use_c_rect) { | ||
1691 | /* | ||
1692 | * for CROP/COMPOSE target type, return c_rect params from the | ||
1693 | * respective buffer type | ||
1694 | */ | ||
1695 | s->r = q_data->c_rect; | ||
1696 | } else { | ||
1697 | /* | ||
1698 | * for DEFAULT/BOUNDS target type, return width and height from | ||
1699 | * S_FMT of the respective buffer type | ||
1700 | */ | ||
1701 | s->r.left = 0; | ||
1702 | s->r.top = 0; | ||
1703 | s->r.width = q_data->width; | ||
1704 | s->r.height = q_data->height; | ||
1705 | } | ||
1706 | |||
1707 | return 0; | ||
1708 | } | ||
1709 | |||
1710 | |||
1711 | static int vpe_s_selection(struct file *file, void *fh, | ||
1712 | struct v4l2_selection *s) | ||
1713 | { | ||
1714 | struct vpe_ctx *ctx = file2ctx(file); | ||
1715 | struct vpe_q_data *q_data; | ||
1716 | struct v4l2_selection sel = *s; | ||
1717 | int ret; | ||
1718 | |||
1719 | ret = __vpe_try_selection(ctx, &sel); | ||
1720 | if (ret) | ||
1721 | return ret; | ||
1722 | |||
1723 | q_data = get_q_data(ctx, sel.type); | ||
1724 | if (!q_data) | ||
1725 | return -EINVAL; | ||
1726 | |||
1727 | if ((q_data->c_rect.left == sel.r.left) && | ||
1728 | (q_data->c_rect.top == sel.r.top) && | ||
1729 | (q_data->c_rect.width == sel.r.width) && | ||
1730 | (q_data->c_rect.height == sel.r.height)) { | ||
1731 | vpe_dbg(ctx->dev, | ||
1732 | "requested crop/compose values are already set\n"); | ||
1733 | return 0; | ||
1734 | } | ||
1735 | |||
1736 | q_data->c_rect = sel.r; | ||
1737 | |||
1738 | return set_srcdst_params(ctx); | ||
1739 | } | ||
1740 | |||
1594 | static int vpe_reqbufs(struct file *file, void *priv, | 1741 | static int vpe_reqbufs(struct file *file, void *priv, |
1595 | struct v4l2_requestbuffers *reqbufs) | 1742 | struct v4l2_requestbuffers *reqbufs) |
1596 | { | 1743 | { |
@@ -1678,6 +1825,9 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = { | |||
1678 | .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, | 1825 | .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, |
1679 | .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, | 1826 | .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, |
1680 | 1827 | ||
1828 | .vidioc_g_selection = vpe_g_selection, | ||
1829 | .vidioc_s_selection = vpe_s_selection, | ||
1830 | |||
1681 | .vidioc_reqbufs = vpe_reqbufs, | 1831 | .vidioc_reqbufs = vpe_reqbufs, |
1682 | .vidioc_querybuf = vpe_querybuf, | 1832 | .vidioc_querybuf = vpe_querybuf, |
1683 | 1833 | ||