Linux视频设备驱动常用控制命令使用说明
设置视频设备属性通过ioctl来进行设置,ioctl有三个参数,分别是fd, cmd,和parameter,表示设备描述符,控制命令和控制命令参数。
1. 控制命令VIDIOC_QUERYCAP
功能: 查询设备驱动的功能 ;
参数说明:参数类型为V4L2的能力描述类型struct v4l2_capability;
struct v4l2_capability { __u8 driver[16]; /* i.e. "bttv" */ //驱动名称, __u8 card[32]; /* i.e. "Hauppauge WinTV" */ // __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ //PCI总线信息 __u32 version; /* should use KERNEL_VERSION() */ __u32 capabilities; /* Device capabilities */ //设备能力 __u32 reserved[4]; };
struct v4l2_capability cap; iret = ioctl(fd_usbcam, VIDIOC_QUERYCAP, &cap); if(iret < 0){ printf("get vidieo capability error,error code: %d \n", errno); return ; }
struct v4l2_fmtdesc { __u32 index; /* Format number */ enum v4l2_buf_type type; /* buffer type */ __u32 flags; __u8 description[32]; /* Description string */ __u32 pixelformat; /* Format fourcc */ __u32 reserved[4]; };
struct v4l2_fmtdesc fmt; memset(&fmt, 0, sizeof(fmt)); fmt.index = 0; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; while ((ret = ioctl(dev, VIDIOC_ENUM_FMT, &fmt)) == 0) { fmt.index++; printf("{ pixelformat = ''%c%c%c%c'', description = ''%s'' }\n", fmt.pixelformat & 0xFF, (fmt.pixelformat >> 8) & 0xFF, (fmt.pixelformat >> 16) & 0xFF, (fmt.pixelformat >> 24) & 0xFF, fmt.description); }
struct v4l2_format { enum v4l2_buf_type type; //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE union { struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ __u8 raw_data[200]; /* user-defined */ } fmt; }; struct v4l2_pix_format { __u32 width; // 宽,必须是16的倍数 __u32 height; // 高,必须是16的倍数 __u32 pixelformat; // 视频数据存储类型,例如是YUV4:2:2还是RGB enum v4l2_field field; __u32 bytesperline; __u32 sizeimage; enum v4l2_colorspace colorspace; __u32 priv; };
struct v4l2_format tv4l2_format; tv4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tv4l2_format.fmt.pix.width = img_width; tv4l2_format.fmt.pix.height = img_height; tv4l2_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; tv4l2_format.fmt.pix.field = V4L2_FIELD_INTERLACED; iret = ioctl(fd_usbcam, VIDIOC_S_FMT, &tv4l2_format);
struct v4l2_requestbuffers { u32 count; //缓存数量,也就是说在缓存队列里保持多少张照片 enum v4l2_buf_type type; //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE enum v4l2_memory memory; //V4L2_MEMORY_MMAP或V4L2_MEMORY_USERPTR u32 reserved[2]; };
struct v4l2_requestbuffers tV4L2_reqbuf; memset(&tV4L2_reqbuf, 0, sizeof(struct v4l2_requestbuffers )); tV4L2_reqbuf.count = 1; //申请缓冲区的个数 tV4L2_reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4L2_reqbuf.memory = V4L2_MEMORY_MMAP; //mmap方式 iret = ioctl(fd_usbcam, VIDIOC_REQBUFS, &tV4L2_reqbuf);
struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; __u32 flags; enum v4l2_field field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence; /* memory location */ enum v4l2_memory memory; union { __u32 offset; unsigned long userptr; } m; __u32 length; __u32 input; __u32 reserved; };
struct v4l2_buffer tV4L2buf; memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer)); tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4L2buf.memory = V4L2_MEMORY_MMAP; tV4L2buf.index = i; // 要获取内核视频缓冲区的信息编号 iret = ioctl(fd_usbcam, VIDIOC_QUERYBUF, &tV4L2buf); // 把内核空间缓冲区映射到用户空间缓冲区 AppBufLength = tV4L2buf.length; AppBufStartAddr = mmap( NULL, /* start anywhere */ tV4L2buf.length, PROT_READ | PROT_WRITE, /* access privilege */ MAP_SHARED, /* recommended */ fd_usbcam, tV4L2buf.m.offset);
struct v4l2_buffer tV4L2buf; memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer)); tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4L2buf.memory = V4L2_MEMORY_MMAP; tV4L2buf.index = i; //指令(指定)要投放到视频输入队列中的内核空间视频缓冲区的编号; iret = ioctl(fd_usbcam, VIDIOC_QBUF, &tV4L2buf);
struct v4l2_buffer tV4L2buf; memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer)); tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tV4L2buf.memory = V4L2_MEMORY_MMAP; iret = ioctl(fd_usbcam, VIDIOC_DQBUF, &tV4L2buf);
enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, V4L2_BUF_TYPE_VBI_CAPTURE = 4, V4L2_BUF_TYPE_VBI_OUTPUT = 5, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, #if 1 /* Experimental */ V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, #endif V4L2_BUF_TYPE_PRIVATE = 0x80, };
enum v4l2_buf_type v4l2type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fd_set fds ; struct timeval tv; iret = ioctl(fd_usbcam, VIDIOC_STREAMON, &v4l2type); FD_ZERO(&fds); FD_SET(fd_usbcam, &fds); tv.tv_sec = 2; /* Timeout. */ tv.tv_usec = 0; iret = select(fd_usbcam+ 1, &fds, NULL, NULL, &tv);
enum v4l2_buf_type v4l2type = V4L2_BUF_TYPE_VIDEO_CAPTURE; iret = ioctl(fd_usbcam, VIDIOC_STREAMOFF, &v4l2type);
v4l2_std_id std; do{ ret= ioctl(fd, VIDIOC_QUERYSTD, &std); } while(ret== -1 && errno== EAGAIN); switch(std) { caseV4L2_STD_NTSC: //…… caseV4L2_STD_PAL: //…… }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <getopt.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <malloc.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <asm/types.h> #include <linux/videodev2.h> #define CAMERA_DEVICE "/dev/video0" #define CAPTURE_FILE "frame.jpg" #define VIDEO_WIDTH 640 #define VIDEO_HEIGHT 480 #define VIDEO_FORMAT V4L2_PIX_FMT_YUYV #define BUFFER_COUNT 4 typedef struct VideoBuffer { void *start; size_t length; } VideoBuffer; VideoBuffer framebuf[BUFFER_COUNT]; //修改了错误,2012-5.21 int main() { int i, ret; // 打开设备 int fd; fd = open(CAMERA_DEVICE, O_RDWR, 0); if (fd < 0) { printf("Open %s failed\n", CAMERA_DEVICE); return -1; } // 获取驱动信息 struct v4l2_capability cap; ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); if (ret < 0) { printf("VIDIOC_QUERYCAP failed (%d)\n", ret); return ret; } // Print capability infomations printf("Capability Informations:\n"); printf(" driver: %s\n", cap.driver); printf(" card: %s\n", cap.card); printf(" bus_info: %s\n", cap.bus_info); printf(" version: %08X\n", cap.version); printf(" capabilities: %08X\n", cap.capabilities); // 设置视频格式 struct v4l2_format fmt; memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = VIDEO_WIDTH; fmt.fmt.pix.height = VIDEO_HEIGHT; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; ret = ioctl(fd, VIDIOC_S_FMT, &fmt); if (ret < 0) { printf("VIDIOC_S_FMT failed (%d)\n", ret); return ret; } // 获取视频格式 ret = ioctl(fd, VIDIOC_G_FMT, &fmt); if (ret < 0) { printf("VIDIOC_G_FMT failed (%d)\n", ret); return ret; } // Print Stream Format printf("Stream Format Informations:\n"); printf(" type: %d\n", fmt.type); printf(" width: %d\n", fmt.fmt.pix.width); printf(" height: %d\n", fmt.fmt.pix.height); char fmtstr[8]; memset(fmtstr, 0, 8); memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4); printf(" pixelformat: %s\n", fmtstr); printf(" field: %d\n", fmt.fmt.pix.field); printf(" bytesperline: %d\n", fmt.fmt.pix.bytesperline); printf(" sizeimage: %d\n", fmt.fmt.pix.sizeimage); printf(" colorspace: %d\n", fmt.fmt.pix.colorspace); printf(" priv: %d\n", fmt.fmt.pix.priv); printf(" raw_date: %s\n", fmt.fmt.raw_data); // 请求分配内存 struct v4l2_requestbuffers reqbuf; reqbuf.count = BUFFER_COUNT; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.memory = V4L2_MEMORY_MMAP; ret = ioctl(fd , VIDIOC_REQBUFS, &reqbuf); if(ret < 0) { printf("VIDIOC_REQBUFS failed (%d)\n", ret); return ret; } // 获取空间 VideoBuffer* buffers = calloc( reqbuf.count, sizeof(*buffers) ); struct v4l2_buffer buf; for (i = 0; i < reqbuf.count; i++) { buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(fd , VIDIOC_QUERYBUF, &buf); if(ret < 0) { printf("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret); return ret; } // mmap buffer framebuf[i].length = buf.length; framebuf[i].start = (char *) mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (framebuf[i].start == MAP_FAILED) { printf("mmap (%d) failed: %s\n", i, strerror(errno)); return -1; } // Queen buffer ret = ioctl(fd , VIDIOC_QBUF, &buf); if (ret < 0) { printf("VIDIOC_QBUF (%d) failed (%d)\n", i, ret); return -1; } printf("Frame buffer %d: address=0x%x, length=%d\n", i, (unsigned int)framebuf[i].start, framebuf[i].length); } // 开始录制 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = ioctl(fd, VIDIOC_STREAMON, &type); if (ret < 0) { printf("VIDIOC_STREAMON failed (%d)\n", ret); return ret; } // Get frame ret = ioctl(fd, VIDIOC_DQBUF, &buf); if (ret < 0) { printf("VIDIOC_DQBUF failed (%d)\n", ret); return ret; } // Process the frame FILE *fp = fopen(CAPTURE_FILE, "wb"); if (fp < 0) { printf("open frame data file failed\n"); return -1; } fwrite(framebuf[buf.index].start, 1, buf.length, fp); fclose(fp); printf("Capture one frame saved in %s\n", CAPTURE_FILE); // Re-queen buffer ret = ioctl(fd, VIDIOC_QBUF, &buf); if (ret < 0) { printf("VIDIOC_QBUF failed (%d)\n", ret); return ret; } // Release the resource for (i=0; i< 4; i++) { munmap(framebuf[i].start, framebuf[i].length); } close(fd); printf("Camera test Done.\n"); return 0; }