You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FFmpeg API编码YUV420P帧时avcodec_receive_packet返回错误1的排查

FFmpeg MPEG2编码时avcodec_receive_packet返回错误码1的排查方案

问题背景

使用FFmpeg API对640*480、30FPS的YUV420P原始视频帧编码为MPEG2格式,调用avcodec_receive_packet()时返回错误码1(对应FFmpeg定义的AVERROR(EAGAIN)),需排查问题以获取编码后的数据包用于TCP传输。用户提供的省略错误处理的代码如下:

EncodeFrame(const uint8_t* rawBuffer, size_t size) {
    const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO);
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);

    codec_ctx->bit_rate = 200000;
    codec_ctx->width = 640;
    codec_ctx->height = 480;
    codec_ctx->time_base = (AVRational){1,30};
    codec_ctx->gop_size = 10;
    codec_ctx->max_b_frames = 1;
    codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;

    avcodec_open2(codec_ctx, codec, nullptr);

    AVFrame* frame = av_frame_alloc();
    frame->format  = AV_PIX_FMT_YUV420P;
    frame->width   = 640;
    frame->height  = 480;

    av_image_fill_arrays(frame->data, frame->linesize, rawBuffer, AV_PIX_FMT_YUV420P, 640, 480, 1);

    avcodec_send_frame(codec_ctx, frame);

    AVPacket* pkt = av_packet_alloc();
    avcodec_receive_packet(codec_ctx, pkt)
    ...
}

错误码1的含义

错误码1对应AVERROR(EAGAIN),表示当前编码器无可用输出数据包,原因通常是:需要输入更多帧供编码器处理,或编码器因帧依赖(如B帧、GOP初始化)暂无法生成输出。

具体排查与修复步骤

1. 补全所有关键步骤的错误检查

代码省略了核心错误处理,会掩盖编码器初始化、帧数据填充等环节的潜在问题:

  • 检查avcodec_find_encoder()返回值,确认MPEG2编码器已编译进当前FFmpeg库
  • 检查avcodec_alloc_context3()是否成功分配上下文
  • 检查avcodec_open2()返回值,确保编码器正常打开
  • 检查av_image_fill_arrays()返回值,验证原始帧数据填充正确
  • 检查avcodec_send_frame()返回值,确认帧成功送入编码器

示例错误检查片段:

int ret;
const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO);
if (!codec) {
    // 处理编码器不存在的错误
}
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
    // 处理上下文分配失败的错误
}
// ... 设置编码器参数 ...
ret = avcodec_open2(codec_ctx, codec, nullptr);
if (ret < 0) {
    // 处理编码器打开失败的错误
}
ret = av_image_fill_arrays(frame->data, frame->linesize, rawBuffer, AV_PIX_FMT_YUV420P, 640, 480, 1);
if (ret < 0) {
    // 处理帧数据填充失败的错误
}
ret = avcodec_send_frame(codec_ctx, frame);
if (ret < 0) {
    // 处理帧送入编码器失败的错误
}

2. 修正编码器输入输出的循环逻辑

MPEG2编码器(尤其是开启B帧时)依赖多帧输入生成输出:

  • 设置max_b_frames = 1时,编码器需要后续帧作为参考生成B帧,首次送帧后可能无输出
  • GOP大小设为10时,编码器需积累足够帧才能生成I帧及后续P/B帧

正确处理逻辑是循环调用avcodec_receive_packet(),直到返回AVERROR(EAGAIN)或错误:

AVPacket* pkt = av_packet_alloc();
if (!pkt) {
    // 处理数据包分配失败的错误
}
while (true) {
    int ret = avcodec_receive_packet(codec_ctx, pkt);
    if (ret == AVERROR(EAGAIN)) {
        // 当前无输出,需输入更多帧,退出循环等待下一次送帧
        break;
    } else if (ret < 0) {
        // 处理编码错误
        break;
    }
    // 成功获取编码数据包,执行TCP传输等后续操作
    // 处理完成后必须调用av_packet_unref重置数据包
    av_packet_unref(pkt);
}
av_packet_free(&pkt);

3. 补充帧时间戳设置

代码未设置帧的pts(显示时间戳),编码器需要时间戳来处理帧顺序和GOP逻辑:

// 假设当前是第n帧(从0开始计数)
frame->pts = n;
// 对应30FPS的time_base(1/30),pts直接用帧索引即可

4. 补充编码器帧率参数

MPEG2编码器需明确设置帧率,否则可能无法正确识别输入帧速率:

codec_ctx->framerate = (AVRational){30, 1};

5. 优化资源管理逻辑

每次调用EncodeFrame()都重新创建编码器上下文、帧和数据包,会导致内存泄漏且效率低下。正确做法是将编码器初始化、上下文创建放在函数外部,仅在首次调用时执行,后续调用仅负责送帧和取数据包。

6. 验证原始YUV数据正确性

确认输入的rawBuffer是标准640*480 YUV420P格式:

  • YUV420P的总大小应为640*480*3/2 = 460800字节,检查size参数是否匹配
  • 确认Y、U、V分量顺序正确,无额外行对齐干扰(av_image_fill_arrays()的align设为1符合要求)

总结

错误码1的核心原因是编码器暂无可输出数据包,可能由输入帧不足、时间戳缺失、编码器未正确初始化或原始数据异常导致。按上述步骤逐一排查,重点补全错误检查和修正编码器输入输出循环逻辑,即可解决问题。

内容的提问来源于stack exchange,提问作者CrIcKeT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:17:24