zoukankan      html  css  js  c++  java
  • Android S5PV210 fimc驱动分析

    fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片

    http://blog.csdn.net/kickxxx/article/details/7733482

    [cpp] view plaincopy
     
    1. 43 static const struct v4l2_fmtdesc capture_fmts[] = {  
    2.  44     {  
    3.  45         .index      = 0,  
    4.  46         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    5.  47         .flags      = FORMAT_FLAGS_PACKED,  
    6.  48         .description    = "RGB-5-6-5",  
    7.  49         .pixelformat    = V4L2_PIX_FMT_RGB565,  
    8.  50     }, {  
    9.  51         .index      = 1,  
    10.  52         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    11.  53         .flags      = FORMAT_FLAGS_PACKED,  
    12.  54         .description    = "RGB-8-8-8, unpacked 24 bpp",  
    13.  55         .pixelformat    = V4L2_PIX_FMT_RGB32,  
    14.  56     }, {  
    15.  57         .index      = 2,  
    16.  58         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    17.  59         .flags      = FORMAT_FLAGS_PACKED,  
    18.  60         .description    = "YUV 4:2:2 packed, YCbYCr",  
    19.  61         .pixelformat    = V4L2_PIX_FMT_YUYV,  
    20.  62     }, {  
    21.  63         .index      = 3,  
    22.  64         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    23.  65         .flags      = FORMAT_FLAGS_PACKED,  
    24.  66         .description    = "YUV 4:2:2 packed, CbYCrY",  
    25.  67         .pixelformat    = V4L2_PIX_FMT_UYVY,  
    26.  68     }, {  
    27.  69         .index      = 4,  
    28.  70         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    29.  71         .flags      = FORMAT_FLAGS_PACKED,  
    30.  72         .description    = "YUV 4:2:2 packed, CrYCbY",  
    31.  73         .pixelformat    = V4L2_PIX_FMT_VYUY,  
    32.  74     }, {  
    33.  75         .index      = 5,  
    34.  76         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    35.  77         .flags      = FORMAT_FLAGS_PACKED,  
    36.  78         .description    = "YUV 4:2:2 packed, YCrYCb",  
    37.  79         .pixelformat    = V4L2_PIX_FMT_YVYU,  
    38.  80     }, {  
    39.  81         .index      = 6,  
    40.  82         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    41.  83         .flags      = FORMAT_FLAGS_PLANAR,  
    42.  84         .description    = "YUV 4:2:2 planar, Y/Cb/Cr",  
    43. 85         .pixelformat    = V4L2_PIX_FMT_YUV422P,  
    44.  86     }, {  
    45.  87         .index      = 7,  
    46.  88         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    47.  89         .flags      = FORMAT_FLAGS_PLANAR,  
    48.  90         .description    = "YUV 4:2:0 planar, Y/CbCr",  
    49.  91         .pixelformat    = V4L2_PIX_FMT_NV12,  
    50.  92     }, {  
    51.  93         .index      = 8,  
    52.  94         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    53.  95         .flags      = FORMAT_FLAGS_PLANAR,  
    54.  96         .description    = "YUV 4:2:0 planar, Y/CbCr, Tiled",  
    55.  97         .pixelformat    = V4L2_PIX_FMT_NV12T,  
    56.  98     }, {  
    57.  99         .index      = 9,  
    58. 100         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    59. 101         .flags      = FORMAT_FLAGS_PLANAR,  
    60. 102         .description    = "YUV 4:2:0 planar, Y/CrCb",  
    61. 103         .pixelformat    = V4L2_PIX_FMT_NV21,  
    62. 104     }, {  
    63. 105         .index      = 10,  
    64. 106         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    65. 107         .flags      = FORMAT_FLAGS_PLANAR,  
    66. 108         .description    = "YUV 4:2:2 planar, Y/CbCr",  
    67. 109         .pixelformat    = V4L2_PIX_FMT_NV16,  
    68. 110     }, {  
    69. 111         .index      = 11,  
    70. 112         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    71. 113         .flags      = FORMAT_FLAGS_PLANAR,  
    72. 114         .description    = "YUV 4:2:2 planar, Y/CrCb",  
    73. 115         .pixelformat    = V4L2_PIX_FMT_NV61,  
    74. 116     }, {  
    75. 117         .index      = 12,  
    76. 118         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    77. 119         .flags      = FORMAT_FLAGS_PLANAR,  
    78. 120         .description    = "YUV 4:2:0 planar, Y/Cb/Cr",  
    79. 121         .pixelformat    = V4L2_PIX_FMT_YUV420,  
    80. 122     }, {  
    81. 123         .index      = 13,  
    82. 124         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
    83. 125         .flags      = FORMAT_FLAGS_ENCODED,  
    84. 126         .description    = "Encoded JPEG bitstream",  
    85. 127         .pixelformat    = V4L2_PIX_FMT_JPEG,  
    86. 128     },  
    87. 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格式

    [cpp] view plaincopy
     
    1. 131 static const struct v4l2_queryctrl fimc_controls[] = {  
    2. 132     {  
    3. 133         .id = V4L2_CID_ROTATION,  
    4. 134         .type = V4L2_CTRL_TYPE_BOOLEAN,  
    5. 135         .name = "Roataion",  
    6. 136         .minimum = 0,  
    7. 137         .maximum = 270,  
    8. 138         .step = 90,  
    9. 139         .default_value = 0,  
    10. 140     }, {  
    11. 141         .id = V4L2_CID_HFLIP,  
    12. 142         .type = V4L2_CTRL_TYPE_BOOLEAN,  
    13. 143         .name = "Horizontal Flip",  
    14. 144         .minimum = 0,  
    15. 145         .maximum = 1,  
    16. 146         .step = 1,  
    17. 147         .default_value = 0,  
    18. 148     }, {  
    19. 149         .id = V4L2_CID_VFLIP,  
    20. 150         .type = V4L2_CTRL_TYPE_BOOLEAN,  
    21. 151         .name = "Vertical Flip",  
    22. 152         .minimum = 0,  
    23. 153         .maximum = 1,  
    24. 154         .step = 1,  
    25. 155         .default_value = 0,  
    26. 156     }, {  
    27. 157         .id = V4L2_CID_PADDR_Y,  
    28. 158         .type = V4L2_CTRL_TYPE_BOOLEAN,  
    29. 159         .name = "Physical address Y",  
    30. 160         .minimum = 0,  
    31. 161         .maximum = 1,  
    32. 162         .step = 1,  
    33. 163         .default_value = 0,  
    34. 164         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
    35. 165     }, {  
    36. 166         .id = V4L2_CID_PADDR_CB,  
    37. 167         .type = V4L2_CTRL_TYPE_BOOLEAN,  
    38. 168         .name = "Physical address Cb",  
    39. 169         .minimum = 0,  
    40. 170         .maximum = 1,  
    41. 171         .step = 1,  
    42. 172         .default_value = 0,  
    43. 173         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
    44. 174     }, {  
    45. 175         .id = V4L2_CID_PADDR_CR,  
    46. 176         .type = V4L2_CTRL_TYPE_BOOLEAN,  
    47. 177         .name = "Physical address Cr",  
    48. 178         .minimum = 0,  
    49. 179         .maximum = 1,  
    50. 180         .step = 1,  
    51. 181         .default_value = 0,  
    52. 182         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
    53. 183     }, {  
    54. 184         .id = V4L2_CID_PADDR_CBCR,  
    55. 185         .type = V4L2_CTRL_TYPE_BOOLEAN,  
    56. 186         .name = "Physical address CbCr",  
    57. 187         .minimum = 0,  
    58. 188         .maximum = 1,  
    59. 189         .step = 1,  
    60. 190         .default_value = 0,  
    61. 191         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
    62. 192     },  
    63. 193 };  

    定义了FIMC支持的ctrl,后面四个ctrl: V4L2_CID_PADDR_Y, V4L2_CID_PADDR_CB, V4L2_CID_PADDR_CR, V4L2_CID_PADDR_CBCR 是samsung fimc私有的ctrl id, 用来获取分量的物理起始地址。

    [cpp] view plaincopy
     
    1. 201 static int fimc_camera_init(struct fimc_control *ctrl)  
    2. 202 {  
    3. 203     int ret;  
    4. 204   
    5. 205     fimc_dbg("%s ", __func__);  
    6. 206   
    7. 207     /* do nothing if already initialized */  
    8. 208     if (ctrl->cam->initialized)  
    9. 209         return 0;  
    10. 210   
    11. 211     /* enable camera power if needed */  
    12. 212     if (ctrl->cam->cam_power)  
    13. 213         ctrl->cam->cam_power(1);  
    14. 214   
    15. 215     /* subdev call for init */  
    16. 216     ret = subdev_call(ctrl, core, init, 0);  
    17. 217     if (ret == -ENOIOCTLCMD) {  
    18. 218         fimc_err("%s: init subdev api not supported ",  
    19. 219             __func__);  
    20. 220         return ret;  
    21. 221     }  
    22. 222   
    23. 223     if (ctrl->cam->type == CAM_TYPE_MIPI) {  
    24. 224         /* subdev call for sleep/wakeup: 
    25. 225          * no error although no s_stream api support 
    26. 226          */  
    27. 227         u32 pixelformat;  
    28. 228         if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)  
    29. 229             pixelformat = V4L2_PIX_FMT_JPEG;  
    30. 230         else  
    31. 231             pixelformat = ctrl->cam->pixelformat;  
    32. 232   
    33. 233         subdev_call(ctrl, video, s_stream, 0);  
    34. 234         s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle,   
    35. 235                 ctrl->cam->mipi_align, ctrl->cam->width,   
    36. 236                 ctrl->cam->height, pixelformat);  
    37. 237         subdev_call(ctrl, video, s_stream, 1);  
    38. 238     }  
    39. 239   
    40. 240     ctrl->cam->initialized = 1;  
    41. 241   
    42. 242     return 0;  
    43. 243 }  

    这个函数主要对camera的sensor进行上电,初始化,这个函数最早的调用位置是streamon。

    但是有一个问题,假定外围电路是一个video AD转换芯片托多个cvbs s-video或者YPbPr输入,那么在执行streamon之前,要首先执行s_input操作选择哪个video AD芯片的输入。选择video AD 的input输入是要操作AD芯片I2C寄存器的,因此这个上电位置是有问题的。

    [cpp] view plaincopy
     
    1. 368 static int fimc_add_inqueue(struct fimc_control *ctrl, int i)  
    2. 369 {  
    3. 370     struct fimc_capinfo *cap = ctrl->cap;  
    4. 371  
    5. 372     struct fimc_buf_set *buf;  
    6. 373  
    7. 374     if (i >= cap->nr_bufs)  
    8. 375         return -EINVAL;  
    9. 376  
    10. 377     list_for_each_entry(buf, &cap->inq, list) {  
    11. 378         if (buf->id == i) {  
    12. 379             fimc_dbg("%s: buffer %d already in inqueue. ",   
    13. 380                     __func__, i);  
    14. 381             return -EINVAL;  
    15. 382         }  
    16. 383     }  
    17. 384  
    18. 385     list_add_tail(&cap->bufs[i].list, &cap->inq);  
    19. 386  
    20. 387     return 0;  
    21. 388 }  

    这个函数被qbuf调用,把@i指定的buffer加到cap->inq链表中

    cap->inq是可用buffer链表,当FIMC更新out DMA address时,就设置为cap->inq中的一个buffer

    [cpp] view plaincopy
     
    1. 390 static int fimc_add_outqueue(struct fimc_control *ctrl, int i)  
    2. 391 {  
    3. 392     struct fimc_capinfo *cap = ctrl->cap;  
    4. 393     struct fimc_buf_set *buf;  
    5. 394  
    6. 395     unsigned int mask = 0x2;  
    7. 396  
    8. 397     /* PINGPONG_2ADDR_MODE Only */  
    9. 398     /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */  
    10. 399  
    11. 400     int pair_buf_index = (i^mask);  
    12. 401  
    13. 402     /* FIMC have 4 h/w registers */  
    14. 403     if (i < 0 || i >= FIMC_PHYBUFS) {  
    15. 404         fimc_err("%s: invalid queue index : %d ", __func__, i);  
    16. 405         return -ENOENT;  
    17. 406     }  
    18. 407  
    19. 408     if (list_empty(&cap->inq))  
    20. 409         return -ENOENT;  
    21. 410  
    22. 411     buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);  
    23. 412  
    24. 413     /* pair index buffer should be allocated first */  
    25. 414     cap->outq[pair_buf_index] = buf->id;  
    26. 415     fimc_hwset_output_address(ctrl, buf, pair_buf_index);  
    27. 416  
    28. 417     cap->outq[i] = buf->id;  
    29. 418     fimc_hwset_output_address(ctrl, buf, i);  
    30. 419  
    31. 420     if (cap->nr_bufs != 1)  
    32. 421         list_del(&buf->list);  
    33. 422  
    34. 423     return 0;  
    35. 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

    [cpp] view plaincopy
     
    1. 516 int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)  
    2. 517 {  
    3. 518     struct fimc_global *fimc = get_fimc_dev();  
    4. 519     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    5. 520  
    6. 521     fimc_dbg("%s: index %d ", __func__, inp->index);  
    7. 522  
    8. 523     if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {  
    9. 524         fimc_err("%s: invalid input index, received = %d ",   
    10. 525                 __func__, inp->index);  
    11. 526         return -EINVAL;  
    12. 527     }  
    13. 528  
    14. 529     if (!fimc->camera_isvalid[inp->index])  
    15. 530         return -EINVAL;  
    16. 531  
    17. 532     strcpy(inp->name, fimc->camera[inp->index].info->type);  
    18. 533     inp->type = V4L2_INPUT_TYPE_CAMERA;  
    19. 534  
    20. 535     return 0;  
    21. 536 }  


    我觉得fimc应该把ENUMINPUT ioctl调用传递给sensor驱动实现,毕竟std, status甚至name,是隶属于sensor的特性,fimc不该管理这些信息,管理就破坏了fimc驱动的通用性。

    [cpp] view plaincopy
     
    1. 538 int fimc_g_input(struct file *file, void *fh, unsigned int *i)  
    2. 539 {  
    3. 540     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    4. 541     struct fimc_global *fimc = get_fimc_dev();  
    5. 542   
    6. 543     /* In case of isueing g_input before s_input */  
    7. 544     if (!ctrl->cam) {  
    8. 545         fimc_err("no camera device selected yet!"   
    9. 546                 "do VIDIOC_S_INPUT first ");  
    10. 547         return -ENODEV;  
    11. 548     }  
    12. 549   
    13. 550     *i = (unsigned int) fimc->active_camera;  
    14. 551   
    15. 552     fimc_dbg("%s: index %d ", __func__, *i);  
    16. 553   
    17. 554     return 0;  
    18. 555 }  

    与fimc_enum_input不同,fimc_g_input可以完全由fimc驱动实现,毕竟这个函数仅仅返回current input的编号,这个编号应该算是隶属于video设备@file的一个特性。

    [cpp] view plaincopy
     
    1. 637 int fimc_s_input(struct file *file, void *fh, unsigned int i)  
    2.  638 {  
    3.  639     struct fimc_global *fimc = get_fimc_dev();  
    4.  640     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    5.  641     int ret = 0;  
    6.  642   
    7.  643     fimc_dbg("%s: index %d ", __func__, i);  
    8.  644   
    9.  645     if (i < 0 || i >= FIMC_MAXCAMS) {  
    10.  646         fimc_err("%s: invalid input index ", __func__);  
    11.  647         return -EINVAL;  
    12.  648     }  
    13.  649   
    14.  650     if (!fimc->camera_isvalid[i])  
    15.  651         return -EINVAL;  
    16.  652   
    17.  653     if (fimc->camera[i].sd && ctrl->id != 2) {  
    18.  654         fimc_err("%s: Camera already in use. ", __func__);  
    19.  655         return -EBUSY;  
    20.  656     }  
    21.  657   
    22.  658     mutex_lock(&ctrl->v4l2_lock);  
    23.  659     /* If ctrl->cam is not NULL, there is one subdev already registered. 
    24.  660      * We need to unregister that subdev first. 
    25.  661      */  
    26.  662     if (i != fimc->active_camera) {  
    27.  663         fimc_release_subdev(ctrl);  
    28.  664         ctrl->cam = &fimc->camera[i];  
    29.  665         ret = fimc_configure_subdev(ctrl);  
    30.  666         if (ret < 0) {  
    31.  667             mutex_unlock(&ctrl->v4l2_lock);  
    32.  668             fimc_err("%s: Could not register camera sensor "  
    33.  669                     "with V4L2. ", __func__);  
    34.  670             return -ENODEV;  
    35.  671         }  
    36.  672         fimc->active_camera = i;  
    37.  673     }  
    38.  674   
    39.  675     if (ctrl->id == 2) {  
    40.  676         if (i == fimc->active_camera) {  
    41.  677             ctrl->cam = &fimc->camera[i];  
    42.  678         } else {  
    43.  679             mutex_unlock(&ctrl->v4l2_lock);  
    44.  680             return -EINVAL;  
    45.  681         }  
    46.  682     }  
    47.  683   
    48.  684     mutex_unlock(&ctrl->v4l2_lock);  
    49.  685   
    50.  686     return 0;  
    51.  687 }  


    这个函数选择@file指定的video设备的input路径,我的理解是s_input必须要有sensor驱动参与,这里的实现并没有调用sensor的接口

    [cpp] view plaincopy
     
    1. 897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)  
    2. 898 {  
    3. 899     struct fimc_capinfo *cap = ctrl->cap;  
    4. 900     int i, plane;  
    5. 901  
    6. 902     for (i = 0; i < cap->nr_bufs; i++) {  
    7. 903         for (plane = 0; plane < 4; plane++) {  
    8. 904             cap->bufs[i].length[plane] = size[plane];  
    9. 905             if (!cap->bufs[i].length[plane])  
    10. 906                 continue;  
    11. 907  
    12. 908             fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);  
    13. 909  
    14. 910             if (!cap->bufs[i].base[plane])  
    15. 911                 goto err_alloc;  
    16. 912         }  
    17. 913  
    18. 914         cap->bufs[i].state = VIDEOBUF_PREPARED;  
    19. 915         cap->bufs[i].id = i;  
    20. 916     }  
    21. 917  
    22. 918     return 0;  
    23. 919  
    24. 920 err_alloc:  
    25. 921     for (i = 0; i < cap->nr_bufs; i++) {  
    26. 922         if (cap->bufs[i].base[plane])  
    27. 923             fimc_dma_free(ctrl, &cap->bufs[i], plane);  
    28. 924  
    29. 925         memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));  
    30. 926     }  
    31. 927  
    32. 928     return -ENOMEM;  
    33. 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数量。

    [cpp] view plaincopy
     
    1.  950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)  
    2.  951 {  
    3.  952     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    4.  953     struct fimc_capinfo *cap = ctrl->cap;  
    5.  954     int ret = 0, i;  
    6.  955     int size[4] = { 0, 0, 0, 0};  
    7.  956     int align = SZ_4K;  
    8.  957   
    9.  958     if (b->memory != V4L2_MEMORY_MMAP) {  
    10.  959         fimc_err("%s: invalid memory type ", __func__);  
    11.  960         return -EINVAL;  
    12.  961     }  
    13.  962   
    14.  963     if (!cap) {  
    15.  964         fimc_err("%s: no capture device info ", __func__);  
    16.  965         return -ENODEV;  
    17.  966     }  
    18.  967   
    19.  968     if (!ctrl->cam || !ctrl->cam->sd) {  
    20.  969         fimc_err("%s: No capture device. ", __func__);  
    21.  970         return -ENODEV;  
    22.  971     }  
    23.  972   
    24.  973     mutex_lock(&ctrl->v4l2_lock);  
    25.  974   
    26.  975     if (b->count < 1 || b->count > FIMC_CAPBUFS)  
    27.  976         return -EINVAL;  
    28.  977   
    29.  978     /* It causes flickering as buf_0 and buf_3 refer to same hardware 
    30.  979      * address. 
    31.  980      */  
    32.  981     if (b->count == 3)  
    33.  982         b->count = 4;  
    34.  983   
    35.  984     cap->nr_bufs = b->count;  
    36.  985   
    37.  986     fimc_dbg("%s: requested %d buffers ", __func__, b->count);  
    38.  987   
    39.  988     INIT_LIST_HEAD(&cap->inq);  
    40.  989   
    41.  990     fimc_free_buffers(ctrl);  
    42.  991   
    43.  992     switch (cap->fmt.pixelformat) {  
    44.  993     case V4L2_PIX_FMT_RGB32:    /* fall through */  
    45.  994     case V4L2_PIX_FMT_RGB565:   /* fall through */  
    46.  995     case V4L2_PIX_FMT_YUYV:     /* fall through */  
    47.  996     case V4L2_PIX_FMT_UYVY:     /* fall through */  
    48.  997     case V4L2_PIX_FMT_VYUY:     /* fall through */  
    49.  998     case V4L2_PIX_FMT_YVYU:     /* fall through */  
    50.  999     case V4L2_PIX_FMT_YUV422P:  /* fall through */  
    51. 1000         size[0] = cap->fmt.sizeimage;  
    52. 1001         break;  
    53. 1002   
    54. 1003     case V4L2_PIX_FMT_NV16:     /* fall through */  
    55. 1004     case V4L2_PIX_FMT_NV61:  
    56. 1005         size[0] = cap->fmt.width * cap->fmt.height;  
    57. 1006         size[1] = cap->fmt.width * cap->fmt.height;  
    58. 1007         size[3] = 16; /* Padding buffer */  
    59. 1008         break;  
    60. 1009     case V4L2_PIX_FMT_NV12:  
    61. 1010         size[0] = cap->fmt.width * cap->fmt.height;  
    62. 1011         size[1] = cap->fmt.width * cap->fmt.height/2;  
    63. 1012         break;  
    64. 1013     case V4L2_PIX_FMT_NV21:  
    65. 1014         size[0] = cap->fmt.width * cap->fmt.height;  
    66. 1015         size[1] = cap->fmt.width * cap->fmt.height/2;  
    67. 1016         size[3] = 16; /* Padding buffer */  
    68. 1017         break;  
    69. 1018     case V4L2_PIX_FMT_NV12T:  
    70. 1019         /* Tiled frame size calculations as per 4x2 tiles 
    71. 1020          *  - Width: Has to be aligned to 2 times the tile width 
    72. 1021          *  - Height: Has to be aligned to the tile height 
    73. 1022          *  - Alignment: Has to be aligned to the size of the 
    74. 1023          *  macrotile (size of 4 tiles) 
    75. 1024          * 
    76. 1025          * NOTE: In case of rotation, we need modified calculation as 
    77. 1026          * width and height are aligned to different values. 
    78. 1027          */  
    79. 1028         if (cap->rotate == 90 || cap->rotate == 270) {  
    80. 1029             size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *  
    81. 1030                     ALIGN(cap->fmt.width, 32),  
    82. 1031                     SZ_8K);  
    83. 1032             size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *  
    84. 1033                     ALIGN(cap->fmt.width/2, 32),  
    85. 1034                     SZ_8K);  
    86. 1035         } else {  
    87. 1036             size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *  
    88. 1037                     ALIGN(cap->fmt.height, 32),  
    89. 1038                     SZ_8K);  
    90. 1039             size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *  
    91. 1040                     ALIGN(cap->fmt.height/2, 32),  
    92. 1041                     SZ_8K);  
    93. 1042         }  
    94. 1043         align = SZ_8K;  
    95. 1044         break;  
    96. 1045   
    97. 1046     case V4L2_PIX_FMT_YUV420:  
    98. 1047         size[0] = cap->fmt.width * cap->fmt.height;  
    99. 1048         size[1] = cap->fmt.width * cap->fmt.height >> 2;  
    100. 1049         size[2] = cap->fmt.width * cap->fmt.height >> 2;  
    101. 1050         size[3] = 16; /* Padding buffer */  
    102. 1051         break;  
    103. 1052   
    104. 1053     case V4L2_PIX_FMT_JPEG:  
    105. 1054         size[0] = fimc_camera_get_jpeg_memsize(ctrl);  
    106. 1055     default:  
    107. 1056         break;  
    108. 1057     }  
    109. 1058   
    110. 1059     ret = fimc_alloc_buffers(ctrl, size, align);  
    111. 1060     if (ret) {  
    112. 1061         fimc_err("%s: no memory for "  
    113. 1062                 "capture buffer ", __func__);  
    114. 1063         mutex_unlock(&ctrl->v4l2_lock);  
    115. 1064         return -ENOMEM;  
    116. 1065     }  
    117. 1066   
    118. 1067     for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) {  
    119. 1068         memcpy(&cap->bufs[i],   
    120. 1069             &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i]));  
    121. 1070     }  
    122. 1071   
    123. 1072     mutex_unlock(&ctrl->v4l2_lock);  
    124. 1073   
    125. 1074     return 0;  
    126. 1075 }  

    975 ~978 FIMC_CAPBUFS是fimc支持的最大queue buffers数量,可以根据最大capture buffers数目,以及帧buffer所需空间大小(所有子buffers空间总和),加上alignment所带来的空间损失,大致算出fimc capture设备需要预留的物理空间
    992 ~ 1057 根据pixelformat和width/height计算每个帧子buffers的尺寸。

    [cpp] view plaincopy
     
    1. 1077 int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b)  
    2. 1078 {     
    3. 1079     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    4. 1080       
    5. 1081     if (!ctrl->cap || !ctrl->cap->bufs) {  
    6. 1082         fimc_err("%s: no capture device info ", __func__);  
    7. 1083         return -ENODEV;   
    8. 1084     }  
    9. 1085       
    10. 1086     if (ctrl->status != FIMC_STREAMOFF) {  
    11. 1087         fimc_err("fimc is running ");  
    12. 1088         return -EBUSY;        
    13. 1089     }  
    14. 1090           
    15. 1091     mutex_lock(&ctrl->v4l2_lock);  
    16. 1092       
    17. 1093     b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y]  
    18. 1094             + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB]  
    19. 1095             + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR];  
    20. 1096   
    21. 1097     b->m.offset = b->index * PAGE_SIZE;  
    22. 1098   
    23. 1099     ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE;  
    24. 1100   
    25. 1101     mutex_unlock(&ctrl->v4l2_lock);  
    26. 1102   
    27. 1103     fimc_dbg("%s: %d bytes at index: %d ", __func__, b->length, b->index);  
    28. 1104   
    29. 1105     return 0;  
    30. 1106 }  


    1093 ~ 1095 buffer的length由三个分量buffer总长度决定
    1097 这个需要结合fimc_mmap_cap来看,b->m.offset可以用来表示buffer的索引值

    [cpp] view plaincopy
     
    1. 1255 int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a)  
    2. 1256 {  
    3. 1257     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    4. 1258     struct fimc_capinfo *cap = ctrl->cap;  
    5. 1259   
    6. 1260     fimc_dbg("%s ", __func__);  
    7. 1261   
    8. 1262     if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {  
    9. 1263         fimc_err("%s: No capture device. ", __func__);  
    10. 1264         return -ENODEV;  
    11. 1265     }  
    12. 1266   
    13. 1267     mutex_lock(&ctrl->v4l2_lock);  
    14. 1268   
    15. 1269     /* crop limitations */  
    16. 1270     cap->cropcap.bounds.left = 0;  
    17. 1271     cap->cropcap.bounds.top = 0;  
    18. 1272     cap->cropcap.bounds.width = ctrl->cam->width;  
    19. 1273     cap->cropcap.bounds.height = ctrl->cam->height;  
    20. 1274   
    21. 1275     /* crop default values */  
    22. 1276     cap->cropcap.defrect.left = 0;  
    23. 1277     cap->cropcap.defrect.top = 0;  
    24. 1278     cap->cropcap.defrect.width = ctrl->cam->width;  
    25. 1279     cap->cropcap.defrect.height = ctrl->cam->height;  
    26. 1280   
    27. 1281     a->bounds = cap->cropcap.bounds;  
    28. 1282     a->defrect = cap->cropcap.defrect;  
    29. 1283   
    30. 1284     mutex_unlock(&ctrl->v4l2_lock);  
    31. 1285   
    32. 1286     return 0;  
    33. 1287 }  

    fimc_cropcap_capture:fimc的VIDIOC_CROPCAP的实现

    cropcap.bounds 是capture window 最大边界,capture.defrect是capture window的默认方框

    cropcap.defrect一定不会超出cropcap.bounds的范围,他们的关系如下图

    cropcap.pixelaspect =垂直像素数 / 水平像素数

    [cpp] view plaincopy
     
    1. 1289 int fimc_g_crop_capture(void *fh, struct v4l2_crop *a)  
    2. 1290 {  
    3. 1291     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    4. 1292   
    5. 1293     fimc_dbg("%s ", __func__);  
    6. 1294   
    7. 1295     if (!ctrl->cap) {  
    8. 1296         fimc_err("%s: No capture device. ", __func__);  
    9. 1297         return -ENODEV;  
    10. 1298     }  
    11. 1299   
    12. 1300     mutex_lock(&ctrl->v4l2_lock);  
    13. 1301     a->c = ctrl->cap->crop;  
    14. 1302     mutex_unlock(&ctrl->v4l2_lock);  
    15. 1303   
    16. 1304     return 0;  
    17. 1305 }  
    18. 1306   


    fimc_g_crop_capture 是capture设备的VIDIOC_G_CROP实现,返回当前的crop

    [cpp] view plaincopy
     
      1. <pre name="code" class="cpp">1307 static int fimc_capture_crop_size_check(struct fimc_control *ctrl)  
      2. 1308 {  
      3. 1309     struct fimc_capinfo *cap = ctrl->cap;  
      4. 1310     int win_hor_offset = 0, win_hor_offset2 = 0;  
      5. 1311     int win_ver_offset = 0, win_ver_offset2 = 0;  
      6. 1312     int crop_width = 0, crop_height = 0;  
      7. 1313   
      8. 1314     /* check win_hor_offset, win_hor_offset2 */  
      9. 1315     win_hor_offset = ctrl->cam->window.left;  
      10. 1316     win_hor_offset2 = ctrl->cam->width - ctrl->cam->window.left -  
      11. 1317                         ctrl->cam->window.width;  
      12. 1318   
      13. 1319     win_ver_offset = ctrl->cam->window.top;  
      14. 1320     win_ver_offset2 = ctrl->cam->height - ctrl->cam->window.top -  
      15. 1321                         ctrl->cam->window.height;  
      16. 1322   
      17. 1323     if (win_hor_offset < 0 || win_hor_offset2 < 0) {  
      18. 1324         fimc_err("%s: Offset (left-side(%d) or right-side(%d) "  
      19. 1325                 "is negative. ", __func__,   
      20. 1326                 win_hor_offset, win_hor_offset2);  
      21. 1327         return -1;  
      22. 1328     }  
      23. 1329   
      24. 1330     if (win_ver_offset < 0 || win_ver_offset2 < 0) {  
      25. 1331         fimc_err("%s: Offset (top-side(%d) or bottom-side(%d)) "  
      26. 1332                 "is negative. ", __func__,   
      27. 1333                 win_ver_offset, win_ver_offset2);  
      28. 1334         return -1;  
      29. 1335     }  
      30. 1336   
      31. 1337     if ((win_hor_offset % 2) || (win_hor_offset2 % 2)) {  
      32. 1338         fimc_err("%s: win_hor_offset must be multiple of 2 ",   
      33. 1339                 __func__);  
      34. 1340         return -1;  
      35. 1341     }  
      36. 1342   
      37. 1343     /* check crop_width, crop_height */  
      38. 1344     crop_width = ctrl->cam->window.width;  
      39. 1345     crop_height = ctrl->cam->window.height;  
      40. 1346   
      41. 1347     if (crop_width % 16) {  
      42. 1348         fimc_err("%s: crop_width must be multiple of 16 ", __func__);  
      43. 1349         return -1;  
      44. 1350     }  
      45. 1351   
      46. 1352     switch (cap->fmt.pixelformat) {  
      47. 1353     case V4L2_PIX_FMT_YUV420:       /* fall through */  
      48. 1354     case V4L2_PIX_FMT_NV12:         /* fall through */  
      49. 1355     case V4L2_PIX_FMT_NV21:         /* fall through */  
      50. 1356     case V4L2_PIX_FMT_NV12T:         /* fall through */  
      51. 1357         if ((crop_height % 2) || (crop_height < 8)) {  
      52. 1358             fimc_err("%s: crop_height error! ", __func__);  
      53. 1359             return -1;  
      54. 1360         }  
      55. 1361         break;  
      56. 1362     default:  
      57. 1363         break;  
      58. 1364     }  
      59. 1365   
      60. 1366     return 0;  
      61. 1367 }  
      62. </pre><p></p>  
      63. <pre></pre>  
      64. <br>  
      65. cam->cam->window是crop设置后的取景框,这个函数就是检测这个取景框是否符合规范  
      66. <p></p>  
      67. <p><br>  
      68. </p>  
      69. <p></p><pre name="code" class="cpp">1377 static void fimc_capture_update_crop_window(struct fimc_control *ctrl)  
      70. 1378 {  
      71. 1379     unsigned int zoom_hor = 0;  
      72. 1380     unsigned int zoom_ver = 0;  
      73. 1381     unsigned int multiplier = 1024;  
      74. 1382   
      75. 1383     if (!ctrl->cam->width || !ctrl->cam->height)  
      76. 1384         return;  
      77. 1385   
      78. 1386     zoom_hor = ctrl->cap->fmt.width * multiplier / ctrl->cam->width;  
      79. 1387     zoom_ver = ctrl->cap->fmt.height * multiplier / ctrl->cam->height;  
      80. 1388   
      81. 1389     if (!zoom_hor || !zoom_ver)  
      82. 1390         return;  
      83. 1391   
      84. 1392     /* Width */  
      85. 1393     ctrl->cam->window.width = ctrl->cap->crop.width * multiplier / zoom_hor;  
      86. 1394     if (ctrl->cam->window.width > ctrl->cam->width)  
      87. 1395         ctrl->cam->window.width = ctrl->cam->width;  
      88. 1396     if (ctrl->cam->window.width % 16)  
      89. 1397         ctrl->cam->window.width =  
      90. 1398             (ctrl->cam->window.width + 0xF) & ~0xF;  
      91. 1399   
      92. 1400     /* Left offset */  
      93. 1401     ctrl->cam->window.left = ctrl->cap->crop.left * multiplier / zoom_hor;  
      94. 1402     if (ctrl->cam->window.width + ctrl->cam->window.left > ctrl->cam->width)  
      95. 1403         ctrl->cam->window.left =  
      96. 1404             (ctrl->cam->width - ctrl->cam->window.width)/2;  
      97. 1405     if (ctrl->cam->window.left % 2)  
      98. 1406         ctrl->cam->window.left--;  
      99. 1407   
      100. 1408     /* Height */  
      101. 1409     ctrl->cam->window.height =  
      102. 1410         (ctrl->cap->crop.height * multiplier) / zoom_ver;  
      103. 1411     if (ctrl->cam->window.top > ctrl->cam->height)  
      104. 1412         ctrl->cam->window.height = ctrl->cam->height;  
      105. 1413     if (ctrl->cam->window.height % 2)  
      106. 1414         ctrl->cam->window.height--;  
      107. 1415   
      108. 1416     /* Top offset */  
      109. 1417     ctrl->cam->window.top = ctrl->cap->crop.top * multiplier / zoom_ver;  
      110. 1418     if (ctrl->cam->window.height + ctrl->cam->window.top >  
      111. 1419             ctrl->cam->height)  
      112. 1420         ctrl->cam->window.top =  
      113. 1421             (ctrl->cam->height - ctrl->cam->window.height)/2;  
      114. 1422     if (ctrl->cam->window.top % 2)  
      115. 1423         ctrl->cam->window.top--;  
      116. 1424   
      117. 1425     fimc_dbg("Cam (%dx%d) Crop: (%d %d %d %d) Win: (%d %d %d %d) ",   
      118. 1426             ctrl->cam->width, ctrl->cam->height,   
      119. 1427             ctrl->cap->crop.left, ctrl->cap->crop.top,   
      120. 1428             ctrl->cap->crop.width, ctrl->cap->crop.height,   
      121. 1429             ctrl->cam->window.left, ctrl->cam->window.top,   
      122. 1430             ctrl->cam->window.width, ctrl->cam->window.height);  
      123. 1431   
      124. 1432 }  
      125. </pre><br>  
      126. 根据s_crop设置的curr_crop设置capture 的取景框<br>  
      127. <p></p>  
      128. <p><br>  
      129. </p>  
      130. <p></p><pre name="code" class="cpp">1434 int fimc_s_crop_capture(void *fh, struct v4l2_crop *a)  
      131. 1435 {  
      132. 1436     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
      133. 1437     int ret = 0;  
      134. 1438   
      135. 1439     fimc_dbg("%s ", __func__);  
      136. 1440   
      137. 1441     if (!ctrl->cap) {  
      138. 1442         fimc_err("%s: No capture device. ", __func__);  
      139. 1443         return -ENODEV;  
      140. 1444     }  
      141. 1445   
      142. 1446     mutex_lock(&ctrl->v4l2_lock);  
      143. 1447     ctrl->cap->crop = a->c;  
      144. 1448   
      145. 1449     fimc_capture_update_crop_window(ctrl);  
      146. 1450   
      147. 1451     ret = fimc_capture_crop_size_check(ctrl);  
      148. 1452     if (ret < 0) {  
      149. 1453         mutex_unlock(&ctrl->v4l2_lock);  
      150. 1454         fimc_err("%s: Invalid crop parameters. ", __func__);  
      151. 1455         return -EINVAL;  
      152. 1456     }  
      153. 1457   
      154. 1458     if (ctrl->status == FIMC_STREAMON &&  
      155. 1459             ctrl->cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) {  
      156. 1460         fimc_hwset_shadow_disable(ctrl);  
      157. 1461         fimc_hwset_camera_offset(ctrl);  
      158. 1462         fimc_capture_scaler_info(ctrl);  
      159. 1463         fimc_hwset_prescaler(ctrl, &ctrl->sc);  
      160. 1464         fimc_hwset_scaler(ctrl, &ctrl->sc);  
      161. 1465         fimc_hwset_shadow_enable(ctrl);  
      162. 1466     }  
      163. 1467   
      164. 1468     mutex_unlock(&ctrl->v4l2_lock);  
      165. 1469   
      166. 1470     return 0;  
      167. 1471 }  
      168. </pre>fimc_s_crop_capture是capture设备的VIDIOC_S_CROP ioctl实现<p></p>  
      169. <p>1449 用@a更新capture window</p>  
      170. <p>1451 检测新生成的capture window参数合法性</p>  
      171. <p>1458 ~ 1466 FIMC支持streamon正在进行时,修改capture取景框<br>  
      172. </p>  
      173. <p><br>  
      174. </p>  
      175. <p><br>  
      176. </p>  
      177. <p><br>  
      178. <br>  
      179. </p>  
  • 相关阅读:
    Asp.net 后台添加CSS、JS、Meta标签(帮助类)
    Jquery 事件冒泡
    一个例子理解C#位移
    CodeSmith 创建Ado.Net自定义模版(四)
    .NET4.0下网站应用程序用UrlRewriter.dll重写无后缀路径 (在IIS7.5中的配置方法)
    用泛型的IEqualityComparer<T>接口去重复项
    Why MapReduce?
    SYN flood攻击介绍
    tmux使用方法详解
    理解Linux系统负荷
  • 原文地址:https://www.cnblogs.com/cainiaoaixuexi/p/3357279.html
Copyright © 2011-2022 走看看