Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2149266
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: Android平台

2014-02-20 14:22:15

一. 上层与内核的交互
1. camera驱动的目录结构
cong@ubuntu:/tmp/media/video$ tree
├── generic_sensor.c
├── generic_sensor.h
├── ir-kbd-i2c.c
├── Kconfig
├── Makefile
├── rk30_camera.c                          //设备:platform_device_register RK29_CAM_DRV_NAME "rk3066b-camera"
├── rk30_camera_oneframe.c          //驱动: RK29_CAM_DRV_NAME "rk3066b-camera"
├── soc_camera.c
├── soc_mediabus.c
├── sp0a19.c
├── v4l2-common.c
├── v4l2-ctrls.c
├── v4l2-dev.c
├── v4l2-device.c
├── v4l2-event.c
├── v4l2-fh.c
├── v4l2-int-device.c
├── v4l2-ioctl.c
├── v4l2-subdev.c
├── videobuf2-core.c
├── videobuf-core.c
└── videobuf-dma-contig.c
2. 用户空间的调用过程以VIDIOC_REQBUFS为例
在hardware/rk29/camera/CameraHal.cpp中
CameraHal.cpp:    if (ioctl(iCamFd, VIDIOC_REQBUFS, &creqbuf) < 0)     //用户空间
-------------------------------------------------------------------------------------
v4l2_ioctl    没干啥事,只是调用video_ioctl2                       //v4l2-dev.c      //内核空间
    --> video_ioctl2      没干啥事,只是调用video_usercopy   //v4l2-ioctl.c                                            
    -->  video_usercopy      将用户空间的cmd 和参数拷贝到内核空间   //v4l2-ioctl.c
        -->  __video_do_ioctl     进行cmd解析,并调用相应的函数处理    //v4l2_ioctl.c
            --> soc_camera_reqbufs                     //soc_camra.c
                --> videobuf_reqbufs                      //videobuf-core.c
                    --> __videobuf_mmap_setup     //videobuf-core.c
                         --> videobuf_alloc_vb            //videobuf-core.c
                             --> __videobuf_alloc_vb    //videobuf-core.c

在soc_camera.c中
  1. static int soc_camera_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p)
  2. {
  3.     struct soc_camera_device *icd = file->private_data;
  4.     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
  5.  
  6.     videobuf_reqbufs(&icd->vb_vidq, p);   
  7.     ici->ops->reqbufs(icd, p);  //rk_camera_reqbufs
  8.   
  9.     if (!ret && !icd->streamer)
  10.         icd->streamer = file;
  11.     return ret;
  12. }



  1. int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req)
  2. {
  3.     unsigned int size, count;   
  4.     videobuf_queue_lock(q);  
  5.     count = req->count;                    //count=4
  6.     q->ops->buf_setup(q, &count, &size);   //调用rk_videobuf_setup设转置count与size
  7.     retval = __videobuf_mmap_setup(q, count, size, req->memory);   //count=4 size=0x71000=452K
  8.     req->count = retval;

  9.     videobuf_queue_unlock(q);
  10.     return 0;
  11. }
  12. EXPORT_SYMBOL_GPL(videobuf_reqbufs);

在rk30_camera_oneframe.c中
  1. static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
  2. {
  3.     struct soc_camera_device *icd = vq->priv_data;
  4.     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
  5.     struct rk_camera_dev *pcdev = ici->priv;
  6.     struct rk_camera_work *wk;
  7.     struct soc_mbus_pixelfmt fmt;

  8.      //icd->user_width=640
  9.     //bytes_pre_line = 640*3/2= 960 
  10.     //bytes_per_line_host=960
  11.     //输出格式 NV12
  12.     //size = 960*480= 460800 = 0x70800 = PAGE(0x71000)
  13.     *size = PAGE_ALIGN(bytes_per_line*icd->user_height); 
  14.     //vipmem_bsize = 960*480 = 0x70800 = PAGE(0x71000)  
  15.     pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height);
  16.    
  17.     pcdev->camera_work = wk = kzalloc(sizeof(struct rk_camera_work)*(*count), GFP_KERNEL);
  18.     INIT_LIST_HEAD(&pcdev->camera_work_queue);
  19.     for (i=0; i<(*count); i++) {
  20.        wk->index = i;
  21.        list_add_tail(&wk->queue, &pcdev->camera_work_queue);
  22.        wk++;
  23.      }
  24.      pcdev->camera_work_count = (*count); 
  25.      pcdev->vbinfo = kzalloc(sizeof(struct rk29_camera_vbinfo)*(*count), GFP_KERNEL);           
  26.      memset(pcdev->vbinfo,0,sizeof(struct rk29_camera_vbinfo)*(*count));
  27.      pcdev->vbinfo_count = *count;
  28.     }
  29.     pcdev->video_vq = vq;
  30.     return 0;
  31. }

在videobuf-core.c中
  1. int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount, unsigned int bsize, enum v4l2_memory memory)
  2. {
  3.     unsigned int i;
  4.     //这个函数只执行一次,所以开始时先释放以前分配的内存队列
  5.     __videobuf_free(q);            
  6.     //bcount=4
  7.     for (i = 0; i < bcount; i++) {
  8.         q->bufs[i] = videobuf_alloc_vb(q);
  9.         q->bufs[i]->i = i;
  10.         q->bufs[i]->input = UNSET;
  11.         q->bufs[i]->memory = memory;
  12.         q->bufs[i]->bsize = bsize;       
  13.     }   
  14.     return i;
  15. }
  16. EXPORT_SYMBOL_GPL(__videobuf_mmap_setup);


在videobuf-core.c中
  1. struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
  2. {
  3.     struct videobuf_buffer *vb;
  4.     vb = q->int_ops->alloc_vb(q->msize);
  5.     if (NULL != vb) {
  6.         init_waitqueue_head(&vb->done);
  7.         vb->magic = MAGIC_BUFFER;
  8.     }
  9.     return vb;
  10. }
  11. EXPORT_SYMBOL_GPL(videobuf_alloc_vb);


在videobuf-dma-contig.c中
分配一块内存,真正分配的内存大小是size+sizeof(mem)180个字节,返回分配内存的首地址
  1. static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
  2. {
  3.     struct videobuf_dma_contig_memory *mem;
  4.     struct videobuf_buffer *vb;

  5.     vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);   //注意:大小为size+mem,既分配size的内存还有mem的地方
  6.     if (vb) {
  7.         mem = vb->priv = ((char *)vb) + size;        //priv指向刚分配内存的mem处
  8.         mem->magic = MAGIC_DC_MEM;
  9.     }

  10.     return vb;
  11. }

二. camera 每一帧数据的获取
1. 先看一下用户空间是如何调用的
在hardware/rk29/camera/CameraHal.cpp中
  1. int CameraHal::cameraStart()
  2. {
  3.     struct v4l2_format format;
  4.     enum v4l2_buf_type type;
  5.     struct v4l2_requestbuffers creqbuf;
  6.     struct v4l2_buffer buffer;
  7.     

  8.     creqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  9.     creqbuf.memory = mCamDriverV4l2MemType;
  10.     creqbuf.count = CONFIG_CAMERA_PRVIEW_BUF_CNT;
  11.     ioctl(iCamFd, VIDIOC_REQBUFS, &creqbuf);                     //1. VIDIOC_REQBUFS在内核中会申请内存空间

  12.     memset(mCamDriverV4l2Buffer, 0x00, sizeof(mCamDriverV4l2Buffer));
  13.     for (int i = 0; i < mPreviewBufferCount; i++) {
  14.         if (CAMERA_PREVIEWBUF_ALLOW_WRITE(mPreviewBufferMap[i]->buf_state)) {
  15.             memset(&buffer, 0, sizeof(struct v4l2_buffer));
  16.             buffer.type = creqbuf.type;
  17.             buffer.memory = creqbuf.memory;
  18.             buffer.flags = 0;
  19.             buffer.index = i;

  20.             ioctl(iCamFd, VIDIOC_QUERYBUF, &buffer);         //2. VIDIOC_QUERYBUF
  21.             //不管是overlay 还是 mmap 都是要获取 camera数据帧的首地址
  22.             if (buffer.memory == V4L2_MEMORY_OVERLAY) {    
  23.                 buffer.m.offset = mPreviewBufferMap[i]->phy_addr;
  24.                 mCamDriverV4l2Buffer[i] = (char*)mPreviewBufferMap[i]->vir_addr;
  25.             } else if (buffer.memory == V4L2_MEMORY_MMAP) {
  26.                 mCamDriverV4l2Buffer[i] = (char*)mmap(0, buffer.length,
  27.                         PROT_READ, MAP_SHARED, iCamFd,buffer.m.offset);
  28.             }
  29.             mCamDriverV4l2BufferLen = buffer.length;           
  30.             cameraPreviewBufferSetSta(mPreviewBufferMap[i], CMD_PREVIEWBUF_WRITING, 1);
  31.             ioctl(iCamFd, VIDIOC_QBUF, &buffer);             //3. VIDIOC_QBUF
  32.         }
  33.     }
  34.     
  35.     if(!mPreviewMemory) {
  36.      mPreviewMemory = mRequestMemory(-1, mPreviewFrame2AppSize, CONFIG_CAMERA_PRVIEW_BUF_CNT, NULL);
  37.     } else if (mPreviewMemory->size != (unsigned int)(mPreviewFrame2AppSize*CONFIG_CAMERA_PRVIEW_BUF_CNT)) {
  38.         mPreviewMemory->release(mPreviewMemory);
  39.         mPreviewMemory = mRequestMemory(-1, mPreviewFrame2AppSize, CONFIG_CAMERA_PRVIEW_BUF_CNT, NULL);
  40.     }
  41.     
  42.     if (mPreviewMemory) {
  43.         for (int i=0; i < CONFIG_CAMERA_PRVIEW_BUF_CNT; i++) {
  44.             mPreviewBufs[i] = (unsigned char*) mPreviewMemory->data + (i*mPreviewFrame2AppSize);
  45.         }
  46.     } else {
  47.         LOGE("%s(%d): mPreviewMemory create failed",__FUNCTION__,__LINE__);
  48.     }
  49.     
  50.     int *addr;    
  51.     
  52.     for (int i=0; i < CONFIG_CAMERA_PRVIEW_BUF_CNT; i++) {
  53.         if(!mVideoBufs[i])
  54.             mVideoBufs[i] = mRequestMemory(-1, 4, 1, NULL);
  55.         if( (NULL == mVideoBufs[i]) || ( NULL == mVideoBufs[i]->data)) {
  56.             mVideoBufs[i] = NULL;
  57.             LOGE("%s(%d): video buffer %d create failed",__FUNCTION__,__LINE__,i);
  58.         }
  59.         if (mVideoBufs[i]) {
  60.             addr = (int*)mVideoBufs[i]->data;
  61.             *addr = mPreviewBufferMap[i]->phy_addr;
  62.         }
  63.     }
  64.     mPreviewErrorFrameCount = 0;
  65.     mPreviewFrameIndex = 0;

  66.     cameraStream(true);
  67.     LOG_FUNCTION_NAME_EXIT
  68.     return 0;
  69. }
VIDIOC_REQBUFS:      分配内存
VIDIOC_QUERYBUF:    把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
VIDIOC_QUERYCAP:    查询驱动功能
VIDIOC_ENUM_FMT:   获取当前驱动支持的视频格式
VIDIOC_S_FMT:          设置当前驱动的频捕获格式
VIDIOC_G_FMT:          读取当前驱动的频捕获格式
VIDIOC_TRY_FMT:       验证当前驱动的显示格式
VIDIOC_CROPCAP:      查询驱动的修剪能力
VIDIOC_S_CROP:        设置视频信号的边框
VIDIOC_G_CROP:        读取视频信号的边框
VIDIOC_QBUF:           把数据从缓存中读取出来
VIDIOC_DQBUF:         把数据放回缓存队列
VIDIOC_STREAMON:   开始视频显示函数
VIDIOC_STREAMOFF:  结束视频显示函数
VIDIOC_QUERYSTD:    检查当前视频设备支持的标准,例如PAL或NTSC



在soc_camera.c中
  1. static int soc_camera_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
  2. {
  3.     struct soc_camera_device *icd = file->private_data;
  4.     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
  5.     return videobuf_querybuf(&icd->vb_vidq, p); 
  6. }
在videobuf-core.c中
  1. int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
  2. {
  3.     videobuf_queue_lock(q);
  4.     videobuf_status(q, b, q->bufs[b->index], q->type);
  5.     videobuf_queue_unlock(q);
  6.     return ret;
  7. }
  8. EXPORT_SYMBOL_GPL(videobuf_querybuf);





在soc_camera.c中
  1. static int soc_camera_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
  2. {
  3.     struct soc_camera_device *icd = file->private_data;
  4.     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
  5.     videobuf_qbuf(&icd->vb_vidq, p);   
  6. }


  1. int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
  2. {
  3.     struct videobuf_buffer *buf;
  4.     enum v4l2_field field;
  5.     unsigned long flags = 0;

  6.     videobuf_queue_lock(q);
  7.    
  8.     buf = q->bufs[b->index];   //这个index值是 0-3 一直循环
  9.     buf->input = UNSET;  
  10.   
  11.     buf->boff = b->m.offset;   //这个buf->boff是用户空间传入的buffer
  12.     field = videobuf_next_field(q);
  13.     retval = q->ops->buf_prepare(q, buf, field);
  14.     list_add_tail(&buf->stream, &q->stream);
  15.     if (q->streaming) {
  16.         spin_lock_irqsave(q->irqlock, flags);
  17.         q->ops->buf_queue(q, buf);
  18.         spin_unlock_irqrestore(q->irqlock, flags);
  19.     }
  20.     wake_up_interruptible_sync(&q->wait);
  21.     videobuf_queue_unlock(q);
  22.     return 0;
  23. }
  24. EXPORT_SYMBOL_GPL(videobuf_qbuf);





  1. static int rk_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field)
  2. {
  3.     struct soc_camera_device *icd = vq->priv_data;
  4.     struct rk_camera_buffer *buf;
  5.     int ret;
  6.     int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,  icd->current_fmt->host_fmt);
  7.    
  8.     buf = container_of(vb, struct rk_camera_buffer, vb);

  9.     if (buf->code != icd->current_fmt->code || vb->width != icd->user_width ||
  10.             vb->height != icd->user_height ||  vb->field != field) {
  11.         buf->code = icd->current_fmt->code;
  12.         vb->width = icd->user_width;
  13.         vb->height = icd->user_height;
  14.         vb->field = field;
  15.         vb->state = VIDEOBUF_NEEDS_INIT;
  16.     }

  17.     vb->size = bytes_per_line*vb->height;
  18.     if (vb->state == VIDEOBUF_NEEDS_INIT) {
  19.         ret = videobuf_iolock(vq, vb, NULL);       
  20.         vb->state = VIDEOBUF_PREPARED;
  21.     }
  22.     return 0;
  23. }






在drivers/media/video/videobuf-core.c中
  1. int videobuf_dqbuf(struct videobuf_queue *q, struct v4l2_buffer *b, int nonblocking)
  2. {
  3.     struct videobuf_buffer *buf = NULL;
  4.     memset(b, 0, sizeof(*b));
  5.   videobuf_queue_lock(q);
  6.     stream_next_buffer(q, &buf, nonblocking);
  7.     videobuf_status(q, b, buf, q->type);       //将结果保存在buf中
  8.     list_del(&buf->stream);
  9.     buf->state = VIDEOBUF_IDLE;
  10.     b->flags &= ~V4L2_BUF_FLAG_DONE;              
  11.   videobuf_queue_unlock(q);
  12.     return retval;
  13. }
  14. EXPORT_SYMBOL_GPL(videobuf_dqbuf);


videobuf_dqbuf
    --> stream_next_buffer
  1. static int stream_next_buffer(struct videobuf_queue *q, struct videobuf_buffer **vb, int nonblocking)
  2. {
  3.     struct videobuf_buffer *buf = NULL;
  4.   
  5.     retval = stream_next_buffer_check_queue(q, nonblocking);
  6.   
  7.     buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
  8.     retval = videobuf_waiton(q, buf, nonblocking, 1);
  9.     *vb = buf;
  10.     return retval;
  11. }









阅读(5159) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~