avcodec_send_frame持续返回-22错误的AAC音频编码器问题求助
avcodec_send_frame持续返回-22错误的AAC音频编码器问题求助
大家好,我正在用ffmpeg/libavcodec写一个WAV转AAC的编码器,找编码器、创建上下文、填充帧数据这些步骤都走通了,但调用avcodec_send_frame()的时候一直返回-22(无效参数错误)。我已经参考ffmpeg官方的音频编码示例,把实际输入数据换成了正弦波测试,但还是没解决问题。
下面是我当前的核心代码片段:
#ifndef AACCONVERTER_H #define AACCONVERTER_H extern "C" { #include <libavcodec/avcodec.h> class AacConverter { public: AacConverter() : ctx{nullptr}, codec{nullptr} {}; AacConverter(const int sampleRate, const int channels) { // Set up audio encoder codec = avcodec_find_encoder(AV_CODEC_ID_AAC); if (codec == NULL) { qDebug() << "Failed to find AAC encoder"; return; } ctx = avcodec_alloc_context3(codec); if (!ctx) { qDebug() << "Failed to allocate context"; } ctx->bit_rate = 128000; ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; ctx->sample_rate = sampleRate; ctx->channel_layout = AV_CH_LAYOUT_STEREO; ctx->channels = av_get_channel_layout_nb_channels(ctx->channel_layout); ctx->profile = FF_PROFILE_AAC_MAIN; ctx->time_base = (AVRational){1, sampleRate}; ctx->codec_type = AVMEDIA_TYPE_AUDIO; int ret = avcodec_open2(ctx, codec, nullptr); if (ret < 0) { qDebug() << "Failed to open codec:" << ret; } }; ~AacConverter() { if (ctx) { avcodec_close(ctx); av_free(ctx); ctx = nullptr; } }; unsigned char* encodeWav(const char* data, unsigned int length, unsigned int& bufSize) { frameEncode = av_frame_alloc(); if (!frameEncode) return nullptr; frameEncode->nb_samples = ctx->frame_size; frameEncode->format = ctx->sample_fmt; frameEncode->channel_layout = ctx->channel_layout; int rawOffset = 0; int rawDelta = 0; int rawSamplesCount = frameEncode->nb_samples <= length ? frameEncode->nb_samples : length; char* dataPtr = (char*)data; int i, j, k, ret; uint16_t* samples = nullptr; float t, tincr; qDebug() << "AAC rawSamplesCount" << rawSamplesCount << "frameEncode->nb_samples" << frameEncode->nb_samples << "length" << length; /* allocate the data buffers */ ret = av_frame_get_buffer(frameEncode, 0); if (ret < 0) { qDebug() << "Could not allocate audio data buffers:" << ret; return nullptr; } ret = av_frame_make_writable(frameEncode); if (ret < 0) { qDebug() << "Failed to make frame writable:" << ret; return nullptr; } /* encode a single tone sound */ t = 0; tincr = 2 * M_PI * 440.0 / ctx->sample_rate; for (i = 0; i < 200; i++) { /* make sure the frame is writable -- makes a copy if the encoder * kept a reference internally */ ret = av_frame_make_writable(frameEncode); if (ret < 0) exit(1); samples = (uint16_t*)frameEncode->data[0]; for (j = 0; j < ctx->frame_size; j++) { samples[2*j] = (int)(sin(t) * 10000); for (k = 1; k < ctx->ch_layout.nb_channels; k++) samples[2*j + k] = samples[2*j]; t += tincr; } encodeFrame(); } qDebug() << "2" << samples << frameEncode->data[0] << &dataPtr[rawOffset]; av_frame_unref(frameEncode); bufSize = collectedSamples.size(); return collectedSamples.data(); } void encodeFrame() { qDebug() << Q_FUNC_INFO; /* send the frame for encoding */ int ret = avcodec_send_frame(ctx, frameEncode); if (ret < 0) { qDebug() << "avcodec_send_frame returned" << ret; return; } qDebug() << ret; /* read all the available output packets (in general there may be any number of them) */ while (ret >= 0) { ret = avcodec_receive_packet(ctx, &packetEncode); if (ret < 0 && ret != AVERROR(EAGAIN)) continue; if (ret < 0) break; uint8_t* data = (uint8_t *)(malloc(sizeof(uint8_t) * packetEncode.size)); memcpy(data, packetEncode.data, (size_t)packetEncode.size); const auto size = (unsigned int)(packetEncode.size); for (unsigned int i = 0; i < size; i++) { collectedSamples.push_back(data[i]); } free(data); } av_packet_unref(&packetEncode); } private: AVCodecContext *ctx; AVCodec *codec; AVPacket packetEncode; AVFrame* frameEncode; std::vector<uint8_t> collectedSamples; }; } #endif
我梳理出的问题根源&修复方案
1. 采样格式与数据填充完全不匹配
你设置的编码器采样格式是AV_SAMPLE_FMT_FLTP(浮点Planar格式),但代码里却用uint16_t*(16位整型)来强制转换帧数据指针:
- FLTP格式的每个声道数据是分开存储的:左声道在
frame->data[0],右声道在frame->data[1],不是交错存储 - FLTP的样本值范围是
[-1.0, 1.0]的浮点数,不是16位整型的[-32768, 32767]
修复代码:
// 替换原有的样本填充逻辑 float t = 0; float tincr = 2 * M_PI * 440.0 / ctx->sample_rate; // 分别获取左右声道的浮点数据指针 float* left_ch = static_cast<float*>(frameEncode->data[0]); float* right_ch = static_cast<float*>(frameEncode->data[1]); for (int j = 0; j < ctx->frame_size; j++) { float sample = sin(t) * 0.5f; // 控制幅度避免过载 left_ch[j] = sample; right_ch[j] = sample; // 左右声道复用同一数据 t += tincr; }
2. 帧样本数不符合编码器要求
AAC编码器要求每次发送的帧样本数必须严格等于ctx->frame_size(通常是1024或2048),你代码里计算rawSamplesCount时和输入length做比较,会导致帧样本数不匹配,触发无效参数错误。
修复方式:
- 移除
rawSamplesCount相关的逻辑,直接使用ctx->frame_size作为每次发送的样本数 - 如果是处理实际WAV输入,需要先把数据按
ctx->frame_size分块,不足的部分补零
3. 未初始化编码用Packet
类成员packetEncode没有提前初始化,直接传入avcodec_receive_packet()会导致野指针问题。
修复方式:
在类构造函数中初始化Packet:
AacConverter(const int sampleRate, const int channels) { // ... 其他初始化代码 ... av_init_packet(&packetEncode); packetEncode.data = nullptr; packetEncode.size = 0; }
4. 声道布局硬编码不合理
你直接硬编码了AV_CH_LAYOUT_STEREO,但构造函数参数里有channels,如果传入非2的声道数会导致矛盾。建议根据传入的声道数自动匹配布局:
// 替换原有的声道布局设置 ctx->channels = channels; ctx->channel_layout = av_get_default_channel_layout(channels); if (!ctx->channel_layout) { qDebug() << "Unsupported channel count:" << channels; return; }
5. 重复调用av_frame_make_writable()
在循环里每次都调用av_frame_make_writable()是冗余的,只需要在第一次分配帧后,或者发送帧后需要修改数据时调用一次即可。
额外调试技巧
如果还是报错,可以用av_strerror()把错误码转成可读字符串,精准定位问题:
char err_buf[256]; av_strerror(ret, err_buf, sizeof(err_buf)); qDebug() << "avcodec_send_frame failed:" << err_buf;
按上面的方案修改后,应该就能解决avcodec_send_frame()返回-22的问题了!




