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

使用libav编码生成H264 MP4文件时帧率异常过高问题求助

问题原因与修复方案

核心原因

你遇到的帧率异常问题根源是时间基不匹配:

  1. 编码器输出的AVPacket的时间戳使用的是你给AVCodecContext设置的1/60时间基,单位是1/60秒。
  2. MP4封装器会在调用avformat_write_header时自动调整AVStream的时间基以适配MP4格式规范,你ffprobe输出的tbn=15360就是调整后的流时间基分母,单位是1/15360秒。
  3. 你没有对Packet的时间戳做转换就直接写入容器,原本每帧间隔对应1/60秒,被封装器误判为1/15360秒,最终帧率就变成了15360fps,和你的测试结果完全吻合。

另外你的编码循环逻辑不符合libav编码规范,以及未指定Packet的stream_index,也会提升异常概率。

修复步骤

1. 修正编码循环逻辑,增加时间基转换

每次从编码器拿到Packet后,先调用av_packet_rescale_ts做时间基转换,指定stream_index后再写入容器。

2. 修正YUV分量行宽

YUV420P格式的U、V分量宽高是Y分量的一半,所以linesize[1]和linesize[2]应该设为960,避免色彩异常。

修正后的核心代码片段

// ... 原有初始化代码不变 ...

avio_open(&avfc->pb, filename, AVIO_FLAG_WRITE);
avformat_write_header(avfc, NULL);

Mat frame, nothing_u = Mat::zeros(540, 960, CV_8UC1);
Mat nothing_v = Mat::zeros(540, 960, CV_8UC1);
AVFrame *avf = av_frame_alloc();
AVPacket *avp = av_packet_alloc();
int ret;

avf->format = AV_PIX_FMT_YUV420P;
avf->width = 1920;
avf->height = 1080;
avf->linesize[0] = 1920;
avf->linesize[1] = 960;
avf->linesize[2] = 960;

for(int x=0; x<1000; x++) {
    frame = Mat::zeros(1080, 1920, CV_8UC1);
    circle(frame, Point(1920/2, 1080/2), 250*(sin(2*M_PI*x/1000*3)+1.01), Scalar(255), 10);
    
    avf->data[0] = frame.data;
    avf->data[1] = nothing_u.data;
    avf->data[2] = nothing_v.data;
    avf->pts = x;

    // 标准编码流程:先发帧,再循环收包
    ret = avcodec_send_frame(avcc, avf);
    if (ret < 0) break;

    while (ret >= 0) {
        ret = avcodec_receive_packet(avcc, avp);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;
        else if (ret < 0) goto clean;

        // 关键:转换时间基,指定流索引
        av_packet_rescale_ts(avp, avcc->time_base, stream->time_base);
        avp->stream_index = stream->index;
        av_write_frame(avfc, avp);
        av_packet_unref(avp);
    }
}

// 刷新编码器缓存
ret = avcodec_send_frame(avcc, NULL);
while (ret >= 0) {
    ret = avcodec_receive_packet(avcc, avp);
    if (ret == AVERROR_EOF) break;
    else if (ret < 0) break;

    av_packet_rescale_ts(avp, avcc->time_base, stream->time_base);
    avp->stream_index = stream->index;
    av_write_frame(avfc, avp);
    av_packet_unref(avp);
}

clean:
// ... 原有释放资源代码不变 ...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 23:24:03