查看摄像头支持的MJPG格式的分辨率和帧率:
$ v4l2-ctl --list-formats-ext --device /dev/video0
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture
[0]: 'MJPG' (Motion-JPEG, compressed)
Size: Discrete 1280x720
Interval: Discrete 0.008s (120.000 fps)
Interval: Discrete 0.017s (60.000 fps)
Interval: Discrete 0.033s (30.000 fps)
Interval: Discrete 0.040s (25.000 fps)
Size: Discrete 640x480
Interval: Discrete 0.008s (120.000 fps)
[1]: 'YUYV' (YUYV 4:2:2)
Size: Discrete 640x480
Interval: Discrete 0.033s (30.000 fps)
由v4l2-ctl命令的执行结果可知,最大支持1280X70,该分辨率最高120帧每秒。
测试结果:
这是
测试代码
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d -- "format"\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
#define _DEBUG_PRINT
#ifdef _DEBUG_PRINT
#define DEBUG_PRINT(format,...) printf(format,##__VA_ARGS__)
#else
#define DEBUG_PRINT(format,...)
#endif
// ip addr add 192.168.0.12/24 dev ens33
#define _DEBUG_CORE
#ifdef _DEBUG_CORE
#define DEBUG_CORE(format, ...) printf("%s:%s:%d -- "format"\n" \
,__FILE__,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_CORE(format, ...)
#endif
#define DEV_NAME "/dev/video0"
int fd = 0;
int write_mjpg(char *data,int len,int index)
{
char name[20];
snprintf(name,sizeof(name),"%d.mjpg",index);
int fd = open(name,O_WRONLY | O_CREAT | O_TRUNC,0660);
if(fd < 0){
perror("open");
return 0;
}
DEBUG_INFO("open %s ok",name);
int res = write(fd,data,len);
DEBUG_INFO("write %s ok,res = %d",name,res);
close(fd);
return 0;
}
int main(int argc, char **argv)
{
int fd = 0;
int res = 0;
fd = open(DEV_NAME,O_RDWR);
if(fd < 0){
perror("open");
DEBUG_INFO("open %s fail",DEV_NAME);
return -1;
}
struct v4l2_capability cap;
res = ioctl(fd,VIDIOC_QUERYCAP,&cap);
if(res < 0){
perror("VIDIOC_QUERYCAP:");
return -1;
}
if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
DEBUG_INFO("%s is not a camera",DEV_NAME);
return -1;
}
if((cap.capabilities & V4L2_CAP_READWRITE)){
DEBUG_INFO("V4L2_CAP_READWRITE is ok");
}else{
DEBUG_INFO("V4L2_CAP_READWRITE is not ok");
}
if((cap.capabilities & V4L2_CAP_STREAMING)){
DEBUG_INFO("V4L2_CAP_STREAMING is ok");
}else{
DEBUG_INFO("V4L2_CAP_STREAMING is not ok");
}
DEBUG_INFO("%s is a camera",DEV_NAME);
struct v4l2_fmtdesc v4l2_fmtdesc;
v4l2_fmtdesc.index = 0;
struct v4l2_frmsizeenum v4l2_frmsize;
//枚举支持的像素格式
while(1){
v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
res = ioctl(fd,VIDIOC_ENUM_FMT,&v4l2_fmtdesc);
if(res < 0){
break;
}
if(v4l2_fmtdesc.pixelformat == V4L2_PIX_FMT_YUYV){
DEBUG_INFO("V4L2_PIX_FMT_YUYV");
}
if(v4l2_fmtdesc.pixelformat == V4L2_PIX_FMT_MJPEG){
DEBUG_INFO("V4L2_PIX_FMT_MJPEG");
}
printf("fmt: %s <0x%x> %s\n", v4l2_fmtdesc.description, v4l2_fmtdesc.pixelformat,(char*)&v4l2_fmtdesc.pixelformat);
v4l2_frmsize.index = 0;
v4l2_frmsize.pixel_format = v4l2_fmtdesc.pixelformat;
//枚举指定格式支持的分辨率
while(1){
res = ioctl(fd,VIDIOC_ENUM_FRAMESIZES,&v4l2_frmsize);
if(res < 0){
break;
}
printf("frame_size<%d*%d>\n", v4l2_frmsize.discrete.width, v4l2_frmsize.discrete.height);
struct v4l2_frmivalenum v4l2_frmival;
v4l2_frmival.index = 0;
v4l2_frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_frmival.pixel_format = v4l2_fmtdesc.pixelformat;
v4l2_frmival.width = v4l2_frmsize.discrete.width;
v4l2_frmival.height = v4l2_frmsize.discrete.height;
//枚举指定格式,分辨率,支持的帧率
while(1){
res = ioctl(fd,VIDIOC_ENUM_FRAMEINTERVALS,&v4l2_frmival);
if(res < 0){
break;
}
printf("denominator=%d,numerator=%d,Frame interval<%fps> \n",
v4l2_frmival.discrete.denominator,
v4l2_frmival.discrete.numerator,
(float)v4l2_frmival.discrete.denominator / (float)v4l2_frmival.discrete.numerator);
v4l2_frmival.index++;
}
v4l2_frmsize.index++;
}
v4l2_fmtdesc.index++;
}
//查询当前的支持的格式
DEBUG_INFO("获取当前支持的格式");
struct v4l2_format v4l2_fmt;
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
res = ioctl(fd, VIDIOC_G_FMT, &v4l2_fmt);
if(res < 0){
perror("VIDIOC_G_FMT:");
return -1;
}
printf("width:%d, height:%d format:%d -- %s,byesperline = %d\n", v4l2_fmt.fmt.pix.width,
v4l2_fmt.fmt.pix.height,
v4l2_fmt.fmt.pix.pixelformat,
(char*)&v4l2_fmt.fmt.pix.pixelformat,
v4l2_fmt.fmt.pix.bytesperline);
printf("field = %d,%s\n",v4l2_fmt.fmt.pix.field,(char*)&v4l2_fmt.fmt.pix.field);
printf("colorspace = %d,%s\n",v4l2_fmt.fmt.pix.colorspace,(char*)&v4l2_fmt.fmt.pix.colorspace);
printf("sizeimage = %d,%s\n",v4l2_fmt.fmt.pix.sizeimage,(char*)&v4l2_fmt.fmt.pix.field);
if(V4L2_COLORSPACE_SRGB == v4l2_fmt.fmt.pix.colorspace){
DEBUG_INFO("V4L2_COLORSPACE_SRGB");
}
//设置图像格式
struct v4l2_format v4l2_set_fmt;
v4l2_set_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_set_fmt.fmt.pix.width = 1280;
v4l2_set_fmt.fmt.pix.height = 720;
v4l2_set_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
res = ioctl(fd,VIDIOC_S_FMT,&v4l2_set_fmt);
if(res < 0){
perror("VIDIOC_G_FMT:");
return -1;
}
printf("width:%d, height:%d \n",v4l2_set_fmt.fmt.pix.width,v4l2_set_fmt.fmt.pix.height);
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
res = ioctl(fd, VIDIOC_G_FMT, &v4l2_fmt);
if(res < 0){
perror("VIDIOC_G_FMT:");
return -1;
}
DEBUG_INFO("width:%d, height:%d format:%d -- %s,byesperline = %d\n", v4l2_fmt.fmt.pix.width,
v4l2_fmt.fmt.pix.height,
v4l2_fmt.fmt.pix.pixelformat,
(char*)&v4l2_fmt.fmt.pix.pixelformat,
v4l2_fmt.fmt.pix.bytesperline);
printf("field = %d,%s\n",v4l2_fmt.fmt.pix.field,(char*)&v4l2_fmt.fmt.pix.field);
printf("colorspace = %d,%s\n",v4l2_fmt.fmt.pix.colorspace,(char*)&v4l2_fmt.fmt.pix.colorspace);
printf("sizeimage = %d,%s\n",v4l2_fmt.fmt.pix.sizeimage,(char*)&v4l2_fmt.fmt.pix.field);
if(V4L2_COLORSPACE_SRGB == v4l2_fmt.fmt.pix.colorspace){
DEBUG_INFO("V4L2_COLORSPACE_SRGB");
}
struct v4l2_streamparm v4l2_streamparm;
v4l2_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
res = ioctl(fd,VIDIOC_G_PARM,&v4l2_streamparm);
if(res < 0){
perror("VIDIOC_G_PARM:");
return -1;
}
DEBUG_INFO("denominator = %d,numerator = %d\n",
v4l2_streamparm.parm.capture.timeperframe.denominator,
v4l2_streamparm.parm.capture.timeperframe.numerator);
//申请帧缓冲
struct v4l2_requestbuffers v4l2_reqbuf;
v4l2_reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_reqbuf.count = 3;
v4l2_reqbuf.memory = V4L2_MEMORY_MMAP;
res = ioctl(fd,VIDIOC_REQBUFS,&v4l2_reqbuf);
if(res < 0){
perror("VIDIOC_REQBUFS:");
return -1;
}
#define REQUEST_BUF_COUNT 3
void *frm_base[REQUEST_BUF_COUNT];
struct v4l2_buffer v4l2_buf;
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buf.memory = V4L2_MEMORY_MMAP;
for(v4l2_buf.index = 0;v4l2_buf.index < REQUEST_BUF_COUNT;v4l2_buf.index++){
res = ioctl(fd,VIDIOC_QUERYBUF,&v4l2_buf);
if(res < 0){
perror("VIDIOC_G_PARM:");
return -1;
}
printf("bytesused = %d,",v4l2_buf.bytesused);
printf("offset = %d,",v4l2_buf.m.offset);
printf("length = %d,",v4l2_buf.length);
printf("index = %d,",v4l2_buf.index);
printf("memory = %d\n",v4l2_buf.memory);
frm_base[v4l2_buf.index] = mmap(NULL,v4l2_buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd,v4l2_buf.m.offset);
if(MAP_FAILED == frm_base[v4l2_buf.index]){
perror("mmap");
return -1;
}
DEBUG_INFO("mmap %d ok",v4l2_buf.index);
// v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// v4l2_buf.memory = V4L2_MEMORY_MMAP;
// res = ioctl(fd,VIDIOC_QBUF,&v4l2_buf);
// if(res < 0){
// perror("VIDIOC_QBUF");
// return -1;
// }
// DEBUG_INFO("push %d ok",v4l2_buf.index);
}
struct v4l2_buffer v4l2_push_buf;
v4l2_push_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_push_buf.memory = V4L2_MEMORY_MMAP;
for(v4l2_push_buf.index = 0;v4l2_push_buf.index < REQUEST_BUF_COUNT;v4l2_push_buf.index++){
res = ioctl(fd,VIDIOC_QBUF,&v4l2_push_buf);
if(res < 0){
perror("VIDIOC_QBUF");
return -1;
}
DEBUG_INFO("push %d ok",v4l2_push_buf.index);
}
enum v4l2_buf_type v4l2_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
res = ioctl(fd,VIDIOC_STREAMON,&v4l2_buf_type);
if(res < 0){
perror("VIDIOC_STREAMON");
return -1;
}
DEBUG_INFO("VIDIOC_STREAMON ok");
struct v4l2_buffer v4l2_process_buf;
v4l2_process_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_process_buf.memory = V4L2_MEMORY_MMAP;
// v4l2_process_buf.length = 614400;
int i = 0;
DEBUG_INFO("开始读图");
// char *grey_buf = malloc(614400);
// if(grey_buf == NULL){
// DEBUG_INFO("malloc error");
// return -1;
// }
for(i = 0;i < REQUEST_BUF_COUNT;i++){
// v4l2_process_buf.m.offset = 614400 * v4l2_process_buf.index;
res = ioctl(fd,VIDIOC_DQBUF,&v4l2_process_buf);
if(res < 0){
perror("VIDIOC_DQBUF");
DEBUG_INFO("res = %d,i = %d",res,i);
goto end;
}
printf("出队后:");
printf("bytesused = %d,",v4l2_process_buf.bytesused);
printf("offset = %d,",v4l2_process_buf.m.offset);
printf("length = %d,",v4l2_process_buf.length);
printf("index = %d,",v4l2_process_buf.index);
printf("memory = %d\n",v4l2_process_buf.memory);
//保存MJPG
write_mjpg(frm_base[v4l2_process_buf.index],v4l2_process_buf.bytesused,v4l2_process_buf.index);
res = ioctl(fd,VIDIOC_QBUF,&v4l2_process_buf);
if(res < 0){
perror("VIDIOC_QBUF");
DEBUG_INFO("res = %d,index = %d",res,v4l2_process_buf.index);
goto end;
}
printf("入队后:");
printf("bytesused = %d,",v4l2_process_buf.bytesused);
printf("offset = %d,",v4l2_process_buf.m.offset);
printf("length = %d,",v4l2_process_buf.length);
printf("index = %d,",v4l2_process_buf.index);
printf("memory = %d\n",v4l2_process_buf.memory);
}
DEBUG_INFO("process ok");
end:
res = ioctl(fd,VIDIOC_STREAMOFF,&v4l2_buf_type);
if(res < 0){
perror("VIDIOC_STREAMOFF");
return -1;
}
DEBUG_INFO("VIDIOC_STREAMOFF ok");
DEBUG_INFO("open %s ok",DEV_NAME);
close(fd);
return 0;
};