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 support 226 */ 227 u32 pixelformat; 228 if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG) 229 pixelformat = V4L2_PIX_FMT_JPEG; 230 else 231 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; 371 372 struct fimc_buf_set *buf; 373 374 if (i >= cap->nr_bufs) 375 return -EINVAL; 376 377 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 } 384 385 list_add_tail(&cap->bufs[i].list, &cap->inq); 386 387 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; 394 395 unsigned int mask = 0x2; 396 397 /* PINGPONG_2ADDR_MODE Only */ 398 /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */ 399 400 int pair_buf_index = (i^mask); 401 402 /* 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 } 407 408 if (list_empty(&cap->inq)) 409 return -ENOENT; 410 411 buf = list_first_entry(&cap->inq, struct fimc_buf_set, list); 412 413 /* 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); 416 417 cap->outq[i] = buf->id; 418 fimc_hwset_output_address(ctrl, buf, i); 419 420 if (cap->nr_bufs != 1) 421 list_del(&buf->list); 422 423 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; 520 521 fimc_dbg("%s: index %d\n", __func__, inp->index); 522 523 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 } 528 529 if (!fimc->camera_isvalid[inp->index]) 530 return -EINVAL; 531 532 strcpy(inp->name, fimc->camera[inp->index].info->type); 533 inp->type = V4L2_INPUT_TYPE_CAMERA; 534 535 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; 901 902 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; 907 908 fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align); 909 910 if (!cap->bufs[i].base[plane]) 911 goto err_alloc; 912 } 913 914 cap->bufs[i].state = VIDEOBUF_PREPARED; 915 cap->bufs[i].id = i; 916 } 917 918 return 0; 919 920 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); 924 925 memset(&cap->bufs[i], 0, sizeof(cap->bufs[i])); 926 } 927 928 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 hardware 979 * 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 的取景框<br> 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