ffmpeg命令分析-r

article/2025/11/10 21:52:39

本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8

之前的文章分析 FFMpeg 工程的 do_video_out() 函数的时候,建议不关注 delta0deltanb0_framesnb_frames 等变量。

因为在之前的命令没有用帧率变换参数,-r 。所以上面这些变量赋值,有跟没有是一样的。

现在来补一下之前缺失的内容。命令行指定 -r 之后,delta0deltanb0_framesnb_frames 的变化。

本文章主要讲解 FFMpeg 里面是如何实现帧率变换的,例如 24fps 是如何转成 8fps的,缩小了3倍的帧率。

./ffmpeg -i a.mp4 -r 8 output.flv 本文以此命令讲解,原始视频是24fps,转成 8fps。

a.mp4 下载链接:百度网盘 ,提取码:nl0s


如果没指定 -r ,就会从 buffersink 获取输出的帧率,帧率跟输入文件帧率一样,代码如下:

如果命令行指定了 -r ,就会用命令行参数赋值 给 ost->frame_rate。,代码如下:


上面是 命令行参数 -r 赋值给 ost->frame_rate。然后 ost->frame_rate 会作为时间基赋值给 编码器的time_base,见下图代码:


所以,综上所述,-r 最后主要影响的是 编码器的time_base,那编码器的time_base是怎么影响帧率变换的呢?请看下面。

在讲之前,需要普及一个知识点,请看下面代码

int a = av_rescale_q(1,  (AVRational){1, 24}, (AVRational){1, 12});
int b = av_rescale_q(2,  (AVRational){1, 24}, (AVRational){1, 12});

这里 a 跟 b 都是1,a不会是0.5。av_rescale_q() 返回的整数,所以精度丢失了。这也是为什么 reap_filtes() 内部会搞一个 float_pts 出来,这个float_pts 是有精度的。请看下图,编码器的time_base 的影响就在这里。

可以看到,上图代码把原始视频帧 的pts 的时间基转成 编码器的time_base了。这里是一个什么概念呢。

假如原始视频帧率是每秒24帧,他AVFrame的pts的时间基也是 {1,24}。那这时候这个 filtered_frame->pts 肯定是1,2,3,4 这样递增下去的。

把 filtered_frame->pts 转成编码器时间基 {1,8} 会怎样?

播放时间pts不变,1/24 = 0.041s ,第一帧在 0.041s 播放。然后 x/8 = 0.041,这个x等于多少呢?x = 0.333。

也就是说,第二帧的 filtered_frame->pts 原本是 1,时间基从 {1,24} 转成 {1,8} 之后,pts 从1 变成了 0.333。

类推,第三帧pts变成了 0.666,第四种变成0.999。

然后,这些跟帧率变换有什么关系?请继续看下面分析。

因为帧率变换涉及到好几个场景,这里只介绍 format_video_sync = VSYNC_VFR 的场景

接着分析,虽然上面说到,原始pts转换之后变成了 0.33,0.66 之类的小数。但是对于输入文件,对于编码器来说,编码器的帧率是 8fps,{1,8},传递给编码器的frame的pts,肯定也必须是 1,2,3,4 这样的整数递增的。这里实现这个功能的是 ost->sync_opts 变量。

要好好分析一下 ost->sync_opts 这个变量,这个变量的初始值是 0,每输入一个frame给编码器,ost->sync_opts 就会+1。

如上图所示,do_video_out() 的 in_picture 帧的pts会被 ost->sync_opts 替换,达到 输入给编码器的frame pts 都是 1,2,3,递增的目的。

接下来继续讲,上面那些0.33,0.66小数是用来干嘛的?其实这些小数就是用来丢帧,实现帧率缩小的功能,或者重复上一帧,实现帧率变大功能。

如下图所示,nb0_frames 这个变量不用管,在format_video_sync = VSYNC_VFR 的场景 下,nb0_frames 总是0。

第一帧全是0,看不出上面的逻辑,直接从第二帧开始分析。第二帧 do_video_out() 传递的 sync_ipts 是0.333。但是此时 sync_opts 是 1。

大家可以仔细琢磨一下那句英文注释,老外写注释都比较简洁。

delta0 is the "drift" between the input frame (next_picture) and where it would fall in the output.

delta0 = 0.333 - 1 = -0.666,delta0 代表当前输入帧与输出给编码器的时间差距,在第二帧的时候,时间差是 0.666。解析到这里,应该有点眉目,缩小帧率,肯定要根据时间差距来丢弃某些帧。

说实话,他这个算法有点复杂,我也不太明白他为什么不 sync_ipts < sync_opts 就直接丢弃,这样不是更简单?这个问题先不纠结,接着分析ffmpeg 是如何用delta0 ,delta 实现丢帧的。补充:直接 sync_ipts < sync_opts 不行,会出错。

这个算法涉及到不同刻度表的转换,用两个刻度表来解释这个算法会更明白。

delta0 = sync_ipts - ost->sync_opts; 
delta  = sync_ipts - ost->sync_opts + duration;

可以看到,因为 ost->sync_opts 每次都会 +1 地递增,而 sync_ipts 每次只能 +0.3 递增。所以delta会负得越来越大,duration是固定是 0.33。所以delta也会负得越来越大,然后 delta <= -0.6 就会把 nb_frames 置为 0 ,导致后面的for循环没执行,实现丢帧。至于为什么是0.6我也不知道。实在没想好怎么表达他这个算法逻辑,反正代码逻辑它就是这么跑的,delta越来越大,就丢帧。丢帧后,ost->sync_opts 不会+1,sync_ipts 就会慢慢赶上 sync_opts

case VSYNC_VFR:if (delta <= -0.6){//丢弃 framenb_frames = 0;}else if (delta > 0.6)ost->sync_opts = lrint(sync_ipts);break;

实际丢帧情况如下。

0 0.33 0.66(x) 1(x) 1.33 1.66(x) 2(x) 2.33 2.66(x) 3(x)

只有 .33 后缀的帧才会保留,确实是缩小了3倍帧率。

实际上,他这个算法应该是一个数学公式,sync_ipts + duration + 60% 刻度 > sync_opts,如果大于 sync_opts就可以 输出给解码器,小于就丢弃。这里的刻度是1,所以60%刻度是0.6。sync_ipts + duration 是因为只要这个frame的区间跨过 sync_opts 刻度,哪怕跨过一点点,都可以输出。


如果不改变帧率,sync_opts 跟 sync_ipts 是同步+1的,duration也是1,然后 delta0 一直是一个非常小的接近0的数字,delta 一直是接近1的数字。

所以不改变帧率,delta0 跟delta 这些变量是没有作用的。


接下来继续分析 帧率放大算法是如何实现的。

把 帧率 {1,24} 转成 {1,48},实际上就是把 pts 乘以 2 。

注意,有些MP4 是 VSYNC_CFR,有些是 VSYNC_VFR。

CFR 的帧率翻倍,会插入新帧,文件大小也会翻倍。

VFR 的帧率翻倍,不会插入新帧,文件大小不变。

 case VSYNC_CFR:// FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.cif (frame_drop_threshold && delta < frame_drop_threshold && ost->frame_number) {nb_frames = 0;} else if (delta < -1.1)nb_frames = 0;else if (delta > 1.1) {nb_frames = lrintf(delta);if (delta0 > 1.1)nb0_frames = lrintf(delta0 - 0.6);}break;
case VSYNC_VFR:if (delta <= -0.6){//丢弃 framenb_frames = 0;}else if (delta > 0.6)ost->sync_opts = lrint(sync_ipts);break;

实际上,我个人认为,命令行 参数 -r 在 ffmpeg.c 里面的实现是一个历史遗留问题,这种实现在 ffmpeg.c 里面暴露了太多的复杂性,实际上新版本的ffmpeg,例如 4.4 版本,已经有 fpsframerate 两个新的滤镜来实现帧率转换。

所以,调 API 函数实现帧率转换,推荐使用 fpsframerate 滤镜,就没有这么多 delta 变量之类的。


由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。


http://chatgpt.dhexx.cn/article/SWoqORiq.shtml

相关文章

使用FFmpeg命令处理音视频

文章目录 前言一、ffprobe相关命令1.使用ffprobe查看音频文件的信息2.使用ffprobe查看视频文件的信息 二、ffplay相关命令1.基本的ffplay命令2.音视频同步命令 三、ffmpeg相关命令1.ffmpeg通用参数2.ffmpeg视频参数3.ffmpeg音频参数4.ffmpeg示例 总结 前言 FFmpeg是一套可以用…

ffmpeg-命令行详解

前言 ffmpeg是一个多媒体开发库&#xff0c;提供了关于音频和视频的工具。这个项目的官网是这里。 下载地址 ffmpeg提供了方便地控制台命令&#xff0c;可以在下载页面下载。三个平台&#xff08;windows&#xff0c;linux&#xff0c;macos&#xff09;都有打包好的可执行文…

ffmpeg命令分析-b:v

本系列 以 ffmpeg4.2 源码为准&#xff0c;下载地址&#xff1a;链接&#xff1a;百度网盘 提取码&#xff1a;g3k8 本系列主要分析各种 ffmpeg 命令参数 在代码里是如何实现的。a.mp4下载链接&#xff1a;百度网盘&#xff0c;提取码&#xff1a;nl0s 。 命令如下&#xff1a;…

FFmpeg命令详解

命令格式 功能 FFmpeg命令是在ffmpeg.exe可执行文件环境下执行&#xff0c;ffmpeg.exe用于音视频的转码&#xff0c;加水印&#xff0c;去水印&#xff0c;视频剪切&#xff0c;提取音频&#xff0c;提取视频&#xff0c;码率控制等等功能。 最简单的命令 ffmpeg -i input.a…

FFmpeg命令行转码

本文主要了解FFmpeg进行音视频编码转换。主要学习如下几个知识点&#xff1a; FFmpeg使用libx264进行H,264(AVC)软编码&#xff0c;使用libx265进行H.265(HEVC)软编码使用FFmpeg在MacOS环境下硬编码了解音频编码&#xff0c;MP3&#xff0c;AAC的参数设置编码 FFmpeg软编码H.…

ffmpeg命令行使用

查看视频信息 ffmpeg -i 视频名字视频名字这里输入前几个字符按 tab 键可以自动补全 返回结果&#xff1a; 红框之内的内容没什么用 编码器 &#xff1a;encoder : Lavf57.25.100 持续时间&#xff1a;Duration: 00:14:20.58, start: 0.000000, bitrate: 381 kb/s Duratio…

ffmpeg录屏命令

1.gdigrab抓屏 ffmpeg -f gdigrab -i desktop -q:v 0.01 -vcodec mpeg4 -f mp4 out.mp4-i 输入设备 -vcodec 视频编码格式 -f 视频封装格式 缺点只能录制视频&#xff0c;不能录制音频 2.dshow 下载安装screen capture recorder https://sourceforge.net/projects/screencap…

FFMPEG常用命令行

目录 命令格式&#xff1a; 1.获取视频信息 2.转视频/音频格式 视频格式转换 音频格式转换 3.音视频分离 4.图像处理 5.视频旋转 6.视频倒放&视频加速&视频减速 7.视频合并&#xff08;两个10秒的视频合并为20秒&#xff09;&#xff1a; 8.视频拼接&…

FFmpeg命令介绍

FFmpeg 简介轶闻常用命令视频相关音频相关录制命令 简介 FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。使用C语言进行开发&#xff0c;采用LGPL或GPL许可证&#xff0c;可前往Github下载其源码。它提供了录制、转换以及流化音…

ffmpeg命令大全

ffmpeg命令大全 FFMPEG 目录及作用FFMPEG基本概念FFMPEG 命令基本信息查询命令主要参数视频参数音频参数录制录屏 分解与复用滤镜简单滤镜复杂滤镜 直播相关 前言 FFMPEG是特别强大的专门用于处理音视频的开源库。你既可以使用它的API对音视频进行处理&#xff0c;也可以使用它…

音视频ffmpeg——ffmpeg 命令大全

ffmpeg 命令参数 ffmpeg信息查询命令 ffmpeg 控制命令 主要参数&#xff1a; ◼ -i 设定输入流 ◼ -f 设定输出格式(format) ◼ -ss 开始时间 ◼ -t 时间长度 音频参数&#xff1a; ◼ -aframes 设置要输出的音频帧数 ◼ -b:a 音频码率 ◼ -ar 设定采样率 ◼ -ac 设定…

常见FFmpeg命令行全面分析

FFmpeg多媒体库支持的命令行调用分为三个模块&#xff1a;ffmpeg、ffprobe、ffplay。其中ffmpeg命令行常用于音视频剪切、转码、滤镜、拼接、混音、截图等&#xff1b;ffprobe用于检测多媒体流格式&#xff1b;ffplay用于播放视频。详情可查阅FFmpeg官方文档&#xff1a;ffmpeg…

ffmpeg 常用命令汇总

​​​​​​经常用到ffmpeg做一些视频数据的处理转换等&#xff0c;用来做测试&#xff0c;今天总结了一下&#xff0c;参考了网上部分朋友的经验&#xff0c;一起在这里汇总了一下。 1、ffmpeg使用语法 命令格式&#xff1a; ffmpeg -i [输入文件名] [参数选项] -f [格…

FFmpeg常用基本命令行

本文收集记录了笔者使用过的FFmpeg命令&#xff0c;亲测可用&#xff0c;并不是简单的copy别人的FFmpeg大全&#xff0c;下面的命令大部分都是本人测试成功过的&#xff0c;大家可以放心使用。 音视频技术是程序员日常生活中经常用到的&#xff0c;比如转码需求&#xff0c;同事…

Eclipse启动Tomcat逐渐变慢

现象 1、Eclipse用着用着发现启动Tomcat特别慢 原因 断点打多了&#xff0c;之前调试的断点没有取消&#xff0c;导致启动时加载断点&#xff0c;拖慢启动 解决方案 1、点击debug按钮 2、选择breakpoint选项 清空所有断点 3、重新启动

eclipse 解决启动慢、运行慢的方法总结(最全)

由于 CSDN 的目录只在固定地方显示&#xff0c;并不是很方便阅读&#xff0c;又占空间&#xff0c;所以本文章已同步更新到个人博客上&#xff0c;在个人博客上的文章&#xff0c;有滑动侧边目录栏&#xff0c;阅读体验更加&#xff0c;而且文章的样式也更为丰富&#xff0c;推…

eclipse卡慢解决办法

1.设置JVM运行内存 1.1编辑eclipse.ini 1.2 编辑eclipse.ini,设置jvm运行内存参数&#xff0c;最小内存&#xff1a;物理内存*0.2&#xff0c; 最大内存&#xff1a; 物理内存*0.6&#xff1b; 其中-vmargs为必须添加参数&#xff08;-vmargs的意思是设置JVM参数&#xff09;,…

eclipse启动很慢调优

前几天装了个eclipse,发现真的启动很慢&#xff0c;而且运行程序也慢&#xff0c;检查了不是网络问题&#xff0c;jsp修改一下&#xff0c;一保存就卡死&#xff0c;要等十几秒&#xff0c;感觉不能忍&#xff0c;所以就上网找资料&#xff0c;但是都不全面&#xff0c;小编接下…

Eclipse 解决启动慢

般在不对eclipse进行相关设置的时候&#xff0c;使用eclipse总是会觉得启动好慢&#xff0c;用起来好卡&#xff0c;其实只要对eclipse的相关参数进行一些配置&#xff0c;就会有很大的改善。 加快启动速度 1.在eclipse启动的时候&#xff0c;它总是会搜索让其运行的jre&…

Eclipse如何解决启动慢

一般在不对eclipse进行相关设置的时候&#xff0c;使用eclipse总是会觉得启动好慢&#xff0c;用起来好卡&#xff0c;其实只要对eclipse的相关参数进行一些配置&#xff0c;就会有很大的改善。 加快启动速度 1.在eclipse启动的时候&#xff0c;它总是会搜索让其运行的jre&a…