mirror of
https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
synced 2025-11-28 19:11:03 +08:00
发布: [02-3]_videobuffer2缓冲区结构体
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
参考资料:
|
||||
|
||||
* 深入理解linux内核v4l2框架之videobuf2:https://blog.csdn.net/yyjsword/article/details/9243717
|
||||
* V4L2框架-videobuf2:https://blog.csdn.net/u013904227/article/details/81054611
|
||||
|
||||
## 1. 整体框架
|
||||
|
||||
@@ -107,5 +108,41 @@ APP操作buffer的示意图如下:
|
||||
|
||||
|
||||
|
||||
#### 1.3.1 videobuffer2缓冲区结构体
|
||||
|
||||

|
||||
|
||||
分配流程:
|
||||
|
||||
* 驱动程序初始化时,就构造了vb2_queue,这是"buffer的队列",一开始里面没有"buffer"
|
||||
* APP调用ioctl VIDIOC_REQBUFS向驱动申请N个buffer
|
||||
* 驱动程序分配n(n<=N)个vb2_buffer结构体,然后
|
||||
* 对于普通摄像头,还分配一个vb2_plane结构体、vb2_vmalloc_buf结构体,最后分配存数据的buffer
|
||||
* 对于多平面摄像头,给每个vb2_buffer分配多个"vb2_plane结构体、vb2_vmalloc_buf结构体、存数据的buffer"
|
||||
|
||||
|
||||
|
||||
入队列流程:
|
||||
|
||||
* APP调用ioctl VIDIOC_QBUF
|
||||
* 驱动程序根据其index找到vb2_buffer
|
||||
* 把这个vb2_buffer放入链表vb2_queue.queued_list
|
||||
|
||||
硬件驱动接收到数据后,比如URB传输完成后:
|
||||
|
||||
* 从链表vb2_queue.queued_list取出vb2_buffer
|
||||
* 把硬件数据存入vb2_buffer
|
||||
* 把vb2_buffer放入链表vb2_queue.done_list
|
||||
|
||||
出队列流程:
|
||||
|
||||
* APP调用ioctl VIDIOC_DQBUF
|
||||
* 驱动程序从链表vb2_queue.done_list取出并移除第1个vb2_buffer
|
||||
* 驱动程序也把这个vb2_buffer从链表vb2_queue.queued_list移除
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2. 从0编写一个虚拟的摄像头驱动
|
||||
|
||||
|
||||
BIN
IMX6ULL/doc_pic/13_V4L2/2-3_videobuffer2缓冲区结构体.tif
Normal file
BIN
IMX6ULL/doc_pic/13_V4L2/2-3_videobuffer2缓冲区结构体.tif
Normal file
Binary file not shown.
BIN
IMX6ULL/doc_pic/13_V4L2/pic/28_suggestion.png
Normal file
BIN
IMX6ULL/doc_pic/13_V4L2/pic/28_suggestion.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/29_videobuffer2_struct.png
Normal file
BIN
IMX6ULL/doc_pic/13_V4L2/pic/29_videobuffer2_struct.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -20,6 +20,8 @@ GIT简明教程:http://download.100ask.org/tools/Software/git/how_to_use_git.h
|
||||
|
||||
## 2. 收到的建议
|
||||
|
||||

|
||||
|
||||
subdev, media control, media framework, vb2 buffer的分配,怎么轮转,怎么跟硬件打交道,然后图像给应用层用
|
||||
|
||||
有的摄像头有控制接口iic,spi,还有没有控制接口的,我们怎么处理?
|
||||
@@ -225,3 +227,236 @@ V4L2 capture overlay
|
||||
|
||||
|
||||
|
||||
## 4. videobuffer2
|
||||
|
||||
参考资料:
|
||||
|
||||
* https://www.linuxtv.org/downloads/v4l-dvb-apis-old/vidioc-create-bufs.html
|
||||
* https://www.linuxtv.org/downloads/v4l-dvb-apis-old/buffer.html#v4l2-memory
|
||||
* https://www.linuxtv.org/downloads/v4l-dvb-apis-old/mmap.html
|
||||
* V4l2应用框架-Videobuf2数据结构 https://blog.csdn.net/weixin_42581177/article/details/126582465
|
||||
|
||||
|
||||
|
||||
```c
|
||||
static const struct vb2_ops airspy_vb2_ops = {
|
||||
.queue_setup = airspy_queue_setup,
|
||||
.buf_queue = airspy_buf_queue,
|
||||
.start_streaming = airspy_start_streaming,
|
||||
.stop_streaming = airspy_stop_streaming,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
const struct vb2_mem_ops vb2_vmalloc_memops = {
|
||||
.alloc = vb2_vmalloc_alloc,
|
||||
.put = vb2_vmalloc_put,
|
||||
.get_userptr = vb2_vmalloc_get_userptr,
|
||||
.put_userptr = vb2_vmalloc_put_userptr,
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
.get_dmabuf = vb2_vmalloc_get_dmabuf,
|
||||
#endif
|
||||
.map_dmabuf = vb2_vmalloc_map_dmabuf,
|
||||
.unmap_dmabuf = vb2_vmalloc_unmap_dmabuf,
|
||||
.attach_dmabuf = vb2_vmalloc_attach_dmabuf,
|
||||
.detach_dmabuf = vb2_vmalloc_detach_dmabuf,
|
||||
.vaddr = vb2_vmalloc_vaddr,
|
||||
.mmap = vb2_vmalloc_mmap,
|
||||
.num_users = vb2_vmalloc_num_users,
|
||||
};
|
||||
|
||||
|
||||
s->vb_queue.ops = &airspy_vb2_ops; // call_qop,call_vb_qop
|
||||
s->vb_queue.mem_ops = &vb2_vmalloc_memops; // call_ptr_memop
|
||||
|
||||
int vb2_queue_init(struct vb2_queue *q)
|
||||
q->buf_ops = &v4l2_buf_ops;
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.1 APP request buf
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_REQBUFS, &rb);
|
||||
--------------------------------
|
||||
v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
|
||||
ops->vidioc_reqbufs(file, fh, p);
|
||||
vb2_ioctl_reqbufs
|
||||
res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count);
|
||||
num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME);
|
||||
num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
|
||||
|
||||
// 给你机会修改num_buffers,num_planes
|
||||
ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, plane_sizes, q->alloc_devs); // airspy_queue_setup
|
||||
|
||||
/* Finally, allocate buffers and video memory */
|
||||
allocated_buffers =
|
||||
__vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
|
||||
ret = __vb2_buf_mem_alloc(vb);
|
||||
call_ptr_memop(vb, alloc,
|
||||
vb2_queue->mem_ops->alloc
|
||||
vb2_vmalloc_alloc
|
||||
buf->vaddr = vmalloc_user(buf->size);
|
||||
ret = call_vb_qop(vb, buf_init, vb);
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.2 queue buffer
|
||||
|
||||
queue buffer关键点:
|
||||
|
||||
* VB2的链表:list_add_tail(&vb->queued_entry, &q->queued_list);
|
||||
* 驱动自己维护的链表:list_add_tail(&buf->list, &s->queued_bufs);
|
||||
|
||||
驱动的URB传输完成后:
|
||||
|
||||
* 从链表queued_bufs取出buffer
|
||||
* 把URB得到的数据填入buffer
|
||||
* 调用vb2_buffer_done:list_add_tail(&vb->done_entry, &q->done_list);
|
||||
|
||||
dequeue buffer关键点:
|
||||
|
||||
* 从链表done_entry取出并移除第1个vb
|
||||
* 把它也从queued_list中移除
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_QBUF, &buf)
|
||||
-------------------------------
|
||||
v4l_qbuf
|
||||
ops->vidioc_qbuf(file, fh, p);
|
||||
vb2_ioctl_qbuf
|
||||
vb2_qbuf(vdev->queue, p);
|
||||
vb2_queue_or_prepare_buf(q, b, "qbuf");
|
||||
vb2_core_qbuf(q, b->index, b);
|
||||
list_add_tail(&vb->queued_entry, &q->queued_list);
|
||||
vb->state = VB2_BUF_STATE_QUEUED;
|
||||
|
||||
/*
|
||||
* If already streaming, give the buffer to driver for processing.
|
||||
* If not, the buffer will be given to driver on next streamon.
|
||||
*/
|
||||
if (q->start_streaming_called)
|
||||
__enqueue_in_driver(vb);
|
||||
/* sync buffers */
|
||||
for (plane = 0; plane < vb->num_planes; ++plane)
|
||||
call_void_memop(vb, prepare, vb->planes[plane].mem_priv);
|
||||
|
||||
call_void_vb_qop(vb, buf_queue, vb);
|
||||
airspy_buf_queue
|
||||
list_add_tail(&buf->list, &s->queued_bufs);
|
||||
|
||||
if (pb)
|
||||
call_void_bufop(q, fill_user_buffer, vb, pb);
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.3 dequeue buf
|
||||
|
||||
```shell
|
||||
ioctl(fd, VIDIOC_DQBUF, &buf)
|
||||
----------------------------------
|
||||
v4l_dqbuf
|
||||
ops->vidioc_dqbuf(file, fh, p);
|
||||
vb2_ioctl_dqbuf
|
||||
vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);
|
||||
ret = vb2_core_dqbuf(q, NULL, b, nonblocking);
|
||||
ret = __vb2_get_done_vb(q, &vb, pb, nonblocking);
|
||||
*vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
|
||||
list_del(&(*vb)->done_entry);
|
||||
call_void_vb_qop(vb, buf_finish, vb);
|
||||
call_void_bufop(q, fill_user_buffer, vb, pb);
|
||||
__vb2_dqbuf(vb);
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.3 stream on
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_STREAMON, &type)
|
||||
------------------------------------
|
||||
v4l_streamon
|
||||
ops->vidioc_streamon(file, fh, *(unsigned int *)arg)
|
||||
vb2_ioctl_streamon
|
||||
vb2_streamon(vdev->queue, i);
|
||||
vb2_core_streamon(q, type);
|
||||
ret = vb2_start_streaming(q);
|
||||
/*
|
||||
* If any buffers were queued before streamon,
|
||||
* we can now pass them to driver for processing.
|
||||
*/
|
||||
list_for_each_entry(vb, &q->queued_list, queued_entry)
|
||||
__enqueue_in_driver(vb);
|
||||
/* sync buffers */
|
||||
for (plane = 0; plane < vb->num_planes; ++plane)
|
||||
call_void_memop(vb, prepare, vb->planes[plane].mem_priv);
|
||||
|
||||
call_void_vb_qop(vb, buf_queue, vb);
|
||||
airspy_buf_queue
|
||||
|
||||
/* Tell the driver to start streaming */
|
||||
q->start_streaming_called = 1;
|
||||
ret = call_qop(q, start_streaming, q, atomic_read(&q->owned_by_drv_count));
|
||||
airspy_start_streaming // 分配提交URB
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.3 stream off
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_STREAMOFF, &type)
|
||||
-----------------------------------
|
||||
v4l_streamoff
|
||||
ops->vidioc_streamoff(file, fh, *(unsigned int *)arg);
|
||||
vb2_ioctl_streamoff
|
||||
vb2_streamoff(vdev->queue, i);
|
||||
vb2_core_streamoff(q, type);
|
||||
__vb2_queue_cancel(q);
|
||||
call_void_qop(q, stop_streaming, q);
|
||||
airspy_stop_streaming // kill URB
|
||||
|
||||
call_void_vb_qop(vb, buf_finish, vb);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.4 阻塞与唤醒
|
||||
|
||||
#### 4.4.1 阻塞
|
||||
|
||||
```shell
|
||||
memset(fds, 0, sizeof(fds));
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = POLLIN;
|
||||
if (1 == poll(fds, 1, -1))
|
||||
--------------------------------------
|
||||
v4l2_poll
|
||||
res = vdev->fops->poll(filp, poll);
|
||||
vb2_fop_poll
|
||||
res = vb2_poll(vdev->queue, file, wait);
|
||||
vb2_core_poll(q, file, wait);
|
||||
poll_wait(file, &q->done_wq, wait);
|
||||
```
|
||||
|
||||
#### 4.4.2 唤醒
|
||||
|
||||
```shell
|
||||
airspy_urb_complete
|
||||
vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.6 读写buf
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -796,6 +796,12 @@ git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
|
||||
[02-2]_ioctl调用流程分析
|
||||
```
|
||||
|
||||
* 2023.08.10 发布"摄像头驱动"
|
||||
|
||||
```shell
|
||||
[02-3]_videobuffer2缓冲区结构体
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
参考资料:
|
||||
|
||||
* 深入理解linux内核v4l2框架之videobuf2:https://blog.csdn.net/yyjsword/article/details/9243717
|
||||
* V4L2框架-videobuf2:https://blog.csdn.net/u013904227/article/details/81054611
|
||||
|
||||
## 1. 整体框架
|
||||
|
||||
@@ -107,5 +108,41 @@ APP操作buffer的示意图如下:
|
||||
|
||||
|
||||
|
||||
#### 1.3.1 videobuffer2缓冲区结构体
|
||||
|
||||

|
||||
|
||||
分配流程:
|
||||
|
||||
* 驱动程序初始化时,就构造了vb2_queue,这是"buffer的队列",一开始里面没有"buffer"
|
||||
* APP调用ioctl VIDIOC_REQBUFS向驱动申请N个buffer
|
||||
* 驱动程序分配n(n<=N)个vb2_buffer结构体,然后
|
||||
* 对于普通摄像头,还分配一个vb2_plane结构体、vb2_vmalloc_buf结构体,最后分配存数据的buffer
|
||||
* 对于多平面摄像头,给每个vb2_buffer分配多个"vb2_plane结构体、vb2_vmalloc_buf结构体、存数据的buffer"
|
||||
|
||||
|
||||
|
||||
入队列流程:
|
||||
|
||||
* APP调用ioctl VIDIOC_QBUF
|
||||
* 驱动程序根据其index找到vb2_buffer
|
||||
* 把这个vb2_buffer放入链表vb2_queue.queued_list
|
||||
|
||||
硬件驱动接收到数据后,比如URB传输完成后:
|
||||
|
||||
* 从链表vb2_queue.queued_list取出vb2_buffer
|
||||
* 把硬件数据存入vb2_buffer
|
||||
* 把vb2_buffer放入链表vb2_queue.done_list
|
||||
|
||||
出队列流程:
|
||||
|
||||
* APP调用ioctl VIDIOC_DQBUF
|
||||
* 驱动程序从链表vb2_queue.done_list取出并移除第1个vb2_buffer
|
||||
* 驱动程序也把这个vb2_buffer从链表vb2_queue.queued_list移除
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 2. 从0编写一个虚拟的摄像头驱动
|
||||
|
||||
|
||||
BIN
STM32MP157/doc_pic/13_V4L2/2-3_videobuffer2缓冲区结构体.tif
Normal file
BIN
STM32MP157/doc_pic/13_V4L2/2-3_videobuffer2缓冲区结构体.tif
Normal file
Binary file not shown.
BIN
STM32MP157/doc_pic/13_V4L2/pic/28_suggestion.png
Normal file
BIN
STM32MP157/doc_pic/13_V4L2/pic/28_suggestion.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
BIN
STM32MP157/doc_pic/13_V4L2/pic/29_videobuffer2_struct.png
Normal file
BIN
STM32MP157/doc_pic/13_V4L2/pic/29_videobuffer2_struct.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -20,6 +20,8 @@ GIT简明教程:http://download.100ask.org/tools/Software/git/how_to_use_git.h
|
||||
|
||||
## 2. 收到的建议
|
||||
|
||||

|
||||
|
||||
subdev, media control, media framework, vb2 buffer的分配,怎么轮转,怎么跟硬件打交道,然后图像给应用层用
|
||||
|
||||
有的摄像头有控制接口iic,spi,还有没有控制接口的,我们怎么处理?
|
||||
@@ -225,3 +227,236 @@ V4L2 capture overlay
|
||||
|
||||
|
||||
|
||||
## 4. videobuffer2
|
||||
|
||||
参考资料:
|
||||
|
||||
* https://www.linuxtv.org/downloads/v4l-dvb-apis-old/vidioc-create-bufs.html
|
||||
* https://www.linuxtv.org/downloads/v4l-dvb-apis-old/buffer.html#v4l2-memory
|
||||
* https://www.linuxtv.org/downloads/v4l-dvb-apis-old/mmap.html
|
||||
* V4l2应用框架-Videobuf2数据结构 https://blog.csdn.net/weixin_42581177/article/details/126582465
|
||||
|
||||
|
||||
|
||||
```c
|
||||
static const struct vb2_ops airspy_vb2_ops = {
|
||||
.queue_setup = airspy_queue_setup,
|
||||
.buf_queue = airspy_buf_queue,
|
||||
.start_streaming = airspy_start_streaming,
|
||||
.stop_streaming = airspy_stop_streaming,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
const struct vb2_mem_ops vb2_vmalloc_memops = {
|
||||
.alloc = vb2_vmalloc_alloc,
|
||||
.put = vb2_vmalloc_put,
|
||||
.get_userptr = vb2_vmalloc_get_userptr,
|
||||
.put_userptr = vb2_vmalloc_put_userptr,
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
.get_dmabuf = vb2_vmalloc_get_dmabuf,
|
||||
#endif
|
||||
.map_dmabuf = vb2_vmalloc_map_dmabuf,
|
||||
.unmap_dmabuf = vb2_vmalloc_unmap_dmabuf,
|
||||
.attach_dmabuf = vb2_vmalloc_attach_dmabuf,
|
||||
.detach_dmabuf = vb2_vmalloc_detach_dmabuf,
|
||||
.vaddr = vb2_vmalloc_vaddr,
|
||||
.mmap = vb2_vmalloc_mmap,
|
||||
.num_users = vb2_vmalloc_num_users,
|
||||
};
|
||||
|
||||
|
||||
s->vb_queue.ops = &airspy_vb2_ops; // call_qop,call_vb_qop
|
||||
s->vb_queue.mem_ops = &vb2_vmalloc_memops; // call_ptr_memop
|
||||
|
||||
int vb2_queue_init(struct vb2_queue *q)
|
||||
q->buf_ops = &v4l2_buf_ops;
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.1 APP request buf
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_REQBUFS, &rb);
|
||||
--------------------------------
|
||||
v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
|
||||
ops->vidioc_reqbufs(file, fh, p);
|
||||
vb2_ioctl_reqbufs
|
||||
res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count);
|
||||
num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME);
|
||||
num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
|
||||
|
||||
// 给你机会修改num_buffers,num_planes
|
||||
ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, plane_sizes, q->alloc_devs); // airspy_queue_setup
|
||||
|
||||
/* Finally, allocate buffers and video memory */
|
||||
allocated_buffers =
|
||||
__vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
|
||||
ret = __vb2_buf_mem_alloc(vb);
|
||||
call_ptr_memop(vb, alloc,
|
||||
vb2_queue->mem_ops->alloc
|
||||
vb2_vmalloc_alloc
|
||||
buf->vaddr = vmalloc_user(buf->size);
|
||||
ret = call_vb_qop(vb, buf_init, vb);
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.2 queue buffer
|
||||
|
||||
queue buffer关键点:
|
||||
|
||||
* VB2的链表:list_add_tail(&vb->queued_entry, &q->queued_list);
|
||||
* 驱动自己维护的链表:list_add_tail(&buf->list, &s->queued_bufs);
|
||||
|
||||
驱动的URB传输完成后:
|
||||
|
||||
* 从链表queued_bufs取出buffer
|
||||
* 把URB得到的数据填入buffer
|
||||
* 调用vb2_buffer_done:list_add_tail(&vb->done_entry, &q->done_list);
|
||||
|
||||
dequeue buffer关键点:
|
||||
|
||||
* 从链表done_entry取出并移除第1个vb
|
||||
* 把它也从queued_list中移除
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_QBUF, &buf)
|
||||
-------------------------------
|
||||
v4l_qbuf
|
||||
ops->vidioc_qbuf(file, fh, p);
|
||||
vb2_ioctl_qbuf
|
||||
vb2_qbuf(vdev->queue, p);
|
||||
vb2_queue_or_prepare_buf(q, b, "qbuf");
|
||||
vb2_core_qbuf(q, b->index, b);
|
||||
list_add_tail(&vb->queued_entry, &q->queued_list);
|
||||
vb->state = VB2_BUF_STATE_QUEUED;
|
||||
|
||||
/*
|
||||
* If already streaming, give the buffer to driver for processing.
|
||||
* If not, the buffer will be given to driver on next streamon.
|
||||
*/
|
||||
if (q->start_streaming_called)
|
||||
__enqueue_in_driver(vb);
|
||||
/* sync buffers */
|
||||
for (plane = 0; plane < vb->num_planes; ++plane)
|
||||
call_void_memop(vb, prepare, vb->planes[plane].mem_priv);
|
||||
|
||||
call_void_vb_qop(vb, buf_queue, vb);
|
||||
airspy_buf_queue
|
||||
list_add_tail(&buf->list, &s->queued_bufs);
|
||||
|
||||
if (pb)
|
||||
call_void_bufop(q, fill_user_buffer, vb, pb);
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.3 dequeue buf
|
||||
|
||||
```shell
|
||||
ioctl(fd, VIDIOC_DQBUF, &buf)
|
||||
----------------------------------
|
||||
v4l_dqbuf
|
||||
ops->vidioc_dqbuf(file, fh, p);
|
||||
vb2_ioctl_dqbuf
|
||||
vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);
|
||||
ret = vb2_core_dqbuf(q, NULL, b, nonblocking);
|
||||
ret = __vb2_get_done_vb(q, &vb, pb, nonblocking);
|
||||
*vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
|
||||
list_del(&(*vb)->done_entry);
|
||||
call_void_vb_qop(vb, buf_finish, vb);
|
||||
call_void_bufop(q, fill_user_buffer, vb, pb);
|
||||
__vb2_dqbuf(vb);
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.3 stream on
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_STREAMON, &type)
|
||||
------------------------------------
|
||||
v4l_streamon
|
||||
ops->vidioc_streamon(file, fh, *(unsigned int *)arg)
|
||||
vb2_ioctl_streamon
|
||||
vb2_streamon(vdev->queue, i);
|
||||
vb2_core_streamon(q, type);
|
||||
ret = vb2_start_streaming(q);
|
||||
/*
|
||||
* If any buffers were queued before streamon,
|
||||
* we can now pass them to driver for processing.
|
||||
*/
|
||||
list_for_each_entry(vb, &q->queued_list, queued_entry)
|
||||
__enqueue_in_driver(vb);
|
||||
/* sync buffers */
|
||||
for (plane = 0; plane < vb->num_planes; ++plane)
|
||||
call_void_memop(vb, prepare, vb->planes[plane].mem_priv);
|
||||
|
||||
call_void_vb_qop(vb, buf_queue, vb);
|
||||
airspy_buf_queue
|
||||
|
||||
/* Tell the driver to start streaming */
|
||||
q->start_streaming_called = 1;
|
||||
ret = call_qop(q, start_streaming, q, atomic_read(&q->owned_by_drv_count));
|
||||
airspy_start_streaming // 分配提交URB
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.3 stream off
|
||||
|
||||
```c
|
||||
ioctl(fd, VIDIOC_STREAMOFF, &type)
|
||||
-----------------------------------
|
||||
v4l_streamoff
|
||||
ops->vidioc_streamoff(file, fh, *(unsigned int *)arg);
|
||||
vb2_ioctl_streamoff
|
||||
vb2_streamoff(vdev->queue, i);
|
||||
vb2_core_streamoff(q, type);
|
||||
__vb2_queue_cancel(q);
|
||||
call_void_qop(q, stop_streaming, q);
|
||||
airspy_stop_streaming // kill URB
|
||||
|
||||
call_void_vb_qop(vb, buf_finish, vb);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.4 阻塞与唤醒
|
||||
|
||||
#### 4.4.1 阻塞
|
||||
|
||||
```shell
|
||||
memset(fds, 0, sizeof(fds));
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = POLLIN;
|
||||
if (1 == poll(fds, 1, -1))
|
||||
--------------------------------------
|
||||
v4l2_poll
|
||||
res = vdev->fops->poll(filp, poll);
|
||||
vb2_fop_poll
|
||||
res = vb2_poll(vdev->queue, file, wait);
|
||||
vb2_core_poll(q, file, wait);
|
||||
poll_wait(file, &q->done_wq, wait);
|
||||
```
|
||||
|
||||
#### 4.4.2 唤醒
|
||||
|
||||
```shell
|
||||
airspy_urb_complete
|
||||
vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4.6 读写buf
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user