S5PV210 Android fimc驱动分析 - fimc_capture.c
fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片

43 static const struct v4l2_fmtdesc capture_fmts[] = {44 {45 .index = 0,46 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,47 .flags = FORMAT_FLAGS_PACKED,48 .description = "RGB-5-6-5",49 .pixelformat = V4L2_PIX_FMT_RGB565,50 }, {51 .index = 1,52 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,53 .flags = FORMAT_FLAGS_PACKED,54 .description = "RGB-8-8-8, unpacked 24 bpp",55 .pixelformat = V4L2_PIX_FMT_RGB32,56 }, {57 .index = 2,58 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,59 .flags = FORMAT_FLAGS_PACKED,60 .description = "YUV 4:2:2 packed, YCbYCr",61 .pixelformat = V4L2_PIX_FMT_YUYV,62 }, {63 .index = 3,64 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,65 .flags = FORMAT_FLAGS_PACKED,66 .description = "YUV 4:2:2 packed, CbYCrY",67 .pixelformat = V4L2_PIX_FMT_UYVY,68 }, {69 .index = 4,70 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,71 .flags = FORMAT_FLAGS_PACKED,72 .description = "YUV 4:2:2 packed, CrYCbY",73 .pixelformat = V4L2_PIX_FMT_VYUY,74 }, {75 .index = 5,76 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,77 .flags = FORMAT_FLAGS_PACKED,78 .description = "YUV 4:2:2 packed, YCrYCb",79 .pixelformat = V4L2_PIX_FMT_YVYU,80 }, {81 .index = 6,82 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,83 .flags = FORMAT_FLAGS_PLANAR,84 .description = "YUV 4:2:2 planar, Y/Cb/Cr",85 .pixelformat = V4L2_PIX_FMT_YUV422P,86 }, {87 .index = 7,88 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,89 .flags = FORMAT_FLAGS_PLANAR,90 .description = "YUV 4:2:0 planar, Y/CbCr",91 .pixelformat = V4L2_PIX_FMT_NV12,92 }, {93 .index = 8,94 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,95 .flags = FORMAT_FLAGS_PLANAR,96 .description = "YUV 4:2:0 planar, Y/CbCr, Tiled",97 .pixelformat = V4L2_PIX_FMT_NV12T,98 }, {99 .index = 9,100 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,101 .flags = FORMAT_FLAGS_PLANAR,102 .description = "YUV 4:2:0 planar, Y/CrCb",103 .pixelformat = V4L2_PIX_FMT_NV21,104 }, {105 .index = 10,106 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,107 .flags = FORMAT_FLAGS_PLANAR,108 .description = "YUV 4:2:2 planar, Y/CbCr",109 .pixelformat = V4L2_PIX_FMT_NV16,110 }, {111 .index = 11,112 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,113 .flags = FORMAT_FLAGS_PLANAR,114 .description = "YUV 4:2:2 planar, Y/CrCb",115 .pixelformat = V4L2_PIX_FMT_NV61,116 }, {117 .index = 12,118 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,119 .flags = FORMAT_FLAGS_PLANAR,120 .description = "YUV 4:2:0 planar, Y/Cb/Cr",121 .pixelformat = V4L2_PIX_FMT_YUV420,122 }, {123 .index = 13,124 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,125 .flags = FORMAT_FLAGS_ENCODED,126 .description = "Encoded JPEG bitstream",127 .pixelformat = V4L2_PIX_FMT_JPEG,128 },129 };
这个列表列出了FIMC支持的capture格式,app可以通过vidioc_s_fmt设置capture的输出格式,capture的输出格式必须在上面的列表中
这里的flags标志位并不符合V4L2标准,V4L2只支持一种标志:V4L2_FMT_FLAG_COMPRESSED。
samsung扩展了flags标志:
FORMAT_FLAGS_PACKED: 图片的像素点分量放在一同一个buffer中
FORMAT_FLAGS_PLANAR:图片像素的分量放在不同的buffer中
FORMAT_FLAGS_ENCODED:图片数据编码存储,如jpeg格式
131 static const struct v4l2_queryctrl fimc_controls[] = {132 {133 .id = V4L2_CID_ROTATION,134 .type = V4L2_CTRL_TYPE_BOOLEAN,135 .name = "Roataion",136 .minimum = 0,137 .maximum = 270,138 .step = 90,139 .default_value = 0,140 }, {141 .id = V4L2_CID_HFLIP,142 .type = V4L2_CTRL_TYPE_BOOLEAN,143 .name = "Horizontal Flip",144 .minimum = 0,145 .maximum = 1,146 .step = 1,147 .default_value = 0,148 }, {149 .id = V4L2_CID_VFLIP,150 .type = V4L2_CTRL_TYPE_BOOLEAN,151 .name = "Vertical Flip",152 .minimum = 0,153 .maximum = 1,154 .step = 1,155 .default_value = 0,156 }, {157 .id = V4L2_CID_PADDR_Y,158 .type = V4L2_CTRL_TYPE_BOOLEAN,159 .name = "Physical address Y",160 .minimum = 0,161 .maximum = 1,162 .step = 1,163 .default_value = 0,164 .flags = V4L2_CTRL_FLAG_READ_ONLY,165 }, {166 .id = V4L2_CID_PADDR_CB,167 .type = V4L2_CTRL_TYPE_BOOLEAN,168 .name = "Physical address Cb",169 .minimum = 0,170 .maximum = 1,171 .step = 1,172 .default_value = 0,173 .flags = V4L2_CTRL_FLAG_READ_ONLY,174 }, {175 .id = V4L2_CID_PADDR_CR,176 .type = V4L2_CTRL_TYPE_BOOLEAN,177 .name = "Physical address Cr",178 .minimum = 0,179 .maximum = 1,180 .step = 1,181 .default_value = 0,182 .flags = V4L2_CTRL_FLAG_READ_ONLY,183 }, {184 .id = V4L2_CID_PADDR_CBCR,185 .type = V4L2_CTRL_TYPE_BOOLEAN,186 .name = "Physical address CbCr",187 .minimum = 0,188 .maximum = 1,189 .step = 1,190 .default_value = 0,191 .flags = V4L2_CTRL_FLAG_READ_ONLY,192 },193 };
定义了FIMC支持的ctrl,后面四个ctrl: V4L2_CID_PADDR_Y, V4L2_CID_PADDR_CB, V4L2_CID_PADDR_CR, V4L2_CID_PADDR_CBCR 是samsung fimc私有的ctrl id, 用来获取分量的物理起始地址。
201 static int fimc_camera_init(struct fimc_control *ctrl)202 {203 int ret;204 205 fimc_dbg("%s\n", __func__);206 207 /* do nothing if already initialized */208 if (ctrl->cam->initialized)209 return 0;210 211 /* enable camera power if needed */212 if (ctrl->cam->cam_power)213 ctrl->cam->cam_power(1);214 215 /* subdev call for init */216 ret = subdev_call(ctrl, core, init, 0);217 if (ret == -ENOIOCTLCMD) {218 fimc_err("%s: init subdev api not supported\n",219 __func__);220 return ret;221 }222 223 if (ctrl->cam->type == CAM_TYPE_MIPI) {224 /* subdev call for sleep/wakeup:225 * no error although no s_stream api support226 */227 u32 pixelformat;228 if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)229 pixelformat = V4L2_PIX_FMT_JPEG;230 else231 pixelformat = ctrl->cam->pixelformat;232 233 subdev_call(ctrl, video, s_stream, 0);234 s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle, \235 ctrl->cam->mipi_align, ctrl->cam->width, \236 ctrl->cam->height, pixelformat);237 subdev_call(ctrl, video, s_stream, 1);238 }239 240 ctrl->cam->initialized = 1;241 242 return 0;243 }
这个函数主要对camera的sensor进行上电,初始化,这个函数最早的调用位置是streamon。
但是有一个问题,假定外围电路是一个video AD转换芯片托多个cvbs s-video或者YPbPr输入,那么在执行streamon之前,要首先执行s_input操作选择哪个video AD芯片的输入。选择video AD 的input输入是要操作AD芯片I2C寄存器的,因此这个上电位置是有问题的。
368 static int fimc_add_inqueue(struct fimc_control *ctrl, int i)369 {370 struct fimc_capinfo *cap = ctrl->cap;371372 struct fimc_buf_set *buf;373374 if (i >= cap->nr_bufs)375 return -EINVAL;376377 list_for_each_entry(buf, &cap->inq, list) {378 if (buf->id == i) {379 fimc_dbg("%s: buffer %d already in inqueue.\n", \380 __func__, i);381 return -EINVAL;382 }383 }384385 list_add_tail(&cap->bufs[i].list, &cap->inq);386387 return 0;388 }
这个函数被qbuf调用,把@i指定的buffer加到cap->inq链表中
cap->inq是可用buffer链表,当FIMC更新out DMA address时,就设置为cap->inq中的一个buffer
390 static int fimc_add_outqueue(struct fimc_control *ctrl, int i)391 {392 struct fimc_capinfo *cap = ctrl->cap;393 struct fimc_buf_set *buf;394395 unsigned int mask = 0x2;396397 /* PINGPONG_2ADDR_MODE Only */398 /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */399400 int pair_buf_index = (i^mask);401402 /* FIMC have 4 h/w registers */403 if (i < 0 || i >= FIMC_PHYBUFS) {404 fimc_err("%s: invalid queue index : %d\n", __func__, i);405 return -ENOENT;406 }407408 if (list_empty(&cap->inq))409 return -ENOENT;410411 buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);412413 /* pair index buffer should be allocated first */414 cap->outq[pair_buf_index] = buf->id;415 fimc_hwset_output_address(ctrl, buf, pair_buf_index);416417 cap->outq[i] = buf->id;418 fimc_hwset_output_address(ctrl, buf, i);419420 if (cap->nr_bufs != 1)421 list_del(&buf->list);422423 return 0;424 }
411 在cap->inq buffer链表中取得第一个可用buffer
413 ~ 418 一直没明白为什么这里把buf设置到两个输出out DMA address寄存器中,华清远见有篇文档http://www.embedu.org/Column/Column457.htm对这个代码的解释是说最多可以把四个out DMA address都配置上,可以增加画面的流畅度。
我原来也是同意华清讲师的说法的,四个output DMA address把帧数分成四个部分,第一个DMA address存储 1, 5, 9, 13... 帧, 第二个DMA address存储2, 6, 10, 14...帧, 第三个存储3, 7, 11, 15...帧, 第四个存储4, 8, 12, 16...帧,如果仅使用一个output DMA address,那么仅能得到1/4的帧率。
但是测试后发现,删除414~415后重新编译的内核没发现有帧率的变化,对帧率没有任何影响。
420 ~ 421 从cap->inq 链表中删除这个buf
516 int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)517 {518 struct fimc_global *fimc = get_fimc_dev();519 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;520521 fimc_dbg("%s: index %d\n", __func__, inp->index);522523 if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {524 fimc_err("%s: invalid input index, received = %d\n", \525 __func__, inp->index);526 return -EINVAL;527 }528529 if (!fimc->camera_isvalid[inp->index])530 return -EINVAL;531532 strcpy(inp->name, fimc->camera[inp->index].info->type);533 inp->type = V4L2_INPUT_TYPE_CAMERA;534535 return 0;536 }
我觉得fimc应该把ENUMINPUT ioctl调用传递给sensor驱动实现,毕竟std, status甚至name,是隶属于sensor的特性,fimc不该管理这些信息,管理就破坏了fimc驱动的通用性。
538 int fimc_g_input(struct file *file, void *fh, unsigned int *i)539 {540 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;541 struct fimc_global *fimc = get_fimc_dev();542 543 /* In case of isueing g_input before s_input */544 if (!ctrl->cam) {545 fimc_err("no camera device selected yet!" \546 "do VIDIOC_S_INPUT first\n");547 return -ENODEV;548 }549 550 *i = (unsigned int) fimc->active_camera;551 552 fimc_dbg("%s: index %d\n", __func__, *i);553 554 return 0;555 }
与fimc_enum_input不同,fimc_g_input可以完全由fimc驱动实现,毕竟这个函数仅仅返回current input的编号,这个编号应该算是隶属于video设备@file的一个特性。
637 int fimc_s_input(struct file *file, void *fh, unsigned int i)638 {639 struct fimc_global *fimc = get_fimc_dev();640 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;641 int ret = 0;642 643 fimc_dbg("%s: index %d\n", __func__, i);644 645 if (i < 0 || i >= FIMC_MAXCAMS) {646 fimc_err("%s: invalid input index\n", __func__);647 return -EINVAL;648 }649 650 if (!fimc->camera_isvalid[i])651 return -EINVAL;652 653 if (fimc->camera[i].sd && ctrl->id != 2) {654 fimc_err("%s: Camera already in use.\n", __func__);655 return -EBUSY;656 }657 658 mutex_lock(&ctrl->v4l2_lock);659 /* If ctrl->cam is not NULL, there is one subdev already registered.660 * We need to unregister that subdev first.661 */662 if (i != fimc->active_camera) {663 fimc_release_subdev(ctrl);664 ctrl->cam = &fimc->camera[i];665 ret = fimc_configure_subdev(ctrl);666 if (ret < 0) {667 mutex_unlock(&ctrl->v4l2_lock);668 fimc_err("%s: Could not register camera sensor "669 "with V4L2.\n", __func__);670 return -ENODEV;671 }672 fimc->active_camera = i;673 }674 675 if (ctrl->id == 2) {676 if (i == fimc->active_camera) {677 ctrl->cam = &fimc->camera[i];678 } else {679 mutex_unlock(&ctrl->v4l2_lock);680 return -EINVAL;681 }682 }683 684 mutex_unlock(&ctrl->v4l2_lock);685 686 return 0;687 }
这个函数选择@file指定的video设备的input路径,我的理解是s_input必须要有sensor驱动参与,这里的实现并没有调用sensor的接口。
897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)898 {899 struct fimc_capinfo *cap = ctrl->cap;900 int i, plane;901902 for (i = 0; i < cap->nr_bufs; i++) {903 for (plane = 0; plane < 4; plane++) {904 cap->bufs[i].length[plane] = size[plane];905 if (!cap->bufs[i].length[plane])906 continue;907908 fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);909910 if (!cap->bufs[i].base[plane])911 goto err_alloc;912 }913914 cap->bufs[i].state = VIDEOBUF_PREPARED;915 cap->bufs[i].id = i;916 }917918 return 0;919920 err_alloc:921 for (i = 0; i < cap->nr_bufs; i++) {922 if (cap->bufs[i].base[plane])923 fimc_dma_free(ctrl, &cap->bufs[i], plane);924925 memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));926 }927928 return -ENOMEM;929 }
分配queue buffer
@align:queue buffer是DMA buffer,所以会有alignment要求
@size:不同的format,每帧需要的子buffers数目不同,这个函数的plane就代表需要的子buffers数目,size[]是一个数组,表示queue buffers的每个子buffer需求的尺寸
902 cap->nr_bufs,是capture总的queue buffers数量。
950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)951 {952 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;953 struct fimc_capinfo *cap = ctrl->cap;954 int ret = 0, i;955 int size[4] = { 0, 0, 0, 0};956 int align = SZ_4K;957 958 if (b->memory != V4L2_MEMORY_MMAP) {959 fimc_err("%s: invalid memory type\n", __func__);960 return -EINVAL;961 }962 963 if (!cap) {964 fimc_err("%s: no capture device info\n", __func__);965 return -ENODEV;966 }967 968 if (!ctrl->cam || !ctrl->cam->sd) {969 fimc_err("%s: No capture device.\n", __func__);970 return -ENODEV;971 }972 973 mutex_lock(&ctrl->v4l2_lock);974 975 if (b->count < 1 || b->count > FIMC_CAPBUFS)976 return -EINVAL;977 978 /* It causes flickering as buf_0 and buf_3 refer to same hardware979 * address.980 */981 if (b->count == 3)982 b->count = 4;983 984 cap->nr_bufs = b->count;985 986 fimc_dbg("%s: requested %d buffers\n", __func__, b->count);987 988 INIT_LIST_HEAD(&cap->inq);989 990 fimc_free_buffers(ctrl);991 992 switch (cap->fmt.pixelformat) {993 case V4L2_PIX_FMT_RGB32: /* fall through */994 case V4L2_PIX_FMT_RGB565: /* fall through */995 case V4L2_PIX_FMT_YUYV: /* fall through */996 case V4L2_PIX_FMT_UYVY: /* fall through */997 case V4L2_PIX_FMT_VYUY: /* fall through */998 case V4L2_PIX_FMT_YVYU: /* fall through */999 case V4L2_PIX_FMT_YUV422P: /* fall through */
1000 size[0] = cap->fmt.sizeimage;
1001 break;
1002
1003 case V4L2_PIX_FMT_NV16: /* fall through */
1004 case V4L2_PIX_FMT_NV61:
1005 size[0] = cap->fmt.width * cap->fmt.height;
1006 size[1] = cap->fmt.width * cap->fmt.height;
1007 size[3] = 16; /* Padding buffer */
1008 break;
1009 case V4L2_PIX_FMT_NV12:
1010 size[0] = cap->fmt.width * cap->fmt.height;
1011 size[1] = cap->fmt.width * cap->fmt.height/2;
1012 break;
1013 case V4L2_PIX_FMT_NV21:
1014 size[0] = cap->fmt.width * cap->fmt.height;
1015 size[1] = cap->fmt.width * cap->fmt.height/2;
1016 size[3] = 16; /* Padding buffer */
1017 break;
1018 case V4L2_PIX_FMT_NV12T:
1019 /* Tiled frame size calculations as per 4x2 tiles
1020 * - Width: Has to be aligned to 2 times the tile width
1021 * - Height: Has to be aligned to the tile height
1022 * - Alignment: Has to be aligned to the size of the
1023 * macrotile (size of 4 tiles)
1024 *
1025 * NOTE: In case of rotation, we need modified calculation as
1026 * width and height are aligned to different values.
1027 */
1028 if (cap->rotate == 90 || cap->rotate == 270) {
1029 size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *
1030 ALIGN(cap->fmt.width, 32),
1031 SZ_8K);
1032 size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *
1033 ALIGN(cap->fmt.width/2, 32),
1034 SZ_8K);
1035 } else {
1036 size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *
1037 ALIGN(cap->fmt.height, 32),
1038 SZ_8K);
1039 size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *
1040 ALIGN(cap->fmt.height/2, 32),
1041 SZ_8K);
1042 }
1043 align = SZ_8K;
1044 break;
1045
1046 case V4L2_PIX_FMT_YUV420:
1047 size[0] = cap->fmt.width * cap->fmt.height;
1048 size[1] = cap->fmt.width * cap->fmt.height >> 2;
1049 size[2] = cap->fmt.width * cap->fmt.height >> 2;
1050 size[3] = 16; /* Padding buffer */
1051 break;
1052
1053 case V4L2_PIX_FMT_JPEG:
1054 size[0] = fimc_camera_get_jpeg_memsize(ctrl);
1055 default:
1056 break;
1057 }
1058
1059 ret = fimc_alloc_buffers(ctrl, size, align);
1060 if (ret) {
1061 fimc_err("%s: no memory for "
1062 "capture buffer\n", __func__);
1063 mutex_unlock(&ctrl->v4l2_lock);
1064 return -ENOMEM;
1065 }
1066
1067 for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) {
1068 memcpy(&cap->bufs[i], \
1069 &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i]));
1070 }
1071
1072 mutex_unlock(&ctrl->v4l2_lock);
1073
1074 return 0;
1075 }
975 ~978 FIMC_CAPBUFS是fimc支持的最大queue buffers数量,可以根据最大capture buffers数目,以及帧buffer所需空间大小(所有子buffers空间总和),加上alignment所带来的空间损失,大致算出fimc capture设备需要预留的物理空间
992 ~ 1057 根据pixelformat和width/height计算每个帧子buffers的尺寸。
1077 int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b)
1078 {
1079 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1080
1081 if (!ctrl->cap || !ctrl->cap->bufs) {
1082 fimc_err("%s: no capture device info\n", __func__);
1083 return -ENODEV;
1084 }
1085
1086 if (ctrl->status != FIMC_STREAMOFF) {
1087 fimc_err("fimc is running\n");
1088 return -EBUSY;
1089 }
1090
1091 mutex_lock(&ctrl->v4l2_lock);
1092
1093 b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y]
1094 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB]
1095 + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR];
1096
1097 b->m.offset = b->index * PAGE_SIZE;
1098
1099 ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE;
1100
1101 mutex_unlock(&ctrl->v4l2_lock);
1102
1103 fimc_dbg("%s: %d bytes at index: %d\n", __func__, b->length, b->index);
1104
1105 return 0;
1106 }
1093 ~ 1095 buffer的length由三个分量buffer总长度决定
1097 这个需要结合fimc_mmap_cap来看,b->m.offset可以用来表示buffer的索引值
1255 int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a)
1256 {
1257 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1258 struct fimc_capinfo *cap = ctrl->cap;
1259
1260 fimc_dbg("%s\n", __func__);
1261
1262 if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {
1263 fimc_err("%s: No capture device.\n", __func__);
1264 return -ENODEV;
1265 }
1266
1267 mutex_lock(&ctrl->v4l2_lock);
1268
1269 /* crop limitations */
1270 cap->cropcap.bounds.left = 0;
1271 cap->cropcap.bounds.top = 0;
1272 cap->cropcap.bounds.width = ctrl->cam->width;
1273 cap->cropcap.bounds.height = ctrl->cam->height;
1274
1275 /* crop default values */
1276 cap->cropcap.defrect.left = 0;
1277 cap->cropcap.defrect.top = 0;
1278 cap->cropcap.defrect.width = ctrl->cam->width;
1279 cap->cropcap.defrect.height = ctrl->cam->height;
1280
1281 a->bounds = cap->cropcap.bounds;
1282 a->defrect = cap->cropcap.defrect;
1283
1284 mutex_unlock(&ctrl->v4l2_lock);
1285
1286 return 0;
1287 }
fimc_cropcap_capture:fimc的VIDIOC_CROPCAP的实现
cropcap.bounds 是capture window 最大边界,capture.defrect是capture window的默认方框
cropcap.defrect一定不会超出cropcap.bounds的范围,他们的关系如下图

cropcap.pixelaspect =垂直像素数 / 水平像素数
1289 int fimc_g_crop_capture(void *fh, struct v4l2_crop *a)
1290 {
1291 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1292
1293 fimc_dbg("%s\n", __func__);
1294
1295 if (!ctrl->cap) {
1296 fimc_err("%s: No capture device.\n", __func__);
1297 return -ENODEV;
1298 }
1299
1300 mutex_lock(&ctrl->v4l2_lock);
1301 a->c = ctrl->cap->crop;
1302 mutex_unlock(&ctrl->v4l2_lock);
1303
1304 return 0;
1305 }
1306
fimc_g_crop_capture 是capture设备的VIDIOC_G_CROP实现,返回当前的crop
1307 static int fimc_capture_crop_size_check(struct fimc_control *ctrl)
1308 {
1309 struct fimc_capinfo *cap = ctrl->cap;
1310 int win_hor_offset = 0, win_hor_offset2 = 0;
1311 int win_ver_offset = 0, win_ver_offset2 = 0;
1312 int crop_width = 0, crop_height = 0;
1313
1314 /* check win_hor_offset, win_hor_offset2 */
1315 win_hor_offset = ctrl->cam->window.left;
1316 win_hor_offset2 = ctrl->cam->width - ctrl->cam->window.left -
1317 ctrl->cam->window.width;
1318
1319 win_ver_offset = ctrl->cam->window.top;
1320 win_ver_offset2 = ctrl->cam->height - ctrl->cam->window.top -
1321 ctrl->cam->window.height;
1322
1323 if (win_hor_offset < 0 || win_hor_offset2 < 0) {
1324 fimc_err("%s: Offset (left-side(%d) or right-side(%d) "
1325 "is negative.\n", __func__, \
1326 win_hor_offset, win_hor_offset2);
1327 return -1;
1328 }
1329
1330 if (win_ver_offset < 0 || win_ver_offset2 < 0) {
1331 fimc_err("%s: Offset (top-side(%d) or bottom-side(%d)) "
1332 "is negative.\n", __func__, \
1333 win_ver_offset, win_ver_offset2);
1334 return -1;
1335 }
1336
1337 if ((win_hor_offset % 2) || (win_hor_offset2 % 2)) {
1338 fimc_err("%s: win_hor_offset must be multiple of 2\n", \
1339 __func__);
1340 return -1;
1341 }
1342
1343 /* check crop_width, crop_height */
1344 crop_width = ctrl->cam->window.width;
1345 crop_height = ctrl->cam->window.height;
1346
1347 if (crop_width % 16) {
1348 fimc_err("%s: crop_width must be multiple of 16\n", __func__);
1349 return -1;
1350 }
1351
1352 switch (cap->fmt.pixelformat) {
1353 case V4L2_PIX_FMT_YUV420: /* fall through */
1354 case V4L2_PIX_FMT_NV12: /* fall through */
1355 case V4L2_PIX_FMT_NV21: /* fall through */
1356 case V4L2_PIX_FMT_NV12T: /* fall through */
1357 if ((crop_height % 2) || (crop_height < 8)) {
1358 fimc_err("%s: crop_height error!\n", __func__);
1359 return -1;
1360 }
1361 break;
1362 default:
1363 break;
1364 }
1365
1366 return 0;
1367 }cam->cam->window是crop设置后的取景框,这个函数就是检测这个取景框是否符合规范
1377 static void fimc_capture_update_crop_window(struct fimc_control *ctrl)
1378 {
1379 unsigned int zoom_hor = 0;
1380 unsigned int zoom_ver = 0;
1381 unsigned int multiplier = 1024;
1382
1383 if (!ctrl->cam->width || !ctrl->cam->height)
1384 return;
1385
1386 zoom_hor = ctrl->cap->fmt.width * multiplier / ctrl->cam->width;
1387 zoom_ver = ctrl->cap->fmt.height * multiplier / ctrl->cam->height;
1388
1389 if (!zoom_hor || !zoom_ver)
1390 return;
1391
1392 /* Width */
1393 ctrl->cam->window.width = ctrl->cap->crop.width * multiplier / zoom_hor;
1394 if (ctrl->cam->window.width > ctrl->cam->width)
1395 ctrl->cam->window.width = ctrl->cam->width;
1396 if (ctrl->cam->window.width % 16)
1397 ctrl->cam->window.width =
1398 (ctrl->cam->window.width + 0xF) & ~0xF;
1399
1400 /* Left offset */
1401 ctrl->cam->window.left = ctrl->cap->crop.left * multiplier / zoom_hor;
1402 if (ctrl->cam->window.width + ctrl->cam->window.left > ctrl->cam->width)
1403 ctrl->cam->window.left =
1404 (ctrl->cam->width - ctrl->cam->window.width)/2;
1405 if (ctrl->cam->window.left % 2)
1406 ctrl->cam->window.left--;
1407
1408 /* Height */
1409 ctrl->cam->window.height =
1410 (ctrl->cap->crop.height * multiplier) / zoom_ver;
1411 if (ctrl->cam->window.top > ctrl->cam->height)
1412 ctrl->cam->window.height = ctrl->cam->height;
1413 if (ctrl->cam->window.height % 2)
1414 ctrl->cam->window.height--;
1415
1416 /* Top offset */
1417 ctrl->cam->window.top = ctrl->cap->crop.top * multiplier / zoom_ver;
1418 if (ctrl->cam->window.height + ctrl->cam->window.top >
1419 ctrl->cam->height)
1420 ctrl->cam->window.top =
1421 (ctrl->cam->height - ctrl->cam->window.height)/2;
1422 if (ctrl->cam->window.top % 2)
1423 ctrl->cam->window.top--;
1424
1425 fimc_dbg("Cam (%dx%d) Crop: (%d %d %d %d) Win: (%d %d %d %d)\n", \
1426 ctrl->cam->width, ctrl->cam->height, \
1427 ctrl->cap->crop.left, ctrl->cap->crop.top, \
1428 ctrl->cap->crop.width, ctrl->cap->crop.height, \
1429 ctrl->cam->window.left, ctrl->cam->window.top, \
1430 ctrl->cam->window.width, ctrl->cam->window.height);
1431
1432 }
根据s_crop设置的curr_crop设置capture 的取景框
1434 int fimc_s_crop_capture(void *fh, struct v4l2_crop *a)
1435 {
1436 struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1437 int ret = 0;
1438
1439 fimc_dbg("%s\n", __func__);
1440
1441 if (!ctrl->cap) {
1442 fimc_err("%s: No capture device.\n", __func__);
1443 return -ENODEV;
1444 }
1445
1446 mutex_lock(&ctrl->v4l2_lock);
1447 ctrl->cap->crop = a->c;
1448
1449 fimc_capture_update_crop_window(ctrl);
1450
1451 ret = fimc_capture_crop_size_check(ctrl);
1452 if (ret < 0) {
1453 mutex_unlock(&ctrl->v4l2_lock);
1454 fimc_err("%s: Invalid crop parameters.\n", __func__);
1455 return -EINVAL;
1456 }
1457
1458 if (ctrl->status == FIMC_STREAMON &&
1459 ctrl->cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) {
1460 fimc_hwset_shadow_disable(ctrl);
1461 fimc_hwset_camera_offset(ctrl);
1462 fimc_capture_scaler_info(ctrl);
1463 fimc_hwset_prescaler(ctrl, &ctrl->sc);
1464 fimc_hwset_scaler(ctrl, &ctrl->sc);
1465 fimc_hwset_shadow_enable(ctrl);
1466 }
1467
1468 mutex_unlock(&ctrl->v4l2_lock);
1469
1470 return 0;
1471 }
fimc_s_crop_capture是capture设备的VIDIOC_S_CROP ioctl实现
1449 用@a更新capture window
1451 检测新生成的capture window参数合法性
1458 ~ 1466 FIMC支持streamon正在进行时,修改capture取景框
转载自:http://blog.csdn.net/kickxxx/article/details/7733482
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
