v4l2实现Ubuntu视频图像采集并在虚拟机显示屏显示

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include <jpeglib.h>
#include <linux/fb.h>

int read_JPEG_file (const char *jpegData, char *rgbdata, int size)
{
	struct jpeg_error_mgr jerr;
	struct jpeg_decompress_struct cinfo;
	cinfo.err = jpeg_std_error(&jerr);
	//1创建解码对象并且初始化
	jpeg_create_decompress(&cinfo);
	//2.装备解码的数据
	//jpeg_stdio_src(&cinfo, infile);
	jpeg_mem_src(&cinfo,(unsigned char*)jpegData, size);
	//3.获取jpeg图片文件的参数
	(void) jpeg_read_header(&cinfo, TRUE);
	/* Step 4: set parameters for decompression */
	//5.开始解码
	(void) jpeg_start_decompress(&cinfo);
	//6.申请存储一行数据的内存空间
	int row_stride = cinfo.output_width * cinfo.output_components;
	unsigned char *buffer = malloc(row_stride);
	int i=0;
	while (cinfo.output_scanline < cinfo.output_height) {
		//printf("****%d\n",i);
		(void) jpeg_read_scanlines(&cinfo, &buffer, 1); 
		memcpy(rgbdata+i*640*3, buffer, row_stride );
		i++;
	}
	//7.解码完成
	(void) jpeg_finish_decompress(&cinfo);
	//8.释放解码对象
	jpeg_destroy_decompress(&cinfo);
	return 1;
}


int lcdfd=0;
unsigned int *lcdptr=NULL;
int lcd_w=800,lcd_h=480;
void lcd_show_rgb(unsigned char *rgbdata,int w,int h)
{
	printf("jin lai le 1\n");
	unsigned int *ptr=lcdptr;
	for(int i=0;i<h;i++)
	{
		for(int j=0;j<w;j++)
		{
			memcpy(ptr+j,rgbdata+j*3,3);
		}
		ptr+=lcd_w;
		rgbdata+=w*3;
	}
}

int main(void)
{
	//0 chu shi hua lcd
	lcdfd=open("/dev/fb0",O_RDWR);
	if(lcdfd<0)
	{
		printf("lcd open is error\n");
		return -1;
	}

	//huo qu lcd shu xing
	struct fb_var_screeninfo info;
	int lret=ioctl(lcdfd,FBIOGET_VSCREENINFO,&info);
	lcd_w=info.xres_virtual;
	lcd_h=info.yres_virtual;

	lcdptr=(unsigned int*)mmap(NULL,lcd_w*lcd_h*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);

	//1.打开设备
	int fd = open("/dev/video0", O_RDWR);
	if(fd < 0)
	{
		perror("open is error\n");
		return -1;
	}

	//3.设置采集格式
	struct v4l2_format vfmt;
	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
	vfmt.fmt.pix.width = 320;//设置宽(不能任意)
	vfmt.fmt.pix.height = 240;//设置高
	vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//设置视频采集格式
	int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);//set
	if(ret < 0)
	{
		perror("VIDIOC_S_FMT is error\n");
	}
    printf("3 is okey\n");

	//4.申请内核空间
	struct v4l2_requestbuffers reqbuffer;
	reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuffer.count = 4; //申请4个缓冲区
	reqbuffer.memory = V4L2_MEMORY_MMAP ;//映射方式
	ret  = ioctl(fd, VIDIOC_REQBUFS, &reqbuffer);
	if(ret < 0)
	{
		perror("VIDIOC_REQBUFS is error\n");
	}
    printf("4 is okey\n");

	//5.映射
	unsigned char *mptr[4];//保存映射后用户空间的首地址
    unsigned int  size[4];
	struct v4l2_buffer mapbuffer;
	//初始化type, index
	mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	for(int i=0; i<4; i++)
	{
		mapbuffer.index = i;
		ret = ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer);//从内核空间中查询一个空间做映射
		if(ret < 0)
		{
			perror("VIDIOC_QUERYBUF is error\n");
		}
		mptr[i] = (unsigned char *)mmap(NULL, mapbuffer.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mapbuffer.m.offset);
        size[i]=mapbuffer.length;

		//通知使用完毕--‘放回去’
		ret  = ioctl(fd, VIDIOC_QBUF, &mapbuffer);
		if(ret < 0)
		{
			perror("VIDIOC_QBUF is error\n");
		}
	}
    printf("5 is okey\n");

	
	//6.start 
	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd, VIDIOC_STREAMON, &type);
	if(ret < 0)
	{
		perror("VIDIOC_STREAMON is error\n");
	}
	printf("6 is okey\n");

	//ding yi yi ge kong jian cun chu jie ma hou de rgb shu ju
	unsigned char rgbdata[640*480*3];
	while(1)
	{
		//7.cong dui lie zhong ti qu yi zhen shu ju
		struct v4l2_buffer  readbuffer;
		readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		ret = ioctl(fd, VIDIOC_DQBUF, &readbuffer);
		if(ret < 0)
		{
			perror("VIDIOC_DQBUF is error\n");
		}
		printf("777\n");
		//xian shi zai lcd shang
		read_JPEG_file (mptr[readbuffer.index], rgbdata, readbuffer.length);
		printf("1212121212\n");
		lcd_show_rgb(rgbdata,640,480);
		printf("7 is okey\n");

		//通知内核已经使用完毕
		ret = ioctl(fd, VIDIOC_QBUF, &mapbuffer);
		if(ret < 0)
		{
			perror("VIDIOC_QBUF is error\n");
		}
		printf("8 is okey\n");
	}

	//end
	ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
	printf("end is okey\n");
    
    for(int i=0; i<4; i++)
	{
		munmap(mptr[i], size[i]);
	}
	printf("munmap is okey\n");

	//9.关闭设备
	close(fd);
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 首先需要安装v4l2和uvc驱动,在终端中输入以下命令: ``` sudo apt-get install v4l-utils uvcdynctrl ``` 2. 然后使用v4l2-ctl命令查看摄像头设备的信息,例如: ``` v4l2-ctl --list-devices ``` 3. 接下来,使用v4l2-ctl命令设置摄像头的参数,例如分辨率、帧率等。 ``` v4l2-ctl --set-fmt-video=width=640,height=480,pixelformat=YUYV --set-parm=30 ``` 4. 接着,使用OpenCV库来进行视频采集显示,代码示例如下: ``` #include <opencv2/opencv.hpp> #include <iostream> #include <stdio.h> using namespace cv; using namespace std; int main() { VideoCapture cap(0); //打开摄像头 if(!cap.isOpened()) //检查摄像头是否成功打开 { cout << "Error opening camera" << endl; return -1; } int fps = 30; //设置帧率 cap.set(CAP_PROP_FRAME_WIDTH, 640); //设置分辨率 cap.set(CAP_PROP_FRAME_HEIGHT, 480); cap.set(CAP_PROP_FPS, fps); namedWindow("Video", WINDOW_NORMAL); //创建窗口 VideoWriter writer("output.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, Size(640, 480)); //创建视频写入器 while(true) { Mat frame; cap >> frame; //采集一帧图像 imshow("Video", frame); //显示图像 writer.write(frame); //将图像写入视频文件 char c = waitKey(1); if(c == 27) //按下ESC键退出循环 { break; } } cap.release(); //释放摄像头 writer.release(); //释放视频写入器 destroyAllWindows(); //关闭窗口 return 0; } ``` 5. 最后编译并运行代码,即可进行视频采集显示,并将采集到的视频保存成output.avi文件。 ``` g++ -o main main.cpp `pkg-config opencv --cflags --libs` ./main ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值