国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Video4Linux框架簡介(5) - Streaming

2019-11-09 14:13:09
字體:
供稿:網(wǎng)友

譯注:在前幾節(jié)我們介紹了如何初始化v4l2驅(qū)動(dòng)的框架、查詢能力值、設(shè)置輸入/視頻標(biāo)準(zhǔn)/格式,但是還沒有真正地傳輸過一幀數(shù)據(jù)。

萬事俱備,只欠東風(fēng),本節(jié)將會(huì)重點(diǎn)介紹"流媒體"中的數(shù)據(jù)流。

流模式,數(shù)據(jù)流主要通過如下幾種方式進(jìn)行傳輸:

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

●內(nèi)存映射流 I / O:驅(qū)動(dòng)程序分配的內(nèi)存,mmap()到用戶空間。

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

●DMABUF流 I / O:由另一個(gè)設(shè)備驅(qū)動(dòng)分配的內(nèi)存,導(dǎo)出為DMABUF文件處理程序并在此驅(qū)動(dòng)程序中導(dǎo)入。

本例子使用的是第二種,驅(qū)動(dòng)程序分配內(nèi)存。

#include <media/videobuf2-dma-contig.h>         // 處理videobuf需添加的頭文件一共有三種,該頭文件代表使用的dma內(nèi)存是連續(xù)的						//   離散dma使用  videobuf2-dma-sg.h,用戶空間內(nèi)存使用 videobuf2-vmalloc.h struct skeleton {...struct vb2_queue queue;  //video buffer放置在該隊(duì)列中struct vb2_alloc_ctx *alloc_ctx; //用于分配內(nèi)存的上下文spinlock_t ; //用于streaming的同步,和核心鎖配合使用struct list_head buf_list;unsigned int sequence;  //可以認(rèn)為是幀號(hào)};struct skel_buffer {  //本地用于管理buffer的結(jié)構(gòu)體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內(nèi)存是連續(xù)的離散dma使用 *  videobuf2-dma-sg.h,用戶空間內(nèi)存使用  * videobuf2-vmalloc.h */ #include <media/videobuf2-dma-contig.h>     struct skeleton {...struct vb2_queue queue;  //video buffer放置在該隊(duì)列中struct vb2_alloc_ctx *alloc_ctx; //用于分配內(nèi)存的上下文spinlock_t ; //用于streaming的同步,和核心鎖配合使用struct list_head buf_list;unsigned int sequence;  //可以認(rèn)為是幀號(hào)};struct skel_buffer {  //本地用于管理buffer的結(jié)構(gòu)體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結(jié)構(gòu)體中需要添加一系列的成員以外,還需要skel_buffer用于本地管理內(nèi)存。

static int skeleton_PRobe(struct pci_dev *pdev, const struct pci_device_id *ent){...q = &skel->queue;q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //代表是視頻捕獲設(shè)備,也就是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框架的內(nèi)存申請(qǐng)操作,開發(fā)者也可以根據(jù)系統(tǒng)情況自行定義                                                                                                    q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;q->lock = &skel->lock;q->gfp_flags = GFP_DMA32; //系統(tǒng)支持32位dmaret = vb2_queue_init(q);if (ret)goto v4l2_dev_unreg;skel->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); //三種內(nèi)存類型中只有dma連續(xù)內(nèi)存需要                                                       //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;...}以下這些都根據(jù)需要,驅(qū)動(dòng)可以使用v4l2框架的實(shí)現(xiàn)或者自行實(shí)現(xiàn)。

static struct vb2_ops skel_qops = {.queue_setup = queue_setup,                             //在內(nèi)存分配之前從VIDIOC_REQBUFS和VIDIOC_CREATE_BUFS處理程序調(diào)用,                                                        //如果* num_planes!= 0,在分配后驗(yàn)證較少數(shù)量的buffer。驅(qū)動(dòng)程序							//應(yīng)該返回* num_buffers中所需的buffer數(shù)量以及* num_planes中每個(gè)buffer							//所需的planar數(shù)量;每個(gè)planar的大小應(yīng)該在alloc_ctxs[] 數(shù)組中的sizes []數(shù)							//組和可選的每平面分配器特定上下文中設(shè)置。當(dāng)從VIDIOC_REQBUFS,							// fmt == NULL調(diào)用時(shí),驅(qū)動(dòng)程序必須使用當(dāng)前配置的格式,* num_buffers							//是正在分配的buffer總數(shù)。當(dāng)從VIDIOC_CREATE_BUFS,fmt!= NULL調(diào)用時(shí),							//它描述目標(biāo)幀格式。在這種情況下,* num_buffers另外被分配到q-> num_buffers。.buf_prepare = buffer_prepare,                          //每次buffer從用戶空間queue入和VIDIOC_PREPARE_BUF ioctl時(shí)調(diào)用;驅(qū)動(dòng)程序可以							//在該回調(diào)中的硬件操作之前執(zhí)行任何初始化;如果返回錯(cuò)誤,則buffer不							//會(huì)在驅(qū)動(dòng)程序中排隊(duì);.buf_queue = buffer_queue,                              //傳遞buffer vb到驅(qū)動(dòng)程序;驅(qū)動(dòng)器可以在該buffer上開始硬件操作;驅(qū)動(dòng)程序							//應(yīng)該通過調(diào)用vb2_buffer_done()函數(shù)返回buffer;它調(diào)用STREAMON ioctl之							//后被調(diào)用;如果在調(diào)用STREAMON之前用戶預(yù)排隊(duì)buffer,可能在start_streaming							//回調(diào)之前調(diào)用.start_streaming = start_streaming,                     //只需調(diào)用一次進(jìn)入“流”狀態(tài);驅(qū)動(dòng)程序可以在調(diào)用@start_streaming之前						        //接收帶有@buf_queue回調(diào)的buffer;驅(qū)動(dòng)程序在count參數(shù)中獲取已排隊(duì)							//buffer的數(shù)量;驅(qū)動(dòng)程序可能會(huì)返回錯(cuò)誤,如果硬件失敗或沒有足夠的							//已排隊(duì)buffer,在這種情況下,所有已經(jīng)由@buf_queue回調(diào)給出的buffer無效。.stop_streaming = stop_streaming,                       //當(dāng)'streaming'狀態(tài)必須被禁用時(shí)調(diào)用;驅(qū)動(dòng)程序應(yīng)停止任何DMA事務(wù)或等待,							//直到它們完成并返回它從buf_queue()獲得的所有buffer.wait_prepare = vb2_ops_wait_prepare,                   //釋放調(diào)用vb2函數(shù)時(shí)發(fā)生的任何鎖;因此有些驅(qū)動(dòng)直接就命名為XXX_unlock;							//它在ioctl需要等待新的buffer到達(dá)之前被調(diào)用;需要避免阻塞訪問類型中的死鎖.wait_finish = vb2_ops_wait_finish,                     //重新獲取在wait_prepare中釋放的所有鎖;等待新的buffer到達(dá)后需要在繼續(xù)休眠前的操作};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的最小個(gè)數(shù)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填充后的中斷處理函數(shù):
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;}

最后,在如下函數(shù)中

skeleton_s_input()

skeleton_s_std()

skeleton_s_dv_timings()

skeleton_s_fmt_vid_cap() 

增加這項(xiàng)檢查:

if(vb2_is_busy(&skel->queue))

return-EBUSY;


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 延津县| 宁阳县| 平陆县| 祁东县| 大英县| 景泰县| 雷波县| 油尖旺区| 灯塔市| 平潭县| 井冈山市| 扶风县| 任丘市| 斗六市| 丹凤县| 县级市| 长汀县| 白山市| 遵化市| 嘉定区| 千阳县| 高邮市| 平武县| 兴和县| 淅川县| 锦州市| 新余市| 清远市| 南充市| 邓州市| 白山市| 遵义市| 同心县| 西城区| 兴隆县| 惠安县| 上林县| 舞阳县| 泸西县| 聂拉木县| 筠连县|