制作一个基于linux->gec6818开发板的视频播放器

一、项目要求
1、基本操作:暂停,快进快退,视频切换,音量调节,退出
2、进度条

在这里头文件就不展示了,自己编译,查看man手册

触摸屏坐标

static int ts_fd;
//触摸屏初始化 
int open_ts(void)
{
	// 1.打开触摸屏文件	
	int x,y;
	ts_fd = open("/dev/input/event0", O_RDONLY);
	if(ts_fd == -1)
	{
		perror("open ts failed");
		return -1;
	}
	return ts_fd;
}
//关闭触摸屏文件
void close_ts(void)
{
	close(ts_fd);
}

//获取坐标
//push 按下状态 传出参数
int get_xy(int *x,int *y)
{
	// 2.读取触摸屏数据	
	struct input_event ts_buf;
	char x_flag=0,y_flag=0;
	int x_last,y_last;
	int press;
	int x_now,y_now;
	int i=1;
	while(1)
	{
		read(ts_fd, &ts_buf, sizeof(ts_buf));
		//判断事件类型
		if(ts_buf.type == EV_ABS)
		{
			//判断事件代号
			if(ts_buf.code == ABS_X)
			{
					x_now=ts_buf.value*800/1024;
					x_flag=1;y_flag=0;
			}
			if(ts_buf.code == ABS_Y)
			{
					y_now=ts_buf.value*480/600;
					y_flag=1;
			}
		}
		else if(ts_buf.type==EV_KEY && ts_buf.code==BTN_TOUCH)
		{
			press = ts_buf.value;
			//*push = press;
		}
		if(x_flag==1 && y_flag==1 && press==1){

					*x=x_now;
					*y=y_now;
					x_flag=0;y_flag=0;
					//printf("[%d,%d]\n",*x,*y);
					break;
		}
	}

}

调用的时候直接调用这个get_xy(&x,&y);函数,不过在此之前要定义一个int型的x,y的全局变量;在下面的代码中会有演示。

lcd.c显示图片文件

typedef struct {			//bmp图片文件头信息封装 
	// 位图文件头 
	u8  bit_file_type[2];	//位图文件类型:'BM'->0x4d42 
	u32 file_size;	  		//整个文件大小 
	u16 reserved1;	  		//保留 
	u16 reserved2;	  		//保留 
	u32 offset;		  		//文件头到位图数据之间的偏移量 

	// 位图信息头 
	u32 head_size;			//位图信息头长度 
	u32 width;		  		//位图宽度 
	u32 height;		  		//位图高度 
	u16 bit_planes;	  		//位图位面数 
	u16 bits_per_pixel; 	//每个像素的位数 
	u32 compression;		//压缩说明 
	u32 image_size;			//位图数据大小 
	u32 h_res;				//水平分辨率 
	u32 v_res;				//垂直分辨率 
	u32 color_palette;		//位图使用的颜色索引数 
	u32 vip_color;			//重要的颜色索引数目 

}bmp_head;


static unsigned char *FB;

//显示bmp
void show_bmp(char *bmp_patpname,int x_offset,int y_offset)
{
	/*向lcd文件中写入像素点数据*/
	//打开bmp图片
	int  bmp_fd = open(bmp_patpname, O_RDONLY);//完整路径 /mnt/hgfs/shear/day004/1.bmp
	if(bmp_fd == -1)
	{
		perror("打开bmp图片失败");
		return ;
	}
	int n;//多出来的字节数

	//读取图片头部信息
	bmp_head myhead;
	read(bmp_fd, &myhead, sizeof(bmp_head));


	//如果每一行字节数能被4整除,n为0,否则是多出来的字节数
	n = ((myhead.width*3)%4==0) ? 0 : 4 -(myhead.width*3)%4;	


	//申请缓冲区
	char tmp_buf[(myhead.width*3+n)*myhead.height];
	//清空缓冲区
	bzero(tmp_buf,sizeof(tmp_buf));
	
	//读取图片数据
	read(bmp_fd, tmp_buf, sizeof(tmp_buf));
	//关闭图片文件
	close(bmp_fd);
	//将数据存入映射内存
	//将数据存入映射内存
	int i,j;
	for(i=0; i<myhead.height; i++)
		for(j=0; j<myhead.width; j++)
		{
			*(FB+((i+y_offset)*800+j+x_offset)*4) = tmp_buf[((myhead.height-1-i)*myhead.width+j)*3-i*n];
			*(FB+((i+y_offset)*800+j+x_offset)*4+1) = tmp_buf[((myhead.height-1-i)*myhead.width+j)*3+1-i*n];
			*(FB+((i+y_offset)*800+j+x_offset)*4+2) = tmp_buf[((myhead.height-1-i)*myhead.width+j)*3+2-i*n];
			*(FB+((i+y_offset)*800+j+x_offset)*4+3) = 0x00;
		}
	
}

show_bmp(char *bmp_patpname,int x_offset,int y_offset);
char *bmp_patpname:文件名
int x_offset:从设置的x轴坐标开始显示
int y_offset:从设置的y轴坐标开始显示

为了容易理解以下代码不拆分,并且代码中有详细的注释
(注:本代码用到了汉字库,自己搞),因为该文件是.a文件,无法查看,只有声明,汉字库等声明有下:

int   Init_Font(void);  //显示字体库前先调用本函数进行初始化
void  UnInit_Font(void); //程序退出前,调用本函数
//清屏函数
int   Clean_Area(int X,  //x坐标起始点
                 int Y,  //y坐标起始点
				 int width, //绘制的宽度
				 int height,//绘制的高度
				 unsigned long color); //往屏幕指定区域填充颜色

//汉字显示				 
int   Display_characterX(unsigned int x,          //x坐标起始点
                         unsigned int y,          //y坐标起始点
						 unsigned char *string,   //GB2312 中文字符串
						 unsigned int color ,     //字体颜色值
						 int size);               //字体放大倍数 1~8

接下来是本项目最主要的东西:(注:该项目没有声明,所有从下往上看)
有些函数看不懂的话,自己查看资料,man手册都可以

所用到的视频播放中使用到的“暂停/播放”按钮的切换,用刷图片来解决,图片为在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>

#include "ts.h"
#include "lcd.h"
#include "font.h"

int x,y;
FILE* mp;
int c;

struct list_node{
	char video[30];  //视频名字
	
	struct list_node *prev;
	struct list_node *next;
};

struct list_node *init_list_node()
{
	struct list_node *head = NULL;
	head = (struct list_node *)malloc(sizeof(struct list_node));
	if(head == NULL)
		printf("malloc head error!\n");
		
	head->prev = head;
	head->next = head;
	
	return head;
	
};

int video_option(struct list_node *head);


//============================================
//子进程=======================================
void *progress1(void *arg)
{	
	c=0;
	int posy;
	char buf[1024]={0};
	//获取当前播放的进度
	while(1)
	{
		if(c==1)
		{
			break;
		}
		bzero(buf,1024);
		fgets(buf,1024,mp);
		//printf("fgets = %s\n",buf);
		
		int pos = 0;
		sscanf(buf,"ANS_PERCENT_POSITION=%d",&pos);
		//printf("pos=%d\n",pos);
		
		//使用清屏函数实现刷进度条
		Clean_Area(0,  390, pos*8,10,0x0);
				//x轴、y轴、长、 宽、颜色
		
		
		/*特别解释一下*/
		/*在此之前定义了一个整形的posy,一般下面的if是不会满足的,会直接执行if以外下面的代码,
		  每次会进行一次赋值操作(将pos赋值给posy),每过一次循环在“if”里面会判断本次“pos”是否小于上一次循环的“posy”,
		  如果小于,则会在执行满足if条件里面的代码,进行一次定位“x轴”往后的清屏操作*/
		if(pos<posy)
		{
			Clean_Area(pos*8,390,800-(pos*8),10,0x0000f0f0);
		}			  //x轴、y轴、长、        宽、颜色
		posy=pos;
	}	
}

//往管道中写入数据
void *progress2(void *arg)
{	
	c=0;
	int fd = open("/tmp/cmd",O_RDWR);
		if(fd<0)
		{
			printf("管道打开失败!\n");
			exit(0);
		}
	
	while(1)
	{
		if(c==1)
		{
			break;
		}
		char cmd[1024]={"get_percent_pos\n"};
		write(fd,cmd,strlen(cmd));
		sleep(1);
	}
	
	close(fd);
}
//=================================================
//=================================================


///=================================================
//-------------------------------------------------

//播放
int play(struct list_node *p,struct list_node *head)
{	
	
	mkfifo("/tmp/cmd",0777);
	char buf[100];

	sprintf(buf,"mplayer -quiet -slave -zoom -x 800 -y 390 -input file=/tmp/cmd '/fuxue/%s'",p->video);//拼接字符串到buf里
	mp=popen(buf,"r");  	
	
	int i = 1;
	//显示底部控制栏
	show_bmp("./z.bmp",0,400);

	///======================================
	//创两条线程,一条线程用来刷进度条,一条线程来往播放中写入获取进度命令
	pthread_t tid1,tid2;
	pthread_create(&tid1,NULL,progress1,NULL);
	pthread_create(&tid2,NULL,progress2,NULL);
	///======================================
	
	while(1)
	{
		//获取点击的坐标
		get_xy(&x,&y); 
		
		//减音量
		if(x>73&&x<153&&y>400&&y<480)
		{
			system("echo \"volume -20 0\" > /tmp/cmd");
			Display_characterX(2,400,"音量",0x0,2);//屏幕显示字符“音量”(注:要搞汉字库到开发板中)
			Display_characterX(3,450,"-20",0x0,2); //屏幕显示字符“+10”(注:要搞汉字库到开发板中)
			sleep(1);
			Clean_Area(0,  400, 73, 80, 0x00ffffff);  //对左下脚这块区域清屏
		}           //x轴、y轴、长、宽、颜色
		
		//切换到上一个视频
		if(x>156&&x<252&&y>400&&y<480)
		{	
			system("killall -9 mplayer");
			p=p->prev;
	
			if(p==head)                /*现在的p就是之前的p的前面一位,假如现在的p就是链表中的头节点,那么p应该再向前面移动一位*/
			{
				p=p->prev;
			}
			sprintf(buf,"mplayer -quiet -slave -zoom -x 800 -y 390 -input file=/tmp/cmd '/fuxue/%s'",p->video);
			mp = popen(buf,"r");
		}
		
		//快退5s
		if(x>258&&x<360&&y>400&&y<480)
		{	
			system("echo \"seek -5 0\" > /tmp/cmd");	
			printf("前进5S\n");
		}
		
		
		//暂停/播放
		if(x>365&&x<458&&y>400&&y<480)
		{
 			 i++;
			if(i%2==1)
			{
 				show_bmp("./b.bmp",0,400);
				printf("暂停!\n");  
				system("killall -STOP mplayer");//发送一个暂停信号
			}
			if(i%2==0)
			{
				show_bmp("./z.bmp",0,400);
				printf("继续!\n");
				system("killall -CONT mplayer");//发送一个继续信号
			} 
		}
		
		
		
		//快进5s		
		if(x>435&&x<537&&y>400&&y<480)
		{
			//快进5s
			system("echo \"seek +5 0\" > /tmp/cmd");			
			printf("快进5S\n");
		}
		
		//切换到下一个视频		
		if(x>548&&x<632&&y>400&&y<480)
		{
			system("killall -9 mplayer");
			
			p=p->next; 
			if(p==head)    /*现在的p就是之前的p的前面一位,假如现在的p就是链表中的头节点,那么p应该再向前面移动一位*/
			{
				p=p->next; 
			}
			
			//将当前节点的视频文件名拼接到这段字符串中,并保存到buf里
			sprintf(buf,"mplayer -quiet -slave -zoom -x 800 -y 390 -input file=/tmp/cmd '/fuxue/%s'",p->video);
			mp = popen(buf,"r");	
		}
		
		//音量加
		if(x>640&&x<717&&y>400&&y<480)
		{
			system("echo \"volume +10 0\" > /tmp/cmd");
			Display_characterX(2,400,"音量",0x0,2);//屏幕显示字符“音量”(注:要搞汉字库到开发板中)
			Display_characterX(3,450,"+10",0x0,2);  //屏幕显示字符“+10”(注:要搞汉字库到开发板中)
			sleep(1);
			Clean_Area(0,  400,73,80,0x00ffffff);//对左下脚这块区域清屏
		}           //x轴、y轴、长、宽、颜色
		
		if(x>724&&x<800&&y>400&&y<480)
		{
			//退出
			system("killall -9 mplayer");
			c = 1;
			pthread_join(tid1,NULL);
			pthread_join(tid2,NULL);
			video_option(head);

			//break;
		}	
	}
	return 0;
}

//遍历(显示视频图标)(方法二:用链表的方法遍历链表)
int video_option(struct list_node *head)
{
	
	int n;
	char name[8][60];//实时显示到屏幕的名字
	struct list_node *p = NULL;

	while(1)
	{
		int j=1;
		int i = 0;
		
		Clean_Area(0,0,800,480,0x00f0f0);//清屏
		printf("==============\n");
		for(p=head->next;p!=head;p=p->next)
		{
			//保存名字到当前显示数组
			strcpy(name[i],p->video);
			//在终端中显示
			printf("当前目录下的文件为%s\n",name[i]);
			//在开发板屏幕中显示
			Display_characterX(100,50*(i+1),name[i],0x0,2);
			i++;
		}	
		printf("当前有%d个文件\n",i);
		printf("===============\n");
		
		get_xy(&x,&y);//获取点击的坐标
		for(n=0;n<i;n++)
		{
			//这个会根据文件名子在屏幕下的坐标值,实时将坐标搞到二维数组当中(二级指针),也就是说,文件名字文件名字显示的区域对应相应的坐标值
			if(x>0 && x<400&&y>50*(n+1)&&y<50+50*(n+1))
				break;
		}

			name[n];
			
		for(p=head->next;p!=head;p=p->next)
		{
			if(strstr(p->video,name[n]))
			{
				play(p,head);
			}
		}		
		
		
	}
	return 0;
}
//-----------------------------------------------
///===============================================



///==============================================================
//初始化链表(将根目录下->“/fuxue”下的文件进行遍历,尾插到链表中)-
int read_file(struct list_node *head,char *name)
{	
	//为新节点申请空间
	struct list_node *new = NULL;
	new = (struct list_node *)malloc(sizeof(struct list_node));
	if(new == NULL)
		printf("malloc new error!\n");
	
	strcpy(new->video,name);

	//寻找最后一个节点
 	struct list_node *p = NULL;
	for(p=head;p->next!=head;p=p->next);//如果跳出循环,则当前的"p"就是链表的最后一个节点
	p->next = new;
	new->prev = p;
	new->next = head;
	head->prev = new; 

	return 0;
}


int init_old_video(struct list_node *head)
{
	DIR *dp = opendir("/fuxue");
	if(dp == NULL)
		printf("opendir error!\n");
	
	//chdir("/fuxue");
	struct dirent *ep = NULL;
	
	//将读取到的.avi文件尾插到链表中
	while(1)
	{
		ep = readdir(dp);
		if(ep == NULL)
			break;
		if(ep->d_name[0] == '.')
			continue;
		if(strstr(ep->d_name,".avi"))
		{
			read_file(head,ep->d_name);
		}
	}
}
//---------------------------------------------------------------------
///====================================================================



int main(int argc,char *argv[])
{		
	//创建一个管道
	FILE* mp;
	mkfifo("/tmp/cmd",0777);

	//初始化头节点
	struct list_node *head = init_list_node();
	
	//初始化链表视频链表
	init_old_video(head);
	
	open_lcd();   //初始化lcd屏
	open_ts();    //初始化触摸屏
	Init_Font(); //初始化汉字库
	
	video_option(head);//视频选择
	
	return 0;
}
Logo

更多推荐