【v4l2】按照应用程序请求,框架层为队列分配内存的 __reqbufs函数粗浅分析

Linux/drivers/media/v4l2-core/videobuf2-core.c


时间紧迫,粗略读了一下,这个函数的实现,得到以下结论:


(1)用户空间请求驱动分配内存,建立缓冲,要传递这个宏给驱动,实际执行的函数就是下面这个。

用户空间会传递 struct v4l2_requestbuffers *req 结构体,带有请求信息,给驱动的vidioc_reqbufs 处理者来处理。

(2)驱动会有一个回调函数,叫做queue_setup() 来执行设置缓冲区的操作。

(3)当vb2_reqbufs 已经被调用过了,但是,缓冲不处于in use的状态,那么可以free掉,重新按照这次的要求,分配内存。

(4)如果请求为缓冲队列分配的空间req->count是0,那么会释放掉所有内存,返回。

(5)请求分配的内存空间,不能超过VIDEO_MAX_FRAME大小。

(6)会检查驱动是否可以按照请求来分配内存,这部分操作的接口,我不太懂。

(7)如果驱动ok,那么req->count 会被设置为实际分配的缓冲大小。

(8) for MMAP memory type, allocates actual video memory, using the    memory handling/allocation routines provided during queue initialization

对于MMAP的内存操作的函数,是在队列初始化的时候给出的。



597 /**
598  * __reqbufs() - Initiate streaming

599  * @q:          videobuf2 queue
600  * @req:        struct passed from userspace to vidioc_reqbufs handler in driver  从用户空间传递到驱动中的vidioc_reqbufs handler  ,这不是要求分配缓冲空间么???
601  *
602  * Should be called from vidioc_reqbufs ioctl handler of a driver.
603  * This function:
604  * 1) verifies streaming parameters passed from the userspace,
605  * 2) sets up the queue,
606  * 3) negotiates商议 number of buffers and planes per buffer with the driver   to be used during streaming,
608  * 4) allocates internal buffer structures (struct vb2_buffer), according to  the agreed parameters,  分配内部缓冲
610  * 5) for MMAP memory type, allocates actual video memory, using the
611  *    memory handling/allocation routines provided during queue initialization
612  *
613  * If req->count is 0, all the memory will be freed instead.
614  * If the queue has been allocated previously (by a previous vb2_reqbufs) call
615  * and the queue is not busy, memory will be reallocated. 还有重新被分配的情况。

616  *
617  * The return values from this function are intended to be directly returned
618  * from vidioc_reqbufs handler in driver.
619  */
//给 vb2_queue 分配内存空间。
620 static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
621 {
622         unsigned int num_buffers, allocated_buffers, num_planes = 0;
623         int ret;
624 
625         if (q->streaming) {
626                 dprintk(1, "reqbufs: streaming active\n");
627                 return -EBUSY;
628         }
629 

//q->num_buffers != 0  代表缓冲已经被分配了???

630         if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
631                 /*
632                  * We already have buffers allocated, so first check if they
633                  * are not in use and can be freed.
634                  */
635                 if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { //检查缓冲是否被使用中。
636                         dprintk(1, "reqbufs: memory in use, cannot free\n");
637                         return -EBUSY;
638                 }
639 

                     //不在使用中,可以被free掉,然后重新分配。。
640                 __vb2_queue_free(q, q->num_buffers);
641 
642                 /*
643                  * In case of REQBUFS(0) return immediately without calling
644                  * driver's queue_setup() callback and allocating resources.
645                  */
646                 if (req->count == 0)
647                         return 0;
648         }
649 
650         /*
651          * Make sure the requested values and current defaults are sane健全的.
652          */
           //要求分配的空间大小

653         num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
654         memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
655         memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
656         q->memory = req->memory;
657 
658         /*
659          * Ask the driver how many buffers and planes per buffer it requires.
660          * Driver also sets the size and allocator context for each plane.
661          */
662         ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
663                        q->plane_sizes, q->alloc_ctx);
664         if (ret)
665                 return ret;

666 
667         /* Finally, allocate buffers and video memory 分配缓冲空间*/
668         ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
669         if (ret == 0) {
670                 dprintk(1, "Memory allocation failed\n");
671                 return -ENOMEM;
672         }
673 
674         allocated_buffers = ret;
675 
676         /*
677          * Check if driver can handle the allocated number of buffers.
678          */
679         if (allocated_buffers < num_buffers) {
680                 num_buffers = allocated_buffers;
681 
682                 ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
683                                &num_planes, q->plane_sizes, q->alloc_ctx);
684 
685                 if (!ret && allocated_buffers < num_buffers)
686                         ret = -ENOMEM;
687 
688                 /*
689                  * Either the driver has accepted a smaller number of buffers,
690                  * or .queue_setup() returned an error
691                  */

692         }
693 
694         q->num_buffers = allocated_buffers; //缓冲大小
695 
696         if (ret < 0) {
697                 __vb2_queue_free(q, allocated_buffers);
698                 return ret;
699         }
700 
701         /*
702          * Return the number of successfully allocated buffers  to the userspace.
704          */
705         req->count = allocated_buffers; //分配的实际缓冲大小
706 
707         return 0;
708 }



709 封装。。。,暴露给应用程序用。
710 /**
711  * vb2_reqbufs() - Wrapper for __reqbufs() that also verifies the memory and
712  * type values.

713  * @q:          videobuf2 queue
714  * @req:        struct passed from userspace to vidioc_reqbufs handler in driver
715  */
716 int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
717 {
718         int ret = __verify_memory_type(q, req->memory, req->type);
719 
720         return ret ? ret : __reqbufs(q, req);
721 }
722 EXPORT_SYMBOL_GPL(vb2_reqbufs);

你可能感兴趣的:(嵌入式系统及开发,多媒体/流媒体/live555)