开发板上实现开机动画及RGB转JPEG录像回放功能
include <stdio.h>
include <sys/types.h>
include <sys/stat.h>
include <fcntl.h>
include <unistd.h>
include <sys/mman.h>
include <asm/types.h> /* for videodev2.h */
include <string.h>
include <stdlib.h>
include <linux/videodev2.h>
include <sys/ioctl.h>
include "jpeglib.h"
include<linux/input.h>
//触摸屏设备驱动路径
define TOUCHPAD_PATH "/dev/input/event0"
define ABS_X 0x00
define ABS_Y 0x01
//LCD设备驱动路径
define LCD_PATH "/dev/fb0"
//LCD内存大小
define LCD_MEM 8004804
//摄像头采集图像的宽和高
define CAMERA_FRAME_W 640
define CAMERA_FRAME_H 480
static char * dev_name = "/dev/video7"; //摄像头的设备节点路径
static int fd = -1; //摄像头驱动的句柄
struct buffer * buffers = NULL; //用于记录缓存信息
static unsigned int n_buffers = 0;
//LCD屏幕属性
define LCD_width 800
define LCD_height 480
/**************************************************************************
*
- @brief:显示一张BMP图片
- @arg :pathname 指的是bmp图片的路径
- @arg :start_x 指的是bmp图片的起点X轴坐标
- @arg :start_y 指的是bmp图片的起点Y轴坐标
- @arg :lcd_mp 指的是lcd设备的内存映射地址
- @retval: 显示成功 返回0 显示失败 返回-1
- @note : None
***************************************************************************/
int bmp_show2lcd(const char *pathname,unsigned int start_x,unsigned int start_y,unsigned int *lcd_mp)
{
//1.检查参数有效性
if(NULL == lcd_mp)
{
perror("lcd_mp argument is invaild\r\n");
return -1;
}
//2.打开BMP图片
FILE *bmp_handle = fopen(pathname,"rb");
//错误处理
if(NULL == bmp_handle)
{
printf("fopen %s file error\r\n",pathname);
return -1;
}
//3.读取图像信息,获取宽、高、文件大小、文件标识
char bfType[2] = {0};
unsigned int bfSize = 0;
unsigned int width = 0;
unsigned int height = 0;
//读取文件标识
fread(bfType,2,1,bmp_handle);
if(bfType[0] != 'B' || bfType[1] != 'M')
{
printf("%s file type error\r\n",pathname);
fclose(bmp_handle);
return -1;
}
//读取文件大小
fread(&bfSize,4,1,bmp_handle);
//读取图像宽度
fseek(bmp_handle,18,SEEK_SET);
fread(&width,4,1,bmp_handle);
//读取图像高度
fread(&height,4,1,bmp_handle);
//计算图片大小并进行校验
unsigned int padding = (4-(width*3%4))%4;
unsigned int bmpsize =( width * 3 + padding ) * height + 54;
if(bmpsize != bfSize)
{
printf("%s file size error\r\n",pathname);
fclose(bmp_handle);
return -1;
}
//4.偏移文件位置,跳过图片信息
fseek(bmp_handle,54,SEEK_SET);
//5.循环读取BMP一行像素并刷新到LCD
unsigned int linesize = width*3+padding; //计算行大小
unsigned char *linebuf = calloc(1,linesize); //申请行缓冲
if(NULL == linebuf)
{
printf("calloc for linebuf error\r\n");
fclose(bmp_handle);
return -1;
}
//6.处理并转换像素点
for (size_t y = 0; y < height; y++)
{
//读取BMP一行数据 b g r b g r b g r....
fread(linebuf,linesize,1,bmp_handle);
//循环处理一行像素
for (size_t x = 0; x < width; x++)
{
unsigned int point = 0; //用于记录转换完成的像素点 ARGB
//转换1个像素点 b | g<<8 | r<<16
point = linebuf[x3+0] | (linebuf[x3+1]<<8) | (linebuf[x*3+2]<<16) ;
//写入1个像素点
(lcd_mp+width(height-1-y)+x)= point;
}
}
//7.关闭bmp并释放堆空间
fclose(bmp_handle);
free(linebuf);
linebuf = NULL;
return 0;
}
/**************************************************************************
*
- @brief: 在LCD屏幕上绘制左侧斜线辅助线
- @arg : start_x 斜线起点X轴坐标
- @arg : start_y 斜线起点Y轴坐标
- @arg : it 线条厚度
- @arg : color 线条颜色
- @arg : steps 斜线延伸步数
- @arg : lcd_mp LCD内存映射地址
- @retval: 绘制成功 返回0 绘制失败 返回-1
***************************************************************************/
int car_line1(unsigned int start_x, unsigned int start_y, int it, unsigned int color, unsigned int steps, unsigned int *lcd_mp,unsigned int n)
{
// 1.检查参数有效性
if(NULL == lcd_mp)
{
perror("lcd_mp argument is invaild\r\n");
return -1;
}
// 2.绘制斜线部分
for (unsigned int step = 0; step < steps; step++)
{
int x = start_x + n*step;
int y = start_y - step;
// 边界检查
if (x >= LCD_width || y < 0) continue;
// 绘制线条厚度 (沿X轴延展 it 像素)
for (int i = 0; i < it; i++)
{
int draw_x = x + i;
if (draw_x < LCD_width) // 再次检查X坐标是否越界
{
lcd_mp[y * LCD_width + draw_x] = color;
}
}
}
return 0;
}
/**************************************************************************
*
- @brief: 在LCD屏幕上绘制左侧直线辅助线
- @arg : start_x 直线起点X轴坐标
- @arg : xt 直线终点X轴坐标
- @arg : start_y 直线Y轴坐标
- @arg : it 线条厚度
- @arg : color 线条颜色
- @arg : lcd_mp LCD内存映射地址
- @retval: 绘制成功 返回0 绘制失败 返回-1
***************************************************************************/
int car_line2(unsigned int start_x, int xt, unsigned int start_y, int it, unsigned int color, unsigned int *lcd_mp)
{
// 1.检查参数有效性
if(NULL == lcd_mp)
{
perror("lcd_mp argument is invaild\r\n");
return -1;
}
// 2.绘制直线部分:从 start_x 画到 xt,Y轴基点为 start_y
for (int x = start_x; x < xt; x++)
{
// 边界检查
if (x >= LCD_width) break;
// 绘制线条基线
lcd_mp[start_y * LCD_width + x] = color;
// 绘制线条厚度 (Y轴向下延伸 it 个像素)
for (size_t i = 0; i < it; i++)
{
int draw_y = start_y + i;
if (draw_y < LCD_height) // 检查Y坐标是否越界
{
lcd_mp[draw_y * LCD_width + x] = color;
}
}
}
return 0;
}
/**************************************************************************
*
- @brief: 在LCD屏幕上绘制右侧斜线辅助线
- @arg : start_x 斜线起点X轴坐标
- @arg : start_y 斜线起点Y轴坐标
- @arg : it 线条厚度
- @arg : color 线条颜色
- @arg : steps 斜线延伸步数
- @arg : lcd_mp LCD内存映射地址
- @retval: 绘制成功 返回0 绘制失败 返回-1
***************************************************************************/
int car_line3(unsigned int start_x, unsigned int start_y, int it, unsigned int color, unsigned int steps, unsigned int *lcd_mp,unsigned int n)
{
// 1.检查参数有效性
if(NULL == lcd_mp)
{
perror("lcd_mp argument is invaild\r\n");
return -1;
}
// 2.绘制斜线部分
for (unsigned int step = 0; step < steps; step++)
{
int x = 799 - (start_x + n*step); // 从右侧计算X坐标
int y = (479 - start_y) - step; // 从底部计算Y坐标
// 边界检查
if (x < 0 || y < 0) continue;
// 绘制线条厚度 (沿X轴延展 it 像素)
for (int i = 0; i < it; i++)
{
int draw_x = x + i;
if (draw_x < LCD_width) // 再次检查X坐标是否越界
{
lcd_mp[y * LCD_width + draw_x] = color;
}
}
}
return 0;
}
/**************************************************************************
*
- @brief: 在LCD屏幕上绘制右侧直线辅助线
- @arg : start_x 直线起点X轴坐标
- @arg : xt 直线终点X轴坐标
- @arg : start_y 直线起点Y轴坐标
- @arg : it 线条厚度
- @arg : color 线条颜色
- @arg : lcd_mp LCD内存映射地址
- @arg : k 表示斜率
- @retval: 绘制成功 返回0 绘制失败 返回-1
***************************************************************************/
int car_line4(unsigned int start_x, int xt, unsigned int start_y, int it, unsigned int color, unsigned int *lcd_mp)
{
// 1.检查参数有效性
if(NULL == lcd_mp)
{
perror("lcd_mp argument is invaild\r\n");
return -1;
}
// 2.绘制直线部分:从 start_x 画到 xt,Y轴基点为 start_y
for (int x = start_x; x > xt; x--) // 注意:这里是向右递减
{
// 边界检查
if (x < 0) break;
// 绘制线条基线
lcd_mp[start_y * LCD_width + x] = color;
// 绘制线条厚度 (Y轴向下延伸 it 个像素)
for (size_t i = 0; i < it; i++)
{
int y = start_y + i;
if (y < LCD_height) // 检查Y坐标是否越界
{
lcd_mp[y * LCD_width + x] = color;
}
}
}
return 0;
}
//用于存储转换好的RGB
JSAMPLE * image_buffer = NULL;
JSAMPLE * pimage_buffer = NULL;
//清空缓冲区
define CLEAR(x) memset (&(x), 0, sizeof (x))
//自定义类型,用于记录缓冲区信息
struct buffer {
void * start; //记录缓冲区地址
size_t length; //记录缓冲区大小
};
int read_JPEG_file (char * filename,unsigned intlcd_mp)
{
/ This struct contains the JPEG decompression parameters and pointers to
- working space (which is allocated as needed by the JPEG library).
/
struct jpeg_decompress_struct cinfo;
/ We use our private extension JPEG error handler. - Note that this struct must live as long as the main JPEG parameter
- struct, to avoid dangling-pointer problems.
/
struct jpeg_error_mgr jerr;//创建错误处理对象
/ More stuff /
FILE * infile; / source file /
unsigned char * buffer; / Output row buffer /
int row_stride; / physical row width in output buffer */
/* In this example we want to open the input file before doing anything else,
- so that the setjmp() error recovery below can assume the file is open.
- VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- requires it in order to read binary files.
*/
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return -1;
}
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr);//解码对象绑定错误处理对象
jpeg_create_decompress(&cinfo);//初始化解码对象
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, infile);
/* Step 3: read file parameters with jpeg_read_header() */
jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
- (a) suspension is not possible with the stdio data source, and
- (b) we passed TRUE to reject a tables-only JPEG file as an error.
- See libjpeg.txt for more info.
*/
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
- jpeg_read_header(), so we do nothing here.
*/
/* Step 5: Start decompressor */
jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
- with the stdio data source.
*/
/* We may need to do some setup of our own at this point before reading
- the data. After jpeg_start_decompress() we have the correct scaled
- output image dimensions available, as well as the output colormap
- if we asked for color quantization.
- In this example, we need to make an output work buffer of the right size.
/
/ JSAMPLEs per row in output buffer /
row_stride = cinfo.output_width * cinfo.output_components;//计算行缓冲大小
/ Make a one-row-high sample array that will go away when done with image */
//申请行缓冲
buffer =calloc(row_stride,1);
/* Step 6: while (scan lines remain to be read) /
/ jpeg_read_scanlines(...); */
/* Here we use the library's state variable cinfo.output_scanline as the
- loop counter, so that we don't have to keep track ourselves.
/
//重点
while (cinfo.output_scanline < cinfo.output_height)
{
/ jpeg_read_scanlines expects an array of pointers to scanlines.- Here the array is only one element long, but you could ask for
- more than one scanline at a time if that's more convenient.
/
//读取一行解码数据
jpeg_read_scanlines(&cinfo, &buffer, 1);
/ Assume put_scanline_someplace wants a pointer and sample count. */
//转换解码数据并刷新到LCD
for (size_t x = 0; x < cinfo.image_width; x++)
{
unsigned int data = 0;
data = (buffer[x3+0]<<16)|(buffer[x3+1]<<8)|buffer[x*3+2];
(lcd_mp+(cinfo.output_scanline-1)800+x) = data;
}
}
/* Step 7: Finish decompression */
jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
- with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
/* After finish_decompress, we can close the input file.
- Here we postpone it until after no more JPEG errors are possible,
- so as to simplify the setjmp error logic above. (Actually, I don't
- think that jpeg_destroy can do an error exit, but why assume anything...)
*/
fclose(infile);
free(buffer);
/* At this point you may want to check to see whether any corrupt-data
- warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
/* And we're done! /
return 0;
}
GLOBAL(void)
write_JPEG_file (char * filename, int quality)
{
/ This struct contains the JPEG compression parameters and pointers to
- working space (which is allocated as needed by the JPEG library).
- It is possible to have several such structures, representing multiple
- compression/decompression processes, in existence at once. We refer
- to any one struct (and its associated working data) as a "JPEG object".
/
struct jpeg_compress_struct cinfo;
/ This struct represents a JPEG error handler. It is declared separately - because applications often want to supply a specialized error handler
- (see the second half of this file for an example). But here we just
- take the easy way out and use the standard error handler, which will
- print a message on stderr and call exit() if compression fails.
- Note that this struct must live as long as the main JPEG parameter
- struct, to avoid dangling-pointer problems.
/
struct jpeg_error_mgr jerr;
/ More stuff /
FILE * outfile; / target file /
JSAMPROW row_pointer[1]; / pointer to JSAMPLE row[s] /
int row_stride; / physical row width in image buffer */
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
- step fails. (Unlikely, but it could happen if you are out of memory.)
- This routine fills in the contents of struct jerr, and returns jerr's
- address which we place into the link field in cinfo.
/
cinfo.err = jpeg_std_error(&jerr);
/ Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) /
/ Note: steps 2 and 3 can be done in either order. */
/* Here we use the library-supplied code to send compressed data to a
- stdio stream. You can also write your own code to do something else.
- VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- requires it in order to write binary files.
*/
if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
- Four fields of the cinfo struct must be filled in:
/
cinfo.image_width = CAMERA_FRAME_W; / image width and height, in pixels /
cinfo.image_height = CAMERA_FRAME_H;
cinfo.input_components = 3; / # of color components per pixel /
cinfo.in_color_space = JCS_RGB; / colorspace of input image /
/ Now use the library's routine to set default compression parameters. - (You must set at least cinfo.in_color_space before calling this,
- since the defaults depend on the source color space.)
/
jpeg_set_defaults(&cinfo);
/ Now you can set any non-default parameters you wish to. - Here we just illustrate the use of quality (quantization table) scaling:
/
jpeg_set_quality(&cinfo, quality, TRUE / limit to baseline-JPEG values */);
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
- Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) /
/ jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
- loop counter, so that we don't have to keep track ourselves.
- To keep things simple, we pass one scanline per call; you can pass
- more if you wish, though.
/
row_stride = CAMERA_FRAME_W * 3; / JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height)
{
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
fclose(outfile);
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress(&cinfo);
/* And we're done! */
}
//转换一个像素点
int yuyv_to_rgb_pix(int Y,int Cb,int Cr)
{
unsigned int pix_point = 0;//存储一个像素点的数据
unsigned int R,G,B; //用来存储RGB颜色分量
//通过V4L2官方帮助文档中的公式进行计算
R = (255/219)(Y - 16) + 1.402 * (127/112)(Cr - 128);
G = (255/219)(Y - 16) - 0.344 * (127/112)(Cb - 128) - 0.714(127/112)(Cr - 128);
B = (255/219)(Y - 16) + 1.772 * (127/112)(Cb - 128);
//防止越界 RGB分别为占用一个字节 0~255,所以需要进行越界处理
if(R > 255) R = 255;
if(G > 255) G = 255;
if(B > 255) B = 255;
if(R < 0) R = 0;
if(G < 0) G = 0;
if(B < 0) B = 0;
//把转换之后的像素点写入到缓冲区
*(pimage_buffer++) = R;
*(pimage_buffer++) = G;
*(pimage_buffer++) = B;
pix_point = (R<<16)|(G<<8)|B;//把RGB合成一个像素点
return pix_point;
}
//转换一帧 YUYV YUYVYUYVYUYV -- Y0U0V0 + Y1U0V0
void yuv2rgb(char *pbuffer,unsigned int lcd_mp)
{
//申请帧缓冲区,用于存储转换好的一帧图像RGB像素点
image_buffer = (JSAMPLE )calloc(1,CAMERA_FRAME_WCAMERA_FRAME_H3);
pimage_buffer = image_buffer;
int i,j;
//用于记录转换完成的ARGB像素点
unsigned int lcdbuf[CAMERA_FRAME_W*CAMERA_FRAME_H] = {0};
for(i=0,j=0;j<CAMERA_FRAME_W*CAMERA_FRAME_H;i+=4,j+=2)
{
// Y0 U0 V0
lcdbuf[j] = yuyv_to_rgb_pix(pbuffer[i],pbuffer[i+1],pbuffer[i+3]);
// Y1 U0 V0
lcdbuf[j+1] = yuyv_to_rgb_pix(pbuffer[i+2],pbuffer[i+1],pbuffer[i+3]);
}
//7.绘制左侧辅助线
// 红色辅助线
car_line1(300, 479, 10, 0xFF0000, 90, lcd_mp,1); // 红色斜线
car_line2(100, 380, 390, 10, 0xFF0000, lcd_mp); // 红色直线
// 黄色辅助线
car_line1(110, 379, 10, 0xFFFF00, 90, lcd_mp,2); // 黄色斜线
car_line2(200, 380, 290, 10, 0xFFFF00, lcd_mp); // 黄色直线
// 绿色辅助线
car_line1(210, 279, 10, 0x00FF00, 90, lcd_mp,4); // 绿色斜线
car_line2(300, 380, 190, 10, 0x00FF00, lcd_mp); // 绿色直线
//5.绘制右侧辅助线
// 红色辅助线
car_line3(40, 1, 10, 0xFF0000, 90, lcd_mp,1); // 红色斜线
car_line4(680, 420, 390, 10, 0xFF0000, lcd_mp); // 红色直线
// 黄色辅助线
car_line3(140, 100, 10, 0xFFFF00, 90, lcd_mp,2); // 黄色斜线
car_line4(580, 410, 290, 10, 0xFFFF00, lcd_mp); // 黄色直线
// 绿色辅助线
car_line3(230, 200, 10, 0x00FF00, 90, lcd_mp,4); // 绿色斜线
car_line4(490, 420, 190, 10, 0x00FF00, lcd_mp); // 绿色直线
//对帧像素进行jpg编码
static int cnt = 0;
char framename[128] = {0};
sprintf(framename,"frame%d.jpg",cnt++);
write_JPEG_file (framename,75);
//把转换之后的像素点刷新到LCD
for (size_t y = 0; y < CAMERA_FRAME_H; y++)
{
for (size_t x = 0; x < CAMERA_FRAME_W; x++)
{
lcd_mp[y800+x+80] = lcdbuf[yCAMERA_FRAME_W+x];
}
}
}
//打开设备
int open_device(void)
{
//打开摄像头设备
fd = open (dev_name, O_RDWR, 0);
//错误处理
if (-1 == fd)
{
printf("open /dev/video7 error\r\n");
return -1;
}
}
//初始化摄像头
void init_device(void)
{
//初始化采集格式
struct v4l2_format fmt;
//清空结构体
CLEAR (fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = CAMERA_FRAME_W;
fmt.fmt.pix.height = CAMERA_FRAME_H;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
ioctl(fd, VIDIOC_S_FMT, &fmt);
//申请缓冲区
struct v4l2_requestbuffers req;
CLEAR (req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl (fd, VIDIOC_REQBUFS, &req);
//申请4块结构体大小的堆内存,用于记录待申请的缓冲区信息
buffers = calloc (req.count, sizeof (*buffers));
//循环申请4块用于存储图像像素的缓冲区,并记录每块缓冲区的信息
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
ioctl (fd, VIDIOC_QUERYBUF, &buf);
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =
mmap (
NULL /* start anywhere /,
buf.length,
PROT_READ | PROT_WRITE / required /,
MAP_SHARED / recommended */,
fd, buf.m.offset);
}
}
//开始采集
static void
start_capturing (void)
{
unsigned int i;
enum v4l2_buf_type type;
//缓冲区入队
for (i = 0; i < n_buffers; ++i)
{
struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl (fd, VIDIOC_QBUF, &buf);
}
//发送开始采集的请求码
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (fd, VIDIOC_STREAMON, &type);
}
//处理图像
static void
mainloop (unsigned int *lcd_mp)
{
struct v4l2_buffer buf;
unsigned int i;
for (;😉
{
//定义了一个文件描述符的集合
fd_set fds;
struct timeval tv;
int r;
FD_ZERO (&fds); //清空集合
FD_SET (fd, &fds); //添加句柄
/* Timeout. */
//设置超时时间
tv.tv_sec = 2;
tv.tv_usec = 0;
select (fd + 1, &fds, NULL, NULL, &tv);
//循环 出队->处理->入队
for (i = 0; i < 4; ++i)
{
//读取图像帧并进行颜色转码,刷新到LCD
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
//缓冲区出队
ioctl (fd, VIDIOC_DQBUF, &buf);
//处理图像帧并显示到LCD
yuv2rgb(buffers[i].start,lcd_mp);
//缓冲区入队
ioctl (fd, VIDIOC_QBUF, &buf);
}
}
}
int main()
{
//1.打开LCD设备驱动
int lcd_fd = open(LCD_PATH,O_RDWR);
//错误处理
if(-1 == lcd_fd)
{
perror("open lcd device error\r\n");
return -1;
}
//2.对LCD设备文件进行内存映射,目的是提高LCD刷新效率
unsigned int *lcd_mp = mmap(
NULL, //待申请的内存地址,由kernel自动分配
LCD_MEM, //待申请的内存大小
PROT_READ|PROT_WRITE, //权限是可读可写
MAP_SHARED, //共享内存,共享给其他进程
lcd_fd, //待映射的文件句柄,前提是要open
0 //地址偏移,不偏移
);
//3.显示gif图像
for (size_t i = 0; i < 302; i++)
{
char gifname[512]={0};//用于记录图片名称图片路径
//构造图片路径
sprintf(gifname,"./gif/Frame%d.jpg",i);//sprintf 往缓冲区中输出一个字符串//地址
//显示图片
read_JPEG_file (gifname,lcd_mp);
//时间间隔
usleep(1*1000);
}
read_JPEG_file ("demo.jpg",lcd_mp);
//触摸板的驱动
//1.打开LCD设备驱动
int touchpad_fd = open(TOUCHPAD_PATH,O_RDWR);
//错误处理
if(-1 == touchpad_fd)
{
perror("open touchpad device error\r\n");
return -1;
}
//2.定义缓冲区,用于触摸屏文件
struct input_event touchpad_event;
unsigned int touchpad_x,touchpad_y;
memset(&touchpad_event, 0, sizeof(touchpad_event));
for(;😉
{
//3.从触摸屏的驱动中读取输入事件
read(touchpad_fd, &touchpad_event, sizeof(touchpad_event));
//4.分析输入事件的类型 编码 数值
if(touchpad_event.type == EV_ABS)
{
if (touchpad_event.code ==ABS_X)
{
touchpad_x =touchpad_event.value;
}
else if (touchpad_event.code ==ABS_Y)
{
touchpad_y =touchpad_event.value;
if (touchpad_x<=762&&touchpad_x>=659&&touchpad_y>=91&&touchpad_y<=155)
{
//3.打开摄像头
open_device();
//4.初始化摄像头
init_device();
//5.开始采集
start_capturing();
//6.处理图像
mainloop(lcd_mp);
}
else if(touchpad_x<=750&&touchpad_x>=665&&touchpad_y>=252&&touchpad_y<=308)
{
for (size_t i = 0; i < 200; i++)
{
char gifname[512]={0};//用于记录图片名称图片路径
//构造图片路径
sprintf(gifname,"./frame%d.jpg",i);//sprintf 往缓冲区中输出一个字符串//地址
//显示图片
read_JPEG_file (gifname,lcd_mp);
//时间间隔
usleep(15*1000);
}
}
}
}
}
//7.关闭LCD设备文件并解除映射
close(lcd_fd);
close(touchpad_fd);
munmap(lcd_mp,LCD_MEM);
return 0;
}

浙公网安备 33010602011771号