一、主要功能:
(1)当进入监控操作界面后,先是解锁界面,解锁后点击选项进入后,有四个功能按钮模块,分别是:监控(打开摄像头)、录制、播放(显示已经拍的视频)、抓拍、退出(退回到主界面)。
二、详细设计
嵌入式开发板型号GEC6818,开发平台Ubuntu16.04
1,摄像头模块;
在Linux系统下采集摄像头数据,需要用到V4l2的API接口 摄像头的采集的视频画面:是由一帧一帧的数据组合在一起帧格式: mjpeg yuyv rgb yuv 帧的原始格式由摄像头厂家编写的,此时需要调用V4l2 API进行代码的编写Video for Linuxtwo(Video4Linux2)简称V4L2,是V4L的改进版。V4L2是linux操作系统下用于采集图片、视频和音频数据的API接口,配合适当的视频采集设备和相应的驱动程序,可以实现图片、视频、音频等的采集。在远程会议、可视电话、视频监控系统和嵌入式多媒体终端中都有广泛的应用。在Linux下,所有外设都被看成一种特殊的文件,成为“设备文件”,可以象访问普通文件一样对其进行读写。一般来说,采用V4L2驱动的摄像头设备文件是/dev/video7。V4L2支持两种方式来采集图像:内存映射方式(mmap)和直接读取方式(read)。V4L2在include/linux/videodev.h文件中定义了一些重要的数据结构,在采集图像的过程中,就是通过对这些数据的操作来获得最终的图像数据。应用程序通过V4L2进行视频采集的原理V4L2支持内存映射方式(mmap)和直接读取方式(read)来采集数据,前者一般用于连续视频数据的采集,后者常用于静态图片数据的采集,本文重点讨论内存映射方式的视频采集。应用程序通过V4L2接口采集视频数据分为五个步骤:
首先,打开视频设备文件,进行视频采集的参数初始化,通过V4L2接口设置视频图像的采集窗口、采集的点阵大小和格式;
其次,申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间映射到用户空间,便于应用程序读取/处理视频数据;
第三,将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集;
第四,驱动开始视频数据的采集,应用程序从视频采集输出队列取出帧缓冲区,处理完后,将帧缓冲区重新放入视频采集输入队列,循环往复采集连续的视频数据;
第五,停止视频采集。
用户工作流程:
打开设备-> 检查和设置设备属性->设置帧格式-> 设置一种输入输出方法(缓冲区管理)-> 循环获取数据-> 关闭设备。
#include //printf scanf
#include //open write read lseek close
#include
#include
#include
#include
#include
#include "jpeg.h"
#include "camera.h"
#include "api_v4l2.h"
#include "jpeglib.h"
static unsigned char g_color_buf[FB_SIZE]={0};
int ts_x, ts_y;
int flag = 1;
int lcd_fd;
int *mmap_fd;
struct jpg_data video_buf;//定义结构体变量
//初始化LCD
int lcd_open(void)
{
lcd_fd = open("/dev/fb0", O_RDWR);
if(lcd_fd<0)
{
printf("open lcd errorn");
return -1;
}
return 0;
}
int mmap_lcd(void)
{
mmap_fd = (int *)mmap( NULL, //映射区的开始地址,设置为NULL时表示由系统决定映射区的起始地址
FB_SIZE, //映射区的长度
PROT_READ|PROT_WRITE, //内容可以被读取和写入
MAP_SHARED, //共享内存
lcd_fd, //有效的文件描述词
0 //被映射对象内容的起点
);
return lcd_fd;
}
//LCD画点
void lcd_draw_point(unsigned int x,unsigned int y, unsigned int color)
{
*(mmap_fd+y*800+x)=color;
}
//显示摄像头捕捉
int show_video_data(unsigned int x,unsigned int y,char *pjpg_buf,unsigned int jpg_buf_size)
{
/*定义解码对象,错误处理对象*/
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
unsigned char *pcolor_buf = g_color_buf;
char *pjpg;
unsigned int i=0;
unsigned int color =0;
//unsigned int count =0;
unsigned int x_s = x;
unsigned int x_e ;
unsigned int y_e ;
pjpg = pjpg_buf;
/*注册出错处理*/
cinfo.err = jpeg_std_error(&jerr);
/*创建解码*/
jpeg_create_decompress(&cinfo);
/*直接解码内存数据*/
jpeg_mem_src(&cinfo,pjpg,jpg_buf_size);
/*读文件头*/
jpeg_read_header(&cinfo, TRUE);
/*开始解码*/
jpeg_start_decompress(&cinfo);
x_e = x_s+cinfo.output_width;
y_e = y +cinfo.output_height;
/*读解码数据*/
while(cinfo.output_scanline < cinfo.output_height )
{
pcolor_buf = g_color_buf;
/* 读取jpg一行的rgb值 */
jpeg_read_scanlines(&cinfo,&pcolor_buf,1);
for(i=0; i
{
/* 获取rgb值 */
color = *(pcolor_buf+2);
color = color | *(pcolor_buf+1)<<8;
color = color | *(pcolor_buf)<<16;
/* 显示像素点 */
lcd_draw_point(x,y,color);
pcolor_buf +=3;
x++;
}
/* 换行 */
y++;
x = x_s;
}
/*解码完成*/
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return 0;
}
//LCD关闭
void lcd_close(void)
{
/* 取消内存映射 */
munmap(mmap_fd, FB_SIZE);
/* 关闭LCD设备 */
close(lcd_fd);
}
//获取jpg文件的大小
unsigned long file_size_get(const char *pfile_path)
{
unsigned long filesize = -1;
struct stat statbuff;
if(stat(pfile_path, &statbuff) < 0)
{
return filesize;
}
else
{
filesize = statbuff.st_size;
}
return filesize;
}
void *start_routine(void *arg)
{
while(flag)
{
read_ts(&ts_x, &ts_y);
printf("==(x,y):(%d, %d)n", ts_x, ts_y);
}
}
int my_camera(void)
{
int fd_jpg = -1;
int cnt = 0;
char path[30] = {0};
lcd_open();//打开LCD屏幕
mmap_lcd();//创建映射关系,将DDR3中存储的摄像头采集的数据映射到LCD屏幕上显示。
pthread_t ts_thread;
pthread_create(&ts_thread, NULL, start_routine, NULL);
linux_v4l2_yuyv_init("/dev/video7");//初始化摄像头
linux_v4l2_start_yuyv_capturing();//开启摄像头捕捉
while(1)
{
if(ts_x>660 && ts_x<790 && ts_y>10 && ts_y<60)//实时监控
{
linux_v4l2_get_yuyv_data(&video_buf);//获取摄像头捕捉的画面
show_video_data(0, 0, video_buf.jpg_data, video_buf.jpg_size);//显示摄像头捕捉的画面
}
if(ts_x>660 && ts_x<790 && ts_y>200 && ts_y<220)//zhuapai
{
linux_v4l2_get_yuyv_data(&video_buf);//获取摄像头捕捉的画面
show_video_data(0, 0, video_buf.jpg_data, video_buf.jpg_size);//显示摄像头捕捉的画面
sprintf(path, "./video/%d.jpg",1);
fd_jpg = open(path, O_RDWR|O_CREAT|O_TRUNC);
if(fd_jpg == -1)
{
printf("creat errn");
printf("video errn");
}
write(fd_jpg, video_buf.jpg_data, video_buf.jpg_size);
printf("成功抓拍%d张rn",1);
show_jpeg("./video/1.jpg");
sleep(5);
close(fd_jpg);
ts_x=ts_y=0;
}
if(ts_x>650 && ts_x<800 && ts_y>110 && ts_y<180)
{
linux_v4l2_get_yuyv_data(&video_buf);//获取摄像头捕捉的画面
show_video_data(0, 0, video_buf.jpg_data, video_buf.jpg_size);//显示摄像头捕捉的画面
cnt++;
sprintf(path, "./video/%d.jpg",cnt);
fd_jpg = open(path, O_RDWR|O_CREAT|O_TRUNC);
if(fd_jpg == -1)
{
printf("creat errn");
printf("video errn");
}
write(fd_jpg, video_buf.jpg_data, video_buf.jpg_size);
printf("成功录制%d张rn",cnt);
close(fd_jpg);
//ts_x=ts_y=0;
}
//播放录制的图像
if(ts_x>710 && ts_x<800 && ts_y>280&& ts_y<310)
{
int shu;
printf("开始播放。。。rn");
for(shu=1;shu<=cnt;shu++)
{
sprintf(path,"./video/%d.jpg",shu);
show_jpeg(path);
usleep(30000);
}
printf("播放结束!!!rn");
ts_x=ts_y=0;
//break;
}
if(ts_x>660 && ts_x<790 && ts_y>410 && ts_y<480)//退出监控
{
printf("n======退出监控======n");
flag = 0;
//break;
//return;
}
}
//关闭摄像头
linux_v4l2_yuyv_quit();
lcd_close();
return 0;
}
2、 LCD显示模块
通过open打开LCD屏幕驱动(/dev/fb0),然后通过read读取bmp图片数据。期间需要把24bmp的数据转换成32位的LCD数据,通过write将转换的32位数据写入屏幕驱动里面,之后关闭lcd和bmp。最后将此模块封装成函数show_bmp(),以便调用。对JPEG图片的显示通过jpeglib库实现,具体函数已封装为lcd_draw_jpg()。
x : 起点
y : 起点
pjpg_path :图片路径
pjpg_buf :默认为NULL
jpg_buf_size:默认设为0
jpg_half : 为1时显示一半,为0时显示全部
*/
int lcd_draw_jpg(unsigned int x,unsigned int y,const char *pjpg_path,char *pjpg_buf,unsigned int jpg_buf_size,unsigned int jpg_half)
{
char g_color_buf[FB_SIZE]={0};
//初始化LCD
int g_fb_fd = open("/dev/fb0", O_RDWR);
if(g_fb_fd<0)
{
printf("open lcd errorn");
return -1;
}
int *g_pfb_memory = (int *)mmap( NULL, //映射区的开始地址,设置为NULL时表示由系统决定映射区的起始地址
FB_SIZE, //映射区的长度
PROT_READ|PROT_WRITE, //内容可以被读取和写入
MAP_SHARED, //共享内存
g_fb_fd, //有效的文件描述词
0 //被映射对象内容的起点
);
/*定义解码对象,错误处理对象*/
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
char *pcolor_buf = g_color_buf;
char *pjpg;
unsigned int i=0;
unsigned int color =0;
unsigned int count =0;
unsigned int x_s = x;
unsigned int x_e ;
unsigned int y_e ;
int jpg_fd;
unsigned int jpg_size;
unsigned int jpg_width;
unsigned int jpg_height;
if(pjpg_path!=NULL)
{
/* 申请jpg资源,权限可读可写 */
jpg_fd=open(pjpg_path,O_RDWR);
if(jpg_fd == -1)
{
printf("open %s errorn",pjpg_path);
return -1;
}
/* 获取jpg文件的大小 */
jpg_size=file_size_get(pjpg_path);
/* 为jpg文件申请内存空间 */
pjpg = malloc(jpg_size);
/* 读取jpg文件所有内容到内存 */
read(jpg_fd,pjpg,jpg_size);
}
else
{
jpg_size = jpg_buf_size;
pjpg = pjpg_buf;
}
/*注册出错处理*/
cinfo.err = jpeg_std_error(&jerr);
/*创建解码*/
jpeg_create_decompress(&cinfo);
/*直接解码内存数据*/
jpeg_mem_src(&cinfo,pjpg,jpg_size);
/*读文件头*/
jpeg_read_header(&cinfo, TRUE);
/*开始解码*/
jpeg_start_decompress(&cinfo);
if(jpg_half)
{
x_e = x_s+(cinfo.output_width/2);
y_e = y +(cinfo.output_height/2);
/*读解码数据*/
while(cinfo.output_scanline < cinfo.output_height)
{
pcolor_buf = g_color_buf;
/* 读取jpg一行的rgb值 */
jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);
/* 再读取jpg一行的rgb值 */
jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);
for(i=0; i<(cinfo.output_width/2); i++)
{
/* 获取rgb值 */
color = *(pcolor_buf+2);
color = color | *(pcolor_buf+1)<<8;
color = color | *(pcolor_buf)<<16;
/* 显示像素点 */
*(g_pfb_memory+y*800+x)=color;
pcolor_buf +=6;
x++;
}
/* 换行 */
y++;
x = x_s;
}
}
else
{
x_e = x_s+cinfo.output_width;
y_e = y +cinfo.output_height;
/*读解码数据*/
while(cinfo.output_scanline < cinfo.output_height )
{
pcolor_buf = g_color_buf;
/* 读取jpg一行的rgb值 */
jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);
for(i=0; i
{
/* 获取rgb值 */
color = *(pcolor_buf+2);
color = color | *(pcolor_buf+1)<<8;
color = color | *(pcolor_buf)<<16;
/* 显示像素点 */
*(g_pfb_memory+y*800+x)=color;
pcolor_buf +=3;
x++;
}
/* 换行 */
y++;
x = x_s;
}
}
/*解码完成*/
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
if(pjpg_path!=NULL)
{
/* 关闭jpg文件 */
close(jpg_fd);
/* 释放jpg文件内存空间 */
free(pjpg);
}
//LCD关闭
/* 取消内存映射 */
munmap(g_pfb_memory, FB_SIZE);
/* 关闭LCD设备 */
close(g_fb_fd);
return 0;
}
3、触摸屏驱动
首先打开触摸屏的设备驱动 /dev/input/event0,然后通过read从驱动读取触摸信息,之后自己定义结构体保存触摸信息,并分析触摸信息和使用触摸屏信息。最后将此模块封装成函数touch_screen库,以便调用。
#include "touch_screen.h"
int fd_ev0;
int open_ts(void)//1,打开触控屏(open)
{
fd_ev0 = open("/dev/input/event0", O_RDWR);
if(fd_ev0 == -1)
{
printf("open event0 fail!n");
}
return 0;
}
int read_ts(int *coordinate_x, int *coordinate_y)//2,读取触控屏的信息到结构体中。(read)
{
int ret;
struct input_event coordinate;
while(1)
{
read(fd_ev0, &coordinate, sizeof(struct input_event));
if(coordinate.type==3 && coordinate.code==0 && coordinate.value>0 && coordinate.value<800)
{
*coordinate_x = coordinate.value;
}
if(coordinate.type==3 && coordinate.code==1 && coordinate.value>0 && coordinate.value<480)
{
*coordinate_y = coordinate.value;
}
if(coordinate.type==1 && coordinate.code==330 && coordinate.value==0)
{
break;
}
}
return 0;
}
int close_ts(void)
{
close(fd_ev0);
return 0;
}
|
|
2021-12-3 10:15:24
评论
举报
|
|
|