今天整理tw9912驱动,发现FIMC 在capture时,对S_FMT和G_FMT ioctl调用值得商榷,记录下来。
当capture APP调用S_FMT时,会调用到FIMC capture驱动的fimc_s_fmt_vid_capture函数
814 int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f)
815 {
816 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
817 struct fimc_capinfo *cap;
818 int ret = 0;
819 int depth;
820
821 fimc_dbg("%s\n", __func__);
822
823 if (!ctrl->cam || !ctrl->cam->sd) {
824 fimc_err("%s: No capture device.\n", __func__);
825 return -ENODEV;
826 }
827 /*
828 * The first time alloc for struct cap_info, and will be
829 * released at the file close.
830 * Anyone has better idea to do this?
831 */
832 mutex_lock(&ctrl->v4l2_lock);
833
834 if (!ctrl->cap) {
835 ctrl->cap = kmalloc(sizeof(*cap), GFP_KERNEL);
836 if (!ctrl->cap) {
837 mutex_unlock(&ctrl->v4l2_lock);
838 fimc_err("%s: no memory for "
839 "capture device info\n", __func__);
840 return -ENOMEM;
841 }
842
843 }
844 cap = ctrl->cap;
845 memset(cap, 0, sizeof(*cap));
846 memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt));
847
848 /*
849 * Note that expecting format only can be with
850 * available output format from FIMC
851 * Following items should be handled in driver
852 * bytesperline = width * depth / 8
853 * sizeimage = bytesperline * height
854 */
858 depth = fimc_fmt_depth(ctrl, f);
859 if (depth == 0) {
860 mutex_unlock(&ctrl->v4l2_lock);
861 fimc_err("%s: Invalid pixel format\n", __func__);
862 return -EINVAL;
863 } else if (depth < 0) {
864 /*
865 * When the pixelformat is JPEG, the application is requesting
866 * for data in JPEG compressed format.
867 */
868 ret = subdev_call(ctrl, video, try_fmt, f);
869 if (ret < 0) {
870 mutex_unlock(&ctrl->v4l2_lock);
871 return -EINVAL;
872 }
873 cap->fmt.colorspace = V4L2_COLORSPACE_JPEG;
874 } else {
875 cap->fmt.bytesperline = (cap->fmt.width * depth) >> 3;
876 cap->fmt.sizeimage = (cap->fmt.bytesperline * cap->fmt.height);
877 }
878
879 if (cap->fmt.colorspace == V4L2_COLORSPACE_JPEG) {
880 ctrl->sc.bypass = 1;
881 cap->lastirq = 1;
882 }
883
884 if (ctrl->id != 2)
885 ret = subdev_call(ctrl, video, s_fmt, f);
886
887 mutex_unlock(&ctrl->v4l2_lock);
888
889 return ret;
890 }
从代码中可以看到,FIMC驱动并没有先调用video AD驱动的s_fmt接口,而是放在了代码的后面885行。用户设置的任何格式,FIMC驱动都会返回成功。
并且会把用户的设置保存为capture的缺省设置:
memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt));
这是因为FIMC控制器本身有缩放以及颜色空间转换,所以支持的格式并不取决于AD转换芯片输出的限制。
比如TW9912外接video的为PAL制式(720x576),但是用户仍然可以通过S_FMT设置为720x480。
imx51的V4L2构架也有同样的问题。
G_FMT不会返回video AD芯片支持的格式,而是返回FIMC控制器驱动支持的FMT,因此APP是没有机会获取video AD芯片的输出格式。
S5PV210 FIMC控制器驱动这样做带来一个问题,就是如果AD芯片的输出的BT656信号为NTSC制式,那么上层应用没有接口获取这个信息,来设置上层应用的原始图片为720x480。事实是APP可能设置为720x576,那么FIMC会接受这个设置,并且把AD芯片送来的720x480转换为720x576,反之亦然。因此可能造成APP无法获取原始尺寸的图片并且图像被拉伸。
当然如果预先知道AD输入的制式,并且APP或者中间件hard code这个格式可以避免这个问题。但是在实际产品中,输入视频的制式是无法预知的。