iOS 上的 MP3 流媒体播放
我想使用 OpenAL 在 iOS 游戏中播放音乐。音乐文件以 mp3 格式存储,我想使用缓冲队列流式传输它们。我使用 AudioFileReadPacketData() 将音频数据加载到缓冲区中。然而,播放缓冲区只会给我带来噪音。它非常适合 caf 文件,但不适用于 mp3。我是否错过了解码文件的一些重要步骤?
我用来打开声音文件的代码:
- (void) openFile:(NSString*)fileName {
NSBundle *bundle = [NSBundle mainBundle];
CFURLRef url = (CFURLRef)[[NSURL fileURLWithPath:[bundle pathForResource:fileName ofType:@"mp3"]] retain];
AudioFileOpenURL(url, kAudioFileReadPermission, 0, &audioFile);
AudioStreamBasicDescription theFormat;
UInt32 formatSize = sizeof(theFormat);
AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &formatSize, &theFormat);
freq = (ALsizei)theFormat.mSampleRate;
CFRelease(url);
}
我用来填充缓冲区的代码:
- (void) loadOneChunkIntoBuffer:(ALuint)buffer {
char data[STREAM_BUFFER_SIZE];
UInt32 loadSize = STREAM_BUFFER_SIZE;
AudioStreamPacketDescription packetDesc[STREAM_PACKETS];
UInt32 numPackets = STREAM_PACKETS;
AudioFileReadPacketData(audioFile, NO, &loadSize, packetDesc, packetsLoaded, &numPackets, data);
alBufferData(buffer, AL_FORMAT_STEREO16, data, loadSize, freq);
packetsLoaded += numPackets;
}
I want to use OpenAL to play music in an iOS game. The music files are stored in mp3 format and I want to stream them using a buffer queue. I load audio data into the buffers using AudioFileReadPacketData(). However playing the buffers only gives me noise. It works perfectly for caf files, but not for mp3s. Did I miss some vital step in decoding the file?
Code I use to open the sound file:
- (void) openFile:(NSString*)fileName {
NSBundle *bundle = [NSBundle mainBundle];
CFURLRef url = (CFURLRef)[[NSURL fileURLWithPath:[bundle pathForResource:fileName ofType:@"mp3"]] retain];
AudioFileOpenURL(url, kAudioFileReadPermission, 0, &audioFile);
AudioStreamBasicDescription theFormat;
UInt32 formatSize = sizeof(theFormat);
AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &formatSize, &theFormat);
freq = (ALsizei)theFormat.mSampleRate;
CFRelease(url);
}
Code I use to fill in buffers:
- (void) loadOneChunkIntoBuffer:(ALuint)buffer {
char data[STREAM_BUFFER_SIZE];
UInt32 loadSize = STREAM_BUFFER_SIZE;
AudioStreamPacketDescription packetDesc[STREAM_PACKETS];
UInt32 numPackets = STREAM_PACKETS;
AudioFileReadPacketData(audioFile, NO, &loadSize, packetDesc, packetsLoaded, &numPackets, data);
alBufferData(buffer, AL_FORMAT_STEREO16, data, loadSize, freq);
packetsLoaded += numPackets;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因为您正在读取 MP3 数据字节并将它们视为 PCM 数据。
您几乎肯定需要编辑:除了仍然为您提供 MP3 数据;它只是在数据包中给出它并(可能)解析数据包标头。AudioFileReadPacketData()
。如果您不需要 OpenAL,AVAudioPlayer 可能是更好的选择(根据 多媒体编程指南,如果您想要更多控制,还有音频队列服务)。
如果你确实需要使用OpenAL,根据TN2199你需要将其转换为本机字节顺序的 PCM。请参阅 oalTouch/Classes/MyOpenALSupport.c 了解使用扩展音频文件服务来执行此操作的示例。请注意,TN2199 表示该格式“必须……不使用硬件解压缩”——根据多媒体编程指南,自 OS 3.0 起,除 HE-AAC 之外的所有内容都支持软件解码。另请注意,软件 MP3 解码可能会占用大量 CPU 时间。
或者,使用 AudioConverter 或(可能)带有 kAudioUnitSubType_AUConverter 的 AudioUnit 显式转换音频。如果您这样做,可能值得将所有内容解压缩一次并将其保留在内存中以最大程度地减少开销。
Because you're reading bytes of MP3 data and treating them as PCM data.
You almost certainly wantEDIT: Except that still gives you MP3 data; it just gives it in packets and (possibly) parses packet headers.AudioFileReadPacketData()
.If you don't require OpenAL, AVAudioPlayer is probably the better way to go (according to the Multimedia Programming Guide, there's also Audio Queue services if you want more control).
If you really need to use OpenAL, according to TN2199 you'll need to convert it to PCM in the native byte order. See oalTouch/Classes/MyOpenALSupport.c for an example of using Extended Audio File Services to do this. Note that TN2199 says the format "must ... not use hardware decompression" — according to the Multimedia Programming Guide, software decoding is supported for everything except HE-AAC since OS 3.0. Also note that software MP3 decoding can use a significant amount of CPU time.
Alternatively, explicitly convert the audio using AudioConverter or (possibly) AudioUnit with kAudioUnitSubType_AUConverter. If you do this, it might be worthwhile decompressing everything once and keeping it in memory to minimize overhead.