如何通过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
相关产品推荐
相关产品推荐

