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

如何通过FFmpeg C API提取MP4/TS解码时的重复或丢帧数量?

能否通过FFmpeg C API提取解码时的重复/丢弃帧数量?

可以,FFmpeg的C API提供了对应的机制来统计解码.mp4或.ts文件过程中重复或丢弃的视频帧数量,逻辑和命令行工具的统计逻辑一致。

核心实现思路

  • 统计重复帧:重点关注AVFrame结构体的repeat_pict字段,该字段表示当前帧需要重复显示的次数,每出现一次就累加对应数值即可统计重复帧总量;另外也可以通过对比连续帧的显示时间戳(pts),若前后帧pts相同,也可判定为重复帧。
  • 统计丢弃帧:可以通过两种方式统计,一是监听解码过程中的错误返回(比如avcodec_receive_frame()返回错误时,对应帧可能被丢弃);二是直接读取AVCodecContext中的frame_drops_early和frame_drops_late字段,这两个字段分别记录了解码器在早期和晚期自动丢弃的帧数量,能更精准统计解码器内部丢弃的帧。

关键代码示例

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <stdio.h>

int main() {
    AVFormatContext *fmt_ctx = NULL;
    AVCodecContext *codec_ctx = NULL;
    AVCodec *codec = NULL;
    AVPacket pkt;
    AVFrame *frame = NULL;
    int video_stream_idx = -1;
    int repeat_frame_count = 0;
    int drop_frame_count = 0;
    int ret;

    // 初始化格式上下文并打开输入文件
    if (avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL) != 0) {
        fprintf(stderr, "无法打开输入文件\n");
        return -1;
    }
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "无法获取流信息\n");
        return -1;
    }

    // 定位视频流并初始化解码器
    for (int i = 0; i < fmt_ctx->nb_streams; i++) {
        if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_idx = i;
            codec = avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id);
            if (!codec) {
                fprintf(stderr, "找不到对应的解码器\n");
                return -1;
            }
            codec_ctx = avcodec_alloc_context3(codec);
            avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[i]->codecpar);
            if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
                fprintf(stderr, "无法打开解码器\n");
                return -1;
            }
            break;
        }
    }
    if (video_stream_idx == -1) {
        fprintf(stderr, "未找到视频流\n");
        return -1;
    }

    frame = av_frame_alloc();
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index != video_stream_idx) {
            av_packet_unref(&pkt);
            continue;
        }

        ret = avcodec_send_packet(codec_ctx, &pkt);
        while (ret >= 0) {
            ret = avcodec_receive_frame(codec_ctx, frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                break;
            } else if (ret < 0) {
                // 解码错误,计数丢弃帧
                drop_frame_count++;
                break;
            }

            // 统计重复帧
            if (frame->repeat_pict > 0) {
                repeat_frame_count += frame->repeat_pict;
            }

            av_frame_unref(frame);
        }
        av_packet_unref(&pkt);
    }

    // 补充解码器内部自动丢弃的帧统计
    drop_frame_count += codec_ctx->frame_drops_early + codec_ctx->frame_drops_late;

    printf("重复帧总数:%d\n", repeat_frame_count);
    printf("丢弃帧总数:%d\n", drop_frame_count);

    // 释放资源
    av_frame_free(&frame);
    avcodec_close(codec_ctx);
    avformat_close_input(&fmt_ctx);
    return 0;
}

补充说明

  • repeat_pict字段的数值对应帧需要重复显示的次数,比如值为1表示当前帧要多显示一次,直接累加即可得到重复帧的总次数。
  • frame_drops_early和frame_drops_late是FFmpeg解码器内部维护的统计字段,分别对应解码前和解码后丢弃的帧,能覆盖命令行工具统计的丢弃帧场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:40:15