一帧帧的静态jpg图片进行延时显示
struct my_error_mgr
{
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr *my_error_ptr;
/*
* Here's the routine that will replace the standard error_exit method:
*/
METHODDEF(void)
my_error_exit(j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr)cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message)(cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
/* lcd_draw_jpeg : 指定静态/动态图像数据显示
* int x, int y : 图像显示起点位置
* const char *pathname : 指定静态数据源 (例如 图片文件)
* char *jpeg_buf : 指定动态数据源 (例如 摄像头获取到的数据)
* int jpeg_size : 动态数据的大小
* int zoom_flag : 缩放比例 (分子:1/分母:zoom_flag,例如1/2缩小一倍)
*/
int lcd_draw_jpeg(int x, int y, const char *pathname, char *jpeg_buf, int jpeg_size, int zoom_flag)
{
int img_fd;
char *img_buf;
int img_size;
unsigned char *argb_buf = lcd_buf;
int x_c = x;
// jpeg解压缩对象和错误处理对象
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
struct stat statbuf;
if (pathname != NULL)
{
// 打开图片文件
img_fd = open(pathname, O_RDWR);
if (img_fd == -1)
{
printf("open jpeg file [ %s ] failed !\n", pathname);
return -1;
}
// 获取文件大小
fstat(img_fd, &statbuf);
img_size = statbuf.st_size;
img_buf = calloc(1, img_size);
read(img_fd, img_buf, img_size);
}
else
{
img_size = jpeg_size;
img_buf = jpeg_buf;
}
/* Step 1: 分配并初始化jpeg解压缩对象 */
// 错误处理
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer))
{
// 释放资源
jpeg_destroy_decompress(&cinfo);
if (pathname != NULL)
{
close(img_fd);
}
return -1;
}
// 初始化解压缩对象
jpeg_create_decompress(&cinfo);
/* Step 2: 指定解压缩数据源 (eg, a file) */
jpeg_mem_src(&cinfo, img_buf, img_size);
/* Step 3: 读取图片文件的详细信息 */
(void)jpeg_read_header(&cinfo, TRUE);
/* Step 4: 解压缩的参数设置,一般默认 */
cinfo.scale_num = 1; // 1
cinfo.scale_denom = zoom_flag; //
/* Step 5: 开始解压 */
(void)jpeg_start_decompress(&cinfo);
int i, r, g, b, color;
/* Step 6: 取出数据 */
// cinfo.output_scanline:当前行号
// cinfo.output_height:对应的图片的高
// cinfo.output_width:对应的图片的宽
while (cinfo.output_scanline < cinfo.output_height)
{
argb_buf = lcd_buf;
// 每次读取一行的数据
(void)jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&argb_buf, 1);
for (i = 0; i < cinfo.output_width; i++)
{
b = *(argb_buf + 2);
g = *(argb_buf + 1);
r = *(argb_buf + 0);
// 合并
color = b;
color |= (g << 8);
color |= (r << 16);
lcd_draw_point(x, y, color);
argb_buf += 3;
x++;
}
y++;
x = x_c;
}
/* Step 7: 解压完毕 */
(void)jpeg_finish_decompress(&cinfo);
/* Step 8: 释放资源 */
jpeg_destroy_decompress(&cinfo);
if (pathname != NULL)
{
close(img_fd);
}
return 0;
}
int dev_init()
{
lcd_fd = open("/dev/fb0", O_RDWR);
// 错误处理
if (lcd_fd == -1)
{
printf("open lcd device failed!\n");
return -1;
}
// 2,为lcd设备建立内存映射关系
lcd_ptr = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if (lcd_ptr == MAP_FAILED)
{
printf("mmap failed!\n");
return -2;
}
// 清除屏幕
memset(lcd_ptr, 0, 800 * 480 * 4);
return 0;
}
void dev_uninit()
{
munmap(lcd_ptr, 800 * 480 * 4);
close(lcd_fd);
}
int main(void)
{
// 1,设备的初始化
int rt = dev_init();
if (rt != 0)
{
printf("rt : %d\n", rt);
return -1;
}
char buf[4096];
int i;
unsigned int *mem_p = (unsigned int *)mmap(NULL, 800 * 480 * 4,
PROT_READ | PROT_WRITE,
MAP_SHARED, lcd_fd, 0);
for (int i = 0; i < 800 * 480; ++i) // 清空屏幕
{
*(mem_p + i) = 0x00FFFFFF;
}
for (i = 0; i < 70; i++)
{
if (i < 10)
{
sprintf(buf, "IMG0000%d.jpg", i);
lcd_draw_jpeg(i*7, i*3, buf, NULL, 0, 1);
}
else
{
sprintf(buf, "IMG000%d.jpg", i);
lcd_draw_jpeg(i*7, i*2, buf, NULL, 0, 1);
}
/* 延时进行显示 */
usleep(50000);
}
// 3,设备的卸载
dev_uninit();
return 0;
}