avcodec_open2返回负值主因是avcodeccontext未用avcodec_alloc_context3分配、未调avcodec_parameters_to_context填充参数、或解码器与上下文不匹配。

ffmpeg解码失败:avcodec_open2返回负数
多数人卡在这一步,不是代码写错,是没初始化或上下文没配对。avcodec_open2 返回负值(比如 -22)基本等于“参数不合法”,常见原因有三个:
-
AVCodecContext没用avcodec_alloc_context3分配,而是手动生成结构体——C++里容易误用new AVCodecContext,但 FFmpeg 内部依赖其内存布局和默认值 - 调用前漏了
avcodec_parameters_to_context(从AVStream拿参数填进 context),尤其在封装格式(如 MP4)中,codecpar和codec是分离的 - 传入的
AVCodec*和AVCodecContext不匹配,比如用avcodec_find_decoder(AV_CODEC_ID_H264)找到解码器,却往 context 里硬塞了 AAC 的参数
实操建议:先确认 avcodec_find_decoder 返回非空,再用 avcodec_parameters_to_context(ctx, stream->codecpar) 填充,最后才调 avcodec_open2。
C++里怎么安全释放AVFrame和AVPacket
FFmpeg 的内存管理是“谁分配、谁释放”原则,但 C++ 容易误用 delete 或忘记释放导致崩溃或内存泄漏。关键点在于:av_frame_alloc / av_packet_alloc 分配的对象,必须用 av_frame_free / av_packet_unref(不是 free,也不是 delete)。
-
AVFrame:用av_frame_alloc()创建后,每帧处理完必须调av_frame_free(&frame);如果只是借用(比如从解码器拿到的输出帧),不能 free,应改用av_frame_unref清空引用计数 -
AVPacket:av_packet_alloc()后用av_packet_unref()释放数据缓冲区;若用av_packet_move_ref()转移所有权,则原 packet 自动变为空,无需再 unref - RAII 封装可行但需谨慎:FFmpeg 内部可能重用 buffer,直接在析构里
av_frame_free没问题,但别在拷贝构造里做浅拷贝——AVFrame不支持深拷贝,要用av_frame_clone
libavcodec硬解(NVDEC/QSV)启用失败
想用 GPU 解码却 fallback 到 CPU,大概率是没设对 AVCodecContext 的 hw_device_ctx 或没选对 codec。
立即学习“C++免费学习笔记(深入)”;
- 必须先调
av_hwdevice_ctx_create创建设备上下文(比如AV_HWDEVICE_TYPE_CUDA),再把返回的AVBufferRef*赋给ctx->hw_device_ctx - 解码器必须显式选择硬件加速类型:比如 H.264,要找
avcodec_find_decoder_by_name("h264_cuvid")(NVIDIA)或"h264_qsv"(Intel),不能只用avcodec_find_decoder(AV_CODEC_ID_H264) - 硬解成功后,
avcodec_receive_frame返回的AVFrame的format是AV_PIX_FMT_CUDA等硬件格式,不能直接用 OpenCV 显示,得先用av_hwframe_transfer_data拷贝到系统内存
注意:Windows 上 NVDEC 需要驱动支持(≥ 418.x),Linux 上 CUDA 设备需可访问(nvidia-smi 能看到),否则 av_hwdevice_ctx_create 直接返回负值。
avcodec_send_packet后avcodec_receive_frame一直返回EAGAIN
这不是卡死,是 FFmpeg 的流式解码模型正常行为:输入 packet 不够触发一帧输出,或者还没收到关键帧(如 H.264 的 IDR 帧)。典型场景是读取网络流或不完整文件头时。
- 确保至少送入一个含关键帧的
AVPacket(pkt.flags & AV_PKT_FLAG_KEY),否则解码器会等 - 送完所有 packet 后,必须再调一次
avcodec_send_packet(nullptr)告诉解码器“输入结束了”,否则内部缓存不 flush,receive_frame永远不会吐出剩余帧 - 不要在循环里无条件反复调
receive_frame,应配合send_packet的返回值判断:只有send_packet成功后,才值得多试几次receive_frame;连续返回EAGAIN且没新 packet 可送,说明真没数据了
硬解下还可能因 GPU buffer 满而阻塞,这时 receive_frame 也会返回 EAGAIN,但通常伴随 av_hwframe_get_buffer 失败,需要检查设备上下文状态。










