开发板上实现开机动画及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_H
3);
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;
}

posted @ 2026-07-16 19:58  南质冰清  阅读(4)  评论(0)    收藏  举报