春暖花开~~

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一,V4L2驱动申请buffer

视频应用可以通过两种方式从V4L2驱动申请buffer

1. V4L2_MEMORY_USERPTR方式, 顾名思义是用户空间指针的意思,应用层负责分配需要的内存空间,然后以指针的形式传递给V4L2驱动层,V4L2驱动会把capture的内容保存到指针所指的空间

一般来说,应用层需要确保这个内存空间物理上是连续的(IPU处理单元的需求),在android系统可以通过PMEM驱动来分配大块的连续物理内存。应用层在不需要的时候要负责释放申请的PMEM内存。

2. V4L2_MEMORY_MMAP方式,内存映射模式,应用调用VIDIOC_REQBUFS ioctl分配设备buffers,参数标识需要的数目和类型。这个ioctl也可以用来改变buffers的数据以及释放分配的内存,当然

这个内存空间一般也是连续的。在应用空间能够访问这些物理地址之前,必须调用mmap函数把这些物理空间映射为用户虚拟地址空间。

  虚拟地址空间是通过munmap函数释放的; 而物理内存的释放是通过VIDIOC_REQBUFS来实现的(设置参数buf count为(0)),物理内存的释放是实现特定的,mx51 v4l2是在关闭设备时进行释放

的。所以二者都是申请连续的物理内存,只是申请和释放的方式不同

2.V4L2_MEMORY_USERPTRqualcommandroid 4.1后使用ion方式分配内存,原来是使用pmem分配内存,先从hal层申请内存空间,然后给camera驱动用的。

二,camera的测试代码流程

1,打开设备

static int open_device(char *dev_name)

{

assert(dev_name);

int fd = -1;

fd = open(dev_name , O_RDWR);

if( -1 == fd ) {

MYLOGD("open %s fail: %s\n", dev_name, strerror (errno));

exit(EXIT_FAILURE);

}

MYLOGD("the fd of %s is %d ", dev_name, fd);

return fd;

}



2,初始化camera,设置camera输出图像的格式

static int init_cam_device(int dev_fd)

{

int ret = -1;

int input_index;


//ret = fimc_v4l2_querycap(dev_fd);

//assert(ret == 0);

//获取到输入源通道

input_index = cam_v4l2_enuminput(dev_fd);

assert(input_index == 0);

 

ret = cam_v4l2_s_input(dev_fd, input_index);

assert(ret == 0);


MYLOGD("VIDIOC_S_FMT start... dev_fd = %d\n", dev_fd);


ret = cam_v4l2_s_format(dev_fd, IMAGE_HEIGHT, IMAGE_WIDTH,

V4L2_PIX_FMT_YUYV);

assert(ret == 0);


ret = cam_v4l2_g_fmt(dev_fd);

assert(ret == 0);

 

init_cam_mmap(dev_fd);

 

return 1;

 

}


三,向内核申请buffer,并将buffer映射mmap到引用空间

1)数据结构

  struct buffer{

     void *start; //mmap后的地址;
     size_t length//大小;
  }user_buffers[4]; //用于记录将内核buffer映射mmap到用户空间的地址和大小

 

2)申请4buffer

  camera_v4l2_reqbuf(dev_fd, 4);


3)查询申请到的buffer信息,比如每个buffer的其实位置和大小

  camera_v4l2_querybuf(dev_fd, &buf, buf_index);

 

4)将buffer映射到用户空间

  user_buffers[buf_index].length = buf.length;

  user_buffers[buf_index].start = mmap(NULLbuf.length,PROT_READ | PROT_WRITE /* required */ ,MAP_SHARED /* recommended */ ,dev_fd, buf.m.offset);

  注释: NULL/* start anywhere */

  buf.lengthbuffer在内核的地址

  buf.m.offset:内核中的buffer大小

5),将所有的buffer全部放到循环工作队列中,集中管理

  for (i = 0; i < max_buffers; ++i)
  {
    camera_v4l2_qbuf(dev_fd, i);
  }

6),开始获取图像:

  ioctl(dev_fd, VIDIOC_STREAMON, &type);

7),通过select来监控camera数据是否准备好

  FD_ZERO (&rd_set);
  FD_SET (dev_fd, &rd_set);

  ret = select(maxfd + 1, &rd_set, NULL, NULL, NULL);

  if(FD_ISSET(dev_fd, &rd_set))//如果camera准备好,就可以去读数据了

    read_frame(dev_fd)

8)read_frame(dev_fd)的实现:

  //select仅仅是知道有数据可以读了,但是在多个buffer中,

  //不知道是哪个buffer准备好了,所以将准备好的buffer出队列,从而知道buffer的编号

  int index = camera_v4l2_dqbuf(dev_fd);

  //buffer中的yuv420数据转换成rgb565

  //因为lcd是没办法显示yuv的,所以需要将yuv转换成rgb565

  yuyv_to_rgb(src_address, data_buf);

  //将转换好的rgb565数据方到framebuffer中去显示

  show_rgb565_img(data_buf, LCD_WIDTH, LCD_HEIGHT);


四,高通buffer管理使用代码流程

一,HAL->kernel 分配buffer
mm_stream_request_buf->//Mm_camera_stream.c (8953_dual_camera\src\hardware\qcom\camera\qcamera2\stack\mm-camera-interface\src)    
    ioctl(my_obj->fd, VIDIOC_REQBUFS, &bufreq);//向kernel发送IOCTL命令,请求分配buffer
{=================kernel===================<
        v4l_reqbufs->//V4l2-ioctl.c (8953_dual_camera\src\kernel\msm-3.18\drivers\media\v4l2-core)    
                                    //ops->vidioc_reqbufs(file, fh, p)
            camera_v4l2_reqbufs->//Camera.c (camera)    
                vb2_reqbufs->//Videobuf2-core.c (\8953_dual_camera\src\kernel\msm-3.18\drivers\media\v4l2-core)    
                    __reqbufs->//
                        __vb2_queue_alloc->
                            __vb2_buf_mem_alloc->//分配video buffer
                                                                     //最后通过mmap函数将buffer映射到用户空间
 =================kernel===================>
}
二,HAL->kernel 读取一帧数据
mm_stream_read_msm_frame->//Mm_camera_stream.c (8953_dual_camera\src\hardware\qcom\camera\qcamera2\stack\mm-camera-interface\src)    
    ioctl(my_obj->fd, VIDIOC_DQBUF, &vb);//向kernel发送IOCTL命令,向kernel读取一帧数据
                                                                             //kernel流程同【一】
 
三,HAL->kernel 向kernel buffer释放一个buffer,使kernel可以填充新的视频数据
mm_stream_qbuf->//Mm_camera_stream.c (8953_dual_camera\src\hardware\qcom\camera\qcamera2\stack\mm-camera-interface\src)    
     ioctl(my_obj->fd, VIDIOC_QBUF, &buffer);//向kernel发送IOCTL命令,向kernel释放buffer,让kernel可以填充新的视频数据
                                                                                     //kernel流程同【一】
 


 

posted on 2019-04-10 14:38  聆听花开的声音  阅读(1573)  评论(0编辑  收藏  举报