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

调用avformat_write_header后流time_base被修改,高帧率帧丢失如何解决?

问题分析与解决方案

原因分析

Matroska(MKV)复用器默认会根据视频流帧率自动调整time_base,目的是避免时间戳数值过大。当你的帧率达到2000fps时,单帧间隔仅500微秒,而复用器默认选择的毫秒级{1,1000} time_base无法区分相邻帧的时间戳(500微秒在毫秒精度下会被截断为0),导致连续帧的pts值相同,后续提取工具会将这些帧判定为重复帧而丢弃。

另外,仅手动设置AVStream和AVCodecContext的time_base并不足够——复用器在avformat_write_header阶段会根据自身逻辑覆盖这些设置,尤其是当它认为指定的time_base精度超出容器“需求”时。


解决方法

1. 强制Matroska复用器使用微秒级time_base

在调用avformat_write_header之前,通过AVOptions强制锁定流的time_base,阻止复用器自动调整:

// 创建输出流后,先设置基础time_base
AVStream* stream = avformat_new_stream(avFormatContext, codec);
stream->time_base = (AVRational){1, 1000000};
stream->codecpar->time_base = stream->time_base;

// 强制复用器保留指定的time_base参数
av_opt_set_int(stream, "time_base_num", 1, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(stream, "time_base_den", 1000000, AV_OPT_SEARCH_CHILDREN);

2. 对齐编码器与容器的时间戳规则

设置AVCodecContext的time_base为微秒级,同时将帧的pts直接赋值为实际捕获的微秒时间戳(无需额外转换):

AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
codecCtx->time_base = (AVRational){1, 1000000};
codecCtx->framerate = (AVRational){2000, 1}; // 明确声明帧率,辅助复用器识别

// 给捕获帧设置微秒级时间戳
frame->pts = capture_timestamp_us; // capture_timestamp_us为实际捕获的微秒数

3. 禁用复用器的自动格式转换

如果上述方法仍无效,可添加全局选项禁止复用器自动调整时间戳和格式:

av_opt_set(avFormatContext, "auto_convert", "0", AV_OPT_SEARCH_CHILDREN);
av_opt_set(avFormatContext, "avoid_negative_ts", "make_non_negative", AV_OPT_SEARCH_CHILDREN);

4. 验证结果

编码完成后,可用ffprobe工具验证流参数和帧时间戳:

ffprobe -v error -select_streams v:0 -show_entries stream=time_base,avg_frame_rate -show_entries frame=pts,pkt_pts_time -of csv=p=0 input.mkv

确认输出的time_base为1/1000000,且相邻帧的pkt_pts_time间隔为0.0005秒(500微秒)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:32:24