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

使用libav解码统计视频帧数与ffprobe结果差2帧的问题排查

FFmpeg解码视频流帧数统计比ffprobe少2帧问题排查

问题现象

出于学习目的编写可解码指定媒体容器内每个流所有帧的程序时,发现视频流统计帧数与ffprobe计算结果存在固定差值,音频流计数完全一致:

  • 测试样本1(sample-10s.mp4):程序统计301个视频帧、440个音频帧;ffprobe统计303个视频帧、440个音频帧
  • 测试样本2(production ID_3997798.mp4):程序统计736个视频帧、无音频帧;ffprobe统计738个视频帧、无音频帧

所有测试样本均表现为视频流帧数少2帧。

使用的ffprobe统计命令如下(统计音频流时将v:0替换为a:0即可):

ffprobe <media file> -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames

原核心解码逻辑如下:

// 初始化格式上下文、打开文件、查找流信息代码省略
for(uint uiSt=0;uiSt<fcFormatCtx->nb_streams;uiSt++) {
    // 初始化解码器、打开解码器代码省略
    av_seek_frame(fcFormatCtx,uiSt,0,AVSEEK_FLAG_FRAME);
    while(0==av_read_frame(fcFormatCtx,pkPacket)) {
        if(uiSt==pkPacket->stream_index) {
            avcodec_send_packet(ccCodecCtx,pkPacket);
            // 收帧、计数逻辑省略
        }
        av_packet_unref(pkPacket);
    }
    // 释放资源代码省略
}

问题根因

代码存在两个核心逻辑漏洞,刚好导致固定少2帧:

  • seek操作清空了流探测阶段的缓存包
    调用avformat_find_stream_info()时,FFmpeg为了获取流的编码格式、帧率、时长等元信息,会提前读取文件开头的若干个数据包,缓存在AVFormatContext内部。正常顺序读取时,这些缓存包会优先被av_read_frame()返回,不会丢失。但你在处理每个流前调用av_seek_frame(),seek操作会直接清空这部分内部缓存,导致开头被用于探测的2个视频数据包被直接丢弃,永远不会送入解码器,这是少2帧的主要原因。
  • 未在解码结束后flush解码器缓存
    带B帧的视频编码(H.264/H.265等)存在解码顺序和显示顺序不一致的问题,解码器内部会缓存若干帧,等后续参考帧到达后再输出。你在读完所有数据包后,没有发送空包触发解码器进入flush模式,解码器内部缓存的尾部帧无法被取出,也会造成帧数统计偏少。

另外逐流seek重读的实现本身效率极低,也容易因为封装格式的seek精度问题导致丢帧、重复帧,ffprobe做-count_frames统计时从来不会逐流seek重读。

修正方法

  • 删掉逐流处理前的av_seek_frame()调用,不要反复跳回文件开头重读。
  • 调整处理流程:在遍历流初始化阶段,为每个流都创建好对应的解码器上下文、帧计数器;之后只跑一次av_read_frame()循环,顺序读取全文件所有数据包,根据包的stream_index送到对应流的解码器解码、计数。
  • 当av_read_frame()返回AVERROR_EOF(所有数据包读完)后,给每一个流的解码器都传入空packet(调用avcodec_send_packet(ccCodecCtx, NULL))触发flush模式,循环调用avcodec_receive_frame()读取解码器缓存的所有剩余帧,直到返回AVERROR_EOF,将这部分帧也计入统计值。
  • 如果确实需要单独处理单个流、必须使用seek,注意seek后要调用avformat_flush(fcFormatCtx)清空demuxer旧缓存,调用avcodec_flush_buffers(ccCodecCtx)重置解码器状态;读包时丢弃所有pts小于seek目标位置的无效包;所有包送完后同样要执行flush操作取出剩余缓存帧。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 02:39:16