这里结合芯片exynos 4412介绍一下V4L2用来视频编解码的驱动结构
内核代码基于3.4.106
linux-3.4.106\drivers\media\video\s5p-mfc
linux-3.4.106\drivers\media\video
1,V4L2结构
vidioc_qbuf--vb2_qbuf
--- __enqueue_in_driver
---- q->ops->buf_queue(vb);
---- s5p_mfc_buf_queue
---- list_add_tail(&mfc_buf->list, &ctx->dst_queue);
---- s5p_mfc_try_run
v4l2_dqbuf流程
s5p_mfc_irq
--- s5p_mfc_handle_frame
--- s5p_mfc_handle_frame_new
--- vb2_buffer_done
--- wake_up(&q->done_wq);
---- list_add_tail(&vb->done_entry, &q->done_list); 把解出来的一帧挂上队列
vidioc_dqbuf
--- vb2_dqbuf
--- __vb2_get_done_vb
--- __vb2_wait_for_done_vb(查找是否有可用的vb)
--- wait_event_interruptible(q->done_wq,
主要队列:
分为capture plane(解码后)和output plane(解码前)
从另外一个维度看,
每个plane都有一个done_list队列,表示解码完比的,不用的ES buffer,或者存有有效YUV数据的Frame data buffer,用户态dqbuffer就从这里面取
每个plane都有一个另外的queue队列,表示要解码的ES buffer,或者已经显示完毕的YUV数据的Frame data buffer,用户态qbuffer就从这里取
v4l2-core操作的是vb2-buffer, 这只是个handle而已,实际给MFC的是5p_mfc_buf , 这两种buffer通过v4l2-buffer里面的index来对应起来
初始化分配 input buffer:
vidioc_reqbufs
----vb2_reqbufs
----__vb2_queue_alloc(挂到q->bufs)
---__vb2_buf_mem_alloc
---- call_memop(q, alloc, q->alloc_ctx[plane]
----vb2_dma_contig_alloc
----dma_alloc_coherent分配dmabuffer
---- call_qop(q, buf_init, vb);
--- s5p_mfc_buf_init(相关信息填充到 ctx->src_bufs[i]) 这里申请的内存,存放解吗前的数据
vidioc_reqbufs
----vb2_reqbufs
----__vb2_queue_alloc(挂到q->bufs)
---__vb2_buf_mem_alloc
---- call_memop(q, alloc, q->alloc_ctx[plane]
--- vb2_dma_contig_alloc
----dma_alloc_coherent分配dmabuffer
---- call_qop(q, buf_init, vb);
---s5p_mfc_buf_init(相关信息填充到 ctx->src_bufs[i]) 这里申请的内存,存放解码完的数据
分配buffer给mfc用
s5p_mfc_irq
---s5p_mfc_handle_seq_done
---s5p_mfc_try_run
----s5p_mfc_set_dec_frame_buffer
---mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),S5P_FIMV_DEC_CHROMA_ADR + i * 4);
把所有out buffer的地址写进MFC---s5p_mfc_set_dec_stream_buffer
---把此次要解码的原始数据in buffer地址写进MFC
V4L2最终要通过对MFC的寄存器读写来控制解码过程
1,启动需要操作的寄存器2,开始播放需要的寄存器
s5p_mfc_run_init_dec