您的位置:首页 > 移动开发 > Android开发

S5PV210 Android fimc驱动分析 - fimc_capture.c

2012-08-29 21:46 447 查看
fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片



43 static const struct v4l2_fmtdesc capture_fmts[] = {
  44     {
  45         .index      = 0,
  46         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  47         .flags      = FORMAT_FLAGS_PACKED,
  48         .description    = "RGB-5-6-5",
  49         .pixelformat    = V4L2_PIX_FMT_RGB565,
  50     }, {
  51         .index      = 1,
  52         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  53         .flags      = FORMAT_FLAGS_PACKED,
  54         .description    = "RGB-8-8-8, unpacked 24 bpp",
  55         .pixelformat    = V4L2_PIX_FMT_RGB32,
  56     }, {
  57         .index      = 2,
  58         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  59         .flags      = FORMAT_FLAGS_PACKED,
  60         .description    = "YUV 4:2:2 packed, YCbYCr",
  61         .pixelformat    = V4L2_PIX_FMT_YUYV,
  62     }, {
  63         .index      = 3,
  64         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  65         .flags      = FORMAT_FLAGS_PACKED,
  66         .description    = "YUV 4:2:2 packed, CbYCrY",
  67         .pixelformat    = V4L2_PIX_FMT_UYVY,
  68     }, {
  69         .index      = 4,
  70         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  71         .flags      = FORMAT_FLAGS_PACKED,
  72         .description    = "YUV 4:2:2 packed, CrYCbY",
  73         .pixelformat    = V4L2_PIX_FMT_VYUY,
  74     }, {
  75         .index      = 5,
  76         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  77         .flags      = FORMAT_FLAGS_PACKED,
  78         .description    = "YUV 4:2:2 packed, YCrYCb",
  79         .pixelformat    = V4L2_PIX_FMT_YVYU,
  80     }, {
  81         .index      = 6,
  82         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  83         .flags      = FORMAT_FLAGS_PLANAR,
  84         .description    = "YUV 4:2:2 planar, Y/Cb/Cr",
  85         .pixelformat    = V4L2_PIX_FMT_YUV422P,
  86     }, {
  87         .index      = 7,
  88         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  89         .flags      = FORMAT_FLAGS_PLANAR,
  90         .description    = "YUV 4:2:0 planar, Y/CbCr",
  91         .pixelformat    = V4L2_PIX_FMT_NV12,
  92     }, {
  93         .index      = 8,
  94         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  95         .flags      = FORMAT_FLAGS_PLANAR,
  96         .description    = "YUV 4:2:0 planar, Y/CbCr, Tiled",
  97         .pixelformat    = V4L2_PIX_FMT_NV12T,
  98     }, {
  99         .index      = 9,
 100         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 101         .flags      = FORMAT_FLAGS_PLANAR,
 102         .description    = "YUV 4:2:0 planar, Y/CrCb",
 103         .pixelformat    = V4L2_PIX_FMT_NV21,
 104     }, {
 105         .index      = 10,
 106         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 107         .flags      = FORMAT_FLAGS_PLANAR,
 108         .description    = "YUV 4:2:2 planar, Y/CbCr",
 109         .pixelformat    = V4L2_PIX_FMT_NV16,
 110     }, {
 111         .index      = 11,
 112         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 113         .flags      = FORMAT_FLAGS_PLANAR,
 114         .description    = "YUV 4:2:2 planar, Y/CrCb",
 115         .pixelformat    = V4L2_PIX_FMT_NV61,
 116     }, {
 117         .index      = 12,
 118         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 119         .flags      = FORMAT_FLAGS_PLANAR,
 120         .description    = "YUV 4:2:0 planar, Y/Cb/Cr",
 121         .pixelformat    = V4L2_PIX_FMT_YUV420,
 122     }, {
 123         .index      = 13,
 124         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 125         .flags      = FORMAT_FLAGS_ENCODED,
 126         .description    = "Encoded JPEG bitstream",
 127         .pixelformat    = V4L2_PIX_FMT_JPEG,
 128     },
 129 };

这个列表列出了FIMC支持的capture格式,app可以通过vidioc_s_fmt设置capture的输出格式,capture的输出格式必须在上面的列表中

这里的flags标志位并不符合V4L2标准,V4L2只支持一种标志:V4L2_FMT_FLAG_COMPRESSED。

samsung扩展了flags标志:

FORMAT_FLAGS_PACKED: 图片的像素点分量放在一同一个buffer中

FORMAT_FLAGS_PLANAR:图片像素的分量放在不同的buffer中

FORMAT_FLAGS_ENCODED:图片数据编码存储,如jpeg格式

131 static const struct v4l2_queryctrl fimc_controls[] = {
 132     {
 133         .id = V4L2_CID_ROTATION,
 134         .type = V4L2_CTRL_TYPE_BOOLEAN,
 135         .name = "Roataion",
 136         .minimum = 0,
 137         .maximum = 270,
 138         .step = 90,
 139         .default_value = 0,
 140     }, {
 141         .id = V4L2_CID_HFLIP,
 142         .type = V4L2_CTRL_TYPE_BOOLEAN,
 143         .name = "Horizontal Flip",
 144         .minimum = 0,
 145         .maximum = 1,
 146         .step = 1,
 147         .default_value = 0,
 148     }, {
 149         .id = V4L2_CID_VFLIP,
 150         .type = V4L2_CTRL_TYPE_BOOLEAN,
 151         .name = "Vertical Flip",
 152         .minimum = 0,
 153         .maximum = 1,
 154         .step = 1,
 155         .default_value = 0,
 156     }, {
 157         .id = V4L2_CID_PADDR_Y,
 158         .type = V4L2_CTRL_TYPE_BOOLEAN,
 159         .name = "Physical address Y",
 160         .minimum = 0,
 161         .maximum = 1,
 162         .step = 1,
 163         .default_value = 0,
 164         .flags = V4L2_CTRL_FLAG_READ_ONLY,
 165     }, {
 166         .id = V4L2_CID_PADDR_CB,
 167         .type = V4L2_CTRL_TYPE_BOOLEAN,
 168         .name = "Physical address Cb",
 169         .minimum = 0,
 170         .maximum = 1,
 171         .step = 1,
 172         .default_value = 0,
 173         .flags = V4L2_CTRL_FLAG_READ_ONLY,
 174     }, {
 175         .id = V4L2_CID_PADDR_CR,
 176         .type = V4L2_CTRL_TYPE_BOOLEAN,
 177         .name = "Physical address Cr",
 178         .minimum = 0,
 179         .maximum = 1,
 180         .step = 1,
 181         .default_value = 0,
 182         .flags = V4L2_CTRL_FLAG_READ_ONLY,
 183     }, {
 184         .id = V4L2_CID_PADDR_CBCR,
 185         .type = V4L2_CTRL_TYPE_BOOLEAN,
 186         .name = "Physical address CbCr",
 187         .minimum = 0,
 188         .maximum = 1,
 189         .step = 1,
 190         .default_value = 0,
 191         .flags = V4L2_CTRL_FLAG_READ_ONLY,
 192     },
 193 };

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

201 static int fimc_camera_init(struct fimc_control *ctrl)
 202 {
 203     int ret;
 204 
 205     fimc_dbg("%s\n", __func__);
 206 
 207     /* do nothing if already initialized */
 208     if (ctrl->cam->initialized)
 209         return 0;
 210 
 211     /* enable camera power if needed */
 212     if (ctrl->cam->cam_power)
 213         ctrl->cam->cam_power(1);
 214 
 215     /* subdev call for init */
 216     ret = subdev_call(ctrl, core, init, 0);
 217     if (ret == -ENOIOCTLCMD) {
 218         fimc_err("%s: init subdev api not supported\n",
 219             __func__);
 220         return ret;
 221     }
 222 
 223     if (ctrl->cam->type == CAM_TYPE_MIPI) {
 224         /* subdev call for sleep/wakeup:
 225          * no error although no s_stream api support
 226          */
 227         u32 pixelformat;
 228         if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)
 229             pixelformat = V4L2_PIX_FMT_JPEG;
 230         else
 231             pixelformat = ctrl->cam->pixelformat;
 232 
 233         subdev_call(ctrl, video, s_stream, 0);
 234         s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle, \
 235                 ctrl->cam->mipi_align, ctrl->cam->width, \
 236                 ctrl->cam->height, pixelformat);
 237         subdev_call(ctrl, video, s_stream, 1);
 238     }
 239 
 240     ctrl->cam->initialized = 1;
 241 
 242     return 0;
 243 }

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

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

368 static int fimc_add_inqueue(struct fimc_control *ctrl, int i)
 369 {
 370     struct fimc_capinfo *cap = ctrl->cap;
 371
 372     struct fimc_buf_set *buf;
 373
 374     if (i >= cap->nr_bufs)
 375         return -EINVAL;
 376
 377     list_for_each_entry(buf, &cap->inq, list) {
 378         if (buf->id == i) {
 379             fimc_dbg("%s: buffer %d already in inqueue.\n", \
 380                     __func__, i);
 381             return -EINVAL;
 382         }
 383     }
 384
 385     list_add_tail(&cap->bufs[i].list, &cap->inq);
 386
 387     return 0;
 388 }


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

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

390 static int fimc_add_outqueue(struct fimc_control *ctrl, int i)
 391 {
 392     struct fimc_capinfo *cap = ctrl->cap;
 393     struct fimc_buf_set *buf;
 394
 395     unsigned int mask = 0x2;
 396
 397     /* PINGPONG_2ADDR_MODE Only */
 398     /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */
 399
 400     int pair_buf_index = (i^mask);
 401
 402     /* FIMC have 4 h/w registers */
 403     if (i < 0 || i >= FIMC_PHYBUFS) {
 404         fimc_err("%s: invalid queue index : %d\n", __func__, i);
 405         return -ENOENT;
 406     }
 407
 408     if (list_empty(&cap->inq))
 409         return -ENOENT;
 410
 411     buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);
 412
 413     /* pair index buffer should be allocated first */
 414     cap->outq[pair_buf_index] = buf->id;
 415     fimc_hwset_output_address(ctrl, buf, pair_buf_index);
 416
 417     cap->outq[i] = buf->id;
 418     fimc_hwset_output_address(ctrl, buf, i);
 419
 420     if (cap->nr_bufs != 1)
 421         list_del(&buf->list);
 422
 423     return 0;
 424 }


411 在cap->inq buffer链表中取得第一个可用buffer

413 ~ 418 一直没明白为什么这里把buf设置到两个输出out DMA address寄存器中,华清远见有篇文档http://www.embedu.org/Column/Column457.htm对这个代码的解释是说最多可以把四个out DMA address都配置上,可以增加画面的流畅度。

我原来也是同意华清讲师的说法的,四个output DMA address把帧数分成四个部分,第一个DMA address存储 1, 5, 9, 13... 帧, 第二个DMA address存储2, 6, 10, 14...帧, 第三个存储3, 7, 11, 15...帧, 第四个存储4, 8, 12, 16...帧,如果仅使用一个output DMA address,那么仅能得到1/4的帧率。

但是测试后发现,删除414~415后重新编译的内核没发现有帧率的变化,对帧率没有任何影响。

420 ~ 421 从cap->inq 链表中删除这个buf

516 int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
 517 {
 518     struct fimc_global *fimc = get_fimc_dev();
 519     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
 520
 521     fimc_dbg("%s: index %d\n", __func__, inp->index);
 522
 523     if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {
 524         fimc_err("%s: invalid input index, received = %d\n", \
 525                 __func__, inp->index);
 526         return -EINVAL;
 527     }
 528
 529     if (!fimc->camera_isvalid[inp->index])
 530         return -EINVAL;
 531
 532     strcpy(inp->name, fimc->camera[inp->index].info->type);
 533     inp->type = V4L2_INPUT_TYPE_CAMERA;
 534
 535     return 0;
 536 }

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

538 int fimc_g_input(struct file *file, void *fh, unsigned int *i)
 539 {
 540     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
 541     struct fimc_global *fimc = get_fimc_dev();
 542 
 543     /* In case of isueing g_input before s_input */
 544     if (!ctrl->cam) {
 545         fimc_err("no camera device selected yet!" \
 546                 "do VIDIOC_S_INPUT first\n");
 547         return -ENODEV;
 548     }
 549 
 550     *i = (unsigned int) fimc->active_camera;
 551 
 552     fimc_dbg("%s: index %d\n", __func__, *i);
 553 
 554     return 0;
 555 }

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

637 int fimc_s_input(struct file *file, void *fh, unsigned int i)
 638 {
 639     struct fimc_global *fimc = get_fimc_dev();
 640     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
 641     int ret = 0;
 642 
 643     fimc_dbg("%s: index %d\n", __func__, i);
 644 
 645     if (i < 0 || i >= FIMC_MAXCAMS) {
 646         fimc_err("%s: invalid input index\n", __func__);
 647         return -EINVAL;
 648     }
 649 
 650     if (!fimc->camera_isvalid[i])
 651         return -EINVAL;
 652 
 653     if (fimc->camera[i].sd && ctrl->id != 2) {
 654         fimc_err("%s: Camera already in use.\n", __func__);
 655         return -EBUSY;
 656     }
 657 
 658     mutex_lock(&ctrl->v4l2_lock);
 659     /* If ctrl->cam is not NULL, there is one subdev already registered.
 660      * We need to unregister that subdev first.
 661      */
 662     if (i != fimc->active_camera) {
 663         fimc_release_subdev(ctrl);
 664         ctrl->cam = &fimc->camera[i];
 665         ret = fimc_configure_subdev(ctrl);
 666         if (ret < 0) {
 667             mutex_unlock(&ctrl->v4l2_lock);
 668             fimc_err("%s: Could not register camera sensor "
 669                     "with V4L2.\n", __func__);
 670             return -ENODEV;
 671         }
 672         fimc->active_camera = i;
 673     }
 674 
 675     if (ctrl->id == 2) {
 676         if (i == fimc->active_camera) {
 677             ctrl->cam = &fimc->camera[i];
 678         } else {
 679             mutex_unlock(&ctrl->v4l2_lock);
 680             return -EINVAL;
 681         }
 682     }
 683 
 684     mutex_unlock(&ctrl->v4l2_lock);
 685 
 686     return 0;
 687 }

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

897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)
 898 {
 899     struct fimc_capinfo *cap = ctrl->cap;
 900     int i, plane;
 901
 902     for (i = 0; i < cap->nr_bufs; i++) {
 903         for (plane = 0; plane < 4; plane++) {
 904             cap->bufs[i].length[plane] = size[plane];
 905             if (!cap->bufs[i].length[plane])
 906                 continue;
 907
 908             fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);
 909
 910             if (!cap->bufs[i].base[plane])
 911                 goto err_alloc;
 912         }
 913
 914         cap->bufs[i].state = VIDEOBUF_PREPARED;
 915         cap->bufs[i].id = i;
 916     }
 917
 918     return 0;
 919
 920 err_alloc:
 921     for (i = 0; i < cap->nr_bufs; i++) {
 922         if (cap->bufs[i].base[plane])
 923             fimc_dma_free(ctrl, &cap->bufs[i], plane);
 924
 925         memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));
 926     }
 927
 928     return -ENOMEM;
 929 }

分配queue buffer

@align:queue buffer是DMA buffer,所以会有alignment要求

@size:不同的format,每帧需要的子buffers数目不同,这个函数的plane就代表需要的子buffers数目,size[]是一个数组,表示queue buffers的每个子buffer需求的尺寸

902 cap->nr_bufs,是capture总的queue buffers数量。

950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)
 951 {
 952     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
 953     struct fimc_capinfo *cap = ctrl->cap;
 954     int ret = 0, i;
 955     int size[4] = { 0, 0, 0, 0};
 956     int align = SZ_4K;
 957 
 958     if (b->memory != V4L2_MEMORY_MMAP) {
 959         fimc_err("%s: invalid memory type\n", __func__);
 960         return -EINVAL;
 961     }
 962 
 963     if (!cap) {
 964         fimc_err("%s: no capture device info\n", __func__);
 965         return -ENODEV;
 966     }
 967 
 968     if (!ctrl->cam || !ctrl->cam->sd) {
 969         fimc_err("%s: No capture device.\n", __func__);
 970         return -ENODEV;
 971     }
 972 
 973     mutex_lock(&ctrl->v4l2_lock);
 974 
 975     if (b->count < 1 || b->count > FIMC_CAPBUFS)
 976         return -EINVAL;
 977 
 978     /* It causes flickering as buf_0 and buf_3 refer to same hardware
 979      * address.
 980      */
 981     if (b->count == 3)
 982         b->count = 4;
 983 
 984     cap->nr_bufs = b->count;
 985 
 986     fimc_dbg("%s: requested %d buffers\n", __func__, b->count);
 987 
 988     INIT_LIST_HEAD(&cap->inq);
 989 
 990     fimc_free_buffers(ctrl);
 991 
 992     switch (cap->fmt.pixelformat) {
 993     case V4L2_PIX_FMT_RGB32:    /* fall through */
 994     case V4L2_PIX_FMT_RGB565:   /* fall through */
 995     case V4L2_PIX_FMT_YUYV:     /* fall through */
 996     case V4L2_PIX_FMT_UYVY:     /* fall through */
 997     case V4L2_PIX_FMT_VYUY:     /* fall through */
 998     case V4L2_PIX_FMT_YVYU:     /* fall through */
 999     case V4L2_PIX_FMT_YUV422P:  /* fall through */
1000         size[0] = cap->fmt.sizeimage;
1001         break;
1002 
1003     case V4L2_PIX_FMT_NV16:     /* fall through */
1004     case V4L2_PIX_FMT_NV61:
1005         size[0] = cap->fmt.width * cap->fmt.height;
1006         size[1] = cap->fmt.width * cap->fmt.height;
1007         size[3] = 16; /* Padding buffer */
1008         break;
1009     case V4L2_PIX_FMT_NV12:
1010         size[0] = cap->fmt.width * cap->fmt.height;
1011         size[1] = cap->fmt.width * cap->fmt.height/2;
1012         break;
1013     case V4L2_PIX_FMT_NV21:
1014         size[0] = cap->fmt.width * cap->fmt.height;
1015         size[1] = cap->fmt.width * cap->fmt.height/2;
1016         size[3] = 16; /* Padding buffer */
1017         break;
1018     case V4L2_PIX_FMT_NV12T:
1019         /* Tiled frame size calculations as per 4x2 tiles
1020          *  - Width: Has to be aligned to 2 times the tile width
1021          *  - Height: Has to be aligned to the tile height
1022          *  - Alignment: Has to be aligned to the size of the
1023          *  macrotile (size of 4 tiles)
1024          *
1025          * NOTE: In case of rotation, we need modified calculation as
1026          * width and height are aligned to different values.
1027          */
1028         if (cap->rotate == 90 || cap->rotate == 270) {
1029             size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *
1030                     ALIGN(cap->fmt.width, 32),
1031                     SZ_8K);
1032             size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *
1033                     ALIGN(cap->fmt.width/2, 32),
1034                     SZ_8K);
1035         } else {
1036             size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *
1037                     ALIGN(cap->fmt.height, 32),
1038                     SZ_8K);
1039             size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *
1040                     ALIGN(cap->fmt.height/2, 32),
1041                     SZ_8K);
1042         }
1043         align = SZ_8K;
1044         break;
1045 
1046     case V4L2_PIX_FMT_YUV420:
1047         size[0] = cap->fmt.width * cap->fmt.height;
1048         size[1] = cap->fmt.width * cap->fmt.height >> 2;
1049         size[2] = cap->fmt.width * cap->fmt.height >> 2;
1050         size[3] = 16; /* Padding buffer */
1051         break;
1052 
1053     case V4L2_PIX_FMT_JPEG:
1054         size[0] = fimc_camera_get_jpeg_memsize(ctrl);
1055     default:
1056         break;
1057     }
1058 
1059     ret = fimc_alloc_buffers(ctrl, size, align);
1060     if (ret) {
1061         fimc_err("%s: no memory for "
1062                 "capture buffer\n", __func__);
1063         mutex_unlock(&ctrl->v4l2_lock);
1064         return -ENOMEM;
1065     }
1066 
1067     for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) {
1068         memcpy(&cap->bufs[i], \
1069             &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i]));
1070     }
1071 
1072     mutex_unlock(&ctrl->v4l2_lock);
1073 
1074     return 0;
1075 }

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

992 ~ 1057 根据pixelformat和width/height计算每个帧子buffers的尺寸。

1077 int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b)
1078 {   
1079     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1080     
1081     if (!ctrl->cap || !ctrl->cap->bufs) {
1082         fimc_err("%s: no capture device info\n", __func__);
1083         return -ENODEV; 
1084     }
1085     
1086     if (ctrl->status != FIMC_STREAMOFF) {
1087         fimc_err("fimc is running\n");
1088         return -EBUSY;      
1089     }
1090         
1091     mutex_lock(&ctrl->v4l2_lock);
1092     
1093     b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y]
1094             + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB]
1095             + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR];
1096 
1097     b->m.offset = b->index * PAGE_SIZE;
1098 
1099     ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE;
1100 
1101     mutex_unlock(&ctrl->v4l2_lock);
1102 
1103     fimc_dbg("%s: %d bytes at index: %d\n", __func__, b->length, b->index);
1104 
1105     return 0;
1106 }

1093 ~ 1095 buffer的length由三个分量buffer总长度决定

1097 这个需要结合fimc_mmap_cap来看,b->m.offset可以用来表示buffer的索引值

1255 int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a)
1256 {
1257     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1258     struct fimc_capinfo *cap = ctrl->cap;
1259 
1260     fimc_dbg("%s\n", __func__);
1261 
1262     if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {
1263         fimc_err("%s: No capture device.\n", __func__);
1264         return -ENODEV;
1265     }
1266 
1267     mutex_lock(&ctrl->v4l2_lock);
1268 
1269     /* crop limitations */
1270     cap->cropcap.bounds.left = 0;
1271     cap->cropcap.bounds.top = 0;
1272     cap->cropcap.bounds.width = ctrl->cam->width;
1273     cap->cropcap.bounds.height = ctrl->cam->height;
1274 
1275     /* crop default values */
1276     cap->cropcap.defrect.left = 0;
1277     cap->cropcap.defrect.top = 0;
1278     cap->cropcap.defrect.width = ctrl->cam->width;
1279     cap->cropcap.defrect.height = ctrl->cam->height;
1280 
1281     a->bounds = cap->cropcap.bounds;
1282     a->defrect = cap->cropcap.defrect;
1283 
1284     mutex_unlock(&ctrl->v4l2_lock);
1285 
1286     return 0;
1287 }


fimc_cropcap_capture:fimc的VIDIOC_CROPCAP的实现

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

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



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

1289 int fimc_g_crop_capture(void *fh, struct v4l2_crop *a)
1290 {
1291     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1292 
1293     fimc_dbg("%s\n", __func__);
1294 
1295     if (!ctrl->cap) {
1296         fimc_err("%s: No capture device.\n", __func__);
1297         return -ENODEV;
1298     }
1299 
1300     mutex_lock(&ctrl->v4l2_lock);
1301     a->c = ctrl->cap->crop;
1302     mutex_unlock(&ctrl->v4l2_lock);
1303 
1304     return 0;
1305 }
1306


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

1307 static int fimc_capture_crop_size_check(struct fimc_control *ctrl)
1308 {
1309     struct fimc_capinfo *cap = ctrl->cap;
1310     int win_hor_offset = 0, win_hor_offset2 = 0;
1311     int win_ver_offset = 0, win_ver_offset2 = 0;
1312     int crop_width = 0, crop_height = 0;
1313 
1314     /* check win_hor_offset, win_hor_offset2 */
1315     win_hor_offset = ctrl->cam->window.left;
1316     win_hor_offset2 = ctrl->cam->width - ctrl->cam->window.left -
1317                         ctrl->cam->window.width;
1318 
1319     win_ver_offset = ctrl->cam->window.top;
1320     win_ver_offset2 = ctrl->cam->height - ctrl->cam->window.top -
1321                         ctrl->cam->window.height;
1322 
1323     if (win_hor_offset < 0 || win_hor_offset2 < 0) {
1324         fimc_err("%s: Offset (left-side(%d) or right-side(%d) "
1325                 "is negative.\n", __func__, \
1326                 win_hor_offset, win_hor_offset2);
1327         return -1;
1328     }
1329 
1330     if (win_ver_offset < 0 || win_ver_offset2 < 0) {
1331         fimc_err("%s: Offset (top-side(%d) or bottom-side(%d)) "
1332                 "is negative.\n", __func__, \
1333                 win_ver_offset, win_ver_offset2);
1334         return -1;
1335     }
1336 
1337     if ((win_hor_offset % 2) || (win_hor_offset2 % 2)) {
1338         fimc_err("%s: win_hor_offset must be multiple of 2\n", \
1339                 __func__);
1340         return -1;
1341     }
1342 
1343     /* check crop_width, crop_height */
1344     crop_width = ctrl->cam->window.width;
1345     crop_height = ctrl->cam->window.height;
1346 
1347     if (crop_width % 16) {
1348         fimc_err("%s: crop_width must be multiple of 16\n", __func__);
1349         return -1;
1350     }
1351 
1352     switch (cap->fmt.pixelformat) {
1353     case V4L2_PIX_FMT_YUV420:       /* fall through */
1354     case V4L2_PIX_FMT_NV12:         /* fall through */
1355     case V4L2_PIX_FMT_NV21:         /* fall through */
1356     case V4L2_PIX_FMT_NV12T:         /* fall through */
1357         if ((crop_height % 2) || (crop_height < 8)) {
1358             fimc_err("%s: crop_height error!\n", __func__);
1359             return -1;
1360         }
1361         break;
1362     default:
1363         break;
1364     }
1365 
1366     return 0;
1367 }
     cam->cam->window是crop设置后的取景框,这个函数就是检测这个取景框是否符合规范
1377 static void fimc_capture_update_crop_window(struct fimc_control *ctrl)
1378 {
1379     unsigned int zoom_hor = 0;
1380     unsigned int zoom_ver = 0;
1381     unsigned int multiplier = 1024;
1382 
1383     if (!ctrl->cam->width || !ctrl->cam->height)
1384         return;
1385 
1386     zoom_hor = ctrl->cap->fmt.width * multiplier / ctrl->cam->width;
1387     zoom_ver = ctrl->cap->fmt.height * multiplier / ctrl->cam->height;
1388 
1389     if (!zoom_hor || !zoom_ver)
1390         return;
1391 
1392     /* Width */
1393     ctrl->cam->window.width = ctrl->cap->crop.width * multiplier / zoom_hor;
1394     if (ctrl->cam->window.width > ctrl->cam->width)
1395         ctrl->cam->window.width = ctrl->cam->width;
1396     if (ctrl->cam->window.width % 16)
1397         ctrl->cam->window.width =
1398             (ctrl->cam->window.width + 0xF) & ~0xF;
1399 
1400     /* Left offset */
1401     ctrl->cam->window.left = ctrl->cap->crop.left * multiplier / zoom_hor;
1402     if (ctrl->cam->window.width + ctrl->cam->window.left > ctrl->cam->width)
1403         ctrl->cam->window.left =
1404             (ctrl->cam->width - ctrl->cam->window.width)/2;
1405     if (ctrl->cam->window.left % 2)
1406         ctrl->cam->window.left--;
1407 
1408     /* Height */
1409     ctrl->cam->window.height =
1410         (ctrl->cap->crop.height * multiplier) / zoom_ver;
1411     if (ctrl->cam->window.top > ctrl->cam->height)
1412         ctrl->cam->window.height = ctrl->cam->height;
1413     if (ctrl->cam->window.height % 2)
1414         ctrl->cam->window.height--;
1415 
1416     /* Top offset */
1417     ctrl->cam->window.top = ctrl->cap->crop.top * multiplier / zoom_ver;
1418     if (ctrl->cam->window.height + ctrl->cam->window.top >
1419             ctrl->cam->height)
1420         ctrl->cam->window.top =
1421             (ctrl->cam->height - ctrl->cam->window.height)/2;
1422     if (ctrl->cam->window.top % 2)
1423         ctrl->cam->window.top--;
1424 
1425     fimc_dbg("Cam (%dx%d) Crop: (%d %d %d %d) Win: (%d %d %d %d)\n", \
1426             ctrl->cam->width, ctrl->cam->height, \
1427             ctrl->cap->crop.left, ctrl->cap->crop.top, \
1428             ctrl->cap->crop.width, ctrl->cap->crop.height, \
1429             ctrl->cam->window.left, ctrl->cam->window.top, \
1430             ctrl->cam->window.width, ctrl->cam->window.height);
1431 
1432 }
根据s_crop设置的curr_crop设置capture 的取景框<br>
1434 int fimc_s_crop_capture(void *fh, struct v4l2_crop *a)
1435 {
1436     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
1437     int ret = 0;
1438 
1439     fimc_dbg("%s\n", __func__);
1440 
1441     if (!ctrl->cap) {
1442         fimc_err("%s: No capture device.\n", __func__);
1443         return -ENODEV;
1444     }
1445 
1446     mutex_lock(&ctrl->v4l2_lock);
1447     ctrl->cap->crop = a->c;
1448 
1449     fimc_capture_update_crop_window(ctrl);
1450 
1451     ret = fimc_capture_crop_size_check(ctrl);
1452     if (ret < 0) {
1453         mutex_unlock(&ctrl->v4l2_lock);
1454         fimc_err("%s: Invalid crop parameters.\n", __func__);
1455         return -EINVAL;
1456     }
1457 
1458     if (ctrl->status == FIMC_STREAMON &&
1459             ctrl->cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) {
1460         fimc_hwset_shadow_disable(ctrl);
1461         fimc_hwset_camera_offset(ctrl);
1462         fimc_capture_scaler_info(ctrl);
1463         fimc_hwset_prescaler(ctrl, &ctrl->sc);
1464         fimc_hwset_scaler(ctrl, &ctrl->sc);
1465         fimc_hwset_shadow_enable(ctrl);
1466     }
1467 
1468     mutex_unlock(&ctrl->v4l2_lock);
1469 
1470     return 0;
1471 }


fimc_s_crop_capture是capture设备的VIDIOC_S_CROP ioctl实现

1449 用@a更新capture window

1451 检测新生成的capture window参数合法性

1458 ~ 1466 FIMC支持streamon正在进行时,修改capture取景框

转载自:/article/2308830.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: