【问题标题】:How to decode AAC using avcodec_decode_audio4?如何使用 avcodec_decode_audio4 解码 AAC?
【发布时间】:2014-09-21 21:00:18
【问题描述】:

我将代码 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

使用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;
}

【问题讨论】:

    标签: ffmpeg libavcodec libav decoder libavformat


    【解决方案1】:
    <!-- 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...
    

    【讨论】:

    • 最后我想出了如何在 stackoverflow 上粘贴代码...
    【解决方案2】:

    经过数小时的搜索,我发现avcodec_decode_audio4dec_ctx 必须由dec_codec 初始化的av_find_best_stream() 打开

    1° av_find_best_stream(in_fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1,
                    &dec_codec, 0);<br>
    2° dec_ctx = m_in_aud_strm->codec;<br>
    3° av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);<br>
    4° avcodec_open2(dec_ctx, dec_codec, NULL)<br>
    .
    .
    .
    5° avcodec_decode_audio4(dec_ctx, pFrame, &got_frame, &pkt);
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 您应该提供更多详细信息,否则此答案可能没有用。
        猜你喜欢
        • 2015-10-28
        • 1970-01-01
        • 2021-04-20
        • 2021-12-17
        • 2015-06-12
        • 2013-12-21
        • 2013-09-24
        • 2012-10-08
        • 1970-01-01
        相关资源
        最近更新 更多