[openal] FFmpeg + OpenAL - playback streaming sound from video won't work

Jan Drabner jan at jdrabner.eu
Mon Jan 27 14:09:49 EST 2014


Hey,

I am decoding an OGG video (theora & vorbis as codecs) and want to show 
it on the screen (using Ogre 3D) while playing its sound. I can decode 
the image stream just fine and the video plays perfectly with the 
correct frame rate, etc.

However, I cannot get the sound to play at all with OpenAL.

Here is how I decode audio packets (in a background thread, the 
equivalent works just fine for the image stream of the video file):

|//------------------------------------------------------------------------------
int  decodeAudioPacket(   AVPacket&  p_packet,  AVCodecContext*  p_audioCodecContext,  AVFrame*  p_frame,
                         FFmpegVideoPlayer*  p_player,  VideoInfo&  p_videoInfo)
{
     // Decode audio frame
     int  got_frame=  0;
     int  decoded=  avcodec_decode_audio4(p_audioCodecContext,  p_frame,  &got_frame,  &p_packet);
     if  (decoded<  0)  
     {
         p_videoInfo.error=  "Error decoding audio frame.";
         return  decoded;
     }

     // Frame is complete, store it in audio frame queue
     if  (got_frame)
     {
         int  bufferSize=  av_samples_get_buffer_size(NULL,  p_audioCodecContext->channels,  p_frame->nb_samples,  
                                                     p_audioCodecContext->sample_fmt,  0);

         int64_t  duration=  p_frame->pkt_duration;
         int64_t  dts=  p_frame->pkt_dts;

         if  (staticOgreLog)
         {
             staticOgreLog->logMessage("Audio frame bufferSize / duration / dts:"  
                     +  boost::lexical_cast<std::string>(bufferSize)  +  " /"
                     +  boost::lexical_cast<std::string>(duration)  +  " /"
                     +  boost::lexical_cast<std::string>(dts),  Ogre::LML_NORMAL);
         }

         // Create the audio frame
         AudioFrame*  frame=  new  AudioFrame();
         frame->dataSize=  bufferSize;
         frame->data=  new  uint8_t[bufferSize];
         memcpy(frame->data,  p_frame->data,  bufferSize);
         double  timeBase=  ((double)p_audioCodecContext->time_base.num)  /  (double)p_audioCodecContext->time_base.den;
         frame->lifeTime=  duration*  timeBase;

         p_player->addAudioFrame(frame);
     }

     return  decoded;
}

|

So, as you can see, I decode the frame, memcpy it to my own struct, 
AudioFrame. Now, when the sound is played, I use these audio frame like 
this:

|//------------------------------------------------------------------------------||
int  numBuffers=  4;
ALuint  buffers[4];
alGenBuffers(numBuffers,  buffers);
ALenum  success=  alGetError();
if(success!=  AL_NO_ERROR)
{
     CONSOLE_LOG("Error on alGenBuffers :"  +  Ogre::StringConverter::toString(success)  +  alGetString(success));
     return;
}

// Fill a number of data buffers with audio from the stream
std::vector<AudioFrame*>  audioBuffers;
std::vector<unsigned  int>  audioBufferSizes;
unsigned  int  numReturned=  FFMPEG_PLAYER->getDecodedAudioFrames(numBuffers,  audioBuffers,  audioBufferSizes);

// Assign the data buffers to the OpenAL buffers
for  (unsigned  int  i=  0;  i<  numReturned;  ++i)
{
     alBufferData(buffers[i],  _streamingFormat,  audioBuffers[i]->data,  audioBufferSizes[i],  _streamingFrequency);

     success=  alGetError();
     if(success!=  AL_NO_ERROR)
     {
         CONSOLE_LOG("Error on alBufferData :"  +  Ogre::StringConverter::toString(success)  +  alGetString(success)
                         +  " size:"  +  Ogre::StringConverter::toString(audioBufferSizes[i]));
         return;
     }
}

// Queue the buffers into OpenAL
alSourceQueueBuffers(_source,  numReturned,  buffers);
success=  alGetError();
if(success!=  AL_NO_ERROR)
{
     CONSOLE_LOG("Error queuing streaming buffers:"  +  Ogre::StringConverter::toString(success)  +  alGetString(success));
     return;
}
}

alSourcePlay(_source);|

The format and frequency I give to OpenAL are AL_FORMAT_STEREO16 (it is 
a stereo sound stream) and 48000 (which is the sample rate of the 
AVCodecContext of the audio stream).

And during playback, I do the following to refill OpenAL's buffers:

|//------------------------------------------------------------------------------||||
ALint  numBuffersProcessed;

       	// Check if OpenAL is done with any of the queued buffers
         alGetSourcei(_source,  AL_BUFFERS_PROCESSED,  &numBuffersProcessed);
         if(numBuffersProcessed<=  0)
             return;

         // Fill a number of data buffers with audio from the stream
         std::vector<AudiFrame*>  audioBuffers;
         std::vector<unsigned  int>  audioBufferSizes;
         unsigned  int  numFilled=  FFMPEG_PLAYER->getDecodedAudioFrames(numBuffersProcessed,  audioBuffers,  audioBufferSizes);

         // Assign the data buffers to the OpenAL buffers
         ALuint  buffer;
         for  (unsigned  int  i=  0;  i<  numFilled;  ++i)
         {
             // Pop the oldest queued buffer from the source,
             // fill it with the new data, then re-queue it
             alSourceUnqueueBuffers(_source,  1,  &buffer);

             ALenum  success=  alGetError();
             if(success!=  AL_NO_ERROR)
             {
                 CONSOLE_LOG("Error Unqueuing streaming buffers:"  +  Ogre::StringConverter::toString(success));
                 return;
             }

             alBufferData(buffer,  _streamingFormat,  audioBuffers[i]->data,  audioBufferSizes[i],  _streamingFrequency);

             success=  alGetError();
             if(success!=  AL_NO_ERROR)
             {
                 CONSOLE_LOG("Error on re- alBufferData:"  +  Ogre::StringConverter::toString(success));
                 return;
             }

             alSourceQueueBuffers(_source,  1,  &buffer);

             success=  alGetError();
             if(success!=  AL_NO_ERROR)
             {
                 CONSOLE_LOG("Error re-queuing streaming buffers:"  +  Ogre::StringConverter::toString(success)  +  ""
                             +  alGetString(success));
                 return;
             }
         }

         // Make sure the source is still playing,
         // and restart it if needed.
         ALint  playStatus;
         alGetSourcei(_source,  AL_SOURCE_STATE,  &playStatus);
         if(playStatus!=  AL_PLAYING)
             alSourcePlay(_source);|

As you can see, I do quite heavy error checking. But I do not get any 
errors.
What I hear somewhat resembles the actual audio from the video, but VERY 
high pitched and stuttering VERY much. Also, it seems to be playing on 
top of TV noise. Very strange. Plus, it is playing much slower than the 
correct audio would. But it is very hard to hear anything specific in 
that mess.

The video itself is not broken, it can be played fine on any player. 
OpenAL can also play *.way files just fine in the same application, so 
it is also working.

Any ideas what could be wrong here or how to do this correctly?

My only guess is that somehow, FFmpeg's decode function does not produce 
data OpenGL can read. But this is as far as the FFmpeg decode example 
goes, so I don't know what's missing. As I understand it, the 
decode_audio4 function decodes the frame to raw data. And OpenAL should 
be able to work with RAW data (or rather, doesn't work with anything else).


P.S: You can also find this question on StackOverflow, figured it 
wouldn't hurt to ask on multiple places:
http://stackoverflow.com/questions/21386135/ffmpeg-openal-playback-streaming-sound-from-video-wont-work
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://openal.org/pipermail/openal/attachments/20140127/ca2bbcfa/attachment-0001.html>


More information about the openal mailing list