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

命令值如下所示:

头文件 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. }

V4L2驱动程序架构的更多相关文章

  1. 转: V4L2驱动程序架构

    源地址:http://blog.chinaunix.net/uid-26101960-id-3297657.html 1 V4L2简介 video4linux2(V4L2)是Linux内核中关于视频设 ...

  2. V4L2驱动程序框架架构【转】

    本文转载自:http://blog.csdn.net/tommy_wxie/article/details/11728809 1 V4L2简介 video4linux2(V4L2)是Linux内核中关 ...

  3. 基于Linux的v4l2视频架构驱动编写(转载)

    转自:http://www.linuxidc.com/Linux/2011-03/33022.htm 其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自 ...

  4. 基于Linux的v4l2视频架构驱动编写

    其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自己找了一个关于编写Linux下的视频采集监控项目做,然后上学期刚开学的时候听师兄说,跟院长做项目,没做 ...

  5. 【Linux开发】Linux V4L2驱动架构解析与开发导引

    Linux V4L2驱动架构解析与开发导引 Andrew按:众所周知,linux中可以采用灵活的多层次的驱动架构来对接口进行统一与抽象,最低层次的驱动总是直接面向硬件的,而最高层次的驱动在linux中 ...

  6. LCD驱动程序架构和分析

    一.LCD驱动程序架构 1.裸机驱动代码分析 ①LCD初始化:控制器初始化,端口初始化,指明帧缓冲 ②LCD图形显示:将图形数据写入帧缓冲 void lcd_init() { lcd_port_ini ...

  7. 9、基于Linux的v4l2视频架构应用编写

    Linux系统中,视频设备被当作一个设备文件来看待,设备文件存放在 /dev目录下,完整路径的设备文件名为: /dev/video0 . 视频采集基本步骤流程如下: 打开视频设备,设置视频设备属性及采 ...

  8. TTY驱动程序架构

    在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备. • 串口终端(/dev/ttyS*) 串口终端是使用计算机串口连接的终端设备.Linux把每个串行端 ...

  9. [国嵌攻略][142][LCD驱动程序架构]

    LCD裸机驱动回顾 1.LCD初始化 1.1.控制器初始化 1.2.端口初始化 1.3.指明了帧缓冲 2.LCD图形显示 2.1.将图形数据写入帧缓冲 Linux帧缓冲体验 把图片转换成开发板屏对应的 ...

随机推荐

  1. --without-v4l ,make clean, 重新make即可。

    --without-v4l ,make clean, 重新make 2011-02-27 17:38 Error: X11 support required for GUI compilation

  2. Redis 报错:MISCONF Redis is configured to save RDB snapshots

    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Com ...

  3. Sping面试题分析

    1.开放中主要使用Spring的什么技术? (1)IOC容器管理各层的组件 (2) 使用AOP配置声明式事务 (3)整合其他框架 2简述AOP和IOC概念 AOP : Aspect  Orienten ...

  4. cogs 1164. 跑步

    1164. 跑步 ★   输入文件:runa.in   输出文件:runa.out   简单对比时间限制:1 s   内存限制:128 MB [题目描述] 路人甲准备跑N (5≤N≤500)圈来锻炼自 ...

  5. [Beginning SharePoint Designer 2010]Chapter2 编辑页面

    本章概要: 1.如何展开隐藏任务面板和ribbon标签 2.页面编辑模式 3.代码视图模式和智能提示 4.如何组合SharePoint和页面上其他元素

  6. 在Android源码下编译jni所需要知道的事~

    以下只是自己的一些总结,欢迎讨论 通过NDK编译jni网上有很多例子,在这我只总结在Android源码下编译 1.android源码环境下编译so包,编出来的.so的包前面不会自动给添加lib,NDK ...

  7. SQLiteHelp

    using System; using System.Collections.Generic; using System.Text; using System.Data.SQLite; using S ...

  8. SignalR——聊天室的实现

    秒懂——SignalR ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连 ...

  9. 关于在bootstrap的tab栏中渲染echats图表,切换tab时echats不显示问题

    在开发过程中遇到这样个问题: 利用bootstrap中的tab栏,每当点击tab栏的导航时,echats仅仅只渲染第一个tab的内容,切换tab时,echats图表不显示. 其html代码为: < ...

  10. solarwinds之配置系统管理(System manager)

    配置windows的 1.  打开System Manager   2.  点击new新加一个接口   3.  选择要监控的资源   4.  确认好自己要监控的资源后如下   5.  这里以监控内存使 ...