diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2009-08-25 10:50:46 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-18 23:19:17 -0400 |
commit | 6a6c8786725c0b3d143674effa8b772f47b1c189 (patch) | |
tree | 8bb76c5dcbd579f13e876bd1a0bb56bee4bcebdd /drivers/media/video/tw9910.c | |
parent | 0166b74374cae3fa8bff0caef726a3d960a9a50a (diff) |
V4L/DVB (12534): soc-camera: V4L2 API compliant scaling (S_FMT) and cropping (S_CROP)
The initial soc-camera scaling and cropping implementation turned out to be
incompliant with the V4L2 API, e.g., it expected the user to specify cropping
in output window pixels, instead of input window pixels. This patch converts
the soc-camera core and all drivers to comply with the standard.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/tw9910.c')
-rw-r--r-- | drivers/media/video/tw9910.c | 120 |
1 files changed, 86 insertions, 34 deletions
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 94bd5b09f057..fbf4130dfc5d 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c | |||
@@ -715,8 +715,88 @@ tw9910_set_fmt_error: | |||
715 | return ret; | 715 | return ret; |
716 | } | 716 | } |
717 | 717 | ||
718 | static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
719 | { | ||
720 | struct i2c_client *client = sd->priv; | ||
721 | struct tw9910_priv *priv = to_tw9910(client); | ||
722 | |||
723 | if (!priv->scale) { | ||
724 | int ret; | ||
725 | struct v4l2_crop crop = { | ||
726 | .c = { | ||
727 | .left = 0, | ||
728 | .top = 0, | ||
729 | .width = 640, | ||
730 | .height = 480, | ||
731 | }, | ||
732 | }; | ||
733 | ret = tw9910_s_crop(sd, &crop); | ||
734 | if (ret < 0) | ||
735 | return ret; | ||
736 | } | ||
737 | |||
738 | a->c.left = 0; | ||
739 | a->c.top = 0; | ||
740 | a->c.width = priv->scale->width; | ||
741 | a->c.height = priv->scale->height; | ||
742 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
748 | { | ||
749 | a->bounds.left = 0; | ||
750 | a->bounds.top = 0; | ||
751 | a->bounds.width = 768; | ||
752 | a->bounds.height = 576; | ||
753 | a->defrect.left = 0; | ||
754 | a->defrect.top = 0; | ||
755 | a->defrect.width = 640; | ||
756 | a->defrect.height = 480; | ||
757 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
758 | a->pixelaspect.numerator = 1; | ||
759 | a->pixelaspect.denominator = 1; | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
765 | { | ||
766 | struct i2c_client *client = sd->priv; | ||
767 | struct tw9910_priv *priv = to_tw9910(client); | ||
768 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
769 | |||
770 | if (!priv->scale) { | ||
771 | int ret; | ||
772 | struct v4l2_crop crop = { | ||
773 | .c = { | ||
774 | .left = 0, | ||
775 | .top = 0, | ||
776 | .width = 640, | ||
777 | .height = 480, | ||
778 | }, | ||
779 | }; | ||
780 | ret = tw9910_s_crop(sd, &crop); | ||
781 | if (ret < 0) | ||
782 | return ret; | ||
783 | } | ||
784 | |||
785 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
786 | |||
787 | pix->width = priv->scale->width; | ||
788 | pix->height = priv->scale->height; | ||
789 | pix->pixelformat = V4L2_PIX_FMT_VYUY; | ||
790 | pix->colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
791 | pix->field = V4L2_FIELD_INTERLACED; | ||
792 | |||
793 | return 0; | ||
794 | } | ||
795 | |||
718 | static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 796 | static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
719 | { | 797 | { |
798 | struct i2c_client *client = sd->priv; | ||
799 | struct tw9910_priv *priv = to_tw9910(client); | ||
720 | struct v4l2_pix_format *pix = &f->fmt.pix; | 800 | struct v4l2_pix_format *pix = &f->fmt.pix; |
721 | /* See tw9910_s_crop() - no proper cropping support */ | 801 | /* See tw9910_s_crop() - no proper cropping support */ |
722 | struct v4l2_crop a = { | 802 | struct v4l2_crop a = { |
@@ -741,8 +821,8 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
741 | 821 | ||
742 | ret = tw9910_s_crop(sd, &a); | 822 | ret = tw9910_s_crop(sd, &a); |
743 | if (!ret) { | 823 | if (!ret) { |
744 | pix->width = a.c.width; | 824 | pix->width = priv->scale->width; |
745 | pix->height = a.c.height; | 825 | pix->height = priv->scale->height; |
746 | } | 826 | } |
747 | return ret; | 827 | return ret; |
748 | } | 828 | } |
@@ -838,8 +918,11 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { | |||
838 | 918 | ||
839 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | 919 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { |
840 | .s_stream = tw9910_s_stream, | 920 | .s_stream = tw9910_s_stream, |
921 | .g_fmt = tw9910_g_fmt, | ||
841 | .s_fmt = tw9910_s_fmt, | 922 | .s_fmt = tw9910_s_fmt, |
842 | .try_fmt = tw9910_try_fmt, | 923 | .try_fmt = tw9910_try_fmt, |
924 | .cropcap = tw9910_cropcap, | ||
925 | .g_crop = tw9910_g_crop, | ||
843 | .s_crop = tw9910_s_crop, | 926 | .s_crop = tw9910_s_crop, |
844 | }; | 927 | }; |
845 | 928 | ||
@@ -852,20 +935,6 @@ static struct v4l2_subdev_ops tw9910_subdev_ops = { | |||
852 | * i2c_driver function | 935 | * i2c_driver function |
853 | */ | 936 | */ |
854 | 937 | ||
855 | /* This is called during probe, so, setting rect_max is Ok here: scale == 1 */ | ||
856 | static void limit_to_scale(struct soc_camera_device *icd, | ||
857 | const struct tw9910_scale_ctrl *scale) | ||
858 | { | ||
859 | if (scale->width > icd->rect_max.width) | ||
860 | icd->rect_max.width = scale->width; | ||
861 | if (scale->width < icd->width_min) | ||
862 | icd->width_min = scale->width; | ||
863 | if (scale->height > icd->rect_max.height) | ||
864 | icd->rect_max.height = scale->height; | ||
865 | if (scale->height < icd->height_min) | ||
866 | icd->height_min = scale->height; | ||
867 | } | ||
868 | |||
869 | static int tw9910_probe(struct i2c_client *client, | 938 | static int tw9910_probe(struct i2c_client *client, |
870 | const struct i2c_device_id *did) | 939 | const struct i2c_device_id *did) |
871 | 940 | ||
@@ -876,8 +945,7 @@ static int tw9910_probe(struct i2c_client *client, | |||
876 | struct i2c_adapter *adapter = | 945 | struct i2c_adapter *adapter = |
877 | to_i2c_adapter(client->dev.parent); | 946 | to_i2c_adapter(client->dev.parent); |
878 | struct soc_camera_link *icl; | 947 | struct soc_camera_link *icl; |
879 | const struct tw9910_scale_ctrl *scale; | 948 | int ret; |
880 | int i, ret; | ||
881 | 949 | ||
882 | if (!icd) { | 950 | if (!icd) { |
883 | dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); | 951 | dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); |
@@ -908,22 +976,6 @@ static int tw9910_probe(struct i2c_client *client, | |||
908 | icd->ops = &tw9910_ops; | 976 | icd->ops = &tw9910_ops; |
909 | icd->iface = info->link.bus_id; | 977 | icd->iface = info->link.bus_id; |
910 | 978 | ||
911 | /* | ||
912 | * set width and height | ||
913 | */ | ||
914 | icd->rect_max.width = tw9910_ntsc_scales[0].width; /* set default */ | ||
915 | icd->width_min = tw9910_ntsc_scales[0].width; | ||
916 | icd->rect_max.height = tw9910_ntsc_scales[0].height; | ||
917 | icd->height_min = tw9910_ntsc_scales[0].height; | ||
918 | |||
919 | scale = tw9910_ntsc_scales; | ||
920 | for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) | ||
921 | limit_to_scale(icd, scale + i); | ||
922 | |||
923 | scale = tw9910_pal_scales; | ||
924 | for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) | ||
925 | limit_to_scale(icd, scale + i); | ||
926 | |||
927 | ret = tw9910_video_probe(icd, client); | 979 | ret = tw9910_video_probe(icd, client); |
928 | if (ret) { | 980 | if (ret) { |
929 | icd->ops = NULL; | 981 | icd->ops = NULL; |