linux v4l2编程
来源:互联网 发布:外汇复盘软件 编辑:程序博客网 时间:2024/06/03 21:39
参考文档:
https://linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/spec-single/v4l2.html
v4l2 : video for linux api two version //也就是linux系统下视频设备驱动好后,应用程序怎样调用相关的视频设备的编程接口
视频设备: 摄像头, 硬件编解码设备, 图形加速等。
设备文件: /dev/video* //有这些设备文件就是表示相应的视频设备已经驱动好,应用程序就可以使用v4l2的编程接口来实现视频设备的调用.
#include <sys/ioctl.h>int ioctl(int fd, int request, ...); ioctl函数用于把硬件的配置参数传给相应的设备驱动,让设备驱动根据指定的参数来配置硬件. 也可用于从设备驱动里获取出硬件的现用配置参数. 如ioctl用于配置摄像头的数据格式,所用的分辨率等参数的配置
函数返回值, 0表示配置成功, -1表示失败.
参数: fd表示打开设备文件得到文件描述符
request表示让设备驱动具体的操作行为 //如配置分辨率,配置数据格式等
…表示是可选的第三个参数,request是配置参数用时, 第三个参数应为准备好的配置参数变量的地址
V4L2里常用的ioctl介绍:
int ioctl(int fd, VIDIOC_QUERYCAP, struct v4l2_capability *argp); //可用于判断是否一个摄像头设备及所支持的操作接口int ioctl(int fd, VIDIOC_ENUM_FMT, struct v4l2_fmtdesc *argp); //可查询摄像头支持的图像格式int ioctl(int fd, VIDIOC_ENUM_FRAMESIZES, struct v4l2_frmsizeenum *argp); //可查询摄像头在某种图像格式下所能支持的图形分辨率int ioctl(int fd, VIDIOC_ENUMINPUT, struct v4l2_input *argp); //查询摄像头的选择。如前置/后置摄像头int ioctl(int fd, VIDIOC_S_FMT, struct v4l2_format *argp); //设置摄像头的图形格式int ioctl(int fd, VIDIOC_S_INPUT, int *argp); //设置使用前置/后置摄像头int ioctl(int fd, VIDIOC_S_CTRL, struct v4l2_control *argp); //设置摄像头的亮度,对比度等信息int ioctl(int fd, VIDIOC_REQBUFS, struct v4l2_requestbuffers *argp); //设置摄像头驱动申请图像缓冲区int ioctl(int fd, VIDIOC_QBUF/VIDIOC_DQBUF, struct v4l2_buffer *argp); //把指定的图像缓冲区加入/退出图像采集队列int ioctl(int fd, VIDIOC_STREAMON/VIDIOC_STREAMOFF , const int *argp); //启动/停止图像采集
以上结构体及其的成员的含议可在文档或/usr/include/linux/videodev2.h查看
usb摄像常用的图像格式:
V4L2_PIX_FMT_YUYV V4L2_PIX_FMT_MJPG V4L2_PIX_FMT_JPEGV4L2_PIX_FMT_MJPG/V4L2_PIX_FMT_JPEG其实取出来就是一张完整的jpg图像.
查询是否一个摄像头设备的代码:
int fd, i; fd = open("/dev/video0", O_RDWR); if (fd < 0) { perror("open"); return -1; } struct v4l2_capability cap; if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { perror("get capability failed"); return -1; } printf("driver : %s\n", cap.driver); if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { printf("not a camera\n"); return -2; }
获取摄像头设备支持的图像格式:
int fd, i; fd = open("/dev/video0", O_RDWR); if (fd < 0) { perror("open"); return -1; } struct v4l2_fmtdesc fmtdesc; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //视频捕捉类型 for (i = 0; ; i++) { fmtdesc.index = i; //获取摄像头所支持的第几种格式 if (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) break; printf("%s\n", fmtdesc.description); }
获取摄像头设备支持的图像格式的图像分辨率:
int fd, i, j; fd = open("/dev/video0", O_RDWR); if (fd < 0) { perror("open"); return -1; } struct v4l2_fmtdesc fmtdesc; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //视频捕捉类型 struct v4l2_frmsizeenum frmsize; for (i = 0; ; i++) { fmtdesc.index = i; //获取摄像头所支持的第几种格式 if (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) break; printf("%s\n", fmtdesc.description); //每种格式下又会支持几种不同的分辨率 frmsize.pixel_format = fmtdesc.pixelformat; //把获取出来的格式传给frmsize` for (j = 0; ; j++) { frmsize.index = j; if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) < 0) break; printf("w = %d, h = %d\n", frmsize.discrete.width, frmsize.discrete.height); } }
获取摄像头图像数据的步骤流程:
#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <linux/videodev2.h>#include <sys/ioctl.h>#include <sys/mman.h>#define W 640#define H 480#define FMT V4L2_PIX_FMT_YUYV // YUV 4:2:2 #define COUNT 3int main(void){ int fd, i; char *data[COUNT]; // 1. 打开摄像头的设备文件 fd = open("/dev/video0", O_RDWR); if (fd < 0) { perror("open"); return -1; } // 2. 检查是否是一个摄像头的设备文件 struct v4l2_capability cap; if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { perror("get capability failed"); return -1; } printf("driver : %s\n", cap.driver); if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { printf("no a camera\n"); return -2; } // 3. 设置摄像头的数据格式, 分辨率 struct v4l2_format fmt; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = W; fmt.fmt.pix.height = H; fmt.fmt.pix.pixelformat = FMT; if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) { perror("set format"); return -1; } // 4. 让驱动申请出存放图像数据的缓冲区, 每个缓冲区存放一帧图像 // 三个缓冲区 struct v4l2_requestbuffers bufs; bufs.count = COUNT; bufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; bufs.memory = V4L2_MEMORY_MMAP; //指定申请出来的缓冲区用于mmap映射到用户进程使用 if (ioctl(fd, VIDIOC_REQBUFS, &bufs) < 0) { perror("request bufs"); return -2; } //5.查询缓冲区的状态。 前面让驱动申请出3个缓冲区, 实际上是分配出存放三个图像数据的连续的一块内存区域. 所以需要查出每个缓冲区的开始地址,大小等信息 struct v4l2_buffer buffer; buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = V4L2_MEMORY_MMAP; for (i = 0; i < COUNT ; i++) { buffer.index = i; //指定要查询的是第几个缓冲区 if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { perror("query buf"); return -2; } printf("%d: len = %d, offset = %d\n", i, buffer.length, buffer.m.offset); // 6. 把驱动里的缓冲区映射到用户进程来使用 data[i] = mmap(NULL, buffer.length, PROT_READ, MAP_SHARED, fd, buffer.m.offset); if (MAP_FAILED == data[i]) { perror("mmap failed"); return -1; } // 7. 把每个缓冲区加入图像数据的采集队列. 只有在队列里的缓冲区才会被驱动填充新的图像数据. // 当取缓冲区的数据时,需让缓冲区退出采集队列,数据取好后, 再重新加入采集队列 if (ioctl(fd, VIDIOC_QBUF, &buffer) < 0) { perror("qbuf"); return -2; } } //8. 让驱动开始采集图像数据, 采集到的数据将会填入缓冲区里 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) { perror("stream on"); return -3; } // 9. 取出缓冲区里的图像数据。先让一个已采好数据的缓冲区退出采集队列 // 取出10张图像 struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; int dst_fd; char file_name[100]; //如果是MJPG/JPEG的图像格式,直接存起来就是一张jpg图像了. for (i = 0; i < 10; i++) { if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0) { perror("dqbuf"); return -3; } sprintf(file_name, "my%02d.yuyv", i); dst_fd = open(file_name, O_WRONLY|O_CREAT|O_TRUNC, 0644); write(dst_fd, data[buf.index], buf.bytesused); close(dst_fd); //重新加入采集队列 ioctl(fd, VIDIOC_QBUF, &buf); } return 0;}
阅读全文
0 0
- linux V4L2编程
- Linux之V4L2编程
- Linux V4L2基础编程
- Linux摄像头V4L2编程
- linux v4l2编程
- Linux下的V4L2编程
- Linux下V4L2编程小结
- Linux下V4L2编程小结
- linux内核v4l2模型编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- Linux之V4L2基础编程
- 买糖果
- 微信小程序 No.1 Array
- 虚拟机监控
- python标准库手记【2】
- 51 Nod1428活动安排
- linux v4l2编程
- 我与python约个会:08.程序编程基础2~基本数据类型
- spring简介
- BOM.window对象
- keras下基于mnist数据集的cnn
- 首触树链剖分
- LeetCode[338]Counting Bits
- android 特色输入输出
- oracle 通用函数