重頭寫一個v4l2的虛擬驅動_2,重頭v4l2虛擬_2

來源:互聯網
上載者:User

重頭寫一個v4l2的虛擬驅動_2,重頭v4l2虛擬_2
簡介

  因為在qcom平台上和linux原生都是用的v4l2架構作為camera的驅動架構,所以本著學習記錄的筆記,做了如下文檔記錄。該文檔是學習《衛東山老師視頻教程第三期》的個人學習筆記,非常感謝老師的資料。該記錄僅供學習交流,如有侵犯到大家利益,還望海涵,請聯絡博主刪除。

buffer隊列操作
  首先是填充了隊列相關的4個函數:
static int myvivi_vidioc_reqbufs(struct file *file, void *priv,        struct v4l2_requestbuffers *p){    return (videobuf_reqbufs(&myvivi_vb_vidqueue, p));} static int myvivi_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p){    return (videobuf_querybuf(&myvivi_vb_vidqueue, p));} static int myvivi_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p){    return (videobuf_qbuf(&myvivi_vb_vidqueue, p));} static int myvivi_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p){    return (videobuf_dqbuf(&myvivi_vb_vidqueue, p,                file->f_flags & O_NONBLOCK));} static int myvivi_vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i){    return videobuf_streamon(&myvivi_vb_vidqueue);} static int myvivi_vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i){    videobuf_streamoff(&myvivi_vb_vidqueue);    return 0;} static const struct v4l2_ioctl_ops myvivi_ioctl_ops = { .................  /* 緩衝區操作: 申請/查詢/放入隊列/取出隊列 */    .vidioc_reqbufs       = myvivi_vidioc_reqbufs,    .vidioc_querybuf      = myvivi_vidioc_querybuf,    .vidioc_qbuf          = myvivi_vidioc_qbuf,    .vidioc_dqbuf         = myvivi_vidioc_dqbuf,     // 啟動/停止    .vidioc_streamon      = myvivi_vidioc_streamon,    .vidioc_streamoff     = myvivi_vidioc_streamoff, }
   這四個隊列相關函數分別用在申請隊列、查詢隊列、放入隊列、取出隊列、啟動和停止的相關buffer資料操作中,都是直接使用的v4l2提供的現成函數

初始化和銷毀buffer隊列
   前面說到了對buffer隊列的操作,操作的隊列為myvivi_vb_vidqueue,那麼在使用它之前,肯定有初始化的操作;在使用完了之後有銷毀的操作。對應的操作函數在:
static struct videobuf_queue myvivi_vb_vidqueue; static int myvivi_open(struct file *file){    /* 隊列操作2: 初始化 */    videobuf_queue_vmalloc_init(&myvivi_vb_vidqueue, &myvivi_video_qops,            NULL, &myvivi_queue_slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,            sizeof(struct videobuf_buffer), NULL, &lock); /* 倒數第3個參數是buffer的頭部大小 */     return 0;} static int myvivi_close(struct file *file){    videobuf_stop(&myvivi_vb_vidqueue);    videobuf_mmap_free(&myvivi_vb_vidqueue);     return 0;} static int myvivi_mmap(struct file *file, struct vm_area_struct *vma){        return videobuf_mmap_mapper(&myvivi_vb_vidqueue, vma);} static const struct v4l2_file_operations myvivi_fops = {                                                                                 .owner      = THIS_MODULE,    .open       = myvivi_open,    .release    = myvivi_close,    .mmap       = myvivi_mmap,    .ioctl      = video_ioctl2, /* V4L2 ioctl handler */};
   在open函數中,利用videobuf_queue_vmalloc_init對myvivi_vb_vidqueue隊列進行了初始化,並且分配了隊列頭的空間大小,和關聯了該隊列的一個相關操作函數myvivi_video_qops。   在close函數中,先停止了myvivi_vb_vidqueue隊列的使用,然後釋放掉它。   在myvivi_mmap函數中,為隊列myvivi_vb_vidqueue分配真正的資料空間,前面的open函數只分配了資料頭的空間。

關聯的myvivi_video_qops
   前面講到在open函數的videobuf_queue_vmalloc_init初始化的時候關聯了一個myvivi_video_qops操作函數。對應的代碼如下:
/* 參考documentations/video4linux/v4l2-framework.txt: *     drivers\media\video\videobuf-core.c  ops->buf_setup   - calculates the size of the video buffers and avoid they to waste more than some maximum limit of RAM; ops->buf_prepare - fills the video buffer structs and calls videobuf_iolock() to alloc and prepare mmaped memory; ops->buf_queue   - advices the driver that another buffer were requested (by read() or by QBUF); ops->buf_release - frees any buffer that were allocated. */ static struct list_head myvivi_vb_local_queue; /* ------------------------------------------------------------------   Videobuf operations   ------------------------------------------------------------------*//* APP調用ioctl VIDIOC_REQBUFS時會導致此函數被調用, * 它重新調整count和size */static int myvivi_buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size){ *size = myvivi_format.fmt.pix.sizeimage; if (0 == *count)*count = 32; return 0;} /* APP調用ioctlVIDIOC_QBUF時導致此函數被調用, * 它會填充video_buffer結構體並調用videobuf_iolock來分配記憶體(只有在V4L2_MEMORY_USERPTR,也就是在使用者空間的應用中開闢時候才會 × 使用它來分配記憶體,這裡是使用的類型為:V4L2_MEMORY_MMAP,在核心空間開闢的,所以不需要使用videobuf_iolock) *  */static int myvivi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,enum v4l2_field field){vb->state = VIDEOBUF_PREPARED; return 0;} /* APP調用ioctl VIDIOC_QBUF時: * 1. 先調用buf_prepare進行一些準備工作 * 2. 把buf放入stream隊列 * 3. 調用buf_queue(起通知、記錄作用) */static void myvivi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){vb->state = VIDEOBUF_QUEUED; /* 把videobuf放入本地一個隊列尾部 */list_add_tail(&vb->queue, &myvivi_vb_local_queue);} /* APP不再使用隊列時, 用它來釋放記憶體 */static void myvivi_buffer_release(struct videobuf_queue *vq,struct videobuf_buffer *vb){videobuf_vmalloc_free(vb);vb->state = VIDEOBUF_NEEDS_INIT;} static struct videobuf_queue_ops myvivi_video_qops = {.buf_setup      = myvivi_buffer_setup, /* 計算大小以免浪費 */.buf_prepare    = myvivi_buffer_prepare,.buf_queue      = myvivi_buffer_queue,.buf_release    = myvivi_buffer_release,};
   myvivi_buffer_setup:用來計算需要分配的資料空間大小和空間的多少,如代碼所示,我們設定的資料空間大小為之前計算出來的image size的大小,                       分配的空間為32個(一般來說分配空間的範圍為2-32個)。   myvivi_buffer_prepare:進行一些qbuffer之前的準備操作,並將隊列狀態改變為VIDEOBUF_PREPARED。   myvivi_buffer_queue:將隊列中的資料放入一個本地隊列中,等待被取走,同時將隊列狀態改變為VIDEOBUF_QUEUED。   myvivi_buffer_release:釋放掉隊列,同時將它狀態改變為初始狀態:VIDEOBUF_NEEDS_INIT。

調用關係
   1、應用程式首先調用了open函數,初始化了videobuf_queue隊列。   2、調用請求隊列操作函數:                myvivi_vidioc_reqbufs-->videobuf_reqbufs(&myvivi_vb_vidqueue, p)      在videobuf_reqbufs函數中又調用了之前在open-->videobuf_queue_vmalloc_init函數中關聯的                myvivi_video_qops-->myvivi_buffer_setup      獲得了需要分配的隊列資料空間大小和空間塊數。   3、調用請求隊列操作函數:                myvivi_vidioc_querybufs-->videobuf_querybuf      在該函數中查詢和返回隊列相關資訊。   4、調用函數:                myvivi_fops-->myvivi_mmap-->videobuf_mmap_mapper      為隊列分配真正的資料空間。   5、叫用作業函數:                myvivi_vidioc_qbufs-->videobuf_qbuf      在函數videobuf_qbuf中又調用到:                myvivi_video_qops-->myvivi_buffer_prepare                myvivi_video_qops-->myvivi_buffer_queue      在函數myvivi_buffer_prepare中進行一些準備工作,然後在myvivi_buffer_queue中將隊列中的資料儲存到本地隊列myvivi_vb_local_queue中。   6、叫用作業函數:                yvivi_vidioc_qbufs-->myvivi_vidioc_dqbuf      在myvivi_vidioc_dqbuf中,清除掉已經使用過了的隊列資料。
   7、利用select/poll機制檢測,讓步驟5和6不斷迴圈,使得video資料不停的重新整理。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.