从零开始用C语言实现图片解码播放器(有源码)

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始用C语言实现图片解码播放器(有源码)相关的知识,希望对你有一定的参考价值。

1、项目描述

1.1、项目硬件平台介绍

(1)硬件平台:九鼎公司的X210开发板,S5PV210(Cortex-A8内核);
(2)软件平台:linux2.6.35.7内核,直接基于linux API操作

1.2、项目功能介绍

(1)调用编译好的可执行程序时传入图片的存放路径,程序会自动将路径里的图片显示在屏幕上;
(2)程序会自动检索图片路径下包括子目录在内的所有图片文件;
(3)支持的文件格式包括BMP(8bit、16bit、24bit、32bit)、JPG、PNG;
(4)支持触摸屏翻页功能,点击左侧屏幕则向前翻页,点击右侧屏幕可向后翻页,支持循环翻页;

1.3、项目涉及到的技术

(1)C语言和linux基础操作;
(2)通用Makefile管理工程的相关知识;
(3)应用层操作屏幕的代码分析;
(4)bmp、jpg、png格式解码库的移植;
(5)应用层操作触摸屏的代码分析;
(6)linux中递归遍历文件夹内容的操作;
(7)动态库的编译和移植;
(8)实际项目中目录结构的分析;

2、项目代码目录结构介绍

.
├── bin			——存放生成的可执行程序
├── build		——Makefile编译脚本
├── doc			——项目说明文档
├── image		——存放要播放的图片
│   ├── bmp
│   ├── jpg
│   └── png	
├── include		——相关头文件
│   ├── common	——公共的配置头文件
│   ├── decode	——图片解码相关的头文件
│   │   ├── bmp
│   │   ├── jpg
│   │   ├── png
│   │   │   └── libpng16
│   │   └── zlib
│   ├── fb				——屏幕显示相关头文件
│   ├── imageManager	——图片管理头文件
│   └── touchScreen		——触摸屏管理头文件
├── lib					——依赖的动态库
└── src					——源码目录
    ├── decode			——图片解码相关源码
    ├── fb				——屏幕显示相关源码
    ├── imageManager	——图片管理相关源码
    └── touchScreen		——触摸屏相关源码

参考博客:《实际工作开发中C语言工程的目录结构分析》

3、Makefile介绍

项目管理使用的通用Makefile模板,具体参考博客:《项目通用Makefile的编写(包含Makefile.build文件分析)》

4、屏幕显示模块

4.1、屏幕驱动的移植

《嵌入式开发(S5PV210)——LCD显示器》
《Linux 帧缓冲子系统详解:LCD介绍、framebuffer驱动框架、LCD驱动源码分析》
《LCD驱动源码分析(s3cfb.c)》

4.2、应用层操作屏幕的代码

//表示一个屏幕设备
typedef struct

	unsigned int *pfb;		  	// pfb指向framebuffer内存地址首地址
	int fp;					  	// 打开设备节点得到的文件描述符
	int width;					//屏幕的实际宽
	int height;					//屏幕的实际高
	int virWidth;				//屏幕的虚拟宽
	int virHeight;				//屏幕的虚拟高
	int	bpp;					//每个像素占用的位数
fbHandle;

// 结构体用来封装一个图片的各种信息
typedef struct pic_info

	char *pathname;			// 图片在文件系统中的路径名+文件名
	unsigned int width;		// 图片分辨率之宽
	unsigned int height;	// 图片分辨率之高
	unsigned int bpp;		// 图片bpp
	char *pData;			// 指向图片有效数据存储的buf数据
pic_info;

//传入屏幕的设备节点路径,返回屏幕的设备信息
fbHandle *fb_open(char* devPath)

	int ret = -1;
	fbHandle *fbDev = NULL;
	struct fb_fix_screeninfo finfo;
	struct fb_var_screeninfo vinfo;

	fbDev = malloc(sizeof(fbHandle));
	memset(fbDev, 0, sizeof(fbHandle));

	// 第1步:打开设备
	fbDev->fp = -1;
	fbDev->fp = open(devPath, O_RDWR);
	if (fbDev->fp < 0)
	
		perror("open error");
		goto fail;
	
	 
	debug("open %s success.\\n", devPath);

	// 第2步:获取设备的硬件信息
	ret = ioctl(fbDev->fp, FBIOGET_FSCREENINFO, &finfo);
	if (ret < 0)
	
		perror("ioctl");
		goto fail;
	
	debug("smem_start = 0x%lx, smem_len = %u.\\n", finfo.smem_start, finfo.smem_len);
	 
	ret = ioctl(fbDev->fp, FBIOGET_VSCREENINFO, &vinfo);
	if (ret < 0)
	
		perror("ioctl");
		goto fail;
	
	 
	debug("xres = %u, yres = %u.\\n", vinfo.xres, vinfo.yres);
	debug("xres_virtual = %u, yres_virtual = %u.\\n", vinfo.xres_virtual, vinfo.yres_virtual);
	debug("bpp = %u.\\n", vinfo.bits_per_pixel);


	fbDev->width = vinfo.xres;
	fbDev->height = vinfo.yres;
	fbDev->virWidth = vinfo.xres_virtual;
	fbDev->virHeight = vinfo.yres_virtual;
	fbDev->bpp = vinfo.bits_per_pixel;
	 
	// 第3步:进行mmap
	unsigned long len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
	debug("len = %ld\\n", len);
	fbDev->pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fbDev->fp, 0);
	if (NULL == fbDev->pfb)
	
		perror("mmap error");
		goto fail;
	
	 
	debug("pfb = %p.\\n", fbDev->pfb);

	return fbDev;

fail:
	if(fbDev->fp >= 0)
	
		close(fbDev->fp);
	
	
	free(fbDev);
	return NULL;


//往屏幕显示图片
void fb_draw_rgb(fbHandle *fbDev, const struct pic_info *pPic)

	const char *pData = (const char *)pPic->pData;		// 指针指向图像数组
	unsigned int cnt = 0, a = 0;
	unsigned int x, y;

	a = 0;
	for (y = 0; y < pPic->height; y++)
	
		for (x=0; x<pPic->width; x++)
		 
			//cnt表示当前像素点的编号
			cnt = fbDev->width * y + x; 
			// 当前像素点的数据
			*(fbDev->pfb + cnt) = ((pData[a+2]<<0) | (pData[a+1]<<8)| (pData[a+0]<<16)); 
			a += 3;
		
	


参考博客:《应用程序操作LCD源码分析》

5、图片解码模块

(1)bmp图片解码函数编写,参考博客:《C语言实现BMP格式转RGB格式、YUV格式》《C语言实现RGB888转BMP格式图片功能》
(2)jpg解码库移植,参考博客:《jpg解码库移植过程详解》
(2)png解码库移植,参考博客:《png格式解码库移植过程详解》

6、图片管理模块

(1)调用linux系统的文件夹操作的API,比如opendir、 readdir、lstat等函数去遍历文件夹下的所有文件;
(2)判断读取到的文件,如果是bmp、jpg、png图片则添加到数组中管理起来,后续在播放图片时会用到;

7、触摸屏模块

(1)通过操作触摸屏的设备节点来读取坐标信息,通过判断坐标来决定是向前翻页还是向后翻页;
(2)《嵌入式开发(S5PV210)——ADC和触摸屏》《gslx680触摸屏驱动源码码分析(gslX680.c)》《linux输入子系统详解——看这一篇就够了》

8、项目代码移植

8.1、硬件平台要求

(1)开发板必须有显示屏和触摸屏,并且显示屏和触摸屏的驱动移植正确,可以正常功能;
(2)在移植代码前,先通过设备节点,确认显示屏和触摸屏工作正常;

8.2、代码修改

// 屏幕的设备节点
#define FBDEVICE	"/dev/fb0"	

# 支持的图片最大的分辨率
#define PICTURE_BUFFER_MAX_SIZE (1920 * 1080 * 3 )

// 最多支持的图片数目
#define MAX_IMAGE_CNT			100

// 触摸屏设备的设备名
#define DEVICE_TOUCHSCREEN		"/dev/input/event2"

// 定义触摸翻页区域的宽度
#define TOUCH_WIDTH				200				

(1)修改主Makefile中的交叉编译工具链为自己平台的(CROSS_COMPILE);
(2)上面的配置都在config.h文件中,需要根据自己开发板的情况去修改,特别是屏幕和触摸屏的设备节点名称必须正确;

8.3、源码获取

《图片解码播放器源码下载》

9、参考资料

《朱友鹏——核心课程》

以上是关于从零开始用C语言实现图片解码播放器(有源码)的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式Linux小项目之图片编解码播放器

android编程如何实现边下载边播放?

从零开始的异世界!使用<img>和<iFrame>等HTML基础标签制作一个视频播放网站

C语言有什么用?①从零开始撸一个用户态模拟文件系统

从零开始用vuejs做一个简陋但好使的播放器

C/C++提升 | 基于FFmpeg的视频播放器