avcodec_send_packet返回AVERROR(EAGAIN)表示解码器输入缓冲区满,需先调用avcodec_receive_frame取完已解帧,直到返回EAGAIN或EOF,再重试发送;切勿当作错误退出。

avcodec_send_packet 返回 AVERROR(EAGAIN) 怎么处理
这是最常卡住新手的地方:调用 avcodec_send_packet 后返回 AVERROR(EAGAIN),不是出错,而是解码器内部缓冲区已满、暂时无法接收新包。硬切错误处理会直接退出,实际应继续从解码器取帧。
正确做法是先调用 avcodec_receive_frame 尝试取完所有已解码帧,直到它返回 AVERROR(EAGAIN) 或 AVERROR_EOF,再送下一个 AVPacket。
- 不要在
send失败后跳过后续逻辑 - 音频/视频流都适用该模式,但视频帧产出节奏更不规则,更容易遇到连续
EAGAIN - 若持续收不到帧,检查
AVCodecContext是否已正确avcodec_open2,且pkt->stream_index与目标解码流匹配
怎么选对解码器(avcodec_find_decoder)
不能只靠编码格式名硬匹配。比如 AAC 流可能是 ADTS 封装或 LATM 封装,AVCodecParameters->codec_id 才是权威依据;H.264 流若带 Annex B NALU,codec_id 是 AV_CODEC_ID_H264,但如果是 MP4 容器里的 avcC 格式,也仍是同一个 ID。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先用
avformat_find_stream_info解析输入流,确保fmt_ctx->streams[i]->codecpar->codec_id已填充 - 传给
avcodec_find_decoder的必须是codecpar->codec_id,不是字符串如"h264" - 硬件解码器(如
h264_qsv)需额外调用avcodec_find_decoder_by_name,且要提前初始化对应硬件设备上下文(如AVBufferRef* hw_device_ctx)
音频解码后数据格式(frame->format)和重采样必要性
解码出来的 AVFrame 音频样本格式(frame->format)大概率不是你最终要的格式——例如播放需要 AV_SAMPLE_FMT_S16,而 AAC 解码默认输出 AV_SAMPLE_FMT_FLTP(平面浮点)。直接写文件或喂给声卡会失败或失真。
必须用 swr_convert 做重采样,关键点:
- 初始化
SwrContext*时,源格式必须严格等于frame->format,目标格式按需设(如AV_SAMPLE_FMT_S16) - 采样率、声道数也要对齐:
frame->sample_rate和frame->channel_layout是真实值,别硬写 44100 / AV_CH_LAYOUT_STEREO -
swr_convert可能一次不能填满目标缓冲区,需循环调用直到输入样本耗尽
多线程解码音视频流要注意资源隔离
常见错误是把同一个 AVFormatContext* 或 AVCodecContext* 丢进多个线程并发调用 av_read_frame 或 avcodec_send_packet —— FFmpeg 的这些结构体**不是线程安全的**。
安全做法:
- 一个线程独占一个
AVFormatContext*(通过avformat_open_input重新打开同一文件,或用avformat_seek_file同步位置) - 每个解码流(音频/视频)使用独立的
AVCodecContext*,且各自调用avcodec_open2 - 若共用一个输入上下文,必须加锁控制
av_read_frame,并按pkt->stream_index分发到对应解码线程
真正容易被忽略的是时间戳同步:音视频帧的 pts 来自不同流,单位是各自流的 time_base,不做 av_rescale_q 转换就强行对齐,画面和声音一定脱节。


















