1. 内核文档: V4L2-framework.txt
  2.  
  3. UVC:usb video controll
  4. UVC驱动框架:
  5.  
  6. system call: open read write
  7.  
  8. -------------------------------------------------
  9.  
  10. 核心层:
  11. source: v4l2_dev.c
  12. struct: v4l2_device
  13. operation: .分配 file_operations (v4l2_file_operations)
  14. .设置 file_operations (v4l2_file_operations)
  15. .注册 .cdev_alloc
  16. .cdev->ops = v4l2_file_operations
  17. .cdev_add
  18. ----------------------------------------------------
  19.  
  20. 硬件层:
  21. source: uvc_driver.c
  22. struct: video_device
  23. operation: .初始化 v4l2_driver_register
  24. .分配 video_device_alloc
  25. .设置 video_device
  26. .注册 video_register_device
  27.  
  28. ----------------------------------------------------
  29.  
  30. 如何写一个v4l2驱动:
  31. .分配,设置,注册 v4l2_device
  32. .分配 video_device
  33. .设置
  34. . 将自己的video_devicev4l2核心层连接起来
  35. video_device->v4l2_dev = v4l2_device
  36. . 设置自己的video_devicefops操作函数
  37. video_device->fops = xxx_fops
  38. video_device->ioctl_ops = xxx_ioctl
  39. . 设置自己的video_devicev4l2_ctrl_handler,并提交给核心层
  40. .v4l2_ctrl_handler_init
  41. .v4l2_ctrl_new_std
  42. v4l2_ctrl_new_custom
  43. .v4l2_device->ctr_handler = v4l2_ctrl_handler
  44.  
  45. vivi.c 驱动框架分析:
  46.  
  47. ---------------------------------------------------------------
  48. 核心层:
  49. source: v4l2_dev.c
  50. struct: v4l2_device
  51. v4l2_ops(file_operations)
  52.  
  53. ----------------------------------------------------------------
  54. 设备层:
  55. source: uvc_driver.c
  56. struct: video_device
  57.  
  58. -----------------------------------------------------------------
  59. 虚拟设备层:
  60. source: vivi.c
  61. struct: vivi_dev
  62. vivi_ops(v4l2_file_operations)
  63. vivi_ioctl_ops(v4l2_ioctl_ops)
  64.  
  65. ----------------------------------------------------------------
  66.  
  67. 应用程序开启摄像头,驱动ioctl被调用流程:
  68.  
  69. //可以省略的ioctl
  70. . ioctl(VIDIOC_G_FMT)
  71. . for() ioctl(VIDIOC_ENUM_FMT)
  72. . ioctl(VIDIOC_QUERYCAP) // 列举性能
  73. . ioctl(VIDIOC_G_INPUT) // 获得当前使用输入源
  74. . ioctl(VIDIOC_ENUMINPUT) // 列举输入源
  75. . ioctl(VIDIOC_QUERYCTRL) // 查询属性,比如亮度、对比度
  76. . ioctl(VIDIOC_QUERYCAP)
  77. . ioctl(VIDIOC_ENUMINPUT)
  78.  
  79. // 打开设备节点
  80. . fd = open
  81. . ioctl(fd,VIDIOC_QUERYCAP)
  82.  
  83. // 获得设备容量
  84. . for() ioctl(VIDIOC_ENUMINPUT) // 列举输入源,VIDIOC_ENUMINPUT/VIDIOC_G_INPUT/VIDIOC_S_INPUT不是必需的
  85. . for() ioctl(VIDIOC_ENUMSTD) // 列举标准(制式), 不是必需的
  86. . for() ioctl(VIDIOC_ENUM_FMT) // 列举格式
  87. . ioctl(VIDIOC_G_PARM)
  88. . for() ioctl(VIDIOC_QUERYCTRL) // 查询属性(比如说亮度值最小值、最大值、默认值)
  89.  
  90. // 读取属性
  91. . ioctl(VIDIOC_G_STD) // 获得当前使用的标准(制式), 不是必需的
  92. . ioctl(VIDIOC_G_INPUT)
  93. . ioctl(VIDIOC_G_CTRL ) // 获得当前属性, 比如亮度是多少
  94. . ioctl(VIDIOC_TRY_FMT) // 试试能否支持某种格式
  95. . ioctl(VIDIOC_S_FMT) // 设置摄像头使用某种格式
  96.  
  97. // 启动摄像头 streamon
  98. . ioctl(VIDIOC_REQBUFS ) // 请求系统分配缓冲区
  99. . for() ioctl(VIDIOC_QUERYBUF) // 查询所分配的缓冲区
  100. mmap()
  101. . for() ioctl(VIDIOC_QBUF) // 把缓冲区放入队列
  102. . ioctl(VIDIOC_STREAMON) // 启动摄像头
  103.  
  104. // 设置属性
  105. . for () ioctl(VIDIOC_S_CTRL) // 设置属性
  106. ioctl(VIDIOC_S_INPUT ) // 设置输入源
  107. ioctl(VIDIOC_S_STD) // 设置标准(制式), 不是必需的
  108.  
  109. // 不断地读取缓冲区数据 v4l2_nextframe > v4l2_waiton
  110. . v4l2_queue_all
  111. v4l2_waiton
  112. for ()
  113. {
  114. select(, [], NULL, NULL, {, }) = (in [], left {, })
  115. ioctl(, VIDIOC_DQBUF // de-queue, 把缓冲区从队列中取出
  116. // 处理, 之以已经通过mmap获得了缓冲区的地址, 就可以直接访问数据
  117. ioctl(, VIDIOC_QBUF // 把缓冲区放入队列
  118. }
  119.  
  120. 应用程序读取缓冲区数据流程:
  121.  
  122. .请求分配缓冲区 ==>vidioc_reqbufs
  123. .查询映射缓冲区 ==>vidioc_querybuf (mmap)
  124. .把缓冲区加入队列 ==>vidioc_qbuf
  125. .启动摄像头 ==>vidioc_streamon
  126. .select查村是否有数据 ==>select
  127. .队列取出缓冲区数据 ==>vidioc_dqbu
  128.  
  129. 摄像头数据的读取过程:
  130.  
  131. . 请求分配缓冲区:
  132. ioctl(VIDIOC_REQBUFS) // 请求系统分配缓冲区
  133. videobuf_reqbufs(buf_queue, v4l2_requestbuffers) // buf_queue在open函数用videobuf_queue_vmalloc_init初始化
  134. // 注意:这个ioctl只是分配缓冲区的头部信息,真正的缓存还没有分配呢
  135.  
  136. . 查询映射缓冲区:
  137. ioctl(VIDIOC_QUERYBUF) // 查询所分配的缓冲区
  138. videobuf_querybuf // 获得缓冲区的数据格式、大小、每一行长度、高度
  139. mmap(参数里有"大小") // 在这里才分配缓存
  140. v4l2_mmap
  141. vivi_mmap
  142. videobuf_mmap_mapper
  143. videobuf-vmalloc.c里的__videobuf_mmap_mapper
  144. mem->vmalloc = vmalloc_user(pages); // 在这里才给缓冲区分配空间
  145.  
  146. . 把缓冲区放入队列:
  147. ioctl(VIDIOC_QBUF) // 把缓冲区放入队列
  148. videobuf_qbuf
  149. q->ops->buf_prepare(q, buf, field); // 调用驱动程序提供的函数做些预处理
  150. list_add_tail(&buf->stream, &q->stream);// 把缓冲区放入队列的尾部
  151. q->ops->buf_queue(q, buf); // 调用驱动程序提供的"入队列函数"
  152.  
  153. . 启动摄像头
  154. ioctl(VIDIOC_STREAMON)
  155. videobuf_streamon
  156. q->streaming = ;
  157.  
  158. . select查询是否有数据
  159. // 驱动程序里必定有: 产生数据、唤醒进程
  160. v4l2_poll
  161. vdev->fops->poll
  162. vivi_poll
  163. videobuf_poll_stream
  164. // 从队列的头部获得缓冲区
  165. buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
  166. // 如果没有数据则休眠
  167. poll_wait(file, &buf->done, wait);
  168.  
  169. 谁来产生数据、谁来唤醒它?
  170. 内核线程vivi_thread30MS执行一次,它调用
  171. vivi_thread_tick
  172. vivi_fillbuff(fh, buf); // 构造数据
  173. wake_up(&buf->vb.done); // 唤醒进程
  174.  
  175. . 有数据后从队列里取出缓冲区
  176. // 有那么多缓冲区,APP如何知道哪一个缓冲区有数据?调用VIDIOC_DQBUF
  177. ioctl(VIDIOC_DQBUF)
  178. vidioc_dqbuf
  179. // 在队列里获得有数据的缓冲区
  180. retval = stream_next_buffer(buf_queue, &buf, nonblocking);
  181.  
  182. // 把它从队列中删掉
  183. list_del(&buf->stream);
  184.  
  185. // 把这个缓冲区的状态返回给APP
  186. videobuf_status(buf_queue, b, buf, buf_queue->type);
  187.  
  188. . 应用程序根据VIDIOC_DQBUF所得到缓冲区状态,知道是哪一个缓冲区有数据
  189. 就去读对应的地址(该地址来自前面的mmap)
  190.  
  191. 大概流程:
  192. . VIDIOC_REQBUFS:
  193. 设置缓冲区头部 buf_a_head ---> buf_b_head
  194.  
  195. . VIDIOC_QUERYBUF:
  196. mmap分配空间:buf_a_head+buffer---> buf_b_head+buffer
  197.  
  198. . VIDIOC_QBUF:
  199. 把缓冲区放入队列:queue_head: buf_a_head+buffer ---> queue_lastbuf_b_head+buffer
  200.  
  201. . streaming_on:
  202.  
  203. . slect:
  204. 查询队列头部的缓冲区
  205.  
  206. .VIDIOC_DQBUF:
  207. 返回队列头部的buf_a_head+buffer,从队列中删除头部buf_a_head+buffer
  208. 此时buf_b_head+buffer位队列头部,处理完把buf_a_head+buffer添加到队列尾部
  209. 再进行第三部VIDIOC_QBUF

vivi.c源码:

  1. #include <linux/module.h>
  2. #include <linux/delay.h>
  3. #include <linux/errno.h>
  4. #include <linux/fs.h>
  5. #include <linux/kernel.h>
  6. #include <linux/slab.h>
  7. #include <linux/mm.h>
  8. #include <linux/ioport.h>
  9. #include <linux/init.h>
  10. #include <linux/sched.h>
  11. #include <linux/pci.h>
  12. #include <linux/random.h>
  13. #include <linux/version.h>
  14. #include <linux/mutex.h>
  15. #include <linux/videodev2.h>
  16. #include <linux/dma-mapping.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/kthread.h>
  19. #include <linux/highmem.h>
  20. #include <linux/freezer.h>
  21. #include <media/videobuf-vmalloc.h>
  22. #include <media/v4l2-device.h>
  23. #include <media/v4l2-ioctl.h>
  24.  
  25. /* 定义一个video_device */
  26. static struct video_device *my_video_device;
  27.  
  28. /* 摄像头数据格式结构体 */
  29. static struct v4l2_format my_v4l2_format;
  30.  
  31. /* videobuf-core.c维护的缓存队列 */
  32. static struct videobuf_queue my_videobuf_queue;
  33.  
  34. /* 队列自旋锁 */
  35. static spinlock_t my_queue_slock;
  36.  
  37. /* 数据上报定时器*/
  38. static struct timer_list my_timer;
  39.  
  40. /* 本地维护的缓存队列*/
  41. static struct list_head my_local_queue;
  42.  
  43. /*包含摄像头数据构造函数*/
  44. #include"my_fill_buf.c"
  45.  
  46. /**************************************************videobuf_queue_ops start********************************************************/
  47.  
  48. static int my_buf_setup(struct videobuf_queue *q,unsigned int *count, unsigned int *size)
  49. {
  50. /* 重新计算buff size并调整,不要浪费空间 */
  51. *size = my_v4l2_format.fmt.pix.sizeimage;
  52.  
  53. /* 一个队列最多支持32缓存块 */
  54. if(*count == ) *count=;
  55. return ;
  56. }
  57.  
  58. static int my_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field)
  59. {
  60. /*设置video_buf的大小,宽度*/
  61. vb->size = my_v4l2_format.fmt.pix.sizeimage;
  62. vb->bytesperline = my_v4l2_format.fmt.pix.bytesperline;
  63. vb->width = my_v4l2_format.fmt.pix.width;
  64. vb->height = my_v4l2_format.fmt.pix.height;
  65. vb->field = field;
  66.  
  67. /*摄像头数据初始化*/
  68. my_precalculate_bars();
  69.  
  70. /*设置buf状态*/
  71. vb->state = VIDEOBUF_PREPARED;
  72. return ;
  73. }
  74.  
  75. static void my_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
  76. {
  77. /* 应用程序查询缓冲区时把本地队列的buf 放入 videobuf-core.c维护的队列 */
  78. list_add_tail(&vb->queue, &my_local_queue);
  79.  
  80. /* 设置buf状态 */
  81. vb->state = VIDEOBUF_QUEUED;
  82. }
  83.  
  84. static void my_buf_release(struct videobuf_queue *q,struct videobuf_buffer *vb)
  85. {
  86. /*释放buf*/
  87. videobuf_vmalloc_free(vb);
  88.  
  89. /*设置buf状态*/
  90. vb->state = VIDEOBUF_NEEDS_INIT;
  91. }
  92.  
  93. /*
  94. *
  95. ops->buf_setup - calculates the size of the video buffers and avoid they to waste more than some maximum limit of RAM;
  96. ops->buf_prepare - fills the video buffer structs and calls videobuf_iolock() to alloc and prepare mmaped memory;
  97. ops->buf_queue - advices the driver that another buffer were requested (by read() or by QBUF);
  98. ops->buf_release - frees any buffer that were allocated.
  99.  
  100. *
  101. */
  102.  
  103. static struct videobuf_queue_ops my_videobuf_queue_ops =
  104. {
  105. .buf_setup = my_buf_setup, /* app调用ioctl(REQBUF)时,此函数被调用 */
  106. .buf_prepare = my_buf_prepare, /* app调用ioctl(QUERYBUF)时,此函数被调用 */
  107. .buf_queue = my_buf_queue, /* app调用ioctl(QBUF)时,此函数被调用 */
  108. .buf_release = my_buf_release, /* app调用ioctl(DQBUF)时,此函数被调用 */
  109.  
  110. };
  111.  
  112. /**************************************************videobuf_queue_ops end********************************************************/
  113.  
  114. /***************************************************fops start************************************************************/
  115. static int my_vivi_open(struct file *file)
  116. {
  117.  
  118. /* 初始化videobuf_queue结构体
  119. * videobuf_queue->bufs = videobuf_buffer
  120. * videobuf_queue->ops = videobuf_queue_ops
  121. * videobuf_queue->irqlock = my_queue_slock
  122. */
  123. videobuf_queue_vmalloc_init(&my_videobuf_queue, // 缓冲区队列
  124. &my_videobuf_queue_ops, // 缓冲区队列的操作函数
  125. NULL, &my_queue_slock, // 缓冲区操作函数要用的自旋锁
  126. V4L2_BUF_TYPE_VIDEO_CAPTURE, // 单个缓冲区的类型
  127. V4L2_FIELD_INTERLACED, // 奇偶帧
  128. sizeof(struct videobuf_buffer), // 缓冲头部大小
  129. NULL); // 私有数据
  130.  
  131. /*设置超调时间*/
  132. my_timer.expires = jiffies + ;
  133.  
  134. /*将定时器加入内核链表*/
  135. add_timer(&my_timer);
  136. return ;
  137. }
  138.  
  139. static unsigned int my_vivi_poll(struct file *file, struct poll_table_struct *wait)
  140. {

/* 调用内核的poll函数查询数据,如果没有数据,休眠在videobuf->done上
      * poll_wait(file, &buf->done, wait);
      *
      */

   return videobuf_poll_stream(file,&my_videobuf_queue , wait);

  1. }
  2.  
  3. static int my_vivi_mmap(struct file *file, struct vm_area_struct *vma)
  4. {
  5. /*映射缓冲区*/
  6. return videobuf_mmap_mapper(&my_videobuf_queue , vma);
  7. }
  8.  
  9. static int my_vivi_release(struct file *file)
  10. {
  11. /*内核链表删除定时器*/
  12. del_timer(&my_timer);
  13.  
  14. /*停止队列*/
  15. videobuf_stop(&my_videobuf_queue);
  16.  
  17. /*取消缓存区映射*/
  18. videobuf_mmap_free(&my_videobuf_queue );
  19. return ;
  20. }
  21. /***************************************************fops end**************************************************************/
  22.  
  23. /**************************************************ioctl start************************************************************/
  24.  
  25. /*判断是否是摄像头设备*/
  26. static int my_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
  27. {
  28. /* 驱动名称 */
  29. strcpy(cap->driver,"zsy_vivi");
  30. strcpy(cap->card,"zsy_vivi");
  31.  
  32. /* 摄像头版本号 */
  33. cap->version = 0x0011;
  34.  
  35. /* 视频捕捉设备,streaming表明是app通过ioctl 来进行读写数据*/
  36. cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
  37. return ;
  38. }
  39.  
  40. /* 枚举当前设备支持的格式 */
  41. static int my_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
  42. {
  43. /* 支持几种格式 */
  44. if(f->index >= ) return -EINVAL;
  45.  
  46. /* 设置当前格式为YUYV*/
  47. strcpy(f->description,"4:2:2,packed,YUYV");
  48. f->pixelformat = V4L2_PIX_FMT_YUYV;
  49. return ;
  50. }
  51.  
  52. static int my_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
  53. {
  54. /* 返回当前的格式 */
  55. memcpy(f,&my_v4l2_format,sizeof(my_v4l2_format));
  56. return ;
  57. }
  58.  
  59. static int my_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
  60. {
  61. unsigned int maxw,maxh;
  62. enum v4l2_field field;
  63.  
  64. /* 测试是否支持这个格式 */
  65. if(f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) return -EINVAL;
  66.  
  67. field = f->fmt.pix.field;
  68.  
  69. if (field == V4L2_FIELD_ANY) field = V4L2_FIELD_INTERLACED;
  70. else if (V4L2_FIELD_INTERLACED != field) return -EINVAL;
  71.  
  72. /* 设置最大宽度和高度 */
  73. maxw = ;
  74. maxh = ;
  75.  
  76. v4l_bound_align_image(&f->fmt.pix.width, , maxw, , &f->fmt.pix.height, , maxh, , );
  77. /* 调整宽度 */
  78. f->fmt.pix.bytesperline =(f->fmt.pix.width * ) >> ;
  79. /* 调整图片大小 */
  80. f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
  81.  
  82. return ;
  83. }
  84.  
  85. static int my_s_fmt_vid_cap(struct file *file, void *fh,struct v4l2_format *f)
  86. {
  87. int ret = my_try_fmt_vid_cap(file,NULL,f);
  88. if(ret < ) return ret;
  89.  
  90. /* 设置上个函数测试好了的格式 */
  91. memcpy(&my_v4l2_format,f,sizeof(my_v4l2_format));
  92.  
  93. return ret;
  94. }
  95.  
  96. static int my_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
  97. {
  98. /* 请求一个video缓存 */
  99. return (videobuf_reqbufs(&my_videobuf_queue, b));
  100. }
  101.  
  102. static int my_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
  103. {
  104. /* 查询缓存 */
  105. return (videobuf_querybuf(&my_videobuf_queue,b));
  106. }
  107.  
  108. static int my_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
  109. {
  110. /*把缓存挂到队列*/
  111. return (videobuf_qbuf(&my_videobuf_queue,b));
  112. }
  113.  
  114. static int my_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
  115. {
  116. /* 把缓存拿出队列 */
  117. return (videobuf_dqbuf(&my_videobuf_queue, b, file->f_flags & O_NONBLOCK));
  118. }
  119.  
  120. static int my_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
  121. {
  122. /* 打开摄像头 */
  123. return videobuf_streamon(&my_videobuf_queue);
  124. }
  125.  
  126. static int my_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
  127. {
  128. /* 关闭摄像头*/
  129. videobuf_streamoff(&my_videobuf_queue);
  130. return ;
  131. }
  132. /*************************************************ioctl end*************************************************************/
  133.  
  134. /* 定义一个v4l2_file_operations */
  135. static struct v4l2_file_operations my_fops =
  136. {
  137. .owner = THIS_MODULE,
  138. .open = my_vivi_open,
  139. .release = my_vivi_release,
  140. .mmap = my_vivi_mmap,
  141. .poll = my_vivi_poll,
  142. .ioctl = video_ioctl2,
  143.  
  144. };
  145.  
  146. /* 定义一个v4l2_ioctl_ops */
  147. static struct v4l2_ioctl_ops my_ioctl_ops =
  148. {
  149. /* 摄像头容量 */
  150. .vidioc_querycap = my_querycap,
  151.  
  152. /* 数据格式 */
  153. .vidioc_enum_fmt_vid_cap = my_enum_fmt_vid_cap,
  154. .vidioc_g_fmt_vid_cap = my_g_fmt_vid_cap ,
  155. .vidioc_try_fmt_vid_cap = my_try_fmt_vid_cap,
  156. .vidioc_s_fmt_vid_cap = my_s_fmt_vid_cap,
  157.  
  158. /* 缓冲区 */
  159. .vidioc_reqbufs = my_reqbufs,
  160. .vidioc_querybuf = my_querybuf,
  161. .vidioc_qbuf = my_qbuf,
  162. .vidioc_dqbuf = my_dqbuf,
  163.  
  164. /* 启动/停止摄像头 */
  165. .vidioc_streamon = my_streamon,
  166. .vidioc_streamoff = my_streamoff,
  167.  
  168. };
  169.  
  170. /*定时器超时函数,填充数据*/
  171. void my_timer_fun(unsigned long data )
  172. {
  173. struct videobuf_buffer *vb;
  174. void *vbuf;
  175. struct timeval ts;
  176.  
  177. /* 1.1如果队列本地队列没有数据 ,结束 */
  178. if(list_empty(&my_local_queue))
  179. {
  180. mod_timer(&my_timer, jiffies + HZ/);
  181. return ;
  182. }
  183.  
  184. /* 1.2从本地队列里面取出第一个buf*/
  185. vb = list_entry(my_local_queue.next, struct videobuf_buffer, queue);
  186.  
  187. /* 1.3如果应用程序没有等待数据 ,结束 */
  188. if(!waitqueue_active(&vb->done))
  189. {
  190. mod_timer(&my_timer, jiffies + HZ/);
  191. return ;
  192. }
  193.  
  194. /* 2.填充假数据*/
  195. vbuf = videobuf_to_vmalloc(vb);
  196. my_fill_buff(vb);
  197.  
  198. vb->field_count++;
  199. do_gettimeofday(&ts);
  200. vb->ts = ts;
  201. vb->state = VIDEOBUF_DONE;
  202.  
  203. /* 3.把填充了数据的buf从队列里面删除*/
  204. list_del(&vb->queue);

    /* 4.唤醒videobuf_buffer->done进程,
     * 当进程使用poll机制查询缓冲区时暂时没有数据时
     * 进程休眠在 videobuf_buffer->done上面

     */

wake_up(&vb->done);

  1. /* 5.修改超时时间,30毫秒产生一帧数据 */
  2. mod_timer(&my_timer, jiffies + HZ/);
  3. }
  4. /* 释放函数 */
  5. void my_video_device_release(struct video_device *vdev)
  6. {}
  7. int my_vivi_init(void)
  8. {
  9. /* 1.分配一个video_device */
  10. my_video_device = video_device_alloc();
  11. /* 2.设置video_device */
  12. my_video_device->release = my_video_device_release;
  13. my_video_device->fops = &my_fops;
  14. my_video_device->ioctl_ops = &my_ioctl_ops;
  15. /* 3.注册video_device*/
  16. video_register_device(my_video_device,VFL_TYPE_GRABBER, -);
  17. /* 初始化定时器*/
  18. init_timer(&my_timer);
  19. my_timer.function = my_timer_fun;
  20. /* 初始化自旋锁 */
  21. spin_lock_init(&my_queue_slock);
  22. /*初始化本地队列*/
  23. INIT_LIST_HEAD(&my_local_queue);
  24. return ;
  25. }
  26. void my_vivi_exit(void)
  27. {
  28. video_unregister_device(my_video_device);
  29. video_device_release(my_video_device);
  30. }
  31. module_init(my_vivi_init);
  32. module_exit(my_vivi_exit);
  33. MODULE_LICENSE("GPL");

fill_buffer.c源码:

  1. /* Bars and Colors should match positions */
  2.  
  3. enum colors {
  4. WHITE,
  5. AMBAR,
  6. CYAN,
  7. GREEN,
  8. MAGENTA,
  9. RED,
  10. BLUE,
  11. BLACK,
  12. };
  13.  
  14. /* R G B */
  15. #define COLOR_WHITE {204, 204, 204}
  16. #define COLOR_AMBAR {208, 208, 0}
  17. #define COLOR_CIAN { 0, 206, 206}
  18. #define COLOR_GREEN { 0, 239, 0}
  19. #define COLOR_MAGENTA {239, 0, 239}
  20. #define COLOR_RED {205, 0, 0}
  21. #define COLOR_BLUE { 0, 0, 255}
  22. #define COLOR_BLACK { 0, 0, 0}
  23.  
  24. struct bar_std {
  25. u8 bar[][];
  26. };
  27.  
  28. /* Maximum number of bars are 10 - otherwise, the input print code
  29. should be modified */
  30. static struct bar_std bars[] = {
  31. { /* Standard ITU-R color bar sequence */
  32. {
  33. COLOR_WHITE,
  34. COLOR_AMBAR,
  35. COLOR_CIAN,
  36. COLOR_GREEN,
  37. COLOR_MAGENTA,
  38. COLOR_RED,
  39. COLOR_BLUE,
  40. COLOR_BLACK,
  41. }
  42. }, {
  43. {
  44. COLOR_WHITE,
  45. COLOR_AMBAR,
  46. COLOR_BLACK,
  47. COLOR_WHITE,
  48. COLOR_AMBAR,
  49. COLOR_BLACK,
  50. COLOR_WHITE,
  51. COLOR_AMBAR,
  52. }
  53. }, {
  54. {
  55. COLOR_WHITE,
  56. COLOR_CIAN,
  57. COLOR_BLACK,
  58. COLOR_WHITE,
  59. COLOR_CIAN,
  60. COLOR_BLACK,
  61. COLOR_WHITE,
  62. COLOR_CIAN,
  63. }
  64. }, {
  65. {
  66. COLOR_WHITE,
  67. COLOR_GREEN,
  68. COLOR_BLACK,
  69. COLOR_WHITE,
  70. COLOR_GREEN,
  71. COLOR_BLACK,
  72. COLOR_WHITE,
  73. COLOR_GREEN,
  74. }
  75. },
  76. };
  77.  
  78. #define NUM_INPUTS ARRAY_SIZE(bars)
  79.  
  80. #define TO_Y(r, g, b) \
  81. ((( * r + * g + * b + ) >> ) + )
  82. /* RGB to V(Cr) Color transform */
  83. #define TO_V(r, g, b) \
  84. ((( * r - * g - * b + ) >> ) + )
  85. /* RGB to U(Cb) Color transform */
  86. #define TO_U(r, g, b) \
  87. (((- * r - * g + * b + ) >> ) + )
  88.  
  89. static unsigned char myvivi_cur_bars[][];
  90.  
  91. /* precalculate color bar values to speed up rendering */
  92. static void my_precalculate_bars(int input)
  93. {
  94. unsigned char r, g, b;
  95. int k, is_yuv;
  96.  
  97. for (k = ; k < ; k++) {
  98. r = bars[input].bar[k][];
  99. g = bars[input].bar[k][];
  100. b = bars[input].bar[k][];
  101. is_yuv = ;
  102.  
  103. switch (my_v4l2_format.fmt.pix.pixelformat) {
  104. case V4L2_PIX_FMT_YUYV:
  105. case V4L2_PIX_FMT_UYVY:
  106. is_yuv = ;
  107. break;
  108. case V4L2_PIX_FMT_RGB565:
  109. case V4L2_PIX_FMT_RGB565X:
  110. r >>= ;
  111. g >>= ;
  112. b >>= ;
  113. break;
  114. case V4L2_PIX_FMT_RGB555:
  115. case V4L2_PIX_FMT_RGB555X:
  116. r >>= ;
  117. g >>= ;
  118. b >>= ;
  119. break;
  120. }
  121.  
  122. if (is_yuv) {
  123. myvivi_cur_bars[k][] = TO_Y(r, g, b); /* Luma */
  124. myvivi_cur_bars[k][] = TO_U(r, g, b); /* Cb */
  125. myvivi_cur_bars[k][] = TO_V(r, g, b); /* Cr */
  126. } else {
  127. myvivi_cur_bars[k][] = r;
  128. myvivi_cur_bars[k][] = g;
  129. myvivi_cur_bars[k][] = b;
  130. }
  131. }
  132.  
  133. }
  134.  
  135. static void myvivi_gen_twopix(unsigned char *buf, int colorpos)
  136. {
  137. unsigned char r_y, g_u, b_v;
  138. unsigned char *p;
  139. int color;
  140.  
  141. r_y = myvivi_cur_bars[colorpos][]; /* R or precalculated Y */
  142. g_u = myvivi_cur_bars[colorpos][]; /* G or precalculated U */
  143. b_v = myvivi_cur_bars[colorpos][]; /* B or precalculated V */
  144.  
  145. for (color = ; color < ; color++) {
  146. p = buf + color;
  147.  
  148. switch (my_v4l2_format.fmt.pix.pixelformat) {
  149. case V4L2_PIX_FMT_YUYV:
  150. switch (color) {
  151. case :
  152. case :
  153. *p = r_y;
  154. break;
  155. case :
  156. *p = g_u;
  157. break;
  158. case :
  159. *p = b_v;
  160. break;
  161. }
  162. break;
  163. case V4L2_PIX_FMT_UYVY:
  164. switch (color) {
  165. case :
  166. case :
  167. *p = r_y;
  168. break;
  169. case :
  170. *p = g_u;
  171. break;
  172. case :
  173. *p = b_v;
  174. break;
  175. }
  176. break;
  177. case V4L2_PIX_FMT_RGB565:
  178. switch (color) {
  179. case :
  180. case :
  181. *p = (g_u << ) | b_v;
  182. break;
  183. case :
  184. case :
  185. *p = (r_y << ) | (g_u >> );
  186. break;
  187. }
  188. break;
  189. case V4L2_PIX_FMT_RGB565X:
  190. switch (color) {
  191. case :
  192. case :
  193. *p = (r_y << ) | (g_u >> );
  194. break;
  195. case :
  196. case :
  197. *p = (g_u << ) | b_v;
  198. break;
  199. }
  200. break;
  201. case V4L2_PIX_FMT_RGB555:
  202. switch (color) {
  203. case :
  204. case :
  205. *p = (g_u << ) | b_v;
  206. break;
  207. case :
  208. case :
  209. *p = (r_y << ) | (g_u >> );
  210. break;
  211. }
  212. break;
  213. case V4L2_PIX_FMT_RGB555X:
  214. switch (color) {
  215. case :
  216. case :
  217. *p = (r_y << ) | (g_u >> );
  218. break;
  219. case :
  220. case :
  221. *p = (g_u << ) | b_v;
  222. break;
  223. }
  224. break;
  225. }
  226. }
  227. }
  228.  
  229. static void myvivi_gen_line(char *basep, int inipos, int wmax,
  230. int hmax, int line, int count)
  231. {
  232. int w;
  233. int pos = inipos;
  234.  
  235. /* We will just duplicate the second pixel at the packet */
  236. wmax /= ;
  237.  
  238. /* Generate a standard color bar pattern */
  239. for (w = ; w < wmax; w++) {
  240. int colorpos = ((w + count) * /(wmax + )) % ;
  241.  
  242. myvivi_gen_twopix(basep + pos, colorpos);
  243. pos += ; /* only 16 bpp supported for now */
  244. }
  245. return;
  246. }
  247.  
  248. static void my_fill_buff(struct videobuf_buffer *vb)
  249. {
  250. int h , pos = ;
  251. int hmax = vb->height;
  252. int wmax = vb->width;
  253. char *tmpbuf;
  254. void *vbuf = videobuf_to_vmalloc(vb);
  255. static int mv_count = ;
  256.  
  257. if (!vbuf)
  258. return;
  259.  
  260. tmpbuf = kmalloc(wmax * , GFP_ATOMIC);
  261. if (!tmpbuf)
  262. return;
  263.  
  264. for (h = ; h < hmax; h++) {
  265. myvivi_gen_line(tmpbuf, , wmax, hmax, h, mv_count);
  266. memcpy(vbuf + pos, tmpbuf, wmax * );
  267. pos += wmax*;
  268. }
  269.  
  270. mv_count++;
  271.  
  272. kfree(tmpbuf);
  273. }

vivi.c框架的更多相关文章

  1. V4L2学习(五)VIVI虚拟摄像头驱动

    概述 前面简单分析了内核中虚拟摄像头驱动 vivi 的框架与实现,本文参考 vivi 来写一个虚拟摄像头驱动,查询.设置视频格式相对简单,难点在于 vb2_buf 的处理过程. 数据采集流程分析 在我 ...

  2. V4L2应用程序框架-二【转】

    本文转载自:http://blog.csdn.net/tommy_wxie/article/details/11371439 V4L2驱动框架 主设备号: 81 次设备号:    0-63    64 ...

  3. Linux摄像头驱动学习之:(一)V4L2_框架分析

    这段时间开始搞安卓camera底层驱动了,把以前的的Linux视频驱动回顾一下,本篇主要概述一下vfl2(video for linux 2). 一. V4L2框架: video for linux ...

  4. (七) UVC框架分析

    title: UVC框架分析 date: 2019/4/23 19:50:00 toc: true --- UVC框架分析 源码的位置在drivers\media\video\uvc,查看下Makef ...

  5. v4l2框架

    参考:https://www.cnblogs.com/tuotuteng/p/4648387.html http://blog.sina.com.cn/s/blog_c91863e60102w65w. ...

  6. 2.5 USB摄像头驱动程序框架

    学习目标:根据vivi驱动架构和linux-2.6.31/linux-2.6.31.14/drivers/media/video/uvc/Uvc_driver.c驱动源码,分析usb摄像头驱动程序框架 ...

  7. 2.1 摄像头V4L2驱动框架分析

    学习目标:学习V4L2(V4L2:vidio for linux version 2)摄像头驱动框架,分析vivi.c(虚拟视频硬件相关)驱动源码程序,总结V4L2硬件相关的驱动的步骤:  一.V4L ...

  8. V4L2(二)虚拟摄像头驱动vivi深入分析【转】

    转自:http://www.cnblogs.com/tureno/articles/6694463.html 转载于: http://blog.csdn.net/lizuobin2/article/d ...

  9. V4L2学习(四)VIVI分析

    vivi 相对于后面要分析的 usb 摄像头驱动程序,它没有真正的硬件相关层的操作,也就是说抛开了复杂的 usb 层的相关知识,便于理解 V4L2 驱动框架,侧重于驱动和应用的交互. 前面我们提到,V ...

随机推荐

  1. 我的IntelliJ IDEA 设置

    1.关闭代码折叠 2.设置代码格式 3.函数参数提醒

  2. Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk

    查下是不是有在环境变量中定义NDK_PROJECT_PATH 这个变量,如果有,删除试试

  3. python多线程应用——DB2数据库备份

    前言:DB2一个实例下,可以存在多个数据库,之前使用shell备份脚本,但是同一时刻只能备份一个数据库,对于几百G的备份文件,这个速度显然太慢,今天学习了Python多线程,刚好应用一下. 分析:1. ...

  4. csv.writer写入文件有多余的空行

    在用csv.writer写入文件的时候发现中间有多余的空行. 最早打开方式只是‘w’,会出现多余的空行,网上建议使用binary形式‘wb’打开可以解决问题: with open('egg2.csv' ...

  5. linux php --ini

    $ php --ini

  6. 此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站。若要允许 GET 请求,请将 JsonRequestBehavior 设置为 AllowGet。

    1.问题描述 mvc从一个路径获取所有的图片信息,ajax方法如下: function getimages(day) { var year = $("#selYear").val( ...

  7. (转)The C10K problem翻译

    The C10K problem 如今的web服务器需要同时处理一万个以上的客户端了,难道不是吗?毕竟如今的网络是个big place了. 现在的计算机也很强大了,你只需要花大概$1200就可以买一个 ...

  8. Houdini技术体系 基础管线(三) :UE4 Landscape Component的多选支持 下篇

    背景 上篇中,我们介绍了如何修改Houdini Enigne来设置单个Landscape Compnent的Height和Layer的数据,但原生Houdini Engine并不支持多选Compone ...

  9. swiper4自动轮播切换手动触碰后停止踩坑——属性disableOnInteraction

    swiper4轮播设置autoplay自动切换后,即默认设置: <script> var mySwiper = new Swiper('.swiper-container', { auto ...

  10. 安卓sdk webview获取淘宝个人信息100项,源码。

    1.贴出主要代码.这个不是python,python只涉及了服务端对信息提取结果的接受.主体是java  + android + js.由于淘宝各模块都是二级子域名,不能只在一个页面完成所有请求,aj ...