avcodec_open2返回Invalid Argument(-22):H264编码AVFrames到MP4遇错求助
排查avcodec_open2返回Invalid Argument(-22)的原因及解决方案
核心问题分析
avcodec_open2返回错误码-22(无效参数),通常是因为编码器上下文缺少关键配置、参数不符合编码器要求,或是编码器实例获取错误导致的。结合你的代码,以下是针对性的排查和修复方案:
具体修复步骤
1. 确认编码器实例获取正确
必须确保你是通过编码器查找函数获取H264编码器,而非解码器或空指针:
const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { std::cout << "H264编码器未找到" << std::endl; return; }
如果误用avcodec_find_decoder获取解码器,调用avcodec_open2会直接返回参数错误。
2. 修正视频分辨率的对齐要求
H264编码器对分辨率有宏块对齐要求(通常为16的倍数),你的宽度270不是16的倍数(16×17=272),这会触发编码器参数校验失败。调整分辨率为16的倍数:
stream->codecpar->width = 272; // 替换原270 stream->codecpar->height = 480; // 480是16的倍数,无需修改
3. 补充编码器上下文的关键参数
从codecpar拷贝参数到codec_ctx后,部分H264编码器需要额外配置核心参数,否则会拒绝启动。在avcodec_parameters_to_context之后添加:
// 配置帧率、GOP、时间基等核心参数 codec_ctx->framerate = (AVRational){1, 30}; codec_ctx->gop_size = 60; // 每60帧生成一个关键帧,可按需调整 codec_ctx->max_b_frames = 0; // 先禁用B帧,避免编码器不兼容 codec_ctx->time_base = stream->time_base; codec_ctx->profile = AV_PROFILE_H264_BASELINE; // 指定H264基线 profile
4. 开启全局头参数(适配MP4封装)
MP4封装要求编码器生成全局头信息,这也是部分编码器启动的必要条件,在avcodec_open2之前添加:
codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
开启后需要将上下文参数回写到流的codecpar:
ret = avcodec_parameters_from_context(stream->codecpar, codec_ctx); if (ret < 0) { std::cout << "更新流编码参数失败: " << av_err2str(ret) << std::endl; // 错误处理逻辑 }
完整修复后的代码片段
// 1. 正确获取H264编码器 const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { std::cout << "H264编码器未找到" << std::endl; avformat_free_context(format_ctx); return; } // 2. 设置流参数(修正分辨率) stream->codecpar->codec_id = AV_CODEC_ID_H264; stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; stream->codecpar->width = 272; // 调整为16的倍数 stream->codecpar->height = 480; stream->codecpar->format = AV_PIX_FMT_YUV420P; stream->codecpar->bit_rate = 500000; // 适度提高码率,避免过低触发校验 AVRational framerate = {1, 30}; stream->time_base = av_inv_q(framerate); // 3. 初始化编码器上下文 AVCodecContext* codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { std::cout << "分配编码器上下文失败" << std::endl; avformat_free_context(format_ctx); return; } ret = avcodec_parameters_to_context(codec_ctx, stream->codecpar); if (ret < 0) { std::cout << "设置编码器上下文参数失败: " << av_err2str(ret) << std::endl; avcodec_free_context(&codec_ctx); avformat_free_context(format_ctx); return; } // 4. 补充编码器关键配置 codec_ctx->framerate = framerate; codec_ctx->gop_size = 60; codec_ctx->max_b_frames = 0; codec_ctx->time_base = stream->time_base; codec_ctx->profile = AV_PROFILE_H264_BASELINE; codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; // 5. 打开编码器 ret = avcodec_open2(codec_ctx, codec, nullptr); if (ret < 0) { wxMessageBox("打开编码器错误: "); wxMessageBox(av_err2str(ret)); avcodec_free_context(&codec_ctx); avformat_free_context(format_ctx); return; } // 6. 将上下文参数回写到流 ret = avcodec_parameters_from_context(stream->codecpar, codec_ctx); if (ret < 0) { std::cout << "更新流编码参数失败: " << av_err2str(ret) << std::endl; avcodec_free_context(&codec_ctx); avformat_free_context(format_ctx); return; }
内容的提问来源于stack exchange,提问作者nokla
相关产品推荐
相关产品推荐

