亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Video4Linux框架簡介(5) - Streaming

2019-11-09 15:14:09
字體:
來源:轉載
供稿:網友

譯注:在前幾節我們介紹了如何初始化v4l2驅動的框架、查詢能力值、設置輸入/視頻標準/格式,但是還沒有真正地傳輸過一幀數據。

萬事俱備,只欠東風,本節將會重點介紹"流媒體"中的數據流。

流模式,數據流主要通過如下幾種方式進行傳輸:

●read/write接口:這種的基本比較少用。

●內存映射流 I / O:驅動程序分配的內存,mmap()到用戶空間。

●用戶指針流 I / O:由用戶空間分配的內存,由于用戶空間的內存可能是零散的,只在虛擬空間上連續,因此需要分散 - 聚集DMA支持。

●DMABUF流 I / O:由另一個設備驅動分配的內存,導出為DMABUF文件處理程序并在此驅動程序中導入。

本例子使用的是第二種,驅動程序分配內存。

#include <media/videobuf2-dma-contig.h>         // 處理videobuf需添加的頭文件一共有三種,該頭文件代表使用的dma內存是連續的						//   離散dma使用  videobuf2-dma-sg.h,用戶空間內存使用 videobuf2-vmalloc.h struct skeleton {...struct vb2_queue queue;  //video buffer放置在該隊列中struct vb2_alloc_ctx *alloc_ctx; //用于分配內存的上下文spinlock_t ; //用于streaming的同步,和核心鎖配合使用struct list_head buf_list;unsigned int sequence;  //可以認為是幀號};struct skel_buffer {  //本地用于管理buffer的結構體struct vb2_buffer vb;struct list_head list;};static inline struct skel_buffer *to_skel_buffer(struct vb2_buffer *vb2){return container_of(vb2, struct skel_buffer, vb);}

/* 處理videobuf需添加的頭文件一共有三種,該頭 * 文件代表使用的dma內存是連續的離散dma使用 *  videobuf2-dma-sg.h,用戶空間內存使用  * videobuf2-vmalloc.h */ #include <media/videobuf2-dma-contig.h>     struct skeleton {...struct vb2_queue queue;  //video buffer放置在該隊列中struct vb2_alloc_ctx *alloc_ctx; //用于分配內存的上下文spinlock_t ; //用于streaming的同步,和核心鎖配合使用struct list_head buf_list;unsigned int sequence;  //可以認為是幀號};struct skel_buffer {  //本地用于管理buffer的結構體struct vb2_buffer vb;struct list_head list;};static inline struct skel_buffer *to_skel_buffer(struct vb2_buffer *vb2){return container_of(vb2, struct skel_buffer, vb);}

從上述代碼可以看出,在原有的skeleton結構體中需要添加一系列的成員以外,還需要skel_buffer用于本地管理內存。

static int skeleton_PRobe(struct pci_dev *pdev, const struct pci_device_id *ent){...q = &skel->queue;q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //代表是視頻捕獲設備,也就是Cameraq->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;q->drv_priv = skel;q->buf_struct_size = sizeof(struct skel_buffer);q->ops = &skel_qops;  /* Required ops for USERPTR types: get_userptr, put_userptr.   * Required ops for MMAP types: alloc, put, num_users, mmap.   * Required ops for read/write access types: alloc, put, num_users, vaddr   * Required ops for DMABUF types: attach_dmabuf, detach_dmabuf, map_dmabuf,   *                unmap_dmabuf.    *   get more in videobuf2-core.h   */q->mem_ops = &vb2_dma_contig_memops; //使用v4l2框架的內存申請操作,開發者也可以根據系統情況自行定義                                                                                                    q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;q->lock = &skel->lock;q->gfp_flags = GFP_DMA32; //系統支持32位dmaret = vb2_queue_init(q);if (ret)goto v4l2_dev_unreg;skel->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); //三種內存類型中只有dma連續內存需要                                                       //alloc_ctxif (IS_ERR(skel->alloc_ctx)) {dev_err(&pdev->dev, "Can't allocate buffer context");ret = PTR_ERR(skel->alloc_ctx);goto v4l2_dev_unreg;}INIT_LIST_HEAD(&skel->buf_list);spin_lock_init(&skel->qlock);...vdev->queue = q;...}以下這些都根據需要,驅動可以使用v4l2框架的實現或者自行實現。

static struct vb2_ops skel_qops = {.queue_setup = queue_setup,                             //在內存分配之前從VIDIOC_REQBUFS和VIDIOC_CREATE_BUFS處理程序調用,                                                        //如果* num_planes!= 0,在分配后驗證較少數量的buffer。驅動程序							//應該返回* num_buffers中所需的buffer數量以及* num_planes中每個buffer							//所需的planar數量;每個planar的大小應該在alloc_ctxs[] 數組中的sizes []數							//組和可選的每平面分配器特定上下文中設置。當從VIDIOC_REQBUFS,							// fmt == NULL調用時,驅動程序必須使用當前配置的格式,* num_buffers							//是正在分配的buffer總數。當從VIDIOC_CREATE_BUFS,fmt!= NULL調用時,							//它描述目標幀格式。在這種情況下,* num_buffers另外被分配到q-> num_buffers。.buf_prepare = buffer_prepare,                          //每次buffer從用戶空間queue入和VIDIOC_PREPARE_BUF ioctl時調用;驅動程序可以							//在該回調中的硬件操作之前執行任何初始化;如果返回錯誤,則buffer不							//會在驅動程序中排隊;.buf_queue = buffer_queue,                              //傳遞buffer vb到驅動程序;驅動器可以在該buffer上開始硬件操作;驅動程序							//應該通過調用vb2_buffer_done()函數返回buffer;它調用STREAMON ioctl之							//后被調用;如果在調用STREAMON之前用戶預排隊buffer,可能在start_streaming							//回調之前調用.start_streaming = start_streaming,                     //只需調用一次進入“流”狀態;驅動程序可以在調用@start_streaming之前						        //接收帶有@buf_queue回調的buffer;驅動程序在count參數中獲取已排隊							//buffer的數量;驅動程序可能會返回錯誤,如果硬件失敗或沒有足夠的							//已排隊buffer,在這種情況下,所有已經由@buf_queue回調給出的buffer無效。.stop_streaming = stop_streaming,                       //當'streaming'狀態必須被禁用時調用;驅動程序應停止任何DMA事務或等待,							//直到它們完成并返回它從buf_queue()獲得的所有buffer.wait_prepare = vb2_ops_wait_prepare,                   //釋放調用vb2函數時發生的任何鎖;因此有些驅動直接就命名為XXX_unlock;							//它在ioctl需要等待新的buffer到達之前被調用;需要避免阻塞訪問類型中的死鎖.wait_finish = vb2_ops_wait_finish,                     //重新獲取在wait_prepare中釋放的所有鎖;等待新的buffer到達后需要在繼續休眠前的操作};static const struct v4l2_ioctl_ops skel_ioctl_ops = {....vidioc_reqbufs = vb2_ioctl_reqbufs,.vidioc_querybuf = vb2_ioctl_querybuf,.vidioc_qbuf = vb2_ioctl_qbuf,.vidioc_dqbuf = vb2_ioctl_dqbuf,.vidioc_streamon = vb2_ioctl_streamon,.vidioc_streamoff = vb2_ioctl_streamoff,};static const struct v4l2_file_Operations skel_fops = {.owner = THIS_MODULE,.open = v4l2_fh_open,.release = vb2_fop_release,.unlocked_ioctl = video_ioctl2,.read = vb2_fop_read,.mmap = vb2_fop_mmap,.poll = vb2_fop_poll,};
static int queue_setup(struct vb2_queue *vq,const struct v4l2_format *fmt,unsigned int *nbuffers,unsigned int *nplanes,unsigned int sizes[],void *alloc_ctxs[]){struct skeleton *skel = vb2_get_drv_priv(vq);if (*nbuffers < 3)*nbuffers = 3;*nplanes = 1;sizes[0] = skel->format.sizeimage;alloc_ctxs[0] = skel->alloc_ctx;return 0;}
static int start_streaming(struct vb2_queue *vq, unsigned int count){struct skeleton *skel = vb2_get_drv_priv(vq);if (count < 2)              //這里控制在啟流前需要queue入buffer的最小個數return -ENOBUFS;skel->sequence = 0;/* TODO: start DMA */return 0;}static int stop_streaming(struct vb2_queue *vq){struct skeleton *skel = vb2_get_drv_priv(vq);struct skel_buffer *buf, *node;unsigned long flags;/* TODO: stop DMA *//* Release all active buffers */spin_lock_irqsave(&skel->qlock, flags);list_for_each_entry_safe(buf, node, &skel->buf_list, list) {vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);list_del(&buf->list);}spin_unlock_irqrestore(&skel->qlock, flags);return 0;}
static int buffer_prepare(struct vb2_buffer *vb){struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);unsigned long size = skel->format.sizeimage;if (vb2_plane_size(vb, 0) < size) {dev_err(&skel->pdev->dev, "buffer too small (%lu < %lu)/n",vb2_plane_size(vb, 0), size);return -EINVAL;}vb2_set_plane_payload(vb, 0, size);vb->v4l2_buf.field = skel->format.field;return 0;}static void buffer_queue(struct vb2_buffer *vb){struct skeleton *skel = vb2_get_drv_priv(vb->vb2_queue);struct skel_buffer *buf = to_skel_buffer(vb);unsigned long flags;spin_lock_irqsave(&skel->qlock, flags);list_add_tail(&buf->list, &skel->buf_list);/* TODO: Update any DMA pointers if necessary */spin_unlock_irqrestore(&skel->qlock, flags);}

在buffer被DMA填充后的中斷處理函數:
static irqreturn_t skeleton_irq(int irq, void *dev_id){struct skeleton *skel = dev_id;/* TODO: handle interrupt */if (captured_new_frame) {...spin_lock(&skel->qlock);list_del(&new_buf->list);spin_unlock(&skel->qlock);new_buf->vb.v4l2_buf.sequence = skel->sequence++;v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp);vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE);}return IRQ_HANDLED;}

最后,在如下函數中

skeleton_s_input()

skeleton_s_std()

skeleton_s_dv_timings()

skeleton_s_fmt_vid_cap() 

增加這項檢查:

if(vb2_is_busy(&skel->queue))

return-EBUSY;


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲成人久久网| 精品久久久久久中文字幕| 久久夜色精品亚洲噜噜国产mv| 97视频免费在线看| 一区二区日韩精品| 欧美巨乳在线观看| 国产精品九九九| 亚洲一区999| 亚洲日韩中文字幕在线播放| 亚洲人成在线播放| 亚洲电影在线看| 亚洲国产精彩中文乱码av| 欧美精品18videos性欧美| 欧美激情国产精品| 亚洲人成免费电影| 欧美精品在线观看91| 日韩精品高清在线观看| 欧美性生活大片免费观看网址| 中文字幕一精品亚洲无线一区| 国产精品久久久久99| 成人免费网视频| 亚洲欧美日韩中文视频| 亚洲护士老师的毛茸茸最新章节| 日韩精品极品在线观看播放免费视频| 丝袜一区二区三区| 日韩电影中文字幕一区| 正在播放欧美一区| 国产精品久久久久久久久久久久久久| 2021久久精品国产99国产精品| 国产精品第三页| 欧美精品免费在线观看| 中文字幕不卡在线视频极品| 日韩精品亚洲视频| 日韩亚洲精品电影| 欧美激情a在线| 日韩风俗一区 二区| 日韩亚洲在线观看| 中文字幕国产精品| 丰满岳妇乱一区二区三区| 亚洲人高潮女人毛茸茸| 26uuu亚洲伊人春色| 亚洲精品美女在线观看播放| 国产午夜精品视频| 成人精品视频99在线观看免费| 欧美高清视频在线| 国产欧美日韩91| 欧美激情一区二区三级高清视频| 这里只有视频精品| 懂色av影视一区二区三区| 91在线观看免费高清完整版在线观看| 亚洲第一视频网站| 久久久噜噜噜久久| 亚洲欧美变态国产另类| 国产色婷婷国产综合在线理论片a| 久久夜精品香蕉| 欧美激情二区三区| 欧美高清在线视频观看不卡| 午夜精品久久久久久99热软件| 国产精品ⅴa在线观看h| 国产日韩欧美综合| 欧美国产中文字幕| 欧美成人激情视频免费观看| 亚洲欧美日韩国产精品| 国产亚洲视频在线| 26uuu久久噜噜噜噜| 日韩高清欧美高清| 91九色国产在线| 亚洲国产精品99久久| 日韩视频免费观看| 操日韩av在线电影| 精品视频在线播放免| 国产日韩欧美中文在线播放| 亚洲永久免费观看| 亚洲一区二区三区乱码aⅴ蜜桃女| 国产精品美女999| 精品调教chinesegay| 精品久久香蕉国产线看观看亚洲| 亚洲视频在线免费观看| 日韩欧美在线网址| 国产精品国产三级国产aⅴ9色| 久久天天躁狠狠躁夜夜躁| 亚洲精品少妇网址| 欧美性xxxx18| 91精品久久久久久久久中文字幕| 8x海外华人永久免费日韩内陆视频| 久久天天躁狠狠躁老女人| 亚洲片国产一区一级在线观看| 亚洲www永久成人夜色| 国产69久久精品成人看| 性欧美xxxx视频在线观看| 日韩在线视频免费观看| 在线观看免费高清视频97| 国产精品免费小视频| 亚洲无线码在线一区观看| 亚洲人成在线观看| 亚洲欧美日韩久久久久久| 中文字幕国产亚洲| 亚洲理论在线a中文字幕| 精品调教chinesegay| 啊v视频在线一区二区三区| 亚洲最新av在线网站| 91香蕉嫩草神马影院在线观看| 欧美性猛交xxxx偷拍洗澡| 亚洲欧美成人网| 国产精品69精品一区二区三区| 在线看日韩av| 日韩在线观看免费全集电视剧网站| 欧美日韩一区免费| 91在线看www| 久久亚洲精品一区二区| 97超级碰碰人国产在线观看| 国产精品爱啪在线线免费观看| 成人激情在线观看| 久久久久久噜噜噜久久久精品| 日本久久久久久久久| 91精品综合久久久久久五月天| 国产视频精品一区二区三区| 国内精久久久久久久久久人| 在线不卡国产精品| 日韩精品免费在线观看| 国产成人精品日本亚洲专区61| 91精品国产乱码久久久久久久久| 日韩电影在线观看免费| 久久精品小视频| 欧美男插女视频| 这里只有精品在线观看| 欧美午夜精品久久久久久久| 久久久之久亚州精品露出| 久久精品一本久久99精品| 最新中文字幕亚洲| 中文字幕精品—区二区| 国产精自产拍久久久久久蜜| 伦伦影院午夜日韩欧美限制| 国产亚洲精品久久久久久| 中文字幕亚洲一区在线观看| 国产精品海角社区在线观看| 欧美一级视频免费在线观看| 91国产精品91| 中文字幕视频在线免费欧美日韩综合在线看| 国产在线不卡精品| 久久久久成人网| 91在线高清视频| 欧美日韩中文字幕在线视频| 在线色欧美三级视频| 久久精品亚洲一区| 成人黄色免费网站在线观看| 亚洲精品不卡在线| 亚洲人成网站色ww在线| 亚洲一二在线观看| 日韩av电影免费观看高清| 欧美视频国产精品| 日韩精品高清在线观看| 黄色成人av网| 亚洲免费福利视频| 国产精品男人的天堂| 亚洲精品97久久| 国产97在线播放| 日韩av成人在线观看| 在线观看精品自拍私拍| 人人澡人人澡人人看欧美| 中文字幕国内精品| 38少妇精品导航| 久久国产精品免费视频| 欧美在线观看日本一区|