1 V4L2简介

video4linux2(V4L2)是Linux内核中关于视频设备的内核驱动,它为Linux中视频设备访问提供了通用接口,在Linux系统中,V4L2驱动的Video设备节点路径通常/dev/video/中的videoX
V4L2驱动对用户空间提供字符设备,主设备号为81,对于视频设备,其次设备号为0-63。除此之外,次设备号为64-127的Radio设备,次设备号为192-223的是Teletext设备,次设备号为224-255的是VBI设备
V4L2驱动的Video设备在用户空间通过各种ioctl调用进行控制,并且可以使用mmap进行内存映射

1.1 V4L2驱动主要使用的ioctl

命令值如下所示:

点击(此处)折叠或打开

  1. #define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) /*查询能力*/
  2. #define VIDIO_G_FMT _IOWR('V', 4, struct v4l2_format) /*获得格式*/
  3. #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) /*设置格式*/
  4. #define VIDIOC_REQBUFS _IOWR('V', 8, strut v4l2_requestbuffers) /*申请内存*/
  5. #define VIDIOC_G_FBUF _IOW('V', 10, struct v4l2_framebuffer) /*获得Framebuffer*/
  6. #define VIDIOC_S_BUF _IOW('V', 11, struct v4l2_framebuffer) /*设置Framebuffer*/
  7. #define VIDIOC_OVERLAY _IOW('V', 14, int) /*设置Overlay*/
  8. #define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) /*将内存加入队列*/
  9. #define VIDIOC_DQBUF _IOWR('V', 17, strut v4l2_buffer) /*从队列取出内存*/
  10. #define VIDIOC_STREAMON _IOW('V', 18, int) /*开始流*/
  11. #define VIDIOC_STREAMOFF _IOW('V', 19, int) /*停止流*/
  12. #define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) /*得到控制*/
  13. #define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) /*设置控制*/

1.2 重要结构

头文件 include/linux/videodev2.h

include/media/v4l2-dev.h

V4L2驱动核心实现文件:driver/media/video/v4l2-dev.c

v4l2-dev.h中定义的video_device是V4L2驱动程序的核心数据结构

  1. struct video_device
  2. {
  3. const struct v4l2_file_operations *fops;
  4. struct cdev *cdev;//字符设备
  5. struct device *parent;//父设备
  6. struct v4l2_device *v4l2_dev;//父v4l2_device
  7. char name[32];//名称
  8. int vfl_type;//类型
  9. int minor;//次设备号
  10. /*释放回调*/
  11. void (*release)(struct video_device *vdev);
  12. /*ioctl回调*/
  13. const struct v4l2_ioctl_ops *ioctl_ops;
  14. }
  15. 常用的结构
  16. 参见/include/linux/videodev2.h
  17. 1)设备能力结构
  18. struct v4l2_capability
  19. {
  20. __u8 driver[16];//驱动名
  21. __u8 card[32];//例如Hauppauge winTV
  22. __u8 bus_info[32];//PCI总线信息
  23. __u32 version;//内核版本
  24. __u32 capabilities;//设备能力
  25. __u32 reserved[4];
  26. };
  27. 2)数据格式结构
  28. struct v4l2_format
  29. {
  30. enum v4l2_buf_type type;//本结构的数据类型
  31. };
  32. 3)像素格式结构
  33. struct v4l2_pix_format
  34. {
  35. __u32   width;//宽度
  36. __u32   height;//高度
  37. }
  38. 4)请求缓冲
  39. struct v4l2_requestbuffers
  40. {
  41. __u32   count;//缓存数量
  42. enum v4l2_buf_type type;//数据流类型
  43. }
  44. 5)数据流类型包括V4L2_MEMORY_MMAP和V4L2_MEMORY_USERPTR
  45. enum v4l2_memory{
  46. };

点击(此处)折叠或打开

5)数据流类型包括V4L2_MEMORY_MMAP和V4L2_MEMORY_USERPTR enum v4l2_memory{ };

2 V4L2驱动注册 2.1 video_register_device

video4linux2驱动程序的注册drivers/media/video

video_register_device函数用来注册一个v4l驱动程序

  1. int video_register_device(struct video_device *vdev, int type, int nr)
  2. {
  3. return __video_register_device(vdev, type, nr, 1);
  4. }
  5. 其中参数type支持的类型如下
  6. #define VFL_TYPE_GRABBER 0//视频
  7. #define VFL_TYPE_VBI    1//从视频消隐的时间取得信息的设备
  8. #define VFL_TYPE_RADIO  2 //广播
  9. #define VFL_TYPE_VTX    3//视传设备
  10. #define VFL_TYPE_MAX    4//最大值
  11. ----------------->返回调用 __video_register_device()
  12. __video_register_device 函数先检查设备类型,接下来
  13. 寻找一个可用的子设备号,最后注册相应的字符设备
  14. static int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use)
  15. {
  16. switch (type) {
  17. case VFL_TYPE_GRABBER:
  18. minor_offset = 0;
  19. minor_cnt = 64;
  20. break;
  21. case VFL_TYPE_RADIO:
  22. minor_offset = 64;
  23. minor_cnt = 64;
  24. break;
  25. case VFL_TYPE_VTX:
  26. minor_offset = 192;
  27. minor_cnt = 32;
  28. break;
  29. case VFL_TYPE_VBI:
  30. minor_offset = 224;
  31. minor_cnt = 32;
  32. break;
  33. nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
  34. }
  35. nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
  36. vdev->cdev->ops = &v4l2_fops;
  37. //注册字符设备
  38. ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
  39. ret = device_register(&vdev->dev);
  40. //注册完毕设备信息存储在video_device数组中
  41. mutex_lock(&videodev_lock);
  42. video_device[vdev->minor] = vdev;
  43. mutex_unlock(&videodev_lock);
  44. }
int video_register_device(struct video_device *vdev, int type, int nr)
{
return __video_register_device(vdev, type, nr, 1);
}
其中参数type支持的类型如下
#define VFL_TYPE_GRABBER 0//视频
#define VFL_TYPE_VBI 1//从视频消隐的时间取得信息的设备
#define VFL_TYPE_RADIO 2 //广播
#define VFL_TYPE_VTX 3//视传设备
#define VFL_TYPE_MAX 4//最大值
----------------->返回调用 __video_register_device() __video_register_device 函数先检查设备类型,接下来寻找一个可用的子设备号,
最后注册相应的字符设备

点击(此处)折叠或打开

2.2 v4l2_fops接口

v4l2_fops为video4linux2设备提供了统一的应用层接口,v4l2_fops定义如下

  1. static const struct file_operations v4l2_fops = {
  2. .owner = THIS_MODULE,
  3. .read = v4l2_read,
  4. .write = v4l2_write,
  5. .open = v4l2_open,
  6. .get_unmapped_area = v4l2_get_unmapped_area,
  7. .mmap = v4l2_mmap,
  8. .unlocked_ioctl = v4l2_ioctl,
  9. .release = v4l2_release,
  10. .poll = v4l2_poll,
  11. .llseek = no_llseek,
  12. };
  13. v4l2_fops中的成员函数最终要调用struct video_device->fops中相应的成员
  14. struct video_device->fops是具体video4linux2摄像头驱动程序必须实现的接口
  15. static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off)
  16. {
  17. return vdev->fops->read(filp, buf, sz, off);
  18. }

2.3 /drivers/media/video/samsung/fimc/s3c_fimc_core.c

驱动探测函数s3c_fimc_probe定义

  1. static int s3c_fimc_probe(struct platform_device *dev)
  2. {
  3. ctrl = s3c_fimc_register_controller(pdev);
  4. clk_enable(ctrl->clock);//使能时钟
  5. //注册V4L2驱动
  6. ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);
  7. }
  8. s3c_fimc_register_contoller函数主要用来分配资源与申请中断
  9. static struct s3c_fimc_control *s3c_fimc_register_controller(struct platform_device *pdev)
  10. {
  11. ctrl->vd = &s3c_fimc_video_device[id];
  12. //申请中断
  13. ctrl->irq = platform_get_irq(pdev, 0);
  14. if(request_irq(ctrl->irq, s3c_fimc_irq, IRQF_DISABLED, ctrl->name, ctrl))
  15. };
  16. struct video_device s3c_fimc_video_device[S3C_FIMC_MAX_CTRLS] = {
  17. [0] = {
  18. .vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,
  19. .fops = &s3c_fimc_fops,
  20. .ioctl_ops = &s3c_fimc_v4l2_ops,
  21. .release  = s3c_fimc_vdev_release,
  22. .name = "sc3_video0",
  23. },
  24. }

s3c_fimc_v4l2_ops,是在drivers/media/video/samsung/fimc中实现的v4l2_ioctl_ops,在用户空间进行ioctl等调用时,要调用到具体实现的各个函数指针

3 V4L2 操作

3.1 s3c_fimc_open

  1. static int s3c_fimc_open(struct file *filp)
  2. {
  3. struct s3c_fimc_control *ctrl;
  4. int id, ret;
  5. id =0;
  6. ctrl = &s3c_fimc.ctrl[id];
  7. mutex_lock(&ctrl->lock);
  8. if (atomic_read(&ctrl->in_use)) {
  9. ret = -EBUSY;
  10. goto resource_busy;
  11. else {
  12. atomic_inc(&ctrl->in_use);
  13. s3c_fimc_reset(ctrl);
  14. filp->private_data = ctrl;
  15. }
  16. mutex_unlock(&ctrl->lock);
  17. return 0;
  18. resource_busy:
  19. mutex_unlock(&ctrl->lock);
  20. return ret;
  21. }
  22. 用户空间
  23. 打开设备文件
  24. fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
用户空间打开设备文件 fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
3.2 获取设备的capability,查看设备有什么功能

1)结构体

  1. struct v4l2_capability cap;
  2. ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
  3. /include/linux/videodev2.h
  4. struct v4l2_capability {
  5. __u8    driver[16]; /* i.e. "bttv" */
  6. __u8    card[32];   /* i.e. "Hauppauge WinTV" */
  7. __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */
  8. __u32   version;        /* should use KERNEL_VERSION() */
  9. __u32   capabilities;   /* Device capabilities */
  10. __u32   reserved[4];
  11. };
  12. 驱动实现
  13. static int s3c_fimc_v4l2_querycap(struct file *filp, void *fh,
  14. struct v4l2_capability *cap)
  15. {
  16. struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
  17. strcpy(cap->driver, "Samsung FIMC Driver");
  18. strlcpy(cap->card, ctrl->vd->name, sizeof(cap->card));
  19. sprintf(cap->bus_info, "FIMC AHB-bus");
  20. cap->version = 0;
  21. cap->capabilities = (V4L2_CAP_VIDEO_OVERLAY | \
  22. V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING);
  23. return 0;
  24. }
  25. 应用层调用
  26. static int video_capability(int fd)
  27. {
  28. int ret = 0;
  29. /***********get the device capability********/
  30. struct v4l2_capability cap;
  31. ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
  32. if (ret < 0) {
  33. perror("VIDIOC_QUERYCAP failed ");
  34. return ret;
  35. }
  36. printf("\n****Capability informations****\n");
  37. printf("driver:   %s\n", cap.driver);
  38. if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
  39. printf("Capture capability is supported\n");
  40. if (cap.capabilities & V4L2_CAP_STREAMING)
  41. printf("Streaming capability is supported\n");
  42. if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
  43. printf("Overlay capability is supported\n");
  44. return 0;
  45. }

3.3 选择视频输入,一个视频设备可以有多个视频输入
  1. 结构体
  2. struct v4l2_input input;
  3. int index;
  4. 得到INPUT
  5. ret = ioctl(fd, VIDIOC_G_INPUT, &index);
  6. input.index = index;
  7. 列举INPUT
  8. ret = ioctl(fd, VIDIOC_ENUMINPUT, &input);
  9. 设置INPUT
  10. ret = ioctl(fd, VIDIOC_S_INPUT, &index);
  11. struct v4l2_input {
  12. __u32        index;     /*  Which input */
  13. __u8         name[32];      /*  Label */
  14. __u32        type;      /*  Type of input */
  15. __u32        audioset;      /*  Associated audios (bitfield) */
  16. __u32        tuner;             /*  Associated tuner */
  17. v4l2_std_id  std;
  18. __u32        status;
  19. __u32        capabilities;
  20. __u32        reserved[3];
  21. };
  22. Ioctl: VIDIOC_S_INPUT This IOCTL takes pointer to integer containing index of the input which has to be set. Application will provide the index number as an argument.
  23. 0 - Composite input,
  24. 1 - S-Video input.
  25. 驱动
  26. static int s3c_fimc_v4l2_s_input(struct file *filp, void *fh,
  27. unsigned int i)
  28. {
  29. struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
  30. if (i >= S3C_FIMC_MAX_INPUT_TYPES)
  31. return -EINVAL;
  32. ctrl->v4l2.input = &s3c_fimc_input_types[i];
  33. if (s3c_fimc_input_types[i].type == V4L2_INPUT_TYPE_CAMERA)
  34. ctrl->in_type = PATH_IN_ITU_CAMERA;
  35. else
  36. ctrl->in_type = PATH_IN_DMA;
  37. return 0;
  38. }
  39. static struct v4l2_input s3c_fimc_input_types[] = {
  40. {
  41. .index      = 0,
  42. .name       = "External Camera Input",
  43. .type       = V4L2_INPUT_TYPE_CAMERA,
  44. .audioset   = 1,
  45. .tuner      = 0,
  46. .std        = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
  47. .status     = 0,
  48. },
  49. {
  50. .index      = 1,
  51. .name       = "Memory Input",
  52. .type       = V4L2_INPUT_TYPE_MEMORY,
  53. .audioset   = 2,
  54. .tuner      = 0,
  55. .std        = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
  56. .status     = 0,
  57. }
  58. };
  59. static int s3c_fimc_v4l2_enum_input(struct file *filp, void *fh,
  60. struct v4l2_input *i)
  61. {
  62. if (i->index >= S3C_FIMC_MAX_INPUT_TYPES)
  63. return -EINVAL;
  64. memcpy(i, &s3c_fimc_input_types[i->index], sizeof(struct v4l2_input));
  65. return 0;
  66. }
  67. 应用
  68. static int video_input(int fd)
  69. {
  70. /***********get and set the VIDIO INPUT********/
  71. int ret = 0;
  72. struct v4l2_input input;//视频输入信息,对应命令VIDIOC_ENUMINPUT
  73. int index;
  74. index = 0;    //0 - Composite input, 1 - S-Video input.
  75. ret = ioctl (fd, VIDIOC_S_INPUT, &index);
  76. if (ret < 0) {
  77. perror ("VIDIOC_S_INPUT");
  78. return ret;
  79. }
  80. input.index = index;
  81. ret = ioctl (fd, VIDIOC_ENUMINPUT, &input);
  82. if (ret < 0){
  83. perror ("VIDIOC_ENUMINPUT");
  84. return ret;
  85. }
  86. printf("\n****input informations****\n");
  87. printf("name of the input = %s\n", input.name);
  88. return 0;
  89. }
3.4 遍历所有视频格式,查询驱动所支持的格式
  1. 结构
  2. struct v4l2_fmtdes fmtdes;
  3. ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmtdes);
  4. struct v4l2_fmtdesc {
  5. __u32           index;             /* Format number      */
  6. enum v4l2_buf_type  type;              /* buffer type        */
  7. __u32               flags;
  8. __u8            description[32];   /* Description string */
  9. __u32           pixelformat;       /* Format fourcc      */
  10. __u32           reserved[4];
  11. };
  12. 驱动
  13. static int s3c_fimc_v4l2_enum_fmt_vid_cap(struct file *filp, void *fh,
  14. struct v4l2_fmtdesc *f)
  15. {
  16. struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
  17. int index = f->index;
  18. if (index >= S3C_FIMC_MAX_CAPTURE_FORMATS)
  19. return -EINVAL;
  20. memset(f, 0, sizeof(*f));
  21. memcpy(f, ctrl->v4l2.fmtdesc + index, sizeof(*f));
  22. return 0;
  23. }
  24. #define S3C_FIMC_MAX_CAPTURE_FORMATS    ARRAY_SIZE(s3c_fimc_capture_formats)
  25. const static struct v4l2_fmtdesc s3c_fimc_capture_formats[] = {
  26. {
  27. .index      = 0,
  28. .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  29. .flags      = FORMAT_FLAGS_PLANAR,
  30. .description    = "4:2:0, planar, Y-Cb-Cr",
  31. .pixelformat    = V4L2_PIX_FMT_YUV420,
  32. },
  33. {
  34. .index      = 1,
  35. .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  36. .flags      = FORMAT_FLAGS_PLANAR,
  37. .description    = "4:2:2, planar, Y-Cb-Cr",
  38. .pixelformat    = V4L2_PIX_FMT_YUV422P,
  39. },
  40. {
  41. .index      = 2,
  42. .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  43. .flags      = FORMAT_FLAGS_PACKED,
  44. .description    = "4:2:2, packed, YCBYCR",
  45. .pixelformat    = V4L2_PIX_FMT_YUYV,
  46. },
  47. {
  48. .index      = 3,
  49. .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  50. .flags      = FORMAT_FLAGS_PACKED,
  51. .description    = "4:2:2, packed, CBYCRY",
  52. .pixelformat    = V4L2_PIX_FMT_UYVY,
  53. }
  54. };
  55. const static struct v4l2_fmtdesc s3c_fimc_overlay_formats[] = {
  56. {
  57. .index      = 0,
  58. .type       = V4L2_BUF_TYPE_VIDEO_OVERLAY,
  59. .flags      = FORMAT_FLAGS_PACKED,
  60. .description    = "16 bpp RGB, le",
  61. .pixelformat    = V4L2_PIX_FMT_RGB565,
  62. },
  63. {
  64. .index      = 1,
  65. .type       = V4L2_BUF_TYPE_VIDEO_OVERLAY,
  66. .flags      = FORMAT_FLAGS_PACKED,
  67. .description    = "24 bpp RGB, le",
  68. .pixelformat    = V4L2_PIX_FMT_RGB24,
  69. },
  70. };
  71. 应用层
  72. static int video_fmtdesc(int fd)
  73. {
  74. /***********Format Enumeration************/
  75. int ret = 0;
  76. struct v4l2_fmtdesc fmtdes;
  77. CLEAR(fmtdes);
  78. fmtdes.index = 0;
  79. fmtdes.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  80. printf("\n**********vidioc enumeration stream format informations:****\n");
  81. while (1) {
  82. ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmtdes);
  83. if (ret < 0)
  84. break;
  85. printf("{ pixelformat = %c%c%c%c, description = %s }\n",
  86. (fmtdes.pixelformat & 0xFF),
  87. (fmtdes.pixelformat >> 8) & 0xFF,
  88. (fmtdes.pixelformat >> 16) & 0xFF,
  89. (fmtdes.pixelformat >> 24) & 0xFF,
  90. fmtdes.description);
  91. if (fmtdes.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
  92. printf("video capture type:\n");
  93. if (fmtdes.pixelformat == V4L2_PIX_FMT_YUYV)
  94. printf("V4L2_PIX_FMT_YUYV\n");
  95. fmtdes.index++;
  96. }
  97. return 0;
  98. }
3.5 设置视频捕获格式(重要)
  1. 结构体
  2. 帧格式包括宽度和高度
  3. struct v4l2_format fmt;
  4. ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
  5. struct v4l2_format {
  6. enum v4l2_buf_type type;//数据流类型,必须是V4L2_BUF_TYPE_VIDEO_CAPTURE
  7. union {
  8. struct v4l2_pix_format      pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
  9. struct v4l2_window      win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
  10. struct v4l2_vbi_format      vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
  11. struct v4l2_sliced_vbi_format   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
  12. __u8    raw_data[200];                   /* user-defined */
  13. } fmt;
  14. };
  15. struct v4l2_pix_format  {
  16. __u32 pixelformat;//视频数据存储类型,例如是YUV4:2:2还是RGB
  17. }
  18. 驱动
  19. static int s3c_fimc_v4l2_s_fmt_vid_cap(struct file *filp, void *fh,
  20. struct v4l2_format *f)
  21. {
  22. struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
  23. ctrl->v4l2.frmbuf.fmt = f->fmt.pix;
  24. if (f->fmt.pix.priv == V4L2_FMT_IN)
  25. s3c_fimc_set_input_frame(ctrl, &f->fmt.pix);
  26. else
  27. s3c_fimc_set_output_frame(ctrl, &f->fmt.pix);
  28. return 0;
  29. }
  30. int s3c_fimc_set_input_frame(struct s3c_fimc_control *ctrl,
  31. struct v4l2_pix_format *fmt)
  32. {
  33. s3c_fimc_set_input_format(ctrl, fmt);
  34. return 0;
  35. }
  36. static void s3c_fimc_set_input_format(struct s3c_fimc_control *ctrl,
  37. struct v4l2_pix_format *fmt)
  38. {
  39. struct s3c_fimc_in_frame *frame = &ctrl->in_frame;
  40. frame->width = fmt->width;
  41. frame->height = fmt->height;
  42. switch (fmt->pixelformat) {
  43. case V4L2_PIX_FMT_RGB565:
  44. frame->format = FORMAT_RGB565;
  45. frame->planes = 1;
  46. break;
  47. case V4L2_PIX_FMT_RGB24:
  48. frame->format = FORMAT_RGB888;
  49. frame->planes = 1;
  50. break;
  51. case V4L2_PIX_FMT_NV12:
  52. frame->format = FORMAT_YCBCR420;
  53. frame->planes = 2;
  54. frame->order_2p = LSB_CBCR;
  55. break;
  56. case V4L2_PIX_FMT_NV21:
  57. frame->format = FORMAT_YCBCR420;
  58. frame->planes = 2;
  59. frame->order_2p = LSB_CRCB;
  60. break;
  61. case V4L2_PIX_FMT_NV12X:
  62. frame->format = FORMAT_YCBCR420;
  63. frame->planes = 2;
  64. frame->order_2p = MSB_CBCR;
  65. break;
  66. case V4L2_PIX_FMT_NV21X:
  67. frame->format = FORMAT_YCBCR420;
  68. frame->planes = 2;
  69. frame->order_2p = MSB_CRCB;
  70. break;
  71. case V4L2_PIX_FMT_YUV420:
  72. frame->format = FORMAT_YCBCR420;
  73. frame->planes = 3;
  74. break;
  75. case V4L2_PIX_FMT_YUYV:
  76. frame->format = FORMAT_YCBCR422;
  77. frame->planes = 1;
  78. frame->order_1p = IN_ORDER422_YCBYCR;
  79. break;
  80. case V4L2_PIX_FMT_YVYU:
  81. frame->format = FORMAT_YCBCR422;
  82. frame->planes = 1;
  83. frame->order_1p = IN_ORDER422_YCRYCB;
  84. break;
  85. case V4L2_PIX_FMT_UYVY:
  86. frame->format = FORMAT_YCBCR422;
  87. frame->planes = 1;
  88. frame->order_1p = IN_ORDER422_CBYCRY;
  89. break;
  90. case V4L2_PIX_FMT_VYUY:
  91. frame->format = FORMAT_YCBCR422;
  92. frame->planes = 1;
  93. frame->order_1p = IN_ORDER422_CRYCBY;
  94. break;
  95. case V4L2_PIX_FMT_NV16:
  96. frame->format = FORMAT_YCBCR422;
  97. frame->planes = 2;
  98. frame->order_1p = LSB_CBCR;
  99. break;
  100. case V4L2_PIX_FMT_NV61:
  101. frame->format = FORMAT_YCBCR422;
  102. frame->planes = 2;
  103. frame->order_1p = LSB_CRCB;
  104. break;
  105. case V4L2_PIX_FMT_NV16X:
  106. frame->format = FORMAT_YCBCR422;
  107. frame->planes = 2;
  108. frame->order_1p = MSB_CBCR;
  109. break;
  110. case V4L2_PIX_FMT_NV61X:
  111. frame->format = FORMAT_YCBCR422;
  112. frame->planes = 2;
  113. frame->order_1p = MSB_CRCB;
  114. break;
  115. case V4L2_PIX_FMT_YUV422P:
  116. frame->format = FORMAT_YCBCR422;
  117. frame->planes = 3;
  118. break;
  119. }
  120. }
  121. 应用层
  122. static int video_setfmt(int fd)
  123. {
  124. /***********set Stream data format********/
  125. int ret = 0;
  126. struct v4l2_format fmt;
  127. CLEAR(fmt);
  128. fmt.type            =   V4L2_BUF_TYPE_VIDEO_CAPTURE;
  129. fmt.fmt.pix.width   =   640;
  130. fmt.fmt.pix.height  =   480;
  131. fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//for PAL
  132. fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
  133. ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
  134. if (ret < 0) {
  135. perror("VIDIOC_S_FMT");
  136. return ret;
  137. }
  138. return 0;
  139. }
3.6 视频格式查询

在v4l2中,有两种查询视频格式的方法,一个是遍历所有视频格式的

一个是查询出一种格式的

/*查询出一种格式*/

ret = ioctl(fd, VIDIOC_G_FMT, &fmt);

/*遍历所有视频格式,查询驱动所支持的格式*/

VIDIOC_ENUM_FMT

  1. 驱动
  2. static int s3c_fimc_v4l2_g_fmt_vid_cap(struct file *filp, void *fh,
  3. struct v4l2_format *f)
  4. {
  5. struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
  6. int size = sizeof(struct v4l2_pix_format);
  7. memset(&f->fmt.pix, 0, size);
  8. memcpy(&f->fmt.pix, &(ctrl->v4l2.frmbuf.fmt), size);
  9. return 0;
  10. }
  11. 应用
  12. static int video_getfmt(int fd)
  13. {
  14. /***********get Stream data format********/
  15. int ret= 0;
  16. struct v4l2_format fmt;
  17. CLEAR(fmt);
  18. fmt.type    =   V4L2_BUF_TYPE_VIDEO_CAPTURE;
  19. ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
  20. if (ret < 0) {
  21. perror("VIDIOC_G_FMT");
  22. return ret;
  23. }
  24. printf("/n**********vidioc get stream format informations:****\n");
  25. if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
  26. printf("8-bit YUYVV pixel format\n");
  27. printf("Size of the buffer = %d\n", fmt.fmt.pix.sizeimage);
  28. printf("Line offset = %d\n", fmt.fmt.pix.bytesperline);
  29. if (fmt.fmt.pix.field == V4L2_FIELD_INTERLACED)
  30. printf("Storate format is interlaced frame format\n");
  31. return 0;
  32. }  
    3.7 向驱动申请帧缓冲,内存,一般不超过5个,帧缓冲管理
  1. 结构体
  2. struct v4l2_requestbuffers req;
  3. ret = ioctl(fd, VIDIOC_REQBUFS, &req);
  4. ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);//读取缓存
  5. struct v4l2_requestbuffers {
  6. __u32           count;
  7. enum v4l2_buf_type      type;
  8. enum v4l2_memory        memory;
  9. __u32           reserved[2];
  10. };
  11. struct v4l2_buffer {
  12. __u32           index;
  13. enum v4l2_buf_type      type;
  14. __u32           bytesused;
  15. __u32           flags;
  16. enum v4l2_field     field;
  17. struct timeval      timestamp;
  18. struct v4l2_timecode    timecode;
  19. __u32           sequence;
  20. /* memory location */
  21. enum v4l2_memory        memory;
  22. union {
  23. __u32           offset;
  24. unsigned long   userptr;
  25. } m;
  26. __u32           length;
  27. __u32           input;
  28. __u32           reserved;
  29. };
  30. 使用VIDIOC_REQBUFS 我们获取了req.count个缓存,下一步通过
  31. 调用VIDIOC_QUERYBUF 命令来获取这些缓存的地址,然后使用
  32. mmap函数转换成应用程序中的绝对地址,最后把这些缓存放入
  33. 缓存队列。
  34. The main steps that the application must perform for buffer allocation are:
  35. Allocating Memory
  36. Getting Physical Address
  37. Mapping Kernel Space Address to User Space
  38. 驱动支持
  39. static int s3c_fimc_v4l2_reqbufs(struct file *filp, void *fh,
  40. struct v4l2_requestbuffers *b)
  41. {
  42. if (b->memory != V4L2_MEMORY_MMAP) {
  43. err("V4L2_MEMORY_MMAP is only supported\n");
  44. return -EINVAL;
  45. }
  46. /* control user input */
  47. if (b->count > 4)
  48. b->count = 4;
  49. else if (b->count < 1)
  50. b->count = 1;
  51. return 0;
  52. }
  53. static int s3c_fimc_v4l2_querybuf(struct file *filp, void *fh,
  54. struct v4l2_buffer *b)
  55. {
  56. struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
  57. if (b->type != V4L2_BUF_TYPE_VIDEO_OVERLAY && \
  58. b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
  59. return -EINVAL;
  60. if (b->memory != V4L2_MEMORY_MMAP)
  61. return -EINVAL;
  62. b->length = ctrl->out_frame.buf_size;
  63. /*
  64. * NOTE: we use the m.offset as an index for multiple frames out.
  65. * Because all frames are not contiguous, we cannot use it as
  66. * original purpose.
  67. * The index value used to find out which frame user wants to mmap.
  68. */
  69. b->m.offset = b->index * PAGE_SIZE;
  70. return 0;
  71. }
  72. static int s3c_fimc_v4l2_qbuf(struct file *filp, void *fh,
  73. struct v4l2_buffer *b)
  74. {
  75. return 0;
  76. }
  77. 应用层
  78. static int video_mmap(int fd)
  79. {
  80. /*******step 1*****requestbuffers Allocating Memory *******/
  81. int ret = 0;
  82. struct v4l2_requestbuffers req;
  83. CLEAR(req);
  84. req.count    = 4;
  85. req.type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  86. req.memory   = V4L2_MEMORY_MMAP;
  87. ret = ioctl(fd, VIDIOC_REQBUFS, &req);
  88. if (ret < 0) {
  89. perror("VIDIOC_REQBUFS");
  90. return ret;
  91. }
  92. if (req.count < 2)
  93. printf("insufficient buffer memory\n");
  94. printf("Number of buffers allocated = %d\n", req.count);
  95. /*******step 2*****Getting Physical Address  *******/
  96. buffers = calloc(req.count, sizeof(*buffers));
  97. for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
  98. {
  99. struct v4l2_buffer buf;//驱动中的一帧
  100. CLEAR(buf);
  101. buf.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  102. buf.memory  = V4L2_MEMORY_MMAP;
  103. buf.index   = n_buffers;
  104. ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);
  105. if (ret < 0) {
  106. perror("VIDIOC_QUERYBUF");
  107. return ret;
  108. }
  109. /*******step 3*****Mapping Kernel Space Address to User Space*******/
  110. buffers[n_buffers].length = buf.length;
  111. buffers[n_buffers].start =
  112. mmap(NULL,
  113. buf.length,
  114. PROT_READ | PROT_WRITE,
  115. MAP_SHARED,
  116. fd,
  117. buf.m.offset);
  118. //if (MAP_FAILED == buffers[n_buffers].start)
  119. //perror("mmap failed \n");
  120. }
  121. /************requestbuffers in queue***********/
  122. for (i = 0; i < n_buffers; ++i) {
  123. struct v4l2_buffer buf;
  124. CLEAR(buf);
  125. buf.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  126. buf.memory  = V4L2_MEMORY_MMAP;
  127. buf.index = i;
  128. ret = ioctl(fd, VIDIOC_QBUF, &buf);//申请的缓冲进入队列
  129. if (ret < 0) {
  130. perror("VIDIOC_QBUF");
  131. return ret;
  132. }
  133. }
  134. return 0;
  135. }
3.8 开始捕捉图像数据(重要)
  1. <PRE class=csharp name="code">

    结构体

    <PRE class=csharp name="code">enum v4l2_buf_type type;//开始捕捉图像数据

  2. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  3. ret = ioctl(fd, VIDIOC_STREAMON, &type);
  4. enum v4l2_buf_type {
  5. V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
  6. V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,
  7. V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,
  8. V4L2_BUF_TYPE_VBI_CAPTURE          = 4,
  9. V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
  10. V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
  11. V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
  12. #if 1
  13. /* Experimental */
  14. V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
  15. #endif
  16. V4L2_BUF_TYPE_PRIVATE              = 0x80,
  17. };
  18. 驱动
  19. static int s3c_fimc_v4l2_streamon(struct file *filp, void *fh,
  20. enum v4l2_buf_type i)
  21. {
  22. struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
  23. if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
  24. return -EINVAL;
  25. printk("s3c_fimc_v4l2_streamon is called\n");
  26. if (ctrl->in_type != PATH_IN_DMA)
  27. s3c_fimc_init_camera(ctrl);
  28. ctrl->out_frame.skip_frames = 0;
  29. FSET_CAPTURE(ctrl);
  30. FSET_IRQ_NORMAL(ctrl);
  31. s3c_fimc_start_dma(ctrl);
  32. return 0;
  33. }
  34. 硬件控制寄存器的配置
  35. 应用层
  36. static int video_streamon(int fd)
  37. {
  38. int ret = 0;
  39. /************start stream on***********/
  40. enum v4l2_buf_type types;//开始捕捉图像数据
  41. types = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  42. ret = ioctl(fd, VIDIOC_STREAMON, &types);
  43. if (ret < 0) {
  44. perror("VIDIOC_STREAMON");
  45. return ret;
  46. }
  47. return 0;
  48. }

转载于:https://www.cnblogs.com/cainiaoaixuexi/p/3298909.html

V4L2驱动程序架构相关推荐

  1. linux驱动程序混合架构,嵌入式系统最小驱动框架(类似linux驱动程序架构)(示例代码)...

    2010年就打算把linux里的驱动框架核心代码抠出来的,但是由于懒而且linux代码量大,一直下不了手.最近调试的intel curie里驱动架构也类似linux,代码就少多了,由于工作需要不得不梳 ...

  2. Camera | 6.v4l2拓扑架构

    一. 设备节点.模块.拓扑结构关系 拓扑结构是我们了解MIPI-CSI内部模块以及与摄像头连接关系的最直观最便捷的方法. 1. 如何表示拓扑结构? file视角 v4l2视角 来自: 参考文档< ...

  3. Linux设备驱动程序架构分析之I2C架构(基于3.10.1内核)

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 内核版本:3.10.1 I2C体系架构的硬件实体包括两部分: 硬件I2C Adapter:硬件I2C Adapter ...

  4. linux设备驱动程序架构的研究,Linux设备驱动程序学习(12)-Linux设备模型(底层原理简介)...

    Linux设备驱动程序学习(12) -Linux设备模型(底层原理简介) 以<LDD3>的说法:Linux设备模型这部分内容可以认为是高级教材,对于多数程序作者来说是不必要的.但是我个人认 ...

  5. Linux串口驱动程序(1)-tty驱动程序架构

    1.tty概念分析 在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备.由于串口也是一种终端,因此这里引入终端这个概念 串口终端(/dev/ttyS*) ...

  6. Linux的设备驱动程序架构分析之MMC / SD(二)

    转自:http : //blog.csdn.net/liuhaoyutz 内核版本:3.10.1 一,s3cmci_ops分析 在上一篇文章中我们分析了Mini2440 MMC / SD驱动的探针函数 ...

  7. Linux设备驱动程序架构分析之一个I2C驱动实例

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 内核版本:3.10.1 编写一个I2C设备驱动程序的工作可分为两部分,一是定义和注册I2C设备,即i2c_clien ...

  8. Linux设备驱动程序架构分析之SD Spec摘要

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 本文是对SDSpecifications Part 1 Physical Layer Simplified Spec ...

  9. v4l2驱动编写篇【转】

    转自:http://blog.csdn.net/michaelcao1980/article/details/53008418 大部分所需的信息都在这里.作为一个驱动作者,当挖掘头文件的时候,你可能也 ...

  10. 视频驱动V4L2子系统驱动架构-框架

    V4L2驱动框架 v4l2驱动架构如图所示,v4l2也就是video for linux two,那么也就是说还有One了,v4l2前面还有v4l 图中芯片模块对应Soc的各个子模块,video_de ...

最新文章

  1. 郭涛:忽悠 众多人工智能创业公司与AI无关
  2. XIV(5)-- Data Recovery Protection (XDRP)
  3. 网络营销——网络营销专员到底是教你如何选择网站页面制作
  4. hadoop程序开发 --- python
  5. python爬虫分析大学排名_Python爬虫获得国内高校排名,python,获取,大学排名
  6. 如何处理数据中心电缆管理问题?
  7. 校讯通近期爆发短信诈骗:取消不可能 那如何规范
  8. 前端学习(3120):react-hello-react的setstate的一个说明
  9. 信息学奥赛C++语言:石头剪子布
  10. 机器学习中生成模型和判别模型
  11. Java Web学习总结(14)——JSP基础语法
  12. python dataframe取行列_pandas DataFrame 行列索引及值的获取的方法
  13. 点击场景中的物件无法定位到Hierarchy
  14. Ubuntu下Vim的常用操作命令——vi编辑器常用命令
  15. 微信小程序开发——上传图片
  16. 数据库内容:用于园林施工与养护的学习软件系统
  17. golang tomb_古墓丽影》(Tomb Raider)的补丁可改善Linux的游戏性和新游戏
  18. dlna android电视,DLNA怎么用?DLNA连接智能电视和电脑的方法分享
  19. 四足机器人|机器狗|仿生机器人|多足机器人|MATLAB动画仿真|Simulink动画仿真
  20. crc16的c语言函数 计算ccitt_求一个C语言实现的CRC16/CCITT-FALSE校验码函数

热门文章

  1. 阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第3节 线程同步机制_4_解决线程安全问题_同步代码块...
  2. HTTP和HTTPS笔记
  3. phpstudy配置域名后apache无法启动
  4. 构建最基础的Spring项目及所需要的jar包
  5. wxPython练习
  6. 在Ubuntu上安装JDK、Ant、Jmeter和Jenkins
  7. 2015.10.7第一篇
  8. java中String、StringBuffer和StringBuilder的区别(简单介绍)
  9. 【旧文章搬运】从XP到Win7看Windows对象管理的变化(概述)
  10. Pandas 基础学习