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

配置AVStream生成29.97FPS MKV时帧率显示异常,如何解决?

解决FFmpeg编码MKV时time_base被修改导致帧率显示异常的问题

MKV(Matroska)的muxer有个内置行为:它会自动调整视频流的time_base到1/1000(毫秒精度),这就是你设置的1001/30000会被avformat_write_header覆盖的原因。不过别担心,播放正常说明你的PTS转换逻辑是对的,只是播放器和媒体信息工具依赖的帧率参数没被正确设置而已。

这里有两个关键步骤可以解决显示问题:

1. 明确设置视频流的帧率参数

MKV muxer会忽略你设置的time_base来计算帧率,但它会尊重你显式设置的avg_frame_rate和r_frame_rate。对于NTSC的29.97fps,对应的帧率比例是30000/1001,直接把这两个参数加上:

AVStream *videoStream = avformat_new_stream(_formatContext, NULL);
if (!videoStream) {
    // 处理创建流失败的情况
}

// 核心:设置正确的NTSC帧率
videoStream->avg_frame_rate = (AVRational){30000, 1001};
videoStream->r_frame_rate = videoStream->avg_frame_rate;

2. 确保编码器上下文与流参数同步

在调用avcodec_parameters_from_context之前,先把编码器上下文的time_base设置为你需要的值,这样codecpar会同步这个信息(即使muxer后续修改stream的time_base,codecpar里的信息依然能辅助工具识别正确帧率):

// 先设置编码器上下文的time_base
_videoCodecContext->time_base = (AVRational){ (int)_frameDuration.value, (int)_frameDuration.timescale }; // 1001, 30000

// 再复制参数到流的codecpar
int err = avcodec_parameters_from_context(videoStream->codecpar, _videoCodecContext);
if (err < 0) {
    // 处理参数复制失败
}

修改后的完整代码片段

把这些调整整合到你的现有代码中:

AVOutputFormat *outputFormat = av_guess_format("matroska", NULL, NULL);
int err = avformat_alloc_output_context2(&_formatContext, outputFormat, NULL, filename);

// 设置编码器上下文的time_base
_videoCodecContext->time_base = (AVRational){ (int)_frameDuration.value, (int)_frameDuration.timescale }; // 1001, 30000

AVStream *videoStream = avformat_new_stream(_formatContext, NULL);
if (!videoStream) {
    // 错误处理逻辑
}

// 显式设置帧率参数
videoStream->avg_frame_rate = (AVRational){30000, 1001};
videoStream->r_frame_rate = videoStream->avg_frame_rate;

// 同步编码器参数到流
err = avcodec_parameters_from_context(videoStream->codecpar, _videoCodecContext);
if (err < 0) {
    // 错误处理逻辑
}

// 打开文件并写入头
err = avio_open(&_formatContext->pb, filename, AVIO_FLAG_WRITE);
if (err >= 0) {
    err = avformat_write_header(_formatContext, &options);
}

原理说明

  • MKV muxer调整time_base是为了兼容大部分播放设备,这个行为无法直接阻止(也没必要,因为不影响播放同步)。
  • avg_frame_rate是MKV规范中用于标识媒体帧率的关键字段,MediaInfo和VLC都会优先读取这个值来显示帧率,而不是通过time_base计算。
  • 你之前的av_packet_rescale_ts逻辑完全正确,只要基于最终stream的time_base来转换PTS,音视频同步就不会有问题。

这样修改后,VLC会显示正确的29.97fps,MediaInfo也会识别出标准的NTSC帧率,同时播放同步不受任何影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:45:18