?? mp3.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 + -