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

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

  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格式

  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, 用来获取分量的物理起始地址。

  1. 201 static int fimc_camera_init(struct fimc_control *ctrl)
  2. 202 {
  3. 203     int ret;
  4. 204
  5. 205     fimc_dbg("%s\n", __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\n",
  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寄存器的,因此这个上电位置是有问题的。

  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.\n", \
  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

  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\n", __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

  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\n", __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\n", \
  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驱动的通用性。

  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\n");
  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\n", __func__, *i);
  16. 553
  17. 554     return 0;
  18. 555 }

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

  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\n", __func__, i);
  8. 644
  9. 645     if (i < 0 || i >= FIMC_MAXCAMS) {
  10. 646         fimc_err("%s: invalid input index\n", __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.\n", __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.\n", __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的接口

  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数量。

  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\n", __func__);
  11. 960         return -EINVAL;
  12. 961     }
  13. 962
  14. 963     if (!cap) {
  15. 964         fimc_err("%s: no capture device info\n", __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.\n", __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\n", __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\n", __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的尺寸。

  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\n", __func__);
  7. 1083         return -ENODEV;
  8. 1084     }
  9. 1085
  10. 1086     if (ctrl->status != FIMC_STREAMOFF) {
  11. 1087         fimc_err("fimc is running\n");
  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\n", __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的索引值

  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\n", __func__);
  7. 1261
  8. 1262     if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {
  9. 1263         fimc_err("%s: No capture device.\n", __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 =垂直像素数 / 水平像素数

  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\n", __func__);
  6. 1294
  7. 1295     if (!ctrl->cap) {
  8. 1296         fimc_err("%s: No capture device.\n", __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

    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.\n", __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.\n", __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\n", \
    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\n", __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!\n", __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)\n", \
    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\n", __func__);
    136. 1440
    137. 1441     if (!ctrl->cap) {
    138. 1442         fimc_err("%s: No capture device.\n", __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.\n", __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>

Android S5PV210 fimc驱动分析 - fimc_capture.c的更多相关文章

  1. 高通 android平台LCD驱动分析

    目前手机芯片厂家提供的源码里包含整个LCD驱动框架,一般厂家会定义一个xxx_fb.c的源文件,注册一个平台设备和平台驱动,在驱动的probe函数中来调用register_framebuffer(), ...

  2. 【转】android电池(五):电池 充电IC(PM2301)驱动分析篇

    关键词:android 电池  电量计  PL2301任务初始化宏 power_supply 中断线程化 平台信息:内核:linux2.6/linux3.0系统:android/android4.0  ...

  3. 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇

    关键词:android 电池  电量计  MAX17040 任务初始化宏 power_supply 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台: ...

  4. android电池(四):电池 电量计(MAX17040)驱动分析篇【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/8969369 电池电量计,库仑计,用max17040这颗电量IC去计量电池电量,这种方法 ...

  5. s5k4ba摄像头驱动分析

    注释: 本驱动是基于S5PV310的,但是全天下的摄像头驱动都是采用V4L2,因此驱动框架流程基本差不多.其中fimc_init_camera()函数会回调.init函数,该函数主要就是通过IIC总线 ...

  6. ARM-Linux S5PV210 UART驱动(4)----串口驱动初始化过程

    对于S5PV210 UART驱动来说,主要关心的就是drivers/serial下的samsung.c和s5pv210.c连个文件. 由drivers/serial/Kconfig: config S ...

  7. [置顶] Android开发之serviceManager分析

    Android 开发之serviceManager分析 在Android系统中用到最多的通信机制就是Binder,Binder主要由Client.Server.ServiceManager和Binde ...

  8. 《Android系统源代码情景分析》连载回忆录:灵感之源

    上个月,在花了一年半时间之后,写了55篇文章,分析完成了Chromium在Android上的实现,以及Android基于Chromium实现的WebView.学到了很多东西,不过也挺累的,平均不到两个 ...

  9. Android Hal层简要分析

    Android Hal层简要分析 Android Hal层(即 Hardware Abstraction Layer)是Google开发的Android系统里上层应用对底层硬件操作屏蔽的一个软件层次, ...

随机推荐

  1. CentOS 笔记(三) 目录结构

    理解CentOS 目录结构 首次登录进入,应该是进入了,run文件夹 通过  cd  ../ 进入了,最根节点 通过 ls  显示全部文件夹 通过 pwd 查看当前目录 参考: https://www ...

  2. 汇编-理解call,ret

    ; 有意思的东西,主函数调用子函数用汇编来理解 assume cs:codeseg codeseg segment start: main: call sub1 ; 调用子函数1, push IP1 ...

  3. Tensorflow读取文件到队列文件

    TensorFlow读取二进制文件数据到队列 2016-11-03 09:30:00      0个评论    来源:diligent_321的博客   收藏   我要投稿 TensorFlow是一种 ...

  4. Appium遇到问题:

    问题一:问题org.openqa.selenium.remote.UnreachableBrowserException: Could not start a new session. Possibl ...

  5. Oracle中Cursor介绍和使用

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/MyDreamNeverstop/article/details/78604033 一  概念  游标 ...

  6. BA-siemens-insight-event builder使用

    event builder功能主要是用来给report使用的,作为一个独立的对象,这个对象的功能就是收集点位的信息,如果再使用report功能就可以显示或输出点位的信息.

  7. 洛谷—— P1803 凌乱的yyy

    https://www.luogu.org/problem/show?pid=1803 题目背景 快noip了,yyy很紧张! 题目描述 现在各大oj上有n个比赛,每个比赛的开始.结束的时间点是知道的 ...

  8. cogs 1143. [石门中学2009] 切割树

    1143. [石门中学2009] 切割树 ★   输入文件:treecut.in   输出文件:treecut.out   简单对比时间限制:1 s   内存限制:128 MB treecut 题目描 ...

  9. An internal error occurred during: &quot;Building workspace&quot;. java.lang.StackOverflowError

    1 错误描写叙述 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveW91MjNoYWk0NQ==/font/5a6L5L2T/fontsize/400/fi ...

  10. SVN文件恢复

    SVN删除文件 一.本地删除 SVN删除文件里的本地删除,指的是在clientdelete了一个文件,但还没有commit.使用revert来撤销删除. 二.server删除 1.通过本地删除后提交s ...