如何使用avcodec_decode_audio4解码AAC?

时间:2014-07-30 09:22:34

标签: ffmpeg libavcodec libav decoder libavformat

我将代码avcodec_decode_audio3更改为avcodec_decode_audio4并添加了帧处理。但现在我再也无法解码AAC帧了。

为什么avcodec_decode_audio4返回 -22 无效参数)? 根据下面的答案,这是否与AVContext中需要设置的参数有关?

我不得不使用avcodec_decode_audio4因为我更新了我的ffmpeg然后出现了以下错误:

[NULL @ 0xb14f020] Custom get_buffer() for use withavcodec_decode_audio3() detected. 
         Overriding with avcodec_default_get_buffer
[NULL @ 0xb14f020] Please port your application to avcodec_decode_audio4()

根据Buffer error in avcodec_decode_audio4()这是一个回归,除了回到ffmpeg<之外还有其他解决办法吗? 0.8?

解码器使用avcodec_decode_audio4:

AVCodec *codec;
AVCodecContext *avCtx;
AVFrame * decoded_frame = NULL;
uint8_t *outbuf = static_cast<uint8_t *>(malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE));
AVPacket avPacket;

main(){
    av_register_all();
    codec = avcodec_find_decoder(CODEC_ID_AAC);

    //set parameters
    avCtx = avcodec_alloc_context3(codec);
    avCtx->channels = 1;
    avCtx->sample_rate = 44100;
    avCtx->bit_rate=16;

    if (avcodec_open2(avCtx, codec, NULL) < 0) printf("Could not open codec\n");

    av_init_packet(&avPacket);

    //Main decoder loop
    while(1) 
        my_frame_decoder();
    return 0;
}

void my_frame_decoder() {
    //get data
    ...
    avPacket.size = numBytes;
    avPacket.data = inputBytes;
    int len;

    while (avPacket.size > 0) {

    int got_frame = 0;
    if (!decoded_frame) {
        if (!(decoded_frame = avcodec_alloc_frame())) {
            printf("out of memory");
            return;
        }
    } else {
        avcodec_get_frame_defaults(decoded_frame);
    }

    //-------------------->> returns always -22
    len = avcodec_decode_audio4(avCtx, decoded_frame, &got_frame, &avPacket); 

    //do something with the decoded frame
    ...
    avPacket.size -= len;
    avPacket.data += len;
    }

    return;
}

4 个答案:

答案 0 :(得分:1)

我认为问题是编解码器上下文中设置的参数。请参考https://www.ffmpeg.org/doxygen/trunk/structAVCodecContext.html设置参数,该参数已从avcodec_decode_audio3更改为avcodec_decode_audio4。

答案 1 :(得分:1)

经过数小时的搜索,我发现dec_ctx的{​​{1}}必须由avcodec_decode_audio4初始化的dec_codec打开

av_find_best_stream()

答案 2 :(得分:0)

没有解决方案,但解决方法是回到旧版本。在测试了与avcodec_decode_audio3一起使用的各种构建之后,我认为其他人知道来自https://ffmpeg.org/releases/的ffmpeg-0.10.14.tar.bz2可能有用。

答案 3 :(得分:0)

<!-- language: c++ -->

#include <windows.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <math.h>
#include <wctype.h>
#include <wchar.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <locale.h>
#include <signal.h>
#include <limits.h>
#include <float.h>
#include <iso646.h>

#undef NDEBUG
#include <assert.h>

// Use avcodec_send_packet() and avcodec_receive_frame().

//sample code
while (av_read_frame (FormatContext, packet_ptr) >= 0)
{
    /* some code */
    if (packet_ptr->stream_index == audiostream)
    {

        assert(NULL == decoded_frame);

        decoded_frame = av_frame_alloc();

        ret = avcodec_send_packet(pCodecCtx, packet_ptr);
        if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
        {
            av_packet_unref (packet_ptr);

            if (decoded_frame)
            {
                av_frame_unref(decoded_frame);
                decoded_frame = NULL;
            }

            continue;
        }
        else
        {
            if (0 <= ret)
                packet_ptr->size = 0;

            ret = avcodec_receive_frame(pCodecCtx, decoded_frame);
            if (ret >= 0)
                got_frame = 1;
            else
            {
                got_frame = 0;

                if (decoded_frame)
                {
                    av_frame_unref(decoded_frame);
                    decoded_frame = NULL;
                }

                av_packet_unref (packet_ptr);
                continue;
            }
        }

        if(AV_SAMPLE_FMT_FLTP == pCodecCtx->sample_fmt)//AAC sample format for Libav released 10-October-2020 (ffmpeg 4.3.1)
        {
            //now get the PCM data ready to play or save

            int nb_samples = decoded_frame->nb_samples;
            int channels = pCodecCtx->channels;

            if(channels > 2) //for this small sample only 2 channels...
            {
                channels = 2;//it will convert multichannel media files to 2 channels, remember this...more code need to be modified
            }

            int outputBufferLen = nb_samples * channels * 2;
            int size_out //the size of the PCM data as sizeof(char)
                    =outputBufferLen;

            char * buf = malloc(size_out);

            short *outputBuffer=(short *)buf;
            int in_samples = decoded_frame->nb_samples;

            int i=0;
            float * inputChannel0 = (float *)decoded_frame->extended_data[0];

            // Mono
            if (pCodecCtx->channels==1)
            {
                for (i=0; i<in_samples; i++)
                {
                    float sample = *inputChannel0++;
                    if (sample<-1.0f) sample=-1.0f;
                    else if (sample>1.0f) sample=1.0f;
                    outputBuffer[i] = (int16_t) (sample * 32767.0f);//largest positive int16_t
                }
            }
            // Stereo
            else
            {
                float * inputChannel1 = (float *)decoded_frame->extended_data[1];
                for (i=0; i < in_samples; i++)
                {

                    float sample = *inputChannel0++;
                    if (sample<-1.0f) sample=-1.0f;
                    else if (sample>1.0f) sample=1.0f;
                    float sample2 = *inputChannel1++;
                    if (sample2<-1.0f) sample2=-1.0f;
                    else if (sample2>1.0f) sample2=1.0f;

                    outputBuffer[i*2] = (int16_t) ((sample) * 32767.0f);
                    outputBuffer[i*2+1] = (int16_t) ((sample2) * 32767.0f);
                }
            }

            //use buf and size_out here then free the buf

            free(buf);

        }
    }
    av_packet_unref (packet_ptr);

    if (decoded_frame)
    {
        av_frame_unref(decoded_frame);
        decoded_frame = NULL;
    }
}
    
Hope it helps...