libOgg / libVorbis和AudioBufferList

时间:2013-12-17 04:41:19

标签: objective-c core-audio oggvorbis

我正在尝试将“实时”(缓冲)音频数据编码为OggVorbis格式,但它对我不起作用。无论我做什么,输出流只包含Vorbis标头(没有Ogg数据)。

我已经使用libLAME以相同的方式成功编码为MP3流(显然用LAME替换ogg功能)。

我已经包含了用于检索PCM数据的代码,将其提供给libOgg并检索输出并缓冲它。目前我正处于“缓冲区溢出”阶段并使用Xcode查看outputBuffer中包含的内存。

正如我上面所说,这适用于使用libLAME的MP3,所以我知道我不能远。如果我查看ogg.header和ogg.body,它们包含数据,ogg.header_length是282,ogg.body_length是255。

如果需要,我可以将outputBuffer粘贴到bin中供人们查看。

    UInt32 ioLengthInFrames = 256;//ioBufferDuration * self.audioFormat->mSampleRate;
    AudioBufferList *ioData = AllocateABL(self.audioFormat->mChannelsPerFrame, self.audioFormat->mBytesPerFrame, NO, ioLengthInFrames);
    AudioBufferList *floatData = AllocateABL(self.audioFormat->mChannelsPerFrame, self.audioFormat->mBytesPerFrame, NO, ioLengthInFrames);

    UInt32 retVal = TPCircularBufferPeek(inputBuffer, NULL, self.audioFormat);
    if (!retVal > 0)
        return;

    //NSLog (@"Frames Available:  %ld", retVal);

    TPCircularBufferDequeueBufferListFrames(inputBuffer, &ioLengthInFrames, ioData, NULL, self.audioFormat);
    AEFloatConverterToFloatBufferList(self.floatConverter, ioData, floatData, ioLengthInFrames);

    if (ioLengthInFrames <= 0)
    {
        NSLog(@"Not enough frames");
        return;
    }

    float **buffer = vorbis_analysis_buffer(&vd, ioLengthInFrames * self.audioFormat->mBytesPerFrame);

    buffer[0] = floatData->mBuffers[0].mData;
    buffer[1] = floatData->mBuffers[1].mData;

    checkresult (vorbis_analysis_wrote(&vd, ioLengthInFrames * self.audioFormat->mBytesPerFrame), @"Analysis Wrote");

    int wrote = 0;

    while (vorbis_analysis_blockout(&vd, &vb) == 1)
    {
        NSLog(@"Block Out");

        checkresult (vorbis_analysis(&vb, NULL), @"Analysis");
        checkresult (vorbis_bitrate_addblock(&vb), @"BitRate AddBlock");

        while (vorbis_bitrate_flushpacket(&vd, &op))
        {
            NSLog(@"Flush Packet");

            ogg_stream_packetin(&os, &op);

            bool eos = false;
            while (!eos)
            {
                NSLog(@"EOS");
                int result = ogg_stream_pageout(&os, &og);
                if (result==0)break;
                NSLog(@"EOS 2");

                int availableBytes;
                unsigned char* head = TPCircularBufferHead(&outputBuffer, &availableBytes);
                if (availableBytes < og.header_len + og.body_len)
                {
                    return;
                    // Buffer Full
                }
                memcpy(head, og.header, og.header_len);
                memcpy(head+og.header_len, og.body, og.body_len);
                TPCircularBufferProduce(&outputBuffer, og.header_len + og.body_len);

                wrote += og.header_len + og.body_len;

                if (ogg_page_eos(&og))eos=true;
            }
        }
    }

    NSLog(@"Rendering OggVorbis: %d bytes written", wrote);

1 个答案:

答案 0 :(得分:0)

最后我开始工作了。我不得不使用memcpy来填充libOgg输入缓冲区,我必须修复我传入的值,因为我复制到缓冲区的样本数量。

请参阅以下工作代码:

    UInt32 ioLengthInFrames = 256;//ioBufferDuration * self.audioFormat->mSampleRate;
    AudioBufferList *ioData = AllocateABL(self.audioFormat->mChannelsPerFrame, self.audioFormat->mBytesPerFrame, NO, ioLengthInFrames);
    AudioBufferList *floatData = AllocateABL(self.audioFormat->mChannelsPerFrame, self.audioFormat->mBytesPerFrame, NO, ioLengthInFrames);

    UInt32 retVal = TPCircularBufferPeek(inputBuffer, NULL, self.audioFormat);
    if (!retVal > 0)
        return;

    TPCircularBufferDequeueBufferListFrames(inputBuffer, &ioLengthInFrames, ioData, NULL, self.audioFormat);
    AEFloatConverterToFloatBufferList(self.floatConverter, ioData, floatData, ioLengthInFrames);

    if (ioLengthInFrames <= 0)
    {
        NSLog(@"Not enough frames");
        return;
    }

    float **buffer = vorbis_analysis_buffer(&vd, ioLengthInFrames);

    memcpy(buffer[0], floatData->mBuffers[0].mData, floatData->mBuffers[0].mDataByteSize);
    memcpy(buffer[1], floatData->mBuffers[1].mData, floatData->mBuffers[1].mDataByteSize);

    checkresult (vorbis_analysis_wrote(&vd, ioLengthInFrames), @"Analysis Wrote");

    int wrote = 0;

    while (vorbis_analysis_blockout(&vd, &vb) == 1)
    {
        checkresult (vorbis_analysis(&vb, NULL), @"Analysis");
        checkresult (vorbis_bitrate_addblock(&vb), @"BitRate AddBlock");

        while (vorbis_bitrate_flushpacket(&vd, &op))
        {
            //NSLog(@"Flush Packet");

            ogg_stream_packetin(&os, &op);

            bool eos = false;
            while (!eos)
            {
                int result = ogg_stream_pageout(&os, &og);
                if (result==0)break;

                int size = og.header_len + og.body_len;

                int availableBytes;
                unsigned char* head = TPCircularBufferHead(&outputBuffer, &availableBytes);

                if (availableBytes < size)
                {
                    NSLog(@"Buffer Full");
                    return;
                }

                memcpy(head, og.header, og.header_len);
                memcpy(head+og.header_len, og.body, og.body_len);
                TPCircularBufferProduce(&outputBuffer, size);

                wrote += size;

                if (ogg_page_eos(&og))eos=true;
            }
        }
    }

    NSLog(@"Rendering OggVorbis: %d bytes written", wrote);