SDL 与 FFMPEG 音乐播放器开发(2)——混播多个音频
来源:互联网 发布:反美颜软件ios 编辑:程序博客网 时间:2024/06/05 04:31
第一篇总体提了一下SDL,完全没有提到FFMPEG。我的思路是,在说解码之前,你起码要知道怎么使用解码后的文件。
相信大家如果看了网上的一些教程,应该已经能够播放出PCM文件。今天我来谈谈如何播放多个PCM文件。
这回先上代码
#define MAX_MUSIC_DATA 10#define PCM_BUFFER_SIZE 4096
struct AudioData{ Uint8 *audio_chunk; Uint32 audio_len; Uint8 *audio_pos;SDL_Thread *thread;AudioState state;FILE *file;char *pcm_buffer;char *filename;float skipSecond;float HzPercent;int originalFreq;int volume;}m_data[MAX_MUSIC_DATA], *pData;/* Audio Callback * The audio function callback takes the following parameters: * stream: A pointer to the audio buffer to be filled * len: The length (in bytes) of the audio buffer * */ void fill_audio(void *udata,Uint8 *stream,int len){ //SDL 2.0SDL_memset(stream, 0, len);for (int i = 0; i < MAX_MUSIC_DATA; i++){if (m_data[i].audio_len == 0)/* Only play if we have data left */continue;len = (len > m_data[i].audio_len ? m_data[i].audio_len : len);/* Mix as much data as possible */SDL_MixAudio(stream, m_data[i].audio_pos, len, m_data[i].volume);m_data[i].audio_pos += len;m_data[i].audio_len -= len;}}
在fill_audio()当中将每个数据叠加在audio预设的数据流stream,就是混播音频的关键。
而如何更新每个数据中的pcm_buffer呢 看下一段代码。
int PlayMusicbyName(void* fileName){for (int i = 0; i < MAX_MUSIC_DATA; i++){if (m_data[i].file){if (!strcmp(m_data[i].filename, (char*)fileName)){return -1;}}if (!m_data[i].file){thread[5] = SDL_CreateThread(decodeMusicFile, "decodeMusicFile", fileName);SDL_Delay(500);//SDL_WaitThread(thread[5],0);char buf[256];sprintf(buf, "output/%soutput.pcm", fileName);m_data[i].file = fopen(buf, "rb+");if (!m_data[i].file){printf("This file is not exist!!\n");return -1;}m_data[i].filename = (char *)malloc(sizeof(fileName));strcpy(m_data[i].filename, (char *)fileName);m_data[i].pcm_buffer = (char *)malloc(PCM_BUFFER_SIZE);m_data[i].state = play;m_data[i].skipSecond = -1;m_data[i].HzPercent = -1;m_data[i].volume = 128;pData = &m_data[i];break;}}return 0;}
这段代码本质上就是打开PCM文件,并将文件指针信息存入m_data当中,同时malloc申请一部分内存用来储存读出来的数据。
int PlayMusicWithPCM(void* ptr){if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {printf("Could not initialize SDL - %s\n", SDL_GetError());return -1;}//SDL_AudioSpecSDL_AudioSpec wanted_spec;wanted_spec.freq = 44100;wanted_spec.format = AUDIO_S16SYS;wanted_spec.channels = 2;wanted_spec.silence = 0;wanted_spec.samples = 1024;wanted_spec.callback = fill_audio;m_OriginalFreq = wanted_spec.freq;if (SDL_OpenAudio(&wanted_spec, NULL) < 0){printf("can't open audio.-%s\n", SDL_GetError());return -1;}while (1){for (int i = 0; i < MAX_MUSIC_DATA; i++){bool shouldwait = false;if (m_data[i].state == play){if (fread(m_data[i].pcm_buffer, 1, PCM_BUFFER_SIZE, m_data[i].file) != PCM_BUFFER_SIZE){// Loopfseek(m_data[i].file, 0, SEEK_SET);fread(m_data[i].pcm_buffer, 1, PCM_BUFFER_SIZE, m_data[i].file);}//Set audio buffer (PCM data)m_data[i].audio_chunk = (Uint8 *)m_data[i].pcm_buffer;//Audio buffer lengthm_data[i].audio_len = PCM_BUFFER_SIZE;m_data[i].audio_pos = m_data[i].audio_chunk;}}//PlaySDL_PauseAudio(0);while (1)//Wait until finish{bool WAIT = false;for (int i = 0; i < MAX_MUSIC_DATA; i++){if (m_data[i].audio_len > 0){WAIT = true;break;}}if (WAIT){SDL_Delay(1);}else{break;}}}SDL_CloseAudio();return 0;}
每次循环的时候都更新数据的buffer、pos等信息,在每次SDL_PauseAudio回调的时候都能够播放下一时刻的数据(注意 这里必须把每一个PCM文件的数据都进行更新)。
总结一下,SDL混播PCM数据的思路如下:
读取每一个文件的信息----->将待播放部分存入buffer----->将每一个文件的buffer进行mix(使用mixAudio)------>更新数据
到这里,我们就可以把未经过压缩的PCM数据进行播放了,大家可以试一试,感受一下同时播放多个声音带来的成就感与杂乱感。
以及大家可以联系我125650971@qq.com
1 0
- SDL 与 FFMPEG 音乐播放器开发(2)——混播多个音频
- SDL 与 FFMPEG 音乐播放器开发(4)——使用FFMPEG库解码
- SDL 与 FFMPEG 音乐播放器开发(3)——改变音量、跳转
- SDL 与 FFMPEG 音乐播放器开发(1)
- ffmpeg+sdl音频播放器
- ffmpeg+sdl教程——编写一个简单的播放器3(为视频加入音频)
- FFMPEG + SDL音频播放分析
- FFMPEG + SDL音频播放分析
- FFMPEG + SDL音频播放分析
- FFMPEG + SDL音频播放分析
- FFMPEG + SDL音频播放分析
- FFMPEG + SDL音频播放分析
- iOS开发—02音频处理(音乐播放器2)
- iOS开发拓展篇—音频处理(音乐播放器2)
- iOS开发拓展篇—音频处理(音乐播放器2)
- iOS开发拓展篇—音频处理(音乐播放器2)
- android开发笔记之多媒体—播放音频(音乐)
- ffmpeg+SDL+windows 视频播放器的开发(三)
- 第十五章 -------单点登录
- 异常管理 - try-catch-finally异常信息丢失
- 米老师讲 ITOO4.1 ——Java
- 常见的TSO ISPF命令
- Spring 69题
- SDL 与 FFMPEG 音乐播放器开发(2)——混播多个音频
- Android-微信抢红包APP——one
- 第十六章 综合实例
- Android Studio你不知道的调试技巧
- iOS中GCD的使用小结
- 第十七章 OAuth2集成
- 高职组:2、马虎的算式
- 关于JavaScript作用域的练习题
- 92.View the Exhibit and examine the data in the PROMO_NAME and PROMO_END_DATE columns of the PROMOTI