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。
#define AV_TIME_BASE //百万,故单位为微妙 #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; }
讯享网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内部的时间戳) //除以一百万
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));

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