打印

MP3软件解码没有输出PCM数据

[复制链接]
374|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
无幻|  楼主 | 2019-11-20 13:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/**
  * @brief  mp3_player 进行mp3文件解码、播放
  * @param  filename:要播放的文件路径
  * @retval none
  */
static void mp3_player(const char *filename)
{
        int err, i, outputSamps, current_sample_rate = 0;        

        int                                                read_offset = 0;                                /* 读偏移指针                                */
        int                                                bytes_left = 0;                                        /* 剩余字节数                                */        
        unsigned long        Frames = 0;                                                                /* mP3帧计数                                */
        unsigned char        *read_ptr = buffer;                                                /* 缓冲区指针                                */
        HMP3Decoder                Mp3Decoder;                                                                  /* mp3解码器指针                */
        

        
        //打开音频文件
        fres = f_open (&file, filename, FA_READ );
        
        //打开失败
        if (fres!=FR_OK)
        {
                printf("read file %s error  ! open another file\r\n",filename);
                fres = f_close (&file);
               
                if (++play_index>=file_num)        //索引值加1
                {
                                play_index=0;                                                //归0,所以如果所有文件都打开失败会一直循环
                }                                
                return ;                                                                                //文件无法打开,终止解码。进入下一次循环,读取下一个文件
        }
               
        //打开成功
        //初始化MP3解码器
        Mp3Decoder = MP3InitDecoder();        
        
        //获取输入数据流,调用helix库解码,输出PCM数据,约20ms完成一次循环
        //开始进入播放状态,期间中断会修改touch_even状态
        while(player_state != S_SWITCH)        //循环1, 如果touch_even不是切歌状态则继续呆在循环体里
        {
                //有时出现解码错误,错误后继续在本循环体内,继续播放
               
                //显示播放图标
                Lcd_GramScan(1);
                LCD_Clear(12,88,8,145,BACKGROUND);
                Lcd_show_bmp(320-(103+((play_index-((current_page-1)*8))*18)),240-20,"/mp3player/ui_playing.bmp");
               
                //读取mp3文件
                fres = f_read(&file, buffer, sizeof(buffer), &rw_num);
                if(fres != FR_OK)
                {
                        printf("读取%s失败! %d\r\n",filename,fres);
                        break;
                        //return;
                }
                read_ptr = buffer;                                                                        //指向mp3输入流
                bytes_left = rw_num;                                                                //实际读到的输入流大小大小

                //按帧处理        
                while(player_state != S_SWITCH)                        //循环2,循环本过程播放音频,直到按了下一首、上一首        
                {
                        if (player_state == S_STOP)
                        {                                                               
                                even_process();                                                                        //检查是否有事件需要处理
                                continue;                                                                                                //暂停的时候结束本次循环
                        }
                                
                        player_state = S_PLAY;                                                //状态更新为正在播放
                        
                        read_offset = MP3FindSyncWord(read_ptr, bytes_left);        //寻找帧同步,返回第一个同步字的位置
                        if(read_offset < 0)                                                                                                                                                //没有找到同步字
                        {
                                break;                                                                                                                                                                                        //跳出循环2,回到循环1        
                        }
                        
                        read_ptr += read_offset;                                        //偏移至同步字的位置
                        bytes_left -= read_offset;                                        //同步字之后的数据大小        
                        if(bytes_left < 1024)                                                        //补充数据
                        {
                                /* 注意这个地方因为采用的是DMA读取,所以一定要4字节对齐  */
                                i=(uint32_t)(bytes_left)&3;                                                                        //判断多余的字节
                                if(i) i=4-i;                                                                                                                //需要补充的字节
                                memcpy(buffer+i, read_ptr, bytes_left);        //从对齐位置开始复制
                                read_ptr = buffer+i;                                                                                //指向数据对齐位置
                                fres = f_read(&file, buffer+bytes_left+i, sizeof(buffer)-bytes_left-i, &rw_num);//补充数据
                                bytes_left += rw_num;                                                                                //有效数据流大小
                        }
                        err = MP3Decode(Mp3Decoder, &read_ptr, &bytes_left, outBuf[bufflag], 0);                                        //开始解码 参数:mp3解码结构体、输入流指针、输入流大小、输出流指针、数据格式
                        Frames++;                        
                        
                        if (err != ERR_MP3_NONE)                                                                        //错误处理
                        {
                                switch (err)
                                {
                                        case ERR_MP3_INDATA_UNDERFLOW:
                                                printf("ERR_MP3_INDATA_UNDERFLOW\r\n");
                                                read_ptr = buffer;
                                                fres = f_read(&file, read_ptr, sizeof(buffer), &rw_num);
                                                bytes_left = rw_num;
                                                break;
                        
                                        case ERR_MP3_MAINDATA_UNDERFLOW:
                                                /* do nothing - next call to decode will provide more mainData */
                                                printf("ERR_MP3_MAINDATA_UNDERFLOW\r\n");
                                                break;
                        
                                        default:
                                                printf("UNKNOWN ERROR:%d\r\n", err);
                        
                                                // 跳过此帧
                                                if (bytes_left > 0)
                                                {
                                                        bytes_left --;
                                                        read_ptr ++;
                                                }        
                                                break;
                                }
                        }
                        else                //解码无错误,准备把数据输出到PCM
                        {
                                MP3GetLastFrameInfo(Mp3Decoder, &Mp3FrameInfo);                //获取解码信息                                

                                /* 根据解码信息设置采样率 */
                                if (Mp3FrameInfo.samprate != current_sample_rate)        //采样率
                                {
                                        current_sample_rate = Mp3FrameInfo.samprate;

                                        printf(" \r\n Bitrate       %dKbps", Mp3FrameInfo.bitrate/1000);
                                  printf(" \r\n Samprate      %dHz", current_sample_rate);
                                        printf(" \r\n BitsPerSample %db", Mp3FrameInfo.bitsPerSample);
                                        printf(" \r\n nChans        %d", Mp3FrameInfo.nChans);
                                        printf(" \r\n Layer         %d", Mp3FrameInfo.layer);
                                        printf(" \r\n Version       %d", Mp3FrameInfo.version);
                                        printf(" \r\n OutputSamps   %d", Mp3FrameInfo.outputSamps);

                                        if(current_sample_rate >= I2S_AudioFreq_Default)        //I2S_AudioFreq_Default = 2,正常的帧,每次都要改速率
                                        {
                                                I2S_Freq_Config(current_sample_rate);                                                //根据采样率修改iis速率
                                        }
                                }
                                
                                /* 输出到DAC */
                                outputSamps = Mp3FrameInfo.outputSamps;                                                        //PCM数据个数
                                
                                if (outputSamps > 0)
                                {
                                        if (Mp3FrameInfo.nChans == 1)        //单声道
                                        {
                                                //单声道数据需要复制一份到另一个声道
                                                for (i = outputSamps - 1; i >= 0; i--)
                                                {
                                                        outBuf[bufflag][i * 2] = outBuf[bufflag];
                                                        outBuf[bufflag][i * 2 + 1] = outBuf[bufflag];
                                                }
                                                outputSamps *= 2;
                                        }
                                
                                        //非单声道数据可直接由DMA传输到IIS交给DAC
                                        /* 等待DMA播放完,这段时间我们可以干其他的事,扫描事件进行处理 */
                                        while((DMA1_Channel5->CCR&DMA_CCR1_EN) && !(DMA1->ISR&DMA1_IT_TC5))
                                        {

                                                static uint8_t i=0;
                                                if(i==0)
                                                {
                                                  PCM1770_VolumeSet(voice);
                                                  i++;
                                                }

                                                even_process();                                                        
                                        }
                                                
                                        /*DMA传输完毕*/
                                        DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5);
                                        DMA_I2S_Configuration((uint32_t)outBuf[bufflag], outputSamps);
                                        bufflag = 1 -bufflag;                                                                                                                                                        //切换buffer

                                }//if (outputSamps > 0)
                        }//else 解码正常
                        
               
                if(file.fptr==file.fsize)                 //如果指针指向了文件尾,表示数据全部读完
                {
                        printf("END\r\n");
                        if(play_index<file_num-1)                //自动开始下一首歌曲
                        {
                                play_index++;
                                player_state = S_SWITCH;        //进入切歌状态,跳出
                        }
                        else
                        {
                                play_index = 0;
                                player_state = S_SWITCH;
                        }
                                       
                        break;                                                                                 //跳出这首歌的播放状态        while break;
                }
         
        }//循环2                内 while(player_state != S_SWITCH)        
        
}//循环1          外 while(player_state != S_SWITCH)

        f_close(&file);                                                        //结束播放本歌曲,关闭文件
        MP3FreeDecoder(Mp3Decoder);
        I2S_Stop();
        
}

程序执行到红色代码区域,但是没有看到outBuf缓存区有数据,outBuf缓存区全部是00输出PCM个数是2304不知道为啥

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

431

主题

436

帖子

0

粉丝