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 tiles1020          *  - Width: Has to be aligned to 2 times the tile width1021          *  - Height: Has to be aligned to the tile height1022          *  - Alignment: Has to be aligned to the size of the1023          *  macrotile (size of 4 tiles)1024          *1025          * NOTE: In case of rotation, we need modified calculation as1026          * 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

更多相关文章

  1. Android(安卓)Audio相关 AudioFlinger类
  2. android camera开发笔记
  3. Android系统默认Home应用程序(Launcher)的启动过程源代码分析(4)
  4. Android事件处理流程
  5. Android(安卓)Studio 单独编译WebRTC的 vad 模块
  6. Android(安卓)的一些提示框
  7. Android(安卓)编解码

随机推荐

  1. Android(安卓)Exception 记录合集
  2. Android(安卓)判断APP是否在前台
  3. Android(安卓)get target app display na
  4. AMLogic Releases AML8726-MX Linux 3.0.
  5. Android(安卓)EditText用户友好的输入界
  6. android中Browser地址栏隐藏
  7. Android--数据库操作辅助类:SQLiteOpenHel
  8. Android(安卓)4.0 framework modify, emu
  9. Android---30---ProgressBar进度条的使用
  10. android 实现跳动频谱 DEMO