結合芯片exynos 4412介紹V4L2用來視頻編解碼的驅動

這裏結合芯片exynos 4412介紹一下V4L2用來視頻編解碼的驅動結構
內核代碼基於3.4.106
 linux-3.4.106\drivers\media\video\s5p-mfc
 linux-3.4.106\drivers\media\video

1,V4L2結構




2,幾個主要接口
主要接口(ioctl下面的一層)
vidioc_qbuf
vidioc_dqbuf
vidioc_reqbufs
vidioc_s_fmt


3,主要數據結構
struct vb2_queue
struct v4l2_buffer
struct s5p_mfc_ctx
struct vb2_buffer



4,接口調用鏈

V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE是未解碼數據,存放ES流數據
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE是已經解碼數據,存放frame data buffer

v4l2_qbuf流程





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,





5,內存管理方式


主要隊列:
分爲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])    這裏申請的內存,存放解嗎前的數據



初始化分配 out 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]) 這裏申請的內存,存放解碼完的數據


分配buffer給mfc用

vidioc_reqbufs---s5p_mfc_alloc_codec_buffers---vb2_dma_contig_alloc //分配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



有效數據存在哪裏?

解碼前的和解碼後的,都在vb->planes[plane].mem_priv裏面,這個mem_priv是struct vb2_dc_buf ,裏面記錄了這塊DMA內存的虛擬地址和物理地址,都是在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的時候記錄好的。
然後這些內存的物理地址,在vidioc_reqbufs----vb2_reqbufs----__vb2_queue_alloc(掛到q->bufs)--> call_qop(q, buf_init, vb);--->s5p_mfc_buf_init時候,賦給了ctx->dst_bufs[i].cookie.raw.luma (解碼後)   ctx->dst_bufs[i].cookie.raw.chroma(解碼後)    ctx->src_bufs[i].cookie.stream ,(解碼前)
然後這些地址,在s5p_mfc_set_dec_stream_buffer   ,s5p_mfc_set_dec_frame_buffer時候寫進了寄存器,告訴MFC具體地址




Mmap/ querybuf
s5p_mfc_mmap通過 (offset 與 DST_QUEUE_OFF_BASE)來判斷是vq_src還是vq_dst ,這個offset是querybuf的時候填上buf->m.planes[i].m.mem_offset的。
buf->m.planes[i].m.mem_offset 是__vb2_queue_alloc裏面__setup_offsets的時候,爲每個plane的內存寫上的vb->v4l2_planes[plane].m.mem_offset = off;  這個mem_offset實際上沒什麼用。實際上就是個標誌位。就是爲了mmap的時候能通過這個mem_offset找到每個plane的內存__find_plane_by_offset
這樣s5p_mfc_mmap裏面通過這個offset判斷是ctx->vq_src還是ctx->vq_dst,然後調用vb2_mmap,通過__find_plane_by_offset找到對應vb2_buffer和vb2_buffer裏面的plane,然後通過相應的vb->planes[plane].mem_priv,就可以調用vb2_dma_contig_mmap---remap_pfn_range調用標準內核API來mmap了
實際上整個mmap的過程就是找到對應的buffer和plane,一個個的mmap的



6 ,編解碼參數設置在那裏?


vidioc_s_fmt裏面通過fmt = find_format(f, MFC_FMT_DEC);找到static struct s5p_mfc_fmt formats[]裏面對應的要解碼的格式,然後對struct s5p_mfc_ctx *ctx進行賦值,以便後面使用


V4L2最終要通過對MFC的寄存器讀寫來控制解碼過程

1,啓動需要操作的寄存器
MFC poweron 
clk
載入固件
重啓MFC
判斷固件版本
爲兩個plane分配內存
初始化各種等待,以及數據隊列


2,開始播放需要的寄存器

s5p_mfc_run_init_dec
分配一個tmp buffer,給MFC用
設置sharememory
設置slice,delay之類的
設置第一幀
 
3,播放一幀:
s5p_mfc_run_dec_frame
設置ES流數據的地址和size
告訴MFC哪些buffer不能用
設置第一幀還是中間真還是最後一針























發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章