MP3播放

MP3播放

象棋小子    1048272975

有损音频利用人类听觉对声音中的某些频率成分不敏感的特性,从原始PCM数据中将这不敏感的一部分信息去除,以达到压缩的目的。其具有体积小,便于传输的特点,得到了广泛的应用。

1. MP3概述

MP3格式1991年由德国夫琅和费集成电路研究所(FraunhoferInstitute for Integrated Circuits)的一个工程师团队发明,并将其标准化。它丢弃原始PCM音频数据中的高频分量,可以按照不同的位速进行压缩,提供了在数据大小和声音质量之间进行权衡的一个范围,从而达到足够小、音质出色的音频格式文件。

MP3在问世之初相比其他存储音频的格式要高效得多,这样的文件非常有利于在那个网络还不发达的年代持续传播,在容量有限的储存设备上保存更多的音频文件。MP3音乐的免费下载以及各大随身听播放器的支持,使得MP3被广泛传播,时至今日,也仍是应用最广泛的有损压缩音频格式之一。

随着音频研究的深入,相关技术和知识不断完备,新的音频有损压缩格式,如ogg、aac、opus等等已经出现,它们承载的信息量相比MP3更加丰富,更加科学,相信不久的将来,MP3会慢慢淡出历史的舞台。

2、libmad

libmad是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1,提供 24-bit 的 PCM 输出,完全是定点计算,非常适合没有浮点支持的平台上使用。使用 libmad 提供的一系列 API,就可以非常简单地实现 MP3 数据解码工作。libmad源码可以从下面网址下载:

http://www.linuxfromscratch.org/blfs/view/svn/multimedia/libmad.html

把源码包中的C文件、头文件和数据文件拷贝作为库源码加入工程编译即可,MP3解码实现可以参考minimad.c

3、MP3播放

MP3音频的播放涉及到音频驱动、SD卡读写文件的实现,可以参考前面的章节。播放实现主要流程如下:

a.   MDK工程定义libmad的编译选项,FPM_DEFAULT、OPT_SPEED。

b.   打开MP3音频文件,用minimad.c中的参考解码流程进行解码。MP3解码mad_decoder_run()过程中,会通过input()回调函数加载更多的码流用于解码,解码完一帧,会通过output()回调函数播放等处理解码出来的音频数据,如果解码出现错误,通过error()回调函数进行错误的处理。

static int decode(void)

{

       structmad_decoder decoder;

       intresult;

 

       /*configure input, output, and error functions */

       mad_decoder_init(&decoder,0,

              input,0 /* header */, 0 /* filter */, output,

              error,0 /* message */);

 

       /*start decoding */

       result= mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);

       /*release the decoder */

       mad_decoder_finish(&decoder);

       returnresult;

}

c.   input()回调函数加载更多的码流用于解码,从SD卡加载码流填充满缓存MadInputBuffer,libmad会读取一帧的码流长度数据用于解码,剩余的数据会被留作下一帧的解码,通过mad_stream_buffer()上报码流的位置及可用大小。文件结束后,停止播放,关闭文件,返回MAD_FLOW_STOP告知码流结束。

static enum mad_flow input(void *data,

                  struct mad_stream *stream)

{

unsigned char *ReadStart;

unsigned int ReadSize, ReturnSize;

int Remaining;

FRESULT Res;     

      

switch (FileState) {

case 0:

       ReadStart= MadInputBuffer;

       ReadSize= FILE_IO_BUFFER_SIZE;

       Remaining= 0;

       FileState= 1;

       break;

case 1:

       /*Get the remaining frame */

       Remaining= stream->bufend - stream->next_frame;

       memmove(MadInputBuffer,stream->next_frame, Remaining);

       ReadStart= MadInputBuffer + Remaining;

       ReadSize= FILE_IO_BUFFER_SIZE - Remaining;        

       break;

default:

       I2S_TxStop();

       f_close(&file);

       returnMAD_FLOW_STOP;

}

 

/* read the file from SDCard */

Res = f_read(&file, ReadStart,ReadSize, &ReturnSize);

if (Res != RES_OK) {

       f_close(&file);

       returnMAD_FLOW_BREAK;

}

/* if the file is over */

if (ReadSize > ReturnSize) {

       FileState= 2;

}

mad_stream_buffer(stream,MadInputBuffer, ReturnSize+Remaining);

return MAD_FLOW_CONTINUE;

}

d.   output()回调函数把解码出来的音频数据加载到音频输出流进行播放。第一帧解码完成后,可以从mad_header结构体获取MP3的采样率、通道数等等音频格式,对I2S音频驱动初始化。解码的左声道数据放在pcm->samples[0]缓存,右声道数据放在pcm->samples[1]缓存,每次解码一帧包含pcm->length个音频数据,一个一个填充到音频输出缓存,如果输出缓存满,则等待播放完一帧后,继续填充。

static enum mad_flow output(void *data,

                   struct mad_header const *header,

                   struct mad_pcm *pcm)

{

unsigned int nchannels, nsamples;

mad_fixed_t const *left_ch, *right_ch;  

static int Index;

 

if (!Playing) {

       PRINTF("Mode:%s\r\n", header->mode==1?"Mono":"Stereo");

       PRINTF("Samplerate:%d Hz\r\n", header->samplerate);

       PRINTF("Bitrate:%d bps\r\n", header->bitrate);

       I2S_SetSamplerate(header->samplerate);

       I2S_TxStart();

       WriteIndex= I2SState.TxWriteIndex + 1;

       Index= 0;

       Playing= 1;

}

/* pcm->samplerate contains thesampling frequency */

nchannels = pcm->channels;

nsamples = pcm->length;

left_ch  = pcm->samples[0];

right_ch = pcm->samples[1];

 

while (nsamples--) {

       signedshort letf_sample, right_sample;

       /*output sample(s) in 16-bit signed little-endian PCM */

       letf_sample= scale(*left_ch++);

       if(nchannels == 2) {

              right_sample= scale(*right_ch++);

       }else {

              right_sample= letf_sample;

       }

       while(WriteIndex == I2SState.TxReadIndex) {

                           

       }

       //Samplepair is 4 bytes, 16-bit mode

       if(WriteIndex != I2SState.TxReadIndex) {

              I2SState.TxBuffer[I2SState.TxWriteIndex][Index]= (letf_sample&0xffff)

 | (right_sample<<16);

              Index++;

              if(Index >= AUDIO_FRAME_SIZE) {

                     Index= 0;

                     I2SState.TxWriteIndex= WriteIndex;

                     if(WriteIndex >= AUDIO_NUM_BUFFERS-1) {

                            WriteIndex= 0;

                     }else {

                            WriteIndex++;

                     }

              }

       }

}

return MAD_FLOW_CONTINUE;

}

e.   error()回调函数进行错误的处理。

static enum mad_flow error(void *data,

                  struct mad_stream *stream,

                  struct mad_frame *frame)

{

       returnMAD_FLOW_CONTINUE;

}

播放<<同一首歌>>MP3文件the same song.mp3如下:

4. 附录

MDK工程,包含SD卡文件读写代码,I2S音频播放驱动,MP3文件播放的实现、<<同一首歌>>MP3文件the samesong.mp3。

http://pan.baidu.com/s/1bOlDEY

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Spring Boot中播放MP3音频可以通过以下几个步骤实现。 首先,将MP3音频文件放置在资源文件夹(例如src/main/resources/audio)下,这样它们将被打包到生成的JAR文件中。 接下来,在Spring Boot的配置文件(application.properties或application.yaml)中进行配置,指定资源文件夹的路径: ``` spring.resources.static-locations=classpath:/audio/ ``` 然后,创建一个控制器类,用于处理音频播放的相关请求。可以使用Spring MVC的注解,如@Controller和@RequestMapping来标记控制器和请求路径。 在控制器类中,可以使用Java标准库中的javax.sound.sampled包来播放音频。首先,可以通过ResourceLoader来加载MP3文件: ```java @Autowired private ResourceLoader resourceLoader; @RequestMapping("/playAudio") public void playAudio(HttpServletResponse response) throws Exception { Resource resource = resourceLoader.getResource("classpath:audio/my-audio.mp3"); InputStream inputStream = resource.getInputStream(); AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(inputStream); Clip clip = AudioSystem.getClip(); clip.open(audioInputStream); clip.start(); } ``` 在上述代码中,通过ResourceLoader和getResource方法来加载MP3文件,然后通过AudioSystem获取音频流和音频剪辑,并调用剪辑的start方法开始播放音频。 最后,在浏览器中访问对应的URL(例如http://localhost:8080/playAudio),就可以播放MP3音频了。 需要注意的是,上述示例只是演示了简单的MP3播放功能,实际开发中可能需要更复杂的控制逻辑和界面交互。另外,还可以考虑使用第三方的音频库或框架来实现更高级的音频播放功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值