fft基频_ffmpeg命令大全

fft基频_ffmpeg命令大全关于FFmpeg的四种时基和时基相关函数的分析及其场景用法前言:AVRational类型:是一个分数

fft基频_ffmpeg命令大全"

12关于FFmpeg的四种时基和时基相关函数的分析及其场景用法

前言:
AVRational类型:是一个分数。例如{1,25}表示1除以25即1/25。
时基:时间的单位,在ffmpeg下被描述成时基。
时间戳:某个时刻的时间。

1 FFmpeg的四种时基
抛开解码器上下文的时基即stream->codec->time_base(因为编码时基本不用,所以我这里不讲它,它也叫tbc,称之为流中的时基)。我们FFmpeg实际上编码经常使用的时基有四种:

  • 1)输入流封装上下文的时基,也叫容器的时基,即AVFormatCtx->stream->time_base。
  • 2)输出流封装上下文的时基,也叫容器的时基,即AVFormatCtx->stream->time_base。(注意:编码时输入输出各有一个封装上下文,当然也有可能没有输入流的封装上下文,但是这里为了分析四种时基特意不考虑)
  • 3)我们人类实际的时基,也就是以秒为单位。
  • 4)FFmpeg的内部时基AV_TIME_BASE,百万,故单位为微妙。

解释:
1)输入流封装上下文的时基
例如flv为1000,ts的输入流为90k。

2)输出流封装上下文的时基
这个是我们想要输出时的容器格式的时基,同上面输入一样,如果你想输出flv格式的,那么时基为1000,想输出ts格式的那么时基为90k。

3)人类实际的时基
没什么好讲的,就是转来给人类看的。

4)内部时基AV_TIME_BASE
定义如下:

#define AV_TIME_BASE 1000000 //百万,故单位为微妙
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE} //上面倒数

我这里为什么将FFmpeg的时基列为四种呢?
主要是我们在编码的时候使用的时基只有下面四种。
何为转时基转时基就是将输入容器中以输入容器时基为单位的时间戳,转换成输出容器中的以输出容器时基为单位的时间戳。
例如输入容器的时间戳为80,时基为1000,想要输出成ts格式的流,那么由于输入输出帧率是要一样的,所以1000/80=90000/x得出x=7200(实际上我下一篇关于推流时pts的运算步骤也讲到)。
有人会想不懂为什么时基/时间戳=帧率,例如1s下帧率为25那么每帧时间戳为0.04,那么时基1除以时间戳0.04=帧率25。
所以这里我们编码时已经用到了两种时基。

那么还有两种为什么要包含进来呢?
因为另外两种时基在转时基时非常常用,例如人类的实际时间经常依靠帧率运算出每帧显示的时长,而FFmpeg的内部时基被用于转换人类实际的时长,当然你也可以不转,但是转了能更精确表示,但需要舍弃小数,难度相对大点。

例如ffmpeg内部时基与人类标准的时间转换方法:

timestamp(ffmpeg内部的时间戳) = AV_TIME_BASE * time()//乘以一百万即获取到微秒单位的内部时间戳,人为认为它是微秒单位
time() = AV_TIME_BASE_Q * timestamp(ffmpeg内部的时间戳)//上面公式转换得出。即对应除以一百万即可得出原来的标准秒数。

2 与时基转换相关的函数
1)av_q2d函数。

/* * 作用:下面看到,该函数非常简单,只是将传入的AVRational类型转为double类型返回。 */
static inline double av_q2d(AVRational a){ 
   
    return a.num / (double) a.den;
}

但是该函数的用于主要是将某个时基转成doule(可以有小数保留,更加精确),以作计算。
例如将标准时间戳转为内部时间的做法是标准时间乘以对应时基,那么下面利用该函数同样也可以做到。

packet播放时刻值:timestamp(单位秒) = packet.pts × av_q2d(stream.time_base);//除法通常是变大单位,例如stream.time_base={1,1000}那么pts*(1/1000)即pts/25变成大单位time_base。注意:stream.time_base是容器的时基tbn,而stream->codec->time_base是编解码器的时基即tbc
packet播放时长值:duration(单位秒) = packet.duration × av_q2d(stream.time_base);

//实际上上面内部时间戳与标准时间戳的转换也可以写成(并且通常这样做):
timestamp(ffmpeg内部的时间戳) = av_q2d({ 
   AV_TIME_BASE,1}) * time() //乘以一百万
time() = av_q2d(AV_TIME_BASE_Q) * timestamp(ffmpeg内部的时间戳)	//除以一百万

该函数可以使平常的秒按照自己的算法转换成一定的时间戳表示。
注意下面,不能简单的认为是秒转成time_base然后再转成微秒AV_TIME_BASE,毕竟若是秒转成time_base按照上面内部时基的转法,需要在此之前乘以time_base,这里是直接转了,所以我们这里可以认为是一种自定义运算方法。实际上这里也是雷神博主的做法:

int64_t pts = sec / av_q2d(ifmt_ctx->streams[videoindex]->time_base)*AV_TIME_BASE;

2)av_rescale_q函数
作用是将时间戳从一个时基转到另一个时基。常用于将输入容器的时基转成输出容器的时基。例如:
注意:in_stream->time_base,out_stream->time_base在我这里指的是容器的时基(但是很多人也叫视频流的时基,所以很容易歧义),stream->codec->time_base指的是编解码器上下文的时基。

pkt.pts = av_rescale_q(pkt.pts, in_stream->time_base, out_stream->time_base);
pkt.dts = av_rescale_q(pkt.dts, in_stream->time_base, out_stream->time_base);
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);

3)av_rescale_q_rnd函数
这个函数实际上和上面的av_rescale_q函数一样,但是多了一个参数4可以四舍五入小数,对于FFmpeg的pts需要比较精确,这个函数确实是不错的选择,但是要求比较高,该参数设置需要按照不同视频设置去设置,否则容易报错。
例如:

pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

好了,关于时基和其相关函数的讲述差不多了,下一篇我们将讲到使用FFmpeg编码推流时,pts的计算步骤,和运用这些时基及其相关函数理解,因为pts的计算实际上并无固定的算法,你的视频流畅你就是牛逼。
pts的计算有两种可能,一是没有输入流的封装上下文的计算(即没有相关属性,需要自己初始化一些内容),只有输出流的封装上下文;二是有输入流和输出流的封装上下文的计算。但两种的计算步骤是差不多的,只不过内部处理方式有点区别。

今天的文章fft基频_ffmpeg命令大全分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/82892.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注