Linux嵌入式相机 — 项目总结

main函数执行流程

  • 1、初始化触摸屏

    Touch_screen_Init();
    
    struct tsdev *ts = NULL;
    ts = ts_setup(NULL, 0);    //以阻塞打开
    
  • 2、初始化 LCD

    LCD_Init(void);   
    

    通过 ioctl 函数获取 LCD 的固定参数、可变参数,得到分辨率、bpp、一行的长度(以字节为单位),将显存映射到内存上,得到 framebuffer 的首地址,使用 memset 函数将这块区域全部设置为 1,即将LCD设置为白色背景

    struct fb_var_screeninfo var;   /* Current var */
    struct fb_fix_screeninfo fix;   /* Current fix */
    ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);//获取屏幕可变信息
    ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);//获取屏幕固定信息
    ...
    unsigned char* fbbase;
    fbbase = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);   // 映射 screen_size:整块显存的大小
    memset(fbbase, 0xFF, screem_size);
    
  • 3、打开摄像头

    int fd = open("/dev/video1", O_RDWR);
    
  • 4、将背景图片1(带有拍照、相册按钮)显示在 LCD 上

    LCD_Show_JPEG(background1);
    

    这个图片的分辨率是 1024 * 600(板子的屏幕的分辨率也是 1024 * 600)

  • 5、将图片放入相册

    将指定目录(/home/)中已有的图片(.jpg格式)加入双向链表中,image_count 为目前图片名称最大索引

    image_count = xiangce_Init();
    
  • 6、遍历链表

    jpeg_list_printf(void)
    

    遍历双向链表(不包含虚拟头节点),打印所有照片的名字

  • 7、设置摄像头的采集格式

    struct v4l2_format vfmt;
    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	//选择视频抓取
    // 一定是 800 * 600(600等于LCD的高度,8800于LCD的宽度是为了显示相机的按钮)
    vfmt.fmt.pix.width  = 800;//设置宽
    vfmt.fmt.pix.height = 600;//设置高
    vfmt.fmt.pix.pixelformat =  V4L2_PIX_FMT_MJPEG;//设置视频采集像素格式
    
    int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);// VIDIOC_S_FMT:设置捕获格式
    if(ret < 0)
    {
    	perror("设置采集格式错误");
    }
    // 判断是否设置成功
    memset(&vfmt, 0, sizeof(vfmt));
    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd, VIDIOC_G_FMT, &vfmt);	
    if(ret < 0)
    {
    	perror("读取采集格式失败");
    }
    printf("设置分辨率width = %d\n", vfmt.fmt.pix.width);
    printf("设置分辨率height = %d\n", vfmt.fmt.pix.height);
    unsigned char *p = (unsigned char*)&vfmt.fmt.pix.pixelformat;
    printf("pixelformat = %c%c%c%c\n", p[0],p[1],p[2],p[3]);
    
  • 8、申请缓冲队列

    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("申请缓冲队列失败");
    }
    
  • 9、映射

    struct v4l2_buffer mapbuffer;
    unsigned char *mmpaddr[4];   //用于存储映射后的首地址
    unsigned int  addr_length[4];//存储映射后空间的大小
    mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//初始化type
    for(int i = 0; i < 4; i++)
    {
    	mapbuffer.index = i;
    	ret = ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer);	//查询缓存信息
    	if(ret < 0)
    		perror("查询缓存队列失败");
    	mmpaddr[i] = (unsigned char *)mmap(NULL, mapbuffer.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mapbuffer.m.offset);//mapbuffer.m.offset映射文件的偏移量
    	addr_length[i] = mapbuffer.length;
    	//放入队列
    	ret = ioctl(fd, VIDIOC_QBUF, &mapbuffer);   // 将用户空间的视频缓冲区送入内核中
    	if(ret < 0)
    		perror("放入队列失败");
    }
    
  • 10、打开设备(启动视频流传输)

    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd, VIDIOC_STREAMON, &type);
    if(ret < 0)
    {
    	perror("打开设备失败");
    }
    
  • 11、创建线程读取触摸屏输入

    pthread_t pthread_read;
    pthread_create(&pthread_read, NULL, start_read, NULL);
    

    线程函数:

    如果点击触摸屏,并且触摸点在 “ 拍照 ” “ 相册 ” 按钮范围内,则会记录触摸点的坐标 read_x read_y(全局变量)

    void *start_read(void *arg)
    {
    	int x = 0, y =0;
    	while(start_read_flag)     // 初始化为1,当整个程序要退出时,设为0,退出线程
    	{
    		printf("线程\n");
    		read_touchscreen(&x, &y);     // 阻塞读取触点坐标
    		//拍照
    		if(x  > 800 && x < 1000 && y > 0 && y < 600)
    		{
    			printf("chuli\n");
    			pthread_mutex_lock(&mutex);
    			read_x = x;
     			read_y = y;
    			pthread_mutex_unlock(&mutex);
    		}
    		printf("readx = %d, ready = %d", read_x, read_y);
    	}
    	return NULL;
    }
    

    read_touchscreen 函数:

    ts_read 的默认读取是以阻塞的方式

    int read_touchscreen(int *x, int *y)
    {
    	struct ts_sample samp;
    	// ts_setup 以阻塞的方式打开了触摸屏设备,所以 ts_read 是阻塞读取
    	if (ts_read(ts, &samp, 1) < 0)   // 1:代表对一个触摸点的采集数
    	{
    		perror("ts_read error");
    		ts_close(ts);
    		return -1;
    	}
    	*x = samp.x;
    	*y = samp.y;
    	printf("anxia : %d %d", samp.x, samp.y);
    	return 0;
    }
    
  • 12、进入 while 循环,提取摄像头数据,并在LCD上显示同时实现拍照、相册功能

    	while(1)
    	{
    		//从队列中提取一帧数据
    		struct v4l2_buffer readbuffer;
    		readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    		ret = ioctl(fd, VIDIOC_DQBUF, &readbuffer);     //从缓冲队列获取一帧数据(出队列)
    		//出队列后得到缓存的索引index,得到对应缓存映射的地址mmpaddr[readbuffer.index]
    		if(ret < 0)
    			perror("获取数据失败");
    	
    		if(read_x > 850 && read_x < 1000 && read_y > 0 && read_y < 600)
    		{
    			
    			if(read_x > 850 && read_x < 1000 && read_y > 130 && read_y < 210)
    			{
    				printf("paizhao\n");
    				char newname[20] = {0};
    				image_count++;
    				sprintf(newname,"/home/%d.jpg", image_count);
    
    				FILE *file = fopen(newna
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值