我正在使用libogg和libogg,我已经成功地将这些库添加到我的iPhone xCode项目中并用Speex编码我的声音。问题是我无法弄清楚如何使用ogg包装这些音频数据包。有人知道这种包应该是什么样子,或者有我可以使用的参考代码。
我在Java中知道它非常简单(你有专门的功能),但不是在iOS上。请帮忙。
答案 0 :(得分:5)
UPD 10.09.2013:请参阅demo project,它基本上从wave容器中获取pcm audiodata,使用speex编解码器对其进行编码并将所有内容打包到ogg容器中。也许以后我会为IOS上的所有speex例程创建一个完整的库/框架。
UPD 16.02.2015:GitHub上的演示项目为republished。
我最近也在iOS上尝试过Speex,取得了不同程度的成功,但这是我发现的东西。基本上,如果你想将一些speex编码的语音打包成一个ogg文件,你需要遵循三个步骤(假设libogg和libspeex已经编译并添加到项目中)。
1)添加带有Speex标题的第一个ogg页面; libspeex为它提供了内置的tools(下面的代码来自我的项目,不是最优的,只是为了举例):
// create speex header
SpeexHeader spxHeader;
SpeexMode spxMode = speex_wb_mode;
int spxRate = 16000;
int spxNumberOfChannels = 1;
speex_init_header(&spxHeader, spxRate, spxNumberOfChannels, &spxMode);
// set audio and ogg packing parameters
spxHeader.vbr = 0;
spxHeader.bitrate = 16;
spxHeader.frame_size = 320;
spxHeader.frames_per_packet = 1;
// wrap speex header in ogg packet
int oggPacketSize;
_oggPacket.packet = (unsigned char *)speex_header_to_packet(&spxHeader, &oggPacketSize);
_oggPacket.bytes = oggPacketSize;
_oggPacket.b_o_s = 1;
_oggPacket.e_o_s = 0;
_oggPacket.granulepos = 0;
_oggPacket.packetno = 0;
// submit the packet to the ogg streaming layer
ogg_stream_packetin(&_oggStreamState, &_oggPacket);
free(_oggPacket.packet);
// form an ogg page
ogg_stream_flush(&_oggStreamState, &_oggPage);
// write the page to file
[_oggFile appendBytes:&_oggStreamState.header length:_oggStreamState.header_fill];
[_oggFile appendBytes:_oggStreamState.body_data length:_oggStreamState.body_fill];
2)使用Vorbis comment添加第二个ogg页面:
// form any comment you like (I use custom struct with all fields)
vorbisCommentStruct *vorbisComment = calloc(sizeof(vorbisCommentStruct), sizeof(char));
...
// wrap Vorbis comment in ogg packet
_oggPacket.packet = (unsigned char *)vorbisComment;
_oggPacket.bytes = vorbisCommentLength;
_oggPacket.b_o_s = 0;
_oggPacket.e_o_s = 0;
_oggPacket.granulepos = 0;
_oggPacket.packetno = _oggStreamState.packetno;
// the rest should be same as in previous step
...
3)以类似的方式添加带有speex编码音频的后续ogg页面。
首先确定每个ogg页面上你想要拥有多少帧的音频数据(0-255;我非常随意地选择79):
_framesPerOggPage = 79;
然后为每一帧:
// calculate current granule position of audio data within ogg file
int curGranulePos = _spxSamplesPerFrame * _oggTotalFramesCount;
// wrap audio data in ogg packet
oggPacket.packet = (unsigned char *)spxFrame;
oggPacket.bytes = spxFrameLength;
oggPacket.granulepos = curGranulePos;
oggPacket.packetno = _oggStreamState.packetno;
oggPacket.b_o_s = 0;
oggPacket.e_o_s = 0;
// submit packets to streaming layer until their number reaches _framesPerOggPage
...
// if we've reached this limit, we're ready to create another ogg page
ogg_stream_flush(&_oggStreamState, &_oggPage);
[_oggFile appendBytes:&_oggStreamState.header length:_oggStreamState.header_fill];
[_oggFile appendBytes:_oggStreamState.body_data length:_oggStreamState.body_fill];
// finally, if this is the last frame, flush all remaining packets,
// which have been created but not packed into a page, to the last page
// (don't forget to set oggPacket.e_o_s to 1 for this frame)
就是这样。希望它会有所帮助。欢迎任何更正或问题。