libOgg / libVorbis and AudioBufferList

516 views Asked by At

I am trying to encode "live" (buffered) audio data to OggVorbis format however it just isn't working for me. No matter what I do, the output stream contains only the Vorbis header (no Ogg data).

I have successfully encoded to an MP3 stream using libLAME in the same way (replacing ogg functions with LAME obviously).

I have included my code for retrieving the PCM data, feeding it to libOgg and retrieving the output and buffering it. At the moment I am breaking at the "Buffer Overflow" stage and using Xcode to view the memory contained within the outputBuffer.

As I said above, this works for MP3 using libLAME, so I know I can't be far off. If I look at ogg.header and ogg.body, they contain data and ogg.header_length is 282 and ogg.body_length is 255.

If required, I can paste bin the outputBuffer for people to look at.

    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

There are 1 answers

0
Anthony Myatt On

In the end I got it working. I had to use memcpy to fill the libOgg input buffers and I had to fix the value I was passing in for the number of samples I was copying to the buffer.

Please see the working code below:

    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);