FFmpeg + OpenAL-无法播放视频流音频

绵羊皮

我正在解码OGG视频(theora和vorbis作为编解码器),并想在播放声音的同时在屏幕上显示(使用Ogre 3D)。我可以很好地解码图像流,并以正确的帧频等完美播放视频。

但是,我完全无法使用OpenAL播放声音。

编辑:我设法使播放声音至少在某种程度上类似于视频中的实际音频。更新了示例代码。

编辑2:我现在能够获得“几乎”正确的声音。我必须将OpenAL设置为使用AL_FORMAT_STEREO_FLOAT32(在初始化扩展名之后),而不是仅使用STEREO16。现在,声音“只有”极高的音调和结结,但速度正确。

这是我对音频数据包进行解码的方式(在后台线程中,等效功能对于视频文件的图像流来说也很好):

//------------------------------------------------------------------------------
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];
        if (p_frame->channels == 2)
        {
            memcpy(frame->data, p_frame->data[0], bufferSize >> 1);
            memcpy(frame->data + (bufferSize >> 1), p_frame->data[1], bufferSize >> 1);
        }
        else
        {
            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;
}

因此,如您所见,我将帧解码,将其memcpy转换为我自己的结构AudioFrame。现在,当播放声音时,我将使用以下音频帧:

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

我提供给OpenAL的格式和频率为AL_FORMAT_STEREO_FLOAT32(这是立体声声音流,并且确实初始化了FLOAT32扩展名)和48000(这是音频流的AVCodecContext的采样率)。

在播放期间,我执行以下操作以重新填充OpenAL的缓冲区:

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

如您所见,我进行了大量错误检查。但是我既没有从OpenAL也没有从FFmpeg得到任何错误。编辑:我听到的声音有点像视频中的实际音频,但是音高非常高,口吃也很厉害。另外,它似乎在电视噪音之上播放。很奇怪。另外,它的播放速度比正确的音频要慢得多。编辑:2使用AL_FORMAT_STEREO_FLOAT32之后,声音以正确的速度播放,但是音高和口吃仍然很高(尽管比以前少)。

视频本身没有损坏,可以在任何播放器上正常播放。OpenAL也可以在同一应用程序中播放* .way文件,因此它也可以正常工作。

有什么想法在这里有什么问题或如何正确执行吗?

我唯一的猜测是,无论如何,FFmpeg的解码功能不会产生OpenGL可以读取的数据。但这是FFmpeg解码示例所能解决的,所以我不知道缺少了什么。据我了解,decode_audio4函数将帧解码为原始数据。而且OpenAL应该能够处理RAW数据(或者说,不适用于其他任何数据)。

绵羊皮

所以,我终于想出了办法。哎呀,真是一团糟。这是来自libav-users邮件列表上的用户提示,使我进入了正确的路径。

这是我的错误:

  1. 在alBufferData函数中使用了错误的格式。我使用了AL_FORMAT_STEREO16(这就是每个带有OpenAL的流示例所使用的)。我应该使用AL_FORMAT_STEREO_FLOAT32,因为我播放的视频是Ogg,而vorbis存储在浮点中。并使用swr_convert将AV_SAMPLE_FMT_FLTP转换为AV_SAMPLE_FMT_S16会崩溃。不知道为什么。

  2. 不使用swr_convert将解码的音频帧转换为目标格式。在尝试使用swr_convert从FLTP转换为S16之后,它在没有给出原因的情况下完全崩溃,我认为它已损坏。但是在弄清我的第一个错误之后,我再次尝试,从FLTP转换为FLT(非平面),然后就可以了!因此,OpenAL使用交错格式,而不是平面格式。很高兴知道。

所以这是适用于我的Ogg视频,vorbis音频流的encodeAudioPacket函数:

int decodeAudioPacket(  AVPacket& p_packet, AVCodecContext* p_audioCodecContext, AVFrame* p_frame,
                        SwrContext* p_swrContext, uint8_t** p_destBuffer, int p_destLinesize,
                        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;
    }

    if(decoded <= p_packet.size)
    {
        /* Move the unread data to the front and clear the end bits */
        int remaining = p_packet.size - decoded;
        memmove(p_packet.data, &p_packet.data[decoded], remaining);
        av_shrink_packet(&p_packet, remaining);
    }

    // Frame is complete, store it in audio frame queue
    if (got_frame)
    {
        int outputSamples = swr_convert(p_swrContext, 
                                        p_destBuffer, p_destLinesize, 
                                        (const uint8_t**)p_frame->extended_data, p_frame->nb_samples);

        int bufferSize = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT) * p_videoInfo.audioNumChannels
                            * outputSamples;

        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_destBuffer[0], 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;
}

这是我初始化上下文和目标缓冲区的方法:

// Initialize SWR context
SwrContext* swrContext = swr_alloc_set_opts(NULL, 
            audioCodecContext->channel_layout, AV_SAMPLE_FMT_FLT, audioCodecContext->sample_rate,
            audioCodecContext->channel_layout, audioCodecContext->sample_fmt, audioCodecContext->sample_rate, 
            0, NULL);
int result = swr_init(swrContext);

// Create destination sample buffer
uint8_t** destBuffer = NULL;
int destBufferLinesize;
av_samples_alloc_array_and_samples( &destBuffer,
                                    &destBufferLinesize,
                                    videoInfo.audioNumChannels,
                                    2048,
                                    AV_SAMPLE_FMT_FLT,
                                    0);

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

无法让OpenAL播放声音

来自分类Dev

ffmpeg导致没有音频和无法播放的视频

来自分类Dev

无法使用ffmpeg播放录制的视频和音频

来自分类Dev

OpenAL从特定时间戳播放音频

来自分类Dev

AVPlayer无法播放FFMPEG的音频文件

来自分类Dev

ffmpeg无法正确混合视频和音频

来自分类Dev

使用 OpenAL 播放到特定频道

来自分类Dev

在 C 中的 OpenAL 中播放频率

来自分类Dev

ffmpeg图片>视频无法正常播放

来自分类Dev

ffmpeg:如何在播放重叠视频时同步音频

来自分类Dev

ffmpeg-记录等于正在播放的视频的音频音量

来自分类Dev

ffmpeg 在尝试通过音频循环播放视频时卡住

来自分类Dev

音频在ffmpeg播放器中无法正常播放

来自分类Dev

使用ffmpeg创建视频:视频已创建但无法播放

来自分类Dev

使用ffmpeg无法向视频添加多个音频输入

来自分类Dev

ffmpeg无法用音频录制视频该如何解决?

来自分类Dev

网络流视频+音频FFmpeg

来自分类Dev

C ++是否使用OpenAL处理实时PCM fft音频?

来自分类Dev

OpenAL仅适用于caff格式的音频文件

来自分类Dev

OpenAL与AVAudioPlayer与其他播放声音的技术

来自分类Dev

FFmpeg mux 视频使用 libavformat avcodec 但无法播放输出

来自分类Dev

在AVPlayer中录制当前播放视频的流音频

来自分类Dev

在AVPlayer中录制来自当前播放视频的流音频

来自分类Dev

ffmpeg录制视频播放太快

来自分类Dev

FFmpeg 无法识别任何视频文件 - 无法复用视频和音频

来自分类Dev

如果视频持续时间大于ffmpeg中的音频持续时间,如何添加视频的替换音频并循环播放音频?

来自分类Dev

ffmpeg:使用ffmpeg将图像/音频转换为视频

来自分类Dev

ffmpeg:concat视频和音频文件

来自分类Dev

ffmpeg连接音频不同步的视频

Related 相关文章

  1. 1

    无法让OpenAL播放声音

  2. 2

    ffmpeg导致没有音频和无法播放的视频

  3. 3

    无法使用ffmpeg播放录制的视频和音频

  4. 4

    OpenAL从特定时间戳播放音频

  5. 5

    AVPlayer无法播放FFMPEG的音频文件

  6. 6

    ffmpeg无法正确混合视频和音频

  7. 7

    使用 OpenAL 播放到特定频道

  8. 8

    在 C 中的 OpenAL 中播放频率

  9. 9

    ffmpeg图片>视频无法正常播放

  10. 10

    ffmpeg:如何在播放重叠视频时同步音频

  11. 11

    ffmpeg-记录等于正在播放的视频的音频音量

  12. 12

    ffmpeg 在尝试通过音频循环播放视频时卡住

  13. 13

    音频在ffmpeg播放器中无法正常播放

  14. 14

    使用ffmpeg创建视频:视频已创建但无法播放

  15. 15

    使用ffmpeg无法向视频添加多个音频输入

  16. 16

    ffmpeg无法用音频录制视频该如何解决?

  17. 17

    网络流视频+音频FFmpeg

  18. 18

    C ++是否使用OpenAL处理实时PCM fft音频?

  19. 19

    OpenAL仅适用于caff格式的音频文件

  20. 20

    OpenAL与AVAudioPlayer与其他播放声音的技术

  21. 21

    FFmpeg mux 视频使用 libavformat avcodec 但无法播放输出

  22. 22

    在AVPlayer中录制当前播放视频的流音频

  23. 23

    在AVPlayer中录制来自当前播放视频的流音频

  24. 24

    ffmpeg录制视频播放太快

  25. 25

    FFmpeg 无法识别任何视频文件 - 无法复用视频和音频

  26. 26

    如果视频持续时间大于ffmpeg中的音频持续时间,如何添加视频的替换音频并循环播放音频?

  27. 27

    ffmpeg:使用ffmpeg将图像/音频转换为视频

  28. 28

    ffmpeg:concat视频和音频文件

  29. 29

    ffmpeg连接音频不同步的视频

热门标签

归档