⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3.c

📁 fs2410下借用SDL.FFMPEG库实现一个触摸屏的播放器程序。请参照源码在相应目录下自己放置一个要播放的MPG文件。
💻 C
字号:
/**************************************************************************************************************mp3播放模块(由于交叉编译库不完备,在开发板上只能暂时只能播放mp2格式的文件)。该模块由4个主要函数构成:main(),mp3_play(),MPEG4_CtrlMessage()和ShowBMP()。main()负责加载开机画面,创建并管理两个线程。mp3_play()和MPEG4_CtrlMessage()分别是两个独立线程的入口函数,分别负责控制mp3的各个功能和获取用户命令信号。函数open_file()和set_audio()分别负责打开和设置音频设备文件。**************************************************************************************************************//*需要包含的头文件*/#include <SDL/SDL.h>#include <avcodec.h>#include <avformat.h>#include <stdio.h>#include <pthread.h>#include <unistd.h>#include "s3c2410_ts.h"#include <stdlib.h>#include <string.h>#include <math.h>#ifdef HAVE_AV_CONFIG_H#undef HAVE_AV_CONFIG_H#endif#include <SDL/SDL_audio.h>#include <assert.h>#include <sys/soundcard.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/ioctl.h>#include <errno.h>#include <sched.h>/*预定义mp3文件的数目*/#define MusicNumber 3/*全局变量定义和初始化*/int STATE_EVENT = 3; //接受用户mp3机能控制命令的全局变量,初始值设为“停止”。int STATE_VOL = 2;	//接受用户音量控制命令的全局变量,初始值设为“无效”。int volumn = 90;	   //音量。char audiofilename[MusicNumber][100]={"/qinbo/zuobian.mp2","/qinbo/juhuatai.mp2","/qinbo/HaoYanLei.mp2"};     //mp3文件名。/*函数声明*/void *mp3_play(void *junk);void *MPEG4_CtrlMessage(void *junk);void ShowBMP(char *file, SDL_Surface *screen,int x, int y);int open_file (char *file_name, int mode);int set_audio (int fd1, int fd2, AVCodecContext *pCodecCtx);/*按照mode设定的模式打开file_name指向的设备文件,并返回设备文件描述符信息*/int open_file (char *file_name, int mode){  int fd;    if ((fd = open (file_name, mode)) < 0)	// 打开文件和失败处理。    {        fprintf (stderr, " Can't open %s!\n", file_name);        exit (-1);    }    return fd;		//并返回文件描述符信息。}/*根据传入的pCodecCtx变量,初始化音频设备的基本属性(为提高代码效率,可以嵌入到调用的地方)*/int set_audio (int fd1, int fd2, AVCodecContext *pCodecCtx){    int audioset;	            audioset = AFMT_S16_LE;    ioctl (fd1, SNDCTL_DSP_SETFMT, &audioset);	// 设置采样点格式为AFMT_S16_LE    audioset = 2;//pCodecCtx->channels;          // 设置声道,stereo:2 mono:1    ioctl (fd1, SNDCTL_DSP_CHANNELS, &audioset);    audioset = 32000;//pCodecCtx->sample_rate;	// 设置采样率    ioctl (fd1,SNDCTL_DSP_SPEED,&audioset);    ioctl(fd2, MIXER_WRITE(SOUND_MIXER_VOLUME), &volumn); // 初始化音量设置          return 0;} /*主函数。负责加载开机画面,创建并管理两个独立线程*/int main(void){        pthread_t t_b;	//定义线程标识    pthread_t t_c;    SDL_Surface *screen = NULL;	  /*初始化SDL屏幕变量*/    screen = SDL_SetVideoMode (320, 240, 0, SDL_HWSURFACE);	 /*加载开机画面*/    ShowBMP("/qinbo/panasonic_mp2.bmp", screen,0, 0);	 /*创建两个线程*/    pthread_create(&t_b,NULL,mp3_play,(void*)NULL);//创建进程t_b    pthread_create(&t_c,NULL,MPEG4_CtrlMessage,(void*)NULL);//创建进程t_c	 /*等待进程t_b结束*/    pthread_join(t_b, NULL);    return 0;          }/*线程t_c,用于拾取用户操作命令*/void *MPEG4_CtrlMessage(void *junk){   int fileno;				//触摸屏设备文件描述符   int fangdou_flag =1; //防抖标志。1:处理触摸点信息许可 ,0:处理触摸点信息禁止   TS_EVENT ev;			//触摸屏设备信息结构体/*初始化触摸屏结构体*/
   memset(&ev, 0, sizeof(struct s3c2410_ts_event));
/*以O_RDONLY模式打开触摸屏设备文件,并定义失败处理*/ 
    fileno = open("/dev/ts",O_RDONLY);
        if (fileno == -1) {
           printf("open device error!\n");
        	  return NULL;
                              }
/*拾取和处理用户操作信息的循环体*/
	for(;;)		{/*读取一系列触摸点信息到*/
		if(read(fileno, &ev, sizeof(struct s3c2410_ts_event)))		{            			/*变换坐标*/				double i_tmp=2.984,j_tmp=3.708;            ev.x=(unsigned int)((986-ev.x)/i_tmp);				ev.y=(unsigned int)((948-ev.y)/j_tmp);				/*只处理第一个触摸点信息*/			if ((ev.pressure)&&(fangdou_flag==1))			{                //printf("x= %d, y= %d, flag=0x%04x\n", ev.x, ev.y, ev.pressure);		       	 if ((ev.y>=220)&&(ev.y<=240))							//功能控制区域				{					if       ((ev.x>=143)&&(ev.x<=190))STATE_EVENT=1;	//播放开始区域,STATE_EVENT置1					else if((ev.x>250)&&(ev.x<=275)) STATE_EVENT = 2;	//播放暂停区域,STATE_EVENT置2					else if((ev.x>50)&&(ev.x<=75))   STATE_EVENT = 3;	//播放停止区域,STATE_EVENT置3					else if((ev.x>200)&&(ev.x<=245)) STATE_EVENT = 6;	//播放下一首区域,STATE_EVENT置6					else if((ev.x>90)&&(ev.x<=130))  STATE_EVENT = 7;	//播放上一首区域,STATE_EVENT置6				}				else if((ev.y>=0)&&(ev.y<=20))								//音量控制区域				{					if   ((ev.x>=285)&&(ev.x<=320))STATE_EVENT=4;		//退出区域,STATE_EVENT置4					else if((ev.x>21)&&(ev.x<=53)) STATE_VOL = 1;		//减小音量区域,STATE_VOL置1					else if((ev.x>54)&&(ev.x<=85)) STATE_VOL = 0;		//增大音量区域,STATE_VOL置0									}               fangdou_flag = 0;	//防止处理那些由于抖动所产生触摸点信息									}			/*抖动信息屏蔽后,开启触摸点信息处理许可标志,等待下一个用户操作信息*/			if(ev.pressure == 0)			  fangdou_flag = 1;		 }                      
 	      	} 
        /*关闭触摸屏设备文件*/		close(fileno);
       
      	}void *mp3_play(void *junk){       /*FFMPEG 变量定义*/		 AVFormatContext *pFormatCtx_audio;       AVCodecContext *pCodecCtx_audio;        AVCodec *pCodec_audio;		 AVPacket packet_audio;       		  /*音频设备及其描述符定义和初始化*/       char *filename_audio = "/dev/dsp";       char *filename_volumn = "/dev/mixer";       int fd_audio = -1;       int fd_volumn = -1;		  /*音频设备文件打开模式定义*/       int mode = O_WRONLY;       		  /*解码器输出buffer*/       char *outbuf,*outbuf_tmp;		  /*其他与解码有关的变量定义和初始化*/       const int write_buffsize = 1024;	//预定一次写入音频设备的字节数       int frameFinished_audio;				//一次解码输出的字节数		 int i, audioStream_audio = -1; 		//寻找音频流成功标识       int writelen = 0;	    			   //写入音频设备成功标识	    int filenum = 0;							//正在播放的曲目号码       //int frame_count=0;					//帧数/*解码器和系统设备文件的初始化*/       fd_audio = open_file(filename_audio, mode); 	//打开音频设备文件,并返回描述符信息       fd_volumn = open_file(filename_volumn, mode);  //打开音量设备文件,并返回描述符信息		  /*初始化:注册所有解码器信息*/       av_register_all(); /*新选择的mp3功能控制的循环体*/while(1){                   /*打开第filenum个音频文件,并定义失败处理*/			if(av_open_input_file(&pFormatCtx_audio, audiofilename[filenum], NULL, 0, NULL)!=0)           			{					printf("File open failed!");					return NULL;				}	/*根据文件句柄寻找相关流信息,并定义失败处理*/         if(av_find_stream_info(pFormatCtx_audio)<0)                               {			      printf("Cannot find any stream information");					return NULL;				}	/*寻找音频流信息,并定义失败处理*/         audioStream_audio=-1;           for(i=0; i<pFormatCtx_audio->nb_streams; i++)//寻找音频流信息的循环体             if(pFormatCtx_audio->streams[i]->codec.codec_type==CODEC_TYPE_AUDIO)                                       {                  audioStream_audio=i;                  break;                                       }          if(audioStream_audio==-1) //定义失败处理            			      {			         printf("There is no audioStream");						return NULL;				       }         pCodecCtx_audio=(&pFormatCtx_audio->streams[audioStream_audio]->codec);	/*寻找相关的解码器,并定义失败处理*/         pCodec_audio=avcodec_find_decoder(pCodecCtx_audio->codec_id);           if(pCodec_audio==NULL)            				{						printf("There is no suitable decoder");						return NULL;					}        /*分配解码器空间*/          pCodecCtx_audio= avcodec_alloc_context();	/*打开解码器,并定义失败处理*/          if(avcodec_open(pCodecCtx_audio, pCodec_audio)<0)              				{						printf("Cannot open the codec");						return NULL;					}          /*初始化音频设备*/ 	 set_audio(fd_audio,fd_volumn,pCodecCtx_audio);         /*动态分配解码输出空间*/	 outbuf = (char *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);         /*当前mp3文件功能控制循环体*/while(1) {  if(STATE_EVENT==1) //开始播放控制    {       /*正常播放结束后,循环播放该首曲目*/	if(av_read_frame(pFormatCtx_audio, &packet_audio)<0)	{   	 av_free_packet(&packet_audio); //释放该包         break;	}   	/*这是视频流中的一个包吗?*/   if(packet_audio.stream_index==audioStream_audio)   		{       /* 解码视频流*/      avcodec_decode_audio(pCodecCtx_audio, (short *)outbuf, &frameFinished_audio,            packet_audio.data, packet_audio.size);      //set_audio(fd_audio,pCodecCtx_audio);//调用设置参数的函数,可以嵌入到此处。      //ioctl(fd_volumn, MIXER_WRITE(SOUND_MIXER_VOLUME), &volumn);// 设置音量      outbuf_tmp = outbuf; 	/*写音频设备*/	  		 while ( frameFinished_audio > 0 ) 		      {         		/*选择一次写入的字节数,1024或者frameFinished_audio*/			writelen = (frameFinished_audio > write_buffsize)?write_buffsize:frameFinished_audio;         		/*写音频设备,并返回成功写入的字节数*/			writelen = write(fd_audio, outbuf_tmp, writelen);                  if ( writelen == -1 ) //写失败处理                                               {                    printf("write audio device failed");                    continue;                                                 }			/*更新写buffer的起始位置*/         frameFinished_audio -= writelen;         outbuf_tmp += writelen;                           	          }	         		}		/*释放音频包*/			av_free_packet(&packet_audio);  }//IF		 if (STATE_EVENT == 2) //暂停播放		{				// 空循环		}		 if (STATE_EVENT == 3)//停止播放 		  {			/*返回文件起始位置*/		   av_seek_frame(pFormatCtx_audio, -1,0);		 }		 if (STATE_EVENT == 4)//退出 		  {			/*跳出该循环*/			break;		  }		    if (STATE_EVENT == 6)//播放下一首 		 {			filenum++; //下一首			/*到最后一首则循环播放第一首*/			if(filenum >= MusicNumber)			   filenum = 0;			/*模式设置为播放*/			STATE_EVENT = 1;			/*跳出该层循环*/			break; 		}		 if (STATE_EVENT == 7)//播放上一首 		 {			filenum--; //上一首			/*到第一首则循环最后一首*/			if(filenum < 0)			   filenum = MusicNumber - 1;			/*模式设置为播放*/			STATE_EVENT = 1;			/*跳出该层循环*/			break;		}		if (STATE_VOL == 0) //增加音量 		  {			volumn += 5; //一次增加5个音量单位			ioctl(fd_volumn, MIXER_WRITE(SOUND_MIXER_VOLUME), &volumn); //设置音量设备			STATE_VOL = 2; //音量控制禁止		}		if (STATE_VOL == 1)// 减少音量 		  {			volumn -= 5;	//一次减少5个音量单位			ioctl(fd_volumn, MIXER_WRITE(SOUND_MIXER_VOLUME), &volumn); //设置音量设备			STATE_VOL = 2; //音量控制禁止		}   }//while	/*如果是退出命令,则继续跳出最外层循环*/	if (STATE_EVENT == 4) 		  {			/*跳出该层循环*/			break;		}	/*关闭该首曲目的解码文件和释放空间*/	free(outbuf); 		//释放解码buffer	avcodec_close(pCodecCtx_audio);//关闭解码器上下文	av_close_input_file(pFormatCtx_audio); //关闭文件上下文}//WHILE	/*关闭音频设备,退出开机画面并结束线程*/	close (fd_audio); //关闭音频设备文件	close (fd_volumn);//关闭音量控制设备文件	SDL_Quit(); //退出开机画面	pthread_exit(0);//结束该线程}/***********************************************************这个子函数实现的功能是显示一幅位图,作为mp3播放器的开机画面。*************************************************************/void ShowBMP(char *file, SDL_Surface *screen,int x, int y) {			        if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) //初始化SDL			{        fprintf(stderr, "无法初始化SDL: %s\n", SDL_GetError());//初始化失败        exit(1);    			}    	if ( screen==NULL ) {					//screen用于显示图片的基础外框        fprintf(stderr, "无法设置640x480的视频模式:%s\n", SDL_GetError());//无法设置640x480的视频模式,只能播放小于320*240的图片        exit(1); 						}    SDL_Surface *image;    SDL_Rect dest;    /* 将BMP文件加载到一个surface*/    image = SDL_LoadBMP(file);    if ( image == NULL ) {        fprintf(stderr, "无法加载 %s: %s\n", file, SDL_GetError());//加载失败        return;   								 }    /* 初始化界面的长,宽,起始绘图点的坐标值,  */    dest.x = x;    dest.y = y;    dest.w = image->w;    dest.h = image->h;	/*按照设定值显示图片*/    SDL_BlitSurface(image, NULL, screen, &dest);    SDL_UpdateRects(screen, 1, &dest);	SDL_FreeSurface(image);//释放image	atexit(SDL_Quit);//退出}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -