也说alsa音乐播放(mp3文件从零开始)

来源:互联网 发布:神州科捷工作知乎 编辑:程序博客网 时间:2024/06/06 06:52

首先也是最重要的是:我说大话了,本文也就是一个思路而已,如果你是音乐播放小白也想弄明白原理可以往下看,否则,return -1;

现有的音乐格式千差万别,于是就有了ffmpeg话说这个框架真是够牛逼,音频视频转码都不在话下,我是个死脑筋,遇到不懂的老是想弄明白,对于音乐播放感觉是一头雾水,经过几天的研究以后大致想明白了,对一个mp3文件要播放出来需要经过几个步骤:

1.转码,其实也就是提取文件中有用的音频信息
2.经过第一步得到的wav波形文件
3.调用声卡来播放wav文件,对于linux 3.0以后的内核一般为alsa驱动,windows对wav也是天然支持的


关于转码可以见大婶写的转码系列教程http://lfp001.iteye.com/blog/739585

转码命令:
ffmepg -i 1.mp3 -f wav 1.wav

编译: gcc -o alsa alsa.c -lasound

播放命令

./alsa 1.wav

//alsa.c 编写者未知,纯属引用#include<stdio.h>#include<stdlib.h>#include <string.h>#include <alsa/asoundlib.h>struct WAV_HEADER{    char rld[4];    //riff 标志符号    int rLen;       char wld[4];    //格式类型(wave)    char fld[4];    //"fmt"    int fLen;   //sizeof(wave format matex)        short wFormatTag;   //编码格式    short wChannels;    //声道数    int   nSamplesPersec ;  //采样频率    int   nAvgBitsPerSample;//WAVE文件采样大小    short  wBlockAlign; //块对齐    short wBitsPerSample;   //WAVE文件采样大小        char dld[4];        //”data“    int wSampleLength;  //音频数据的大小} wav_header;int set_pcm_play(FILE *fp);int main(int argc,char *argv[]){    if(argc!=2)    {        printf("Usage:wav-player+wav file name\n");        exit(1);    }    int nread;    FILE *fp;    fp=fopen(argv[1],"rb");    if(fp==NULL)    {        perror("open file failed:\n");        exit(1);    }        nread=fread(&wav_header,1,sizeof(wav_header),fp);    printf("nread=%d\n",nread);        //printf("RIFF 标志%s\n",wav_header.rld);    printf("文件大小rLen:%d\n",wav_header.rLen);    //printf("wld=%s\n",wav_header.wld);    //printf("fld=%s\n",wav_header.fld);       // printf("fLen=%d\n",wav_header.fLen);        //printf("wFormatTag=%d\n",wav_header.wFormatTag);    printf("声道数:%d\n",wav_header.wChannels);    printf("采样频率:%d\n",wav_header.nSamplesPersec);    //printf("nAvgBitsPerSample=%d\n",wav_header.nAvgBitsPerSample);    //printf("wBlockAlign=%d\n",wav_header.wBlockAlign);    printf("采样的位数:%d\n",wav_header.wBitsPerSample);       // printf("data=%s\n",wav_header.dld);    printf("wSampleLength=%d\n",wav_header.wSampleLength);                        set_pcm_play(fp);    return 0;}int set_pcm_play(FILE *fp){        int    rc;        int    ret;        int    size;        snd_pcm_t*       handle;        //PCI设备句柄        snd_pcm_hw_params_t*      params;//硬件信息和PCM流配置        unsigned int       val;        int                dir=0;        snd_pcm_uframes_t  frames;        char   *buffer;        int channels=wav_header.wChannels;        int frequency=wav_header.nSamplesPersec;        int bit=wav_header.wBitsPerSample;        int datablock=wav_header.wBlockAlign;        unsigned char ch[100];  //用来存储wav文件的头信息                        rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);        if(rc<0)        {                perror("\nopen PCM device failed:");                exit(1);        }        snd_pcm_hw_params_alloca(¶ms); //分配params结构体        if(rc<0)        {                perror("\nsnd_pcm_hw_params_alloca:");                exit(1);        }         rc=snd_pcm_hw_params_any(handle, params);//初始化params        if(rc<0)        {                perror("\nsnd_pcm_hw_params_any:");                exit(1);        }        rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);                                 //初始化访问权限        if(rc<0)        {                perror("\nsed_pcm_hw_set_access:");                exit(1);        }        //采样位数        switch(bit/8)        {        case 1:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);                break ;        case 2:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);                break ;        case 3:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE);                break ;        }        rc=snd_pcm_hw_params_set_channels(handle, params, channels);  //设置声道,1表示单声>道,2表示立体声        if(rc<0)        {                perror("\nsnd_pcm_hw_params_set_channels:");                exit(1);        }        val = frequency;        rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);  //设置>频率        if(rc<0)        {                perror("\nsnd_pcm_hw_params_set_rate_near:");                exit(1);        }        rc = snd_pcm_hw_params(handle, params);        if(rc<0)        {        perror("\nsnd_pcm_hw_params: ");        exit(1);        }        rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir);  /*获取周期长度*/        if(rc<0)        {                perror("\nsnd_pcm_hw_params_get_period_size:");                exit(1);        }        size = frames * datablock;   /*4 代表数据快长度*/        buffer =(char*)malloc(size);    fseek(fp,58,SEEK_SET);  //定位歌曲到数据区    while (1)        {                memset(buffer,0,sizeof(buffer));                ret = fread(buffer, 1, size, fp);                if(ret == 0)                {                        printf("歌曲写入结束\n");                        break;                }                 else if (ret != size)                {                 }                // 写音频数据到PCM设备          while(ret = snd_pcm_writei(handle, buffer, frames)<0)           {                 usleep(2000);                   if (ret == -EPIPE)                {                  /* EPIPE means underrun */                  fprintf(stderr, "underrun occurred\n");                  //完成硬件参数设置,使设备准备好                    snd_pcm_prepare(handle);                 }                 else if (ret < 0)                 {                          fprintf(stderr,                      "error from writei: %s\n",                      snd_strerror(ret));                 }            }    }        snd_pcm_drain(handle);        snd_pcm_close(handle);        free(buffer);        return 0;}



2 0
原创粉丝点击